mirror of
https://github.com/NEZNAMY/TAB.git
synced 2026-11-12 20:22:01 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a7a105e7b | ||
|
|
f54d024d97 | ||
|
|
94338bd53f | ||
|
|
1a9ecc0313 | ||
|
|
4baeb7b945 | ||
|
|
baee479fb5 | ||
|
|
5ad4b2e9c4 | ||
|
|
26657cddfc | ||
|
|
947a922f8c | ||
|
|
a2be76184e | ||
|
|
8ddb733dc3 | ||
|
|
94e016129b | ||
|
|
5e653ded5d | ||
|
|
1bf8097c3f | ||
|
|
3d2f11ffd2 | ||
|
|
5e77a22d7a | ||
|
|
1dffcb1dc3 | ||
|
|
edc18cbafb | ||
|
|
2f23194432 | ||
|
|
20709472be | ||
|
|
7a8c6a0cec | ||
|
|
88558e40a7 | ||
|
|
79386b2b6b | ||
|
|
3aad8d3cb5 | ||
|
|
272a6f37ad | ||
|
|
e10081025d | ||
|
|
e03a6d8f11 | ||
|
|
98e7dc0321 | ||
|
|
74438c5d74 | ||
|
|
0c4e548565 | ||
|
|
cc70e01e96 | ||
|
|
7c635748af | ||
|
|
0c874ad56d | ||
|
|
2fb7f80b71 | ||
|
|
3f7c3414ce | ||
|
|
97165db44d | ||
|
|
82cdf04cf0 | ||
|
|
171d899609 | ||
|
|
6432278d5d | ||
|
|
ccaff12451 | ||
|
|
11347c080b | ||
|
|
553676c3f9 | ||
|
|
40b70e7418 | ||
|
|
0ea75019ae | ||
|
|
dbc092df77 | ||
|
|
68049f0dca | ||
|
|
9db5dfc175 | ||
|
|
039a316b3b | ||
|
|
f4b529f1ce | ||
|
|
9c6d606103 | ||
|
|
6cdc06aae7 | ||
|
|
2684654e7b | ||
|
|
25bcc33204 | ||
|
|
e5b3f6215b | ||
|
|
9306eadd90 | ||
|
|
a27fbb5b8b | ||
|
|
cd4c82b0b8 | ||
|
|
aa6179ee9e | ||
|
|
6594b8c2dc | ||
|
|
d4c2cdf003 | ||
|
|
2b529c37f5 | ||
|
|
8599cd925b | ||
|
|
89f37b4b9e | ||
|
|
f3136e85ee | ||
|
|
845743073c | ||
|
|
b2c7bacaf9 | ||
|
|
ed1673f032 | ||
|
|
bac9d443ea | ||
|
|
90e3868c08 | ||
|
|
c428572e01 | ||
|
|
884b5755ec | ||
|
|
32d7366795 | ||
|
|
21bf4a5450 | ||
|
|
8042b02cf5 | ||
|
|
ae7cdd3982 | ||
|
|
9ba945ad76 | ||
|
|
9cd04c3660 | ||
|
|
444bc19781 | ||
|
|
eb08c4ba04 | ||
|
|
5846e24a29 | ||
|
|
9c2c09e433 | ||
|
|
3c4329697b | ||
|
|
af9951d993 | ||
|
|
630f6df2f5 | ||
|
|
fcf07b8e7b | ||
|
|
4824c2f626 | ||
|
|
2b6b2e1b63 | ||
|
|
6926c1e57f | ||
|
|
6a00a7f1ca | ||
|
|
288c3d4c87 | ||
|
|
ac497bcc41 | ||
|
|
7b8d0d6845 | ||
|
|
a9a4589fae | ||
|
|
b8f972a774 | ||
|
|
305e388478 | ||
|
|
97e7848a78 | ||
|
|
d33058a924 | ||
|
|
eda3cc1f17 | ||
|
|
47043ad4ad | ||
|
|
acf20088cc | ||
|
|
374cb2766c | ||
|
|
31685b9ba5 | ||
|
|
722ff4ce52 | ||
|
|
161b375043 | ||
|
|
2c14191cde | ||
|
|
486546918f | ||
|
|
23d08e58a4 | ||
|
|
4c4c34ecaa | ||
|
|
bd3f2fd70a | ||
|
|
b80e42a635 | ||
|
|
9446a034d0 | ||
|
|
da0c6ab3fd | ||
|
|
c1adb27ee5 | ||
|
|
980d3027e3 | ||
|
|
53ba533f9b | ||
|
|
e40827da65 | ||
|
|
b9848b6a96 | ||
|
|
147593b11a | ||
|
|
21652f928b | ||
|
|
5b0352aff0 | ||
|
|
b2da2fa096 | ||
|
|
0cbb01a2a8 | ||
|
|
179840968d | ||
|
|
3b9c1649a1 | ||
|
|
5750c7dbe1 | ||
|
|
7ceca359be | ||
|
|
0f8152a6ed | ||
|
|
b3258bb020 | ||
|
|
4b2e705cbc | ||
|
|
31e41382f8 | ||
|
|
ecda7192dc | ||
|
|
9a48562b9f | ||
|
|
c181b58bc1 | ||
|
|
2624afa2ed | ||
|
|
3690af1e35 | ||
|
|
98966d3b38 | ||
|
|
41fdd16ce1 | ||
|
|
1bc94859c0 | ||
|
|
60f6f36437 | ||
|
|
82267ba16a | ||
|
|
14260deef8 | ||
|
|
8ba7342ccf | ||
|
|
f6b935d78e | ||
|
|
8cf3ae2091 | ||
|
|
e02b997521 | ||
|
|
229cef13c9 | ||
|
|
f503d6f896 | ||
|
|
d851166bb7 | ||
|
|
638a861350 | ||
|
|
20d7e4cbb0 | ||
|
|
36ccedd7c6 | ||
|
|
31854ba7a6 | ||
|
|
2639f07f5c | ||
|
|
b6e13f557f | ||
|
|
6333d90059 | ||
|
|
fea5d0ec56 | ||
|
|
c77f02d1fd | ||
|
|
c498965cae | ||
|
|
cdaa77071d | ||
|
|
6a72678c8d | ||
|
|
bb67fc622f | ||
|
|
5b50c02d93 | ||
|
|
ffec7e3266 | ||
|
|
039c1e7027 | ||
|
|
b27a21b3b8 | ||
|
|
2bcb5f617e | ||
|
|
7bf5294f9f | ||
|
|
c2fd1940f0 | ||
|
|
2d095ce6db | ||
|
|
e88bc36fca | ||
|
|
5613ea4f77 | ||
|
|
9c41599d60 | ||
|
|
5f8dd869e0 | ||
|
|
fb17df0b7e |
No files matched your search
@@ -37,3 +37,8 @@ jobs:
|
||||
env:
|
||||
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@v2.3.1
|
||||
with:
|
||||
name: Jar
|
||||
path: jar/build/libs/TAB-**.jar
|
||||
@@ -1,18 +1,41 @@
|
||||
# About
|
||||
This is where you can download the plugin for free without needing to buy me a coffee or just grab some code inspiration for your plugin. God bless opensource.
|
||||
|
||||
# Compiling from source
|
||||
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.
|
||||
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, official support on discord is only provided to
|
||||
those who have purchased the plugin.
|
||||
|
||||
# Compiling
|
||||
Compilation requires JDK 8 and up.
|
||||
To compile the plugin, run `./gradlew build` from the terminal.
|
||||
Once the plugin compiles, you can grab the jar from `jar/build/libs/` folder.
|
||||
Once the plugin compiles, grab the jar from `/jar/build/libs/` folder.
|
||||
|
||||
# Links
|
||||
See [releases](https://github.com/NEZNAMY/TAB/releases) for precompiled jar.
|
||||
|
||||
Has the plugin helped you in any way, and you wish to support the development?
|
||||
You can purchase the plugin on [MC-Market](https://www.mc-market.org/resources/20631/), [Polymart](https://polymart.org/resource/484) or just [send a donation](https://paypal.me/neznamy1).
|
||||
The precompiled JAR can be downloaded for free from
|
||||
[github releases](https://github.com/NEZNAMY/TAB/releases)
|
||||
and [MC-Market](https://www.mc-market.org/resources/20631/).
|
||||
|
||||
Supporters have access to high-quality [discord support](https://discord.gg/EaSvdk6).
|
||||
|
||||
Want to know more about the plugin's functions? Check out the [wiki](https://github.com/NEZNAMY/TAB/wiki).
|
||||
If you want to show your appreciation for my work, you can purchase the plugin on
|
||||
[MC-Market](https://www.mc-market.org/resources/14009/),
|
||||
[Polymart](https://polymart.org/resource/484) or just [send a donation](https://paypal.me/neznamy1).
|
||||
|
||||
Support is provided to buyers on [discord](https://discord.gg/EaSvdk6).
|
||||
|
||||
A detailed explanation of all the plugin's functions can be found on the
|
||||
[wiki](https://github.com/NEZNAMY/TAB/wiki).
|
||||
|
||||
# Issues
|
||||
The [Issues](https://github.com/NEZNAMY/TAB/issues) section is **only** available for **bug reports**
|
||||
or other issues which are not directly a bug (performance issues, errors, etc.).
|
||||
Support is provided on discord and feature requests are currently not accepted due to high demand and
|
||||
being busy with bug reports, which take priority over new features.
|
||||
We are not looking to add any new major features anymore.
|
||||
We would rather spend time improving existing features instead.
|
||||
|
||||
When opening a bug report, make sure you provide all necessary information to reproduce the bug,
|
||||
otherwise we will not able to fix it. Saying "it only occurs randomly" or "I don't know how to
|
||||
reproduce it" has no value and cannot be converted into actual code.
|
||||
@@ -1,7 +1,6 @@
|
||||
package me.neznamy.tab.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -15,7 +14,7 @@ public class ArmorStandManager {
|
||||
private final Map<String, ArmorStand> armorStands = new LinkedHashMap<>();
|
||||
|
||||
//players in entity tracking range
|
||||
private final List<TabPlayer> nearbyPlayers = Collections.synchronizedList(new ArrayList<>());
|
||||
private final List<TabPlayer> nearbyPlayers = new ArrayList<>();
|
||||
|
||||
//array to iterate over to avoid concurrent modification and slightly boost performance & memory
|
||||
private ArmorStand[] armorStandArray = new ArmorStand[0];
|
||||
@@ -27,7 +26,7 @@ public class ArmorStandManager {
|
||||
* @param name - key name of the armor stand
|
||||
* @param as - armor stand to add
|
||||
*/
|
||||
public synchronized void addArmorStand(String name, ArmorStand as) {
|
||||
public void addArmorStand(String name, ArmorStand as) {
|
||||
armorStands.put(name, as);
|
||||
armorStandArray = armorStands.values().toArray(new ArmorStand[0]);
|
||||
for (TabPlayer p : nearbyPlayerArray) as.spawn(p);
|
||||
@@ -57,10 +56,8 @@ public class ArmorStandManager {
|
||||
* @param viewer - player to spawn armor stands for
|
||||
*/
|
||||
public void spawn(TabPlayer viewer) {
|
||||
synchronized (nearbyPlayers) {
|
||||
nearbyPlayers.add(viewer);
|
||||
nearbyPlayerArray = nearbyPlayers.toArray(new TabPlayer[0]);
|
||||
}
|
||||
nearbyPlayers.add(viewer);
|
||||
nearbyPlayerArray = nearbyPlayers.toArray(new TabPlayer[0]);
|
||||
if (viewer.getVersion().getMinorVersion() < 8) return;
|
||||
for (ArmorStand a : armorStandArray) a.spawn(viewer);
|
||||
}
|
||||
@@ -108,10 +105,7 @@ public class ArmorStandManager {
|
||||
* @param viewer - player to remove
|
||||
*/
|
||||
public void unregisterPlayer(TabPlayer viewer) {
|
||||
synchronized (nearbyPlayers) {
|
||||
nearbyPlayers.remove(viewer);
|
||||
nearbyPlayerArray = nearbyPlayers.toArray(new TabPlayer[0]);
|
||||
}
|
||||
if (nearbyPlayers.remove(viewer)) nearbyPlayerArray = nearbyPlayers.toArray(new TabPlayer[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,10 +113,8 @@ public class ArmorStandManager {
|
||||
*/
|
||||
public void destroy() {
|
||||
for (ArmorStand a : armorStandArray) a.destroy();
|
||||
synchronized (nearbyPlayers) {
|
||||
nearbyPlayers.clear();
|
||||
nearbyPlayerArray = new TabPlayer[0];
|
||||
}
|
||||
nearbyPlayers.clear();
|
||||
nearbyPlayerArray = new TabPlayer[0];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,7 +64,7 @@ public enum ProtocolVersion {
|
||||
private final int networkId;
|
||||
|
||||
//minor version, such as 16
|
||||
private final int minorVersion;
|
||||
private int minorVersion;
|
||||
|
||||
//friendly name displayed in %player-version% placeholder
|
||||
private final String friendlyName;
|
||||
@@ -113,6 +113,17 @@ public enum ProtocolVersion {
|
||||
return minorVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides minor version of the version instance. This is used internally to
|
||||
* set minor version of UNKNOWN value to value from package to fix compatibility
|
||||
* with server forks that set bukkit version field value to "Unknown".
|
||||
* @param minorVersion
|
||||
* minor version to change value to
|
||||
*/
|
||||
public void setMinorVersion(int minorVersion) {
|
||||
this.minorVersion = minorVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns enum constant of entered version or UNKNOWN if unknown version
|
||||
* @param friendlyName - friendly name of the version
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.UUID;
|
||||
|
||||
import me.neznamy.tab.api.bossbar.BossBarManager;
|
||||
import me.neznamy.tab.api.config.ConfigurationFile;
|
||||
import me.neznamy.tab.api.event.EventBus;
|
||||
import me.neznamy.tab.api.placeholder.PlaceholderManager;
|
||||
import me.neznamy.tab.api.scoreboard.ScoreboardManager;
|
||||
import me.neznamy.tab.api.task.ThreadManager;
|
||||
@@ -78,6 +79,13 @@ public abstract class TabAPI {
|
||||
|
||||
public abstract TablistFormatManager getTablistFormatManager();
|
||||
|
||||
/**
|
||||
* Gets the event bus for registering listeners for TAB events.
|
||||
*
|
||||
* @return the event bus
|
||||
*/
|
||||
public abstract EventBus getEventBus();
|
||||
|
||||
/**
|
||||
* Returns server version. On proxy installation returns PROXY.
|
||||
* @return server version
|
||||
@@ -104,4 +112,4 @@ public abstract class TabAPI {
|
||||
public abstract void debug(String message);
|
||||
|
||||
public abstract void logError(String message, Throwable t);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package me.neznamy.tab.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardDisplayObjective;
|
||||
@@ -16,7 +14,7 @@ public abstract class TabFeature {
|
||||
private final boolean serverWhitelistMode;
|
||||
protected final String[] disabledWorlds;
|
||||
private final boolean worldWhitelistMode;
|
||||
private final List<TabPlayer> disabledPlayers = new ArrayList<>();
|
||||
private final Set<TabPlayer> disabledPlayers = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private final List<String> methodOverrides = new ArrayList<>();
|
||||
|
||||
protected TabFeature(String featureName, String refreshDisplayName) {
|
||||
@@ -49,6 +47,8 @@ public abstract class TabFeature {
|
||||
methodOverrides.add("onQuit");
|
||||
if (getClass().getMethod("onWorldChange", TabPlayer.class, String.class, String.class).getDeclaringClass() != TabFeature.class)
|
||||
methodOverrides.add("onWorldChange");
|
||||
if (getClass().getMethod("onServerChange", TabPlayer.class, String.class, String.class).getDeclaringClass() != TabFeature.class)
|
||||
methodOverrides.add("onServerChange");
|
||||
if (getClass().getMethod("onDisplayObjective", TabPlayer.class, PacketPlayOutScoreboardDisplayObjective.class).getDeclaringClass() != TabFeature.class)
|
||||
methodOverrides.add("onDisplayObjective");
|
||||
if (getClass().getMethod("onLoginPacket", TabPlayer.class).getDeclaringClass() != TabFeature.class)
|
||||
@@ -105,7 +105,6 @@ public abstract class TabFeature {
|
||||
* @param disconnectedPlayer - player who disconnected
|
||||
*/
|
||||
public void onQuit(TabPlayer disconnectedPlayer) {
|
||||
disabledPlayers.remove(disconnectedPlayer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,7 +124,7 @@ public abstract class TabFeature {
|
||||
* @param to - server player changed to
|
||||
*/
|
||||
public void onServerChange(TabPlayer changed, String from, String to) {
|
||||
onWorldChange(changed, null, null);
|
||||
//empty by default
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -184,16 +184,18 @@ public interface TabPlayer {
|
||||
/**
|
||||
* Loads property from config using standard property loading algorithm
|
||||
* @param property - property name to load
|
||||
* @return true if value did not exist or changed, false otherwise
|
||||
*/
|
||||
void loadPropertyFromConfig(TabFeature feature, String property);
|
||||
boolean loadPropertyFromConfig(TabFeature feature, String property);
|
||||
|
||||
/**
|
||||
* Loads property from config using standard property loading algorithm. If the property is
|
||||
* not set in config, sets it to ifNotSet value
|
||||
* @param property - property name to load
|
||||
* @param ifNotSet - value to use if property is not defined in config
|
||||
* @return true if value did not exist or changed, false otherwise
|
||||
*/
|
||||
void loadPropertyFromConfig(TabFeature feature, String property, String ifNotSet);
|
||||
boolean loadPropertyFromConfig(TabFeature feature, String property, String ifNotSet);
|
||||
|
||||
/**
|
||||
* Returns name of player's scoreboard team or null if NameTag feature is disabled
|
||||
|
||||
@@ -178,6 +178,14 @@ public class ChatModifier {
|
||||
if (TabAPI.getInstance().getServerVersion().getMinorVersion() < 8) throw new UnsupportedOperationException("change_page click action is not supported on <1.8");
|
||||
clickEvent = new ChatClickable(EnumClickAction.CHANGE_PAGE, String.valueOf(newPage));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets click action to COPY_TO_CLIPBOARD and text to provided value
|
||||
* @param text - text to copy to clipboard on click
|
||||
*/
|
||||
public void onClickCopyToClipBoard(String text) {
|
||||
clickEvent = new ChatClickable(EnumClickAction.COPY_TO_CLIPBOARD, text);
|
||||
}
|
||||
|
||||
public void onClick(EnumClickAction action, String value) {
|
||||
clickEvent = new ChatClickable(action, value);
|
||||
|
||||
@@ -30,6 +30,9 @@ public enum EnumChatFormat {
|
||||
ITALIC('o'),
|
||||
RESET('r');
|
||||
|
||||
/** Creating a constant to avoid memory allocations on each request */
|
||||
private static final EnumChatFormat[] VALUES = values();
|
||||
|
||||
/** The symbol minecraft uses to colorize text */
|
||||
public static final char COLOR_CHAR = 0x00a7;
|
||||
|
||||
@@ -116,7 +119,7 @@ public enum EnumChatFormat {
|
||||
* @return instance from the character or null if character is not valid
|
||||
*/
|
||||
public static EnumChatFormat getByChar(char c) {
|
||||
for (EnumChatFormat format : values()) {
|
||||
for (EnumChatFormat format : VALUES) {
|
||||
if (format.character == c) return format;
|
||||
}
|
||||
return null;
|
||||
@@ -135,7 +138,7 @@ public enum EnumChatFormat {
|
||||
String last = getLastColors(legacyText);
|
||||
if (last.length() > 0) {
|
||||
char c = last.toCharArray()[1];
|
||||
for (EnumChatFormat e : values()) {
|
||||
for (EnumChatFormat e : VALUES) {
|
||||
if (e.character == c) return e;
|
||||
}
|
||||
}
|
||||
@@ -177,7 +180,7 @@ public enum EnumChatFormat {
|
||||
* @return enum value or null if no such combination exists
|
||||
*/
|
||||
public static EnumChatFormat fromRGBExact(int red, int green, int blue){
|
||||
for (EnumChatFormat format : values()) {
|
||||
for (EnumChatFormat format : VALUES) {
|
||||
if (format.red == red && format.green == green && format.blue == blue) return format;
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package me.neznamy.tab.api.chat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
|
||||
@@ -14,6 +11,7 @@ import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.chat.ChatClickable.EnumClickAction;
|
||||
import me.neznamy.tab.api.chat.ChatHoverable.EnumHoverAction;
|
||||
import me.neznamy.tab.api.chat.rgb.RGBUtils;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
/**
|
||||
* A class representing the n.m.s.IChatBaseComponent class to make work with it much easier
|
||||
@@ -21,21 +19,21 @@ import me.neznamy.tab.api.chat.rgb.RGBUtils;
|
||||
@SuppressWarnings("unchecked")
|
||||
public class IChatBaseComponent {
|
||||
|
||||
/**
|
||||
* Component cache maps to avoid large memory allocations as well as
|
||||
* higher CPU usage when using animations which send the same text on repeat.
|
||||
*/
|
||||
private static final Map<String, IChatBaseComponent> componentCache = new HashMap<>();
|
||||
private static final Map<IChatBaseComponent, String> serializeCacheModern = new HashMap<>();
|
||||
private static final Map<IChatBaseComponent, String> serializeCacheLegacy = new HashMap<>();
|
||||
|
||||
//constants
|
||||
private static final String EMPTY_TRANSLATABLE = "{\"translate\":\"\"}";
|
||||
private static final String EMPTY_TEXT = "{\"text\":\"\"}";
|
||||
private static final List<IChatBaseComponent> EMPTY_LIST = new ArrayList<>(0);
|
||||
|
||||
//component text
|
||||
/** Text of the component */
|
||||
private String text;
|
||||
|
||||
|
||||
/** Chat modifier containing color, magic codes, hover and click event */
|
||||
private ChatModifier modifier = new ChatModifier();
|
||||
|
||||
//extra components
|
||||
/** Extra components used in "extra" field */
|
||||
private List<IChatBaseComponent> extra;
|
||||
|
||||
/**
|
||||
@@ -46,7 +44,8 @@ public class IChatBaseComponent {
|
||||
|
||||
/**
|
||||
* Constructs a new component which is a clone of provided component
|
||||
* @param component - component to clone
|
||||
* @param component
|
||||
* component to clone
|
||||
*/
|
||||
public IChatBaseComponent(IChatBaseComponent component) {
|
||||
this.text = component.text;
|
||||
@@ -58,25 +57,29 @@ public class IChatBaseComponent {
|
||||
|
||||
/**
|
||||
* Constructs new instance with given text
|
||||
* @param text - text to display
|
||||
* @param text
|
||||
* text to display
|
||||
*/
|
||||
public IChatBaseComponent(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of extra components or null if none are defined
|
||||
* @return list of extras
|
||||
* Returns list of extra components. If no extra components are defined, returns empty list.
|
||||
* @return list of extra components
|
||||
*/
|
||||
public List<IChatBaseComponent> getExtra(){
|
||||
if (extra == null) return EMPTY_LIST;
|
||||
if (extra == null) return Collections.emptyList();
|
||||
return extra;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets full list of extra components to given list
|
||||
* @param components - components to use as extra
|
||||
* @return self
|
||||
* Sets full list of extra components to given list. Does not allow empty list.
|
||||
* @param components
|
||||
* components to use as extra
|
||||
* @return self
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code components} is an empty list
|
||||
*/
|
||||
public IChatBaseComponent setExtra(List<IChatBaseComponent> components){
|
||||
if (components.isEmpty()) throw new IllegalArgumentException("Unexpected empty array of components"); //exception taken from minecraft
|
||||
@@ -86,105 +89,126 @@ public class IChatBaseComponent {
|
||||
|
||||
/**
|
||||
* Appends provided component as extra component
|
||||
* @param child - component to append
|
||||
* @return self
|
||||
* @param child
|
||||
* component to append
|
||||
*/
|
||||
public IChatBaseComponent addExtra(IChatBaseComponent child) {
|
||||
public void addExtra(IChatBaseComponent child) {
|
||||
if (extra == null) extra = new ArrayList<>();
|
||||
extra.add(child);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns text of this component
|
||||
* @return text of this component
|
||||
* @return text of this component
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns chat modifier of this component
|
||||
* @return chat modifier of this component
|
||||
*/
|
||||
public ChatModifier getModifier() {
|
||||
return modifier;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets modifier to provided value
|
||||
* @param modifier
|
||||
* modifier to set value to
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code modifier} is null
|
||||
*/
|
||||
public void setModifier(ChatModifier modifier) {
|
||||
Preconditions.checkNotNull(modifier, "modifier");
|
||||
this.modifier = modifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets text of this component
|
||||
* @param text - text to show
|
||||
* @return self
|
||||
* Changes text of this component
|
||||
* @param text
|
||||
* text to show
|
||||
*/
|
||||
public IChatBaseComponent setText(String text) {
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes string and returns created component
|
||||
* @param json - serialized string
|
||||
* @return Deserialized component
|
||||
* Deserializes string and returns created component. If provided string is null, returns null.
|
||||
* @param json
|
||||
* serialized string
|
||||
* @return Deserialized component or null if input is null
|
||||
*/
|
||||
public static IChatBaseComponent deserialize(String json) {
|
||||
if (json == null) return null;
|
||||
if (json.startsWith("\"") && json.endsWith("\"") && json.length() > 1) {
|
||||
//simple component with only text used, minecraft serializer outputs the text in quotes instead of full json
|
||||
return new IChatBaseComponent(json.substring(1, json.length()-1));
|
||||
}
|
||||
JSONObject jsonObject;
|
||||
try {
|
||||
if (json == null) return null;
|
||||
if (json.startsWith("\"") && json.endsWith("\"") && json.length() > 1) {
|
||||
//simple component with only text used, minecraft serializer outputs the text in quotes instead of full json
|
||||
return new IChatBaseComponent(json.substring(1, json.length()-1));
|
||||
}
|
||||
JSONObject jsonObject = (JSONObject) new JSONParser().parse(json);
|
||||
IChatBaseComponent component;
|
||||
if (jsonObject.containsKey("type")) {
|
||||
return new ChatComponentEntity((String) jsonObject.get("type"), UUID.fromString((String) jsonObject.get("id")), IChatBaseComponent.deserialize(jsonObject.get("name").toString()).toFlatText());
|
||||
}
|
||||
component = new IChatBaseComponent();
|
||||
component.setText((String) jsonObject.get("text"));
|
||||
component.modifier.setBold(getBoolean(jsonObject, "bold"));
|
||||
component.modifier.setItalic(getBoolean(jsonObject, "italic"));
|
||||
component.modifier.setUnderlined(getBoolean(jsonObject, "underlined"));
|
||||
component.modifier.setStrikethrough(getBoolean(jsonObject, "strikethrough"));
|
||||
component.modifier.setObfuscated(getBoolean(jsonObject, "obfuscated"));
|
||||
component.modifier.setColor(TextColor.fromString(((String) jsonObject.get("color"))));
|
||||
if (jsonObject.containsKey("clickEvent")) {
|
||||
JSONObject clickEvent = (JSONObject) jsonObject.get("clickEvent");
|
||||
String action = (String) clickEvent.get("action");
|
||||
String value = clickEvent.get("value").toString();
|
||||
component.modifier.onClick(EnumClickAction.valueOf(action.toUpperCase()), value);
|
||||
}
|
||||
if (jsonObject.containsKey("hoverEvent")) {
|
||||
JSONObject hoverEvent = (JSONObject) jsonObject.get("hoverEvent");
|
||||
String action = (String) hoverEvent.get("action");
|
||||
String value = (String) hoverEvent.get("value");
|
||||
component.modifier.onHover(EnumHoverAction.valueOf(action.toUpperCase()), deserialize(value));
|
||||
}
|
||||
if (jsonObject.containsKey("extra")) {
|
||||
List<Object> list = (List<Object>) jsonObject.get("extra");
|
||||
for (Object extra : list) {
|
||||
String string = extra.toString();
|
||||
//reverting .toString() removing "" for simple text
|
||||
if (!string.startsWith("{")) string = "\"" + string + "\"";
|
||||
component.addExtra(deserialize(string));
|
||||
}
|
||||
}
|
||||
return component;
|
||||
} catch (Exception e) {
|
||||
jsonObject = (JSONObject) new JSONParser().parse(json);
|
||||
} catch (ParseException e) {
|
||||
TabAPI.getInstance().logError("Failed to deserialize json component " + json, e);
|
||||
return null;
|
||||
}
|
||||
IChatBaseComponent component;
|
||||
if (jsonObject.containsKey("type")) {
|
||||
return new ChatComponentEntity((String) jsonObject.get("type"), UUID.fromString((String) jsonObject.get("id")), IChatBaseComponent.deserialize(jsonObject.get("name").toString()).toFlatText());
|
||||
}
|
||||
component = new IChatBaseComponent();
|
||||
component.setText((String) jsonObject.get("text"));
|
||||
component.modifier.setBold(getBoolean(jsonObject, "bold"));
|
||||
component.modifier.setItalic(getBoolean(jsonObject, "italic"));
|
||||
component.modifier.setUnderlined(getBoolean(jsonObject, "underlined"));
|
||||
component.modifier.setStrikethrough(getBoolean(jsonObject, "strikethrough"));
|
||||
component.modifier.setObfuscated(getBoolean(jsonObject, "obfuscated"));
|
||||
component.modifier.setColor(TextColor.fromString(((String) jsonObject.get("color"))));
|
||||
if (jsonObject.containsKey("clickEvent")) {
|
||||
JSONObject clickEvent = (JSONObject) jsonObject.get("clickEvent");
|
||||
String action = (String) clickEvent.get("action");
|
||||
String value = clickEvent.get("value").toString();
|
||||
component.modifier.onClick(EnumClickAction.valueOf(action.toUpperCase()), value);
|
||||
}
|
||||
if (jsonObject.containsKey("hoverEvent")) {
|
||||
JSONObject hoverEvent = (JSONObject) jsonObject.get("hoverEvent");
|
||||
String action = (String) hoverEvent.get("action");
|
||||
String value = (String) hoverEvent.get("value");
|
||||
component.modifier.onHover(EnumHoverAction.valueOf(action.toUpperCase()), deserialize(value));
|
||||
}
|
||||
if (jsonObject.containsKey("extra")) {
|
||||
List<Object> list = (List<Object>) jsonObject.get("extra");
|
||||
for (Object extra : list) {
|
||||
String string = extra.toString();
|
||||
//reverting .toString() removing "" for simple text
|
||||
if (!string.startsWith("{")) string = "\"" + string + "\"";
|
||||
component.addExtra(deserialize(string));
|
||||
}
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns boolean value of requested key
|
||||
* @param jsonObject - object to get value from
|
||||
* @param key - name of key
|
||||
* @return value from json object or null if not present
|
||||
* Returns boolean value of requested key from map
|
||||
* @param jsonObject
|
||||
* map to get value from
|
||||
* @param key
|
||||
* name of key
|
||||
* @return value from json object or null if not present
|
||||
*/
|
||||
private static Boolean getBoolean(JSONObject jsonObject, String key) {
|
||||
String value = String.valueOf(jsonObject.getOrDefault(key, null));
|
||||
return "null".equals(value) ? null : Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the component to a string representing the serialized component.
|
||||
* This method is only used internally by json library since it's missing
|
||||
* protocol version field used by the method.
|
||||
* @return serialized component in string form
|
||||
* @see #toString(ProtocolVersion)
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
JSONObject json = new JSONObject();
|
||||
@@ -196,28 +220,33 @@ public class IChatBaseComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes this component with colors based on client version
|
||||
* @param clientVersion - client version
|
||||
* @return Serialized string
|
||||
* Serializes this component with colors based on client version.
|
||||
* If client version is <1.16, HEX colors will be converted to legacy colors.
|
||||
* @param clientVersion
|
||||
* client version to adapt component for
|
||||
* @return serialized string
|
||||
*/
|
||||
public String toString(ProtocolVersion clientVersion) {
|
||||
return toString(clientVersion, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes this component with colors based on client version
|
||||
* @param clientVersion - client version
|
||||
* @param sendTranslatableIfEmpty - if empty translatable should be sent if text is empty or not
|
||||
* @return Serialized string
|
||||
* Serializes this component with colors based on client version.
|
||||
* If client version is <1.16, HEX colors will be converted to legacy colors.
|
||||
* @param clientVersion
|
||||
* client version to adapt component for
|
||||
* @param sendTranslatableIfEmpty
|
||||
* whether empty translatable should be sent if text is empty or not
|
||||
* @return serialized string
|
||||
*/
|
||||
public String toString(ProtocolVersion clientVersion, boolean sendTranslatableIfEmpty) {
|
||||
if (extra == null) {
|
||||
if (text == null) return null;
|
||||
if (text.length() == 0) {
|
||||
if (sendTranslatableIfEmpty) {
|
||||
return EMPTY_TRANSLATABLE;
|
||||
return "{\"translate\":\"\"}";
|
||||
} else {
|
||||
return EMPTY_TEXT;
|
||||
return "{\"text\":\"\"}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,8 +271,9 @@ public class IChatBaseComponent {
|
||||
|
||||
/**
|
||||
* Returns organized component from colored text
|
||||
* @param originalText - text to convert
|
||||
* @return organized component from colored text
|
||||
* @param originalText
|
||||
* text to convert
|
||||
* @return organized component from colored text
|
||||
*/
|
||||
public static IChatBaseComponent fromColoredText(String originalText){
|
||||
String text = RGBUtils.getInstance().applyFormats(EnumChatFormat.color(originalText), false);
|
||||
@@ -328,9 +358,11 @@ public class IChatBaseComponent {
|
||||
|
||||
/**
|
||||
* Returns true if text contains legacy color request at defined RGB index start
|
||||
* @param text - text to check
|
||||
* @param i - current index start
|
||||
* @return true if legacy color is defined, false if not
|
||||
* @param text
|
||||
* text to check
|
||||
* @param i
|
||||
* current index start
|
||||
* @return true if legacy color is defined, false if not
|
||||
*/
|
||||
private static boolean containsLegacyCode(String text, int i) {
|
||||
if (text.length() - i < 9 || text.charAt(i+7) != '|') return false;
|
||||
@@ -339,7 +371,7 @@ public class IChatBaseComponent {
|
||||
|
||||
/**
|
||||
* Converts this component into a simple text with legacy colors (the closest match if color is set to RGB)
|
||||
* @return The simple text format
|
||||
* @return The simple text format
|
||||
*/
|
||||
public String toLegacyText() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
@@ -348,11 +380,13 @@ public class IChatBaseComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends text to string builder, might also add color and magic codes if different
|
||||
* from previous component in chain
|
||||
* @param builder - builder to append text to
|
||||
* @param previousFormatting - colors and magic codes in previous component
|
||||
* @return New formatting, might be identical to previous one
|
||||
* Appends text to string builder, might also add color and magic codes if they are different
|
||||
* from previous component in chain.
|
||||
* @param builder
|
||||
* builder to append text to
|
||||
* @param previousFormatting
|
||||
* colors and magic codes in previous component
|
||||
* @return wew formatting, might be identical to previous one
|
||||
*/
|
||||
private String append(StringBuilder builder, String previousFormatting) {
|
||||
String formatting = previousFormatting;
|
||||
@@ -372,7 +406,7 @@ public class IChatBaseComponent {
|
||||
|
||||
/**
|
||||
* Returns colors and magic codes of this component
|
||||
* @return used colors and magic codes
|
||||
* @return used colors and magic codes
|
||||
*/
|
||||
private String getFormatting() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
@@ -390,7 +424,7 @@ public class IChatBaseComponent {
|
||||
|
||||
/**
|
||||
* Returns raw text without colors, only works correctly when component is organized
|
||||
* @return raw text in this component
|
||||
* @return raw text in this component and all child components
|
||||
*/
|
||||
public String toRawText() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
@@ -403,7 +437,7 @@ public class IChatBaseComponent {
|
||||
|
||||
/**
|
||||
* Converts the component into flat text with used colors (including rgb) and magic codes
|
||||
* @return converted text
|
||||
* @return converted text
|
||||
*/
|
||||
public String toFlatText() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
@@ -420,8 +454,9 @@ public class IChatBaseComponent {
|
||||
* Returns the most optimized component based on text. Returns null if text is null,
|
||||
* organized component if RGB colors are used or simple component with only text field
|
||||
* containing the whole text when no RGB colors are used
|
||||
* @param text - text to create component from
|
||||
* @return The most performance-optimized component based on text
|
||||
* @param text
|
||||
* text to create component from
|
||||
* @return The most performance-optimized component based on text
|
||||
*/
|
||||
public static IChatBaseComponent optimizedComponent(String text){
|
||||
if (text == null) return null;
|
||||
|
||||
@@ -8,13 +8,11 @@ import me.neznamy.tab.api.util.Preconditions;
|
||||
public class TextColor {
|
||||
|
||||
/**
|
||||
* RGB values from 0 to 255.
|
||||
* They are only initialized if they are actually used to avoid
|
||||
* RGB values as a single number of 3 8-bit numbers (0-255).
|
||||
* It is only initialized if colors are actually used to avoid
|
||||
* unnecessary memory allocations with string operations.
|
||||
*/
|
||||
private short red = -1;
|
||||
private short green = -1;
|
||||
private short blue = -1;
|
||||
private int rgb = -1;
|
||||
|
||||
/** Closest legacy color to this color object. */
|
||||
private EnumChatFormat legacyColor;
|
||||
@@ -37,9 +35,7 @@ public class TextColor {
|
||||
*/
|
||||
public TextColor(TextColor color) {
|
||||
Preconditions.checkNotNull(color, "color cannot be null");
|
||||
red = color.red;
|
||||
green = color.green;
|
||||
blue = color.blue;
|
||||
rgb = color.rgb;
|
||||
legacyColor = color.legacyColor;
|
||||
hexCode = color.hexCode;
|
||||
legacyColorForced = color.legacyColorForced;
|
||||
@@ -83,9 +79,7 @@ public class TextColor {
|
||||
*/
|
||||
public TextColor(EnumChatFormat legacyColor) {
|
||||
Preconditions.checkNotNull(legacyColor, "legacy color cannot be null");
|
||||
this.red = legacyColor.getRed();
|
||||
this.green = legacyColor.getGreen();
|
||||
this.blue = legacyColor.getBlue();
|
||||
this.rgb = (legacyColor.getRed() << 16) + (legacyColor.getGreen() << 8) + legacyColor.getBlue();
|
||||
this.hexCode = legacyColor.getHexCode();
|
||||
}
|
||||
|
||||
@@ -101,12 +95,10 @@ public class TextColor {
|
||||
* if {@code red}, {@code green} or {@code blue} is out of range ({@code 0-255})
|
||||
*/
|
||||
public TextColor(int red, int green, int blue) {
|
||||
Preconditions.checkRange(red, 0, 255);
|
||||
Preconditions.checkRange(green, 0, 255);
|
||||
Preconditions.checkRange(blue, 0, 255);
|
||||
this.red = (short) red;
|
||||
this.green = (short) green;
|
||||
this.blue = (short) blue;
|
||||
Preconditions.checkRange(red, 0, 255, "red color");
|
||||
Preconditions.checkRange(green, 0, 255, "green color");
|
||||
Preconditions.checkRange(blue, 0, 255, "blue color");
|
||||
this.rgb = (red << 16) + (green << 8) + blue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,8 +128,8 @@ public class TextColor {
|
||||
* @return red value
|
||||
*/
|
||||
public int getRed() {
|
||||
if (red == -1) loadColors();
|
||||
return red;
|
||||
if (rgb == -1) rgb = Integer.parseInt(hexCode, 16);
|
||||
return (rgb >> 16) & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,8 +137,8 @@ public class TextColor {
|
||||
* @return green value
|
||||
*/
|
||||
public int getGreen() {
|
||||
if (green == -1) loadColors();
|
||||
return green;
|
||||
if (rgb == -1) rgb = Integer.parseInt(hexCode, 16);
|
||||
return (rgb >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,20 +146,10 @@ public class TextColor {
|
||||
* @return blue value
|
||||
*/
|
||||
public int getBlue() {
|
||||
if (blue == -1) loadColors();
|
||||
return blue;
|
||||
if (rgb == -1) rgb = Integer.parseInt(hexCode, 16);
|
||||
return rgb & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads red, green and blue values based on current hex code string
|
||||
*/
|
||||
private void loadColors(){
|
||||
int hexColor = Integer.parseInt(hexCode, 16);
|
||||
red = (short) ((hexColor >> 16) & 0xFF);
|
||||
green = (short) ((hexColor >> 8) & 0xFF);
|
||||
blue = (short) (hexColor & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the closest legacy color of this color object.
|
||||
* If the color was defined in constructor, it's returned.
|
||||
@@ -175,9 +157,7 @@ public class TextColor {
|
||||
* @return closest legacy color
|
||||
*/
|
||||
public EnumChatFormat getLegacyColor() {
|
||||
if (legacyColor == null) {
|
||||
legacyColor = loadClosestColor();
|
||||
}
|
||||
if (legacyColor == null) legacyColor = loadClosestColor();
|
||||
return legacyColor;
|
||||
}
|
||||
|
||||
@@ -186,9 +166,7 @@ public class TextColor {
|
||||
* @return the rgb combination as a 6-digit hex code string
|
||||
*/
|
||||
public String getHexCode() {
|
||||
if (hexCode == null) {
|
||||
hexCode = String.format("%06X", (red << 16) + (green << 8) + blue);
|
||||
}
|
||||
if (hexCode == null) hexCode = String.format("%06X", rgb);
|
||||
return hexCode;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
*/
|
||||
public class BukkitFormat implements RGBFormatter {
|
||||
|
||||
private final Pattern pattern = Pattern.compile("[" + EnumChatFormat.COLOR_CHAR + "&]x[[" + EnumChatFormat.COLOR_CHAR + "&]\\p{XDigit}]{12}");
|
||||
private final Pattern pattern = Pattern.compile("[" + EnumChatFormat.COLOR_CHAR + "&]x[" + EnumChatFormat.COLOR_CHAR + "&\\p{XDigit}]{12}");
|
||||
|
||||
@Override
|
||||
public String reformat(String text) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public class CMIFormat implements RGBFormatter {
|
||||
|
||||
private final Pattern pattern = Pattern.compile("\\{#[0-9a-fA-F]{6}\\}");
|
||||
private final Pattern pattern = Pattern.compile("\\{#[0-9a-fA-F]{6}}");
|
||||
|
||||
@Override
|
||||
public String reformat(String text) {
|
||||
|
||||
@@ -6,11 +6,11 @@ import java.util.regex.Pattern;
|
||||
public class CMIGradient extends CommonGradient {
|
||||
|
||||
//pattern for {#RRGGBB<>}
|
||||
private final Pattern shortcutPattern = Pattern.compile("\\{#[0-9a-fA-F]{6}<>\\}");
|
||||
private final Pattern shortcutPattern = Pattern.compile("\\{#[0-9a-fA-F]{6}<>}");
|
||||
|
||||
public CMIGradient() {
|
||||
super(Pattern.compile("\\{#[0-9a-fA-F]{6}>\\}[^\\{]*\\{#[0-9a-fA-F]{6}<\\}"),
|
||||
Pattern.compile("\\{#[0-9a-fA-F]{6}\\|.>\\}[^\\{]*\\{#[0-9a-fA-F]{6}<\\}"),
|
||||
super(Pattern.compile("\\{#[0-9a-fA-F]{6}>}[^{]*\\{#[0-9a-fA-F]{6}<}"),
|
||||
Pattern.compile("\\{#[0-9a-fA-F]{6}\\|.>}[^{]*\\{#[0-9a-fA-F]{6}<}"),
|
||||
"{#", 9, 2, 10, 8);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public abstract class ConfigurationFile {
|
||||
protected ConfigurationFile(InputStream source, File destination) throws IOException {
|
||||
if (destination == null) throw new IllegalArgumentException("Destination cannot be null");
|
||||
this.file = destination;
|
||||
if (file.getParentFile() != null) file.getParentFile().mkdirs();
|
||||
if (file.getParentFile() != null) 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());
|
||||
@@ -308,7 +308,6 @@ public abstract class ConfigurationFile {
|
||||
public <K, V> Map<K, V> getConfigurationSection(String path) {
|
||||
if (path == null || path.length() == 0) return (Map<K, V>) values;
|
||||
Object value = getObject(path, null);
|
||||
if (value == null) return new LinkedHashMap<>();
|
||||
if (value instanceof Map) {
|
||||
return (Map<K, V>) value;
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package me.neznamy.tab.api.event;
|
||||
|
||||
/**
|
||||
* The event bus. This is used to register event listeners/handlers for
|
||||
* handling events that may be fired by TAB.
|
||||
*/
|
||||
public interface EventBus {
|
||||
|
||||
/**
|
||||
* Scans the given listener for any method that is annotated with
|
||||
* {@link Subscribe} and registers it as a listener to this event bus.
|
||||
*
|
||||
* All methods in this class that are annotated with {@link Subscribe}
|
||||
* must meet the following criteria:
|
||||
* <ul>
|
||||
* <li>It must be <strong>public</strong>.</li>
|
||||
* <li>It must <strong>not</strong> be abstract.</li>
|
||||
* <li>It must have exactly <strong>one</strong> parameter.</li>
|
||||
* <li>Its single parameter must be <strong>an event</strong>.</li>
|
||||
* </ul>
|
||||
* If a method does not meet the above criteria, an exception <strong>will</strong>
|
||||
* be thrown.
|
||||
*
|
||||
* @param listener the listener to register
|
||||
* @throws RuntimeException if a method does not meet the criteria
|
||||
*/
|
||||
void register(Object listener);
|
||||
|
||||
/**
|
||||
* Registers the given handler to this event bus.
|
||||
*
|
||||
* @param type the class type of the event
|
||||
* @param handler the handler to register
|
||||
* @param <E> the type of the event
|
||||
*/
|
||||
<E extends TabEvent> void register(Class<E> type, EventHandler<E> handler);
|
||||
|
||||
/**
|
||||
* Scans the given listener for any method that is annotated with
|
||||
* {@link Subscribe} and unregisters it from this event bus.
|
||||
*
|
||||
* @param listener the listener to unregister
|
||||
*/
|
||||
void unregister(Object listener);
|
||||
|
||||
/**
|
||||
* Unregisters the given handler from this event bus.
|
||||
*
|
||||
* @param handler the handler to unregister
|
||||
* @param <E> the type of the event
|
||||
*/
|
||||
<E extends TabEvent> void unregister(EventHandler<E> handler);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package me.neznamy.tab.api.event;
|
||||
|
||||
/**
|
||||
* A handler for an event. This allows listening for events in a more
|
||||
* functional style.
|
||||
*
|
||||
* @param <E> the type of event this handler handles
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface EventHandler<E> {
|
||||
|
||||
/**
|
||||
* Called when the given event is fired from an event bus.
|
||||
*
|
||||
* @param event the event to handle
|
||||
*/
|
||||
void handle(E event);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package me.neznamy.tab.api.event;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Subscribes to a {@link TabEvent}.
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Subscribe {
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package me.neznamy.tab.api.event;
|
||||
|
||||
/**
|
||||
* An event that may be fired by TAB when something occurs.
|
||||
*
|
||||
* This is a marker interface. All events <strong>must</strong> implement this
|
||||
* interface.
|
||||
*/
|
||||
public interface TabEvent {
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package me.neznamy.tab.api.event.player;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.event.TabEvent;
|
||||
|
||||
/**
|
||||
* Called when the player has been fully loaded by TAB.
|
||||
*/
|
||||
public interface PlayerLoadEvent extends TabEvent {
|
||||
|
||||
/**
|
||||
* Gets the player that was loaded.
|
||||
*
|
||||
* @return the player that was loaded
|
||||
*/
|
||||
TabPlayer getPlayer();
|
||||
|
||||
/**
|
||||
* Returns true if player was loaded because they joined,
|
||||
* false if the player was loaded because tab reload command was executed
|
||||
* @return true if player joined, false if plugin was reloaded
|
||||
*/
|
||||
boolean isJoin();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package me.neznamy.tab.api.event.plugin;
|
||||
|
||||
import me.neznamy.tab.api.event.TabEvent;
|
||||
import me.neznamy.tab.api.placeholder.Placeholder;
|
||||
|
||||
public interface PlaceholderRegisterEvent extends TabEvent {
|
||||
|
||||
String getIdentifier();
|
||||
|
||||
void setPlaceholder(Placeholder placeholder);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package me.neznamy.tab.api.event.plugin;
|
||||
|
||||
import me.neznamy.tab.api.event.TabEvent;
|
||||
|
||||
/**
|
||||
* Called when TAB is fully loaded.
|
||||
*/
|
||||
public interface TabLoadEvent extends TabEvent {
|
||||
}
|
||||
@@ -41,4 +41,6 @@ public interface PlaceholderManager {
|
||||
void addUsedPlaceholder(String identifier, TabFeature feature);
|
||||
|
||||
String findReplacement(String placeholder, String output);
|
||||
|
||||
List<String> getUsedPlaceholders();
|
||||
}
|
||||
@@ -152,4 +152,14 @@ public interface ScoreboardManager {
|
||||
* is < 0.
|
||||
*/
|
||||
void announceScoreboard(String scoreboard, int duration);
|
||||
|
||||
/**
|
||||
* Returns player's currently displayed scoreboard. This can be either with
|
||||
* configuration, overridden with commands or the API. Will return {@code null}
|
||||
* if player does not see any scoreboard due to not meeting any display condition.
|
||||
* @param player
|
||||
* player to get active scoreboard of
|
||||
* @return player's active scoreboard or {@code null} if player has no scoreboard
|
||||
*/
|
||||
Scoreboard getActiveScoreboard(TabPlayer player);
|
||||
}
|
||||
@@ -14,6 +14,15 @@ public interface ThreadManager {
|
||||
* @param task - the task
|
||||
*/
|
||||
Future<Void> runMeasuredTask(String errorDescription, TabFeature feature, String type, Runnable task);
|
||||
|
||||
/**
|
||||
* Starts a task in new thread and measures how long it took to process
|
||||
* @param errorDescription - description to use if this task throws an error
|
||||
* @param feature - feature to add cpu usage to
|
||||
* @param type - usage type to add cpu usage to
|
||||
* @param task - the task
|
||||
*/
|
||||
Future<Void> runMeasuredTask(String errorDescription, String feature, String type, Runnable task);
|
||||
|
||||
/**
|
||||
* Runs task in a new thread
|
||||
@@ -39,18 +48,9 @@ public interface ThreadManager {
|
||||
* @param feature - feature to add cpu usage to
|
||||
* @param type - usage type to add cpu usage to
|
||||
* @param task - the task
|
||||
* @return future allowing to cancel the task
|
||||
*/
|
||||
Future<Void> runTaskLater(int delayMilliseconds, String errorDescription, TabFeature feature, String type, Runnable task);
|
||||
|
||||
/**
|
||||
* Runs task with a delay and measures how long it took to process
|
||||
* @param delayMilliseconds - how long to run the task after
|
||||
* @param errorDescription - description to use if this task throws an error
|
||||
* @param feature - feature to add cpu usage to
|
||||
* @param type - usage type to add cpu usage to
|
||||
* @param task - the task
|
||||
*/
|
||||
Future<Void> runTaskLater(int delayMilliseconds, String errorDescription, String feature, String type, Runnable task);
|
||||
|
||||
Future<Void> runTaskLater(int delayMilliseconds, String errorDescription, Runnable task);
|
||||
Future<?> runTaskLater(int delayMilliseconds, String errorDescription, TabFeature feature, String type, Runnable task);
|
||||
|
||||
Future<?> runTaskLater(int delayMilliseconds, String errorDescription, Runnable task);
|
||||
}
|
||||
@@ -6,8 +6,8 @@ public class Preconditions {
|
||||
if (obj == null) throw new IllegalArgumentException(exceptionMessage);
|
||||
}
|
||||
|
||||
public static void checkRange(Number number, Number min, Number max){
|
||||
public static void checkRange(Number number, Number min, Number max, String variable){
|
||||
if (number.doubleValue() < min.doubleValue() || number.doubleValue() > max.doubleValue())
|
||||
throw new IllegalArgumentException("Number index out of range (" + min + " - " + max + ")");
|
||||
throw new IllegalArgumentException("Number index out of range (" + min + " - " + max + ") for " + variable);
|
||||
}
|
||||
}
|
||||
@@ -8,5 +8,6 @@ tasks {
|
||||
archiveFileName.set("TAB-${project.name}-${project.version}.jar")
|
||||
relocate("org.bstats", "me.neznamy.tab.libs.org.bstats")
|
||||
relocate("org.json.simple", "me.neznamy.tab.libs.org.json.simple")
|
||||
relocate("net.kyori.event", "me.neznamy.tab.libs.net.kyori.event")
|
||||
}
|
||||
}
|
||||
@@ -239,7 +239,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
*/
|
||||
public Object build(PacketPlayOutEntityDestroy packet) throws ReflectiveOperationException {
|
||||
try {
|
||||
return nms.newPacketPlayOutEntityDestroy.newInstance(packet.getEntities());
|
||||
return nms.newPacketPlayOutEntityDestroy.newInstance(new Object[]{packet.getEntities()});
|
||||
} catch (IllegalArgumentException e) {
|
||||
//1.17.0
|
||||
return nms.newPacketPlayOutEntityDestroy.newInstance(packet.getEntities()[0]);
|
||||
|
||||
@@ -13,6 +13,7 @@ import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.features.NickCompatibility;
|
||||
import me.neznamy.tab.shared.features.PipelineInjector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BukkitPipelineInjector extends PipelineInjector {
|
||||
|
||||
@@ -44,7 +45,7 @@ public class BukkitPipelineInjector extends PipelineInjector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext context, Object packet) {
|
||||
public void channelRead(@NotNull ChannelHandlerContext context, @NotNull Object packet) {
|
||||
try {
|
||||
if (TAB.getInstance().getFeatureManager().onPacketReceive(player, packet)) return;
|
||||
super.channelRead(context, packet);
|
||||
@@ -120,9 +121,8 @@ public class BukkitPipelineInjector extends PipelineInjector {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private String getName(TabPlayer p) {
|
||||
return ((NickCompatibility) TAB.getInstance().getFeatureManager().getFeature("nick")).getNickname(p);
|
||||
return ((NickCompatibility) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.NICK_COMPATIBILITY)).getNickname(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-6
@@ -1,6 +1,8 @@
|
||||
package me.neznamy.tab.platforms.bukkit;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
@@ -45,6 +47,7 @@ public class BukkitPlaceholderRegistry implements PlaceholderRegistry {
|
||||
private boolean paperTps;
|
||||
private boolean paperMspt;
|
||||
private boolean purpur;
|
||||
private Method playerIsAfk;
|
||||
|
||||
private Listener healthListener = null;
|
||||
|
||||
@@ -82,7 +85,7 @@ public class BukkitPlaceholderRegistry implements PlaceholderRegistry {
|
||||
//not paper
|
||||
}
|
||||
try {
|
||||
Player.class.getMethod("isAfk");
|
||||
playerIsAfk = Player.class.getMethod("isAfk");
|
||||
purpur = true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
//not purpur
|
||||
@@ -92,11 +95,10 @@ public class BukkitPlaceholderRegistry implements PlaceholderRegistry {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void registerPlaceholders(PlaceholderManager manager) {
|
||||
NumberFormat roundDown = NumberFormat.getInstance();
|
||||
NumberFormat roundDown = NumberFormat.getNumberInstance(Locale.ENGLISH);
|
||||
roundDown.setRoundingMode(RoundingMode.DOWN);
|
||||
roundDown.setMaximumFractionDigits(2);
|
||||
manager.registerPlayerPlaceholder("%displayname%", 500, p -> ((Player) p.getPlayer()).getDisplayName());
|
||||
manager.registerPlayerPlaceholder("%vanished%", 1000, TabPlayer::isVanished);
|
||||
if (paperTps) {
|
||||
manager.registerServerPlaceholder("%tps%", 1000, () -> formatTPS(Bukkit.getTPS()[0]));
|
||||
} else if (recentTps != null) {
|
||||
@@ -115,7 +117,13 @@ public class BukkitPlaceholderRegistry implements PlaceholderRegistry {
|
||||
}
|
||||
manager.registerPlayerPlaceholder("%afk%", 500, p -> {
|
||||
if (essentials != null && ((Essentials)essentials).getUser(p.getUniqueId()).isAfk()) return true;
|
||||
return purpur && ((Player)p.getPlayer()).isAfk();
|
||||
if (!purpur || playerIsAfk == null) return false;
|
||||
try {
|
||||
return playerIsAfk.invoke(p.getPlayer());
|
||||
} catch (final IllegalAccessException | InvocationTargetException exception) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to invoke isAfk!", exception);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
manager.registerPlayerPlaceholder("%essentialsnick%", 1000, p -> {
|
||||
String nickname = null;
|
||||
@@ -191,11 +199,11 @@ public class BukkitPlaceholderRegistry implements PlaceholderRegistry {
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onRespawn(PlayerRespawnEvent e) {
|
||||
health.updateValue(TAB.getInstance().getPlayer(e.getPlayer().getUniqueId()), e.getPlayer().getMaxHealth());
|
||||
health.updateValue(TAB.getInstance().getPlayer(e.getPlayer().getUniqueId()), (int) e.getPlayer().getMaxHealth());
|
||||
}
|
||||
};
|
||||
Bukkit.getPluginManager().registerEvents(healthListener, plugin);
|
||||
}, () -> HandlerList.unregisterAll(healthListener));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
@@ -36,6 +37,7 @@ import me.neznamy.tab.shared.permission.UltraPermissions;
|
||||
import me.neznamy.tab.shared.placeholders.PlayerPlaceholderImpl;
|
||||
import me.neznamy.tab.shared.placeholders.UniversalPlaceholderRegistry;
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
/**
|
||||
* Bukkit's implementation of Platform interface
|
||||
@@ -67,7 +69,9 @@ public class BukkitPlatform implements Platform {
|
||||
} else if (Bukkit.getPluginManager().isPluginEnabled("UltraPermissions")) {
|
||||
return new UltraPermissions(getPluginVersion("UltraPermissions"));
|
||||
} else if (Bukkit.getPluginManager().isPluginEnabled("Vault")) {
|
||||
return new Vault(Bukkit.getServicesManager().getRegistration(Permission.class).getProvider(), getPluginVersion("Vault"));
|
||||
RegisteredServiceProvider<Permission> provider = Bukkit.getServicesManager().getRegistration(Permission.class);
|
||||
if (provider == null) return new None();
|
||||
return new Vault(provider.getProvider(), getPluginVersion("Vault"));
|
||||
} else {
|
||||
return new None();
|
||||
}
|
||||
@@ -91,20 +95,23 @@ public class BukkitPlatform implements Platform {
|
||||
libsDisguises = Bukkit.getPluginManager().isPluginEnabled("LibsDisguises");
|
||||
essentials = Bukkit.getPluginManager().getPlugin("Essentials");
|
||||
TAB tab = TAB.getInstance();
|
||||
if (tab.getConfiguration().isPipelineInjection()) tab.getFeatureManager().registerFeature("injection", new BukkitPipelineInjector());
|
||||
if (tab.getConfiguration().isPipelineInjection())
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.PIPELINE_INJECTION, new BukkitPipelineInjector());
|
||||
new BukkitPlaceholderRegistry(plugin).registerPlaceholders(tab.getPlaceholderManager());
|
||||
new UniversalPlaceholderRegistry().registerPlaceholders(tab.getPlaceholderManager());
|
||||
loadNameTagFeature(tab);
|
||||
tab.loadUniversalFeatures();
|
||||
if (tab.getConfiguration().getConfig().getBoolean("bossbar.enabled", false)) {
|
||||
if (tab.getServerVersion().getMinorVersion() < 9) {
|
||||
tab.getFeatureManager().registerFeature("bossbar", new WitherBossBar(plugin));
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.BOSS_BAR, new WitherBossBar(plugin));
|
||||
} else {
|
||||
tab.getFeatureManager().registerFeature("bossbar", new BossBarManagerImpl());
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.BOSS_BAR, new BossBarManagerImpl());
|
||||
}
|
||||
}
|
||||
if (tab.getServerVersion().getMinorVersion() >= 9 && tab.getConfiguration().getConfig().getBoolean("fix-pet-names.enabled", false)) tab.getFeatureManager().registerFeature("petfix", new PetFix());
|
||||
if (tab.getConfiguration().getConfig().getBoolean("per-world-playerlist.enabled", false)) tab.getFeatureManager().registerFeature("pwp", new PerWorldPlayerList(plugin));
|
||||
if (tab.getServerVersion().getMinorVersion() >= 9 && tab.getConfiguration().getConfig().getBoolean("fix-pet-names.enabled", false))
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.PET_FIX, new PetFix());
|
||||
if (tab.getConfiguration().getConfig().getBoolean("per-world-playerlist.enabled", false))
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.PER_WORLD_PLAYER_LIST, new PerWorldPlayerList(plugin));
|
||||
if (placeholderAPI) {
|
||||
new TabExpansion(plugin);
|
||||
}
|
||||
@@ -114,7 +121,8 @@ public class BukkitPlatform implements Platform {
|
||||
}
|
||||
|
||||
private String getPluginVersion(String plugin) {
|
||||
return Bukkit.getPluginManager().getPlugin(plugin).getDescription().getVersion();
|
||||
Plugin pl = Bukkit.getPluginManager().getPlugin(plugin);
|
||||
return pl == null ? "" : pl.getDescription().getVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,9 +132,9 @@ public class BukkitPlatform implements Platform {
|
||||
private void loadNameTagFeature(TAB tab) {
|
||||
if (tab.getConfiguration().getConfig().getBoolean("scoreboard-teams.enabled", true)) {
|
||||
if (tab.getConfiguration().getConfig().getBoolean("scoreboard-teams.unlimited-nametag-mode.enabled", false) && tab.getServerVersion().getMinorVersion() >= 8) {
|
||||
tab.getFeatureManager().registerFeature("nametagx", new NameTagX(plugin));
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS, new NameTagX(plugin));
|
||||
} else {
|
||||
tab.getFeatureManager().registerFeature("nametag16", new NameTag());
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.NAME_TAGS, new NameTag());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,11 +186,11 @@ public class BukkitPlatform implements Platform {
|
||||
long time = System.nanoTime();
|
||||
String syncedPlaceholder = identifier.substring(6, identifier.length()-1);
|
||||
String value = placeholderAPI ? PlaceholderAPI.setPlaceholders((Player) p.getPlayer(), "%" + syncedPlaceholder + "%") : identifier;
|
||||
getLastValues().put(p.getName(), value);
|
||||
if (!getForceUpdate().contains(p.getName())) getForceUpdate().add(p.getName());
|
||||
getLastValues().put(p, value);
|
||||
getForceUpdate().add(p);
|
||||
TAB.getInstance().getCPUManager().addPlaceholderTime(getIdentifier(), System.nanoTime()-time);
|
||||
});
|
||||
String value = getLastValues().get(p.getName());
|
||||
String value = getLastValues().get(p);
|
||||
return value == null ? identifier : value;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -103,12 +103,10 @@ public class BukkitTabPlayer extends ITabPlayer {
|
||||
|
||||
private void handle(PacketPlayOutBoss packet) {
|
||||
BossBar bar = bossBars.get(packet.getId());
|
||||
if (bar == null && packet.getOperation() != PacketPlayOutBoss.Action.ADD) return; //no idea how
|
||||
switch (packet.getOperation()) {
|
||||
case ADD:
|
||||
if (packet.getOperation() == PacketPlayOutBoss.Action.ADD) {
|
||||
if (bossBars.containsKey(packet.getId())) return;
|
||||
bar = Bukkit.createBossBar(RGBUtils.getInstance().convertToBukkitFormat(packet.getName(), getVersion().getMinorVersion() >= 16 && TAB.getInstance().getServerVersion().getMinorVersion() >= 16),
|
||||
BarColor.valueOf(packet.getColor().name()),
|
||||
bar = Bukkit.createBossBar(RGBUtils.getInstance().convertToBukkitFormat(packet.getName(), getVersion().getMinorVersion() >= 16 && TAB.getInstance().getServerVersion().getMinorVersion() >= 16),
|
||||
BarColor.valueOf(packet.getColor().name()),
|
||||
BarStyle.valueOf(packet.getOverlay().getBukkitName()));
|
||||
if (packet.isCreateWorldFog()) bar.addFlag(BarFlag.CREATE_FOG);
|
||||
if (packet.isDarkenScreen()) bar.addFlag(BarFlag.DARKEN_SKY);
|
||||
@@ -116,7 +114,10 @@ public class BukkitTabPlayer extends ITabPlayer {
|
||||
bar.setProgress(packet.getPct());
|
||||
bossBars.put(packet.getId(), bar);
|
||||
bar.addPlayer(getPlayer());
|
||||
break;
|
||||
return;
|
||||
}
|
||||
if (bar == null) return; //no idea how
|
||||
switch (packet.getOperation()) {
|
||||
case REMOVE:
|
||||
bar.removePlayer(getPlayer());
|
||||
bossBars.remove(packet.getId());
|
||||
@@ -216,7 +217,7 @@ public class BukkitTabPlayer extends ITabPlayer {
|
||||
try {
|
||||
if (!((BukkitPlatform)TAB.getInstance().getPlatform()).isLibsDisguisesEnabled()) return false;
|
||||
return DisguiseAPI.isDisguised(getPlayer());
|
||||
} catch (NoClassDefFoundError | ExceptionInInitializerError e) {
|
||||
} catch (LinkageError e) {
|
||||
//java.lang.NoClassDefFoundError: Could not initialize class me.libraryaddict.disguise.DisguiseAPI
|
||||
TAB.getInstance().getErrorManager().printError("Failed to check disguise status using LibsDisguises", e);
|
||||
((BukkitPlatform)TAB.getInstance().getPlatform()).setLibsDisguisesEnabled(false);
|
||||
@@ -257,4 +258,4 @@ public class BukkitTabPlayer extends ITabPlayer {
|
||||
public int getGamemode() {
|
||||
return getPlayer().getGameMode().getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,9 @@ import java.util.List;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bstats.charts.SimplePie;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
@@ -46,15 +44,17 @@ public class Main extends JavaPlugin {
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Unknown server version: " + Bukkit.getBukkitVersion() + "! Plugin may not work correctly."));
|
||||
}
|
||||
Bukkit.getPluginManager().registerEvents(new BukkitEventListener(this), this);
|
||||
TABCommand command = new TABCommand();
|
||||
Bukkit.getPluginCommand("tab").setExecutor(command);
|
||||
Bukkit.getPluginCommand("tab").setTabCompleter(command);
|
||||
TAB.getInstance().load();
|
||||
Metrics metrics = new Metrics(this, 5304);
|
||||
metrics.addCustomChart(new SimplePie("unlimited_nametag_mode_enabled", () -> TAB.getInstance().getFeatureManager().isFeatureEnabled("nametagx") ? "Yes" : "No"));
|
||||
metrics.addCustomChart(new SimplePie("unlimited_nametag_mode_enabled", () -> TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.UNLIMITED_NAME_TAGS) ? "Yes" : "No"));
|
||||
metrics.addCustomChart(new SimplePie("placeholderapi", () -> Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI") ? "Yes" : "No"));
|
||||
metrics.addCustomChart(new SimplePie("permission_system", () -> TAB.getInstance().getGroupManager().getPlugin().getName()));
|
||||
metrics.addCustomChart(new SimplePie("server_version", () -> "1." + TAB.getInstance().getServerVersion().getMinorVersion() + ".x"));
|
||||
PluginCommand cmd = Bukkit.getPluginCommand("tab");
|
||||
if (cmd == null) return;
|
||||
TABCommand command = new TABCommand();
|
||||
cmd.setExecutor(command);
|
||||
cmd.setTabCompleter(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,8 +150,9 @@ public class Main extends JavaPlugin {
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return -1;
|
||||
} catch (Exception | NoClassDefFoundError e) {
|
||||
TAB.getInstance().getErrorManager().printError(String.format("Failed to get protocol version of %s using ViaVersion v%s", player.getName(), Bukkit.getPluginManager().getPlugin("ViaVersion").getDescription().getVersion()), e);
|
||||
} catch (Exception | LinkageError e) {
|
||||
Plugin via = Bukkit.getPluginManager().getPlugin("ViaVersion");
|
||||
TAB.getInstance().getErrorManager().printError(String.format("Failed to get protocol version of %s using ViaVersion v%s", player.getName(), via == null ? "" : via.getDescription().getVersion()), e);
|
||||
return TAB.getInstance().getServerVersion().getNetworkId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
/**
|
||||
* Bukkit event that is called each time TAB fully loads. This includes server startup, reload,
|
||||
* /tab reload and /plugman reload tab
|
||||
*
|
||||
* @deprecated for removal, use {@link me.neznamy.tab.api.event.plugin.TabLoadEvent}
|
||||
*/
|
||||
@Deprecated
|
||||
public class TabLoadEvent extends Event {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
@@ -20,4 +23,4 @@ public class TabLoadEvent extends Event {
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Bukkit event that is called when player is successfully loaded after joining. This also includes plugin reloading.
|
||||
*
|
||||
* @deprecated for removal, use {@link me.neznamy.tab.api.event.player.PlayerLoadEvent}
|
||||
*/
|
||||
@Deprecated
|
||||
public class TabPlayerLoadEvent extends Event {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
@@ -31,4 +34,4 @@ public class TabPlayerLoadEvent extends Event {
|
||||
public TabPlayer getPlayer() {
|
||||
return player;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
package me.neznamy.tab.platforms.bukkit.features;
|
||||
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
@@ -26,7 +23,7 @@ public class PetFix extends TabFeature {
|
||||
private final int petOwnerPosition = getPetOwnerPosition();
|
||||
|
||||
//logger of last interacts to prevent feature not working on 1.16
|
||||
private final Map<String, Long> lastInteractFix = new HashMap<>();
|
||||
private final WeakHashMap<TabPlayer, Long> lastInteractFix = new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameter
|
||||
@@ -67,13 +64,13 @@ public class PetFix extends TabFeature {
|
||||
@Override
|
||||
public boolean onPacketReceive(TabPlayer sender, Object packet) throws ReflectiveOperationException {
|
||||
if (nms.PacketPlayInUseEntity.isInstance(packet)) {
|
||||
if (lastInteractFix.containsKey(sender.getName()) && (System.currentTimeMillis() - lastInteractFix.get(sender.getName()) < 5)) {
|
||||
if (lastInteractFix.containsKey(sender) && (System.currentTimeMillis() - lastInteractFix.get(sender) < 5)) {
|
||||
//last interact packet was sent right now, cancelling to prevent double-toggle due to this feature enabled
|
||||
return true;
|
||||
}
|
||||
if (isInteract(nms.PacketPlayInUseEntity_ACTION.get(packet))) {
|
||||
//this is the first packet, saving player so the next packet can be cancelled
|
||||
lastInteractFix.put(sender.getName(), System.currentTimeMillis());
|
||||
lastInteractFix.put(sender, System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -124,12 +121,4 @@ public class PetFix extends TabFeature {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removing player data to not have a memory leak
|
||||
*/
|
||||
@Override
|
||||
public void onQuit(TabPlayer disconnectedPlayer) {
|
||||
lastInteractFix.remove(disconnectedPlayer.getName());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.neznamy.tab.platforms.bukkit.features;
|
||||
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
@@ -12,7 +13,6 @@ import me.neznamy.tab.api.bossbar.BossBarManager;
|
||||
import me.neznamy.tab.api.scoreboard.Scoreboard;
|
||||
import me.neznamy.tab.api.scoreboard.ScoreboardManager;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.features.scoreboard.ScoreboardManagerImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -83,21 +83,21 @@ public class TabExpansion extends PlaceholderExpansion {
|
||||
}
|
||||
|
||||
private boolean hasBossBarVisible(TabPlayer p) {
|
||||
BossBarManager boss = (BossBarManager) TAB.getInstance().getFeatureManager().getFeature("bossbar");
|
||||
BossBarManager boss = (BossBarManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.BOSS_BAR);
|
||||
if (boss == null) return false;
|
||||
return boss.hasBossBarVisible(p);
|
||||
}
|
||||
|
||||
private boolean hasScoreboardVisible(TabPlayer p) {
|
||||
ScoreboardManager scoreboard = (ScoreboardManager) TAB.getInstance().getFeatureManager().getFeature("scoreboard");
|
||||
ScoreboardManager scoreboard = (ScoreboardManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SCOREBOARD);
|
||||
if (scoreboard == null) return false;
|
||||
return scoreboard.hasScoreboardVisible(p);
|
||||
}
|
||||
|
||||
private String getActiveScoreboard(TabPlayer p) {
|
||||
ScoreboardManagerImpl sb = (ScoreboardManagerImpl) TabAPI.getInstance().getScoreboardManager();
|
||||
ScoreboardManager sb = TabAPI.getInstance().getScoreboardManager();
|
||||
if (sb == null) return "";
|
||||
Scoreboard active = sb.getActiveScoreboards().get(p);
|
||||
Scoreboard active = sb.getActiveScoreboard(p);
|
||||
if (active == null) return "";
|
||||
return active.getName();
|
||||
}
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ public class BukkitArmorStand implements ArmorStand {
|
||||
private static int idCounter = 2000000000;
|
||||
|
||||
//NameTag feature
|
||||
private final NameTagX manager = (NameTagX) TAB.getInstance().getFeatureManager().getFeature("nametagx");
|
||||
private final NameTagX manager = (NameTagX) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS);
|
||||
|
||||
//owner of the armor stand
|
||||
private final TabPlayer owner;
|
||||
@@ -119,7 +119,7 @@ public class BukkitArmorStand implements ArmorStand {
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) all.sendCustomPacket(destroyPacket, TabConstants.PacketCategory.UNLIMITED_NAMETAGS_DESPAWN);
|
||||
for (TabPlayer all : owner.getArmorStandManager().getNearbyPlayers()) all.sendCustomPacket(destroyPacket, TabConstants.PacketCategory.UNLIMITED_NAMETAGS_DESPAWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-4
@@ -34,7 +34,7 @@ public class EventListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onSneak(PlayerToggleSneakEvent e) {
|
||||
TabPlayer p = TAB.getInstance().getPlayer(e.getPlayer().getUniqueId());
|
||||
if (p == null || !p.isLoaded() || feature.isPlayerDisabled(p)) return;
|
||||
if (p == null || feature.isPlayerDisabled(p)) return;
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask("processing PlayerToggleSneakEvent", feature, TabConstants.CpuUsageCategory.PLAYER_SNEAK, () -> {
|
||||
if (p.getArmorStandManager() != null) p.getArmorStandManager().sneak(e.isSneaking());
|
||||
});
|
||||
@@ -56,12 +56,11 @@ public class EventListener implements Listener {
|
||||
@EventHandler
|
||||
public void onWorldChange(PlayerChangedWorldEvent e) {
|
||||
TabPlayer p = TAB.getInstance().getPlayer(e.getPlayer().getUniqueId());
|
||||
if (p == null) return;
|
||||
if (p == null || !p.isLoaded()) return;
|
||||
long time = System.nanoTime();
|
||||
String to = e.getPlayer().getWorld().getName();
|
||||
if (feature.isDisabled(to)) {
|
||||
if (!feature.getPlayersInDisabledUnlimitedWorlds().contains(p))
|
||||
feature.getPlayersInDisabledUnlimitedWorlds().add(p);
|
||||
feature.getPlayersInDisabledUnlimitedWorlds().add(p);
|
||||
} else {
|
||||
feature.getPlayersInDisabledUnlimitedWorlds().remove(p);
|
||||
}
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
package me.neznamy.tab.platforms.bukkit.features.unlimitedtags;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
|
||||
public class LocationRefresher extends TabFeature {
|
||||
|
||||
private final NameTagX feature;
|
||||
|
||||
public LocationRefresher(NameTagX feature) {
|
||||
super(feature.getFeatureName(), "Processing passengers / preview");
|
||||
this.feature = feature;
|
||||
TAB.getInstance().getPlaceholderManager().registerPlayerPlaceholder("%location0%", 50, p -> {
|
||||
|
||||
if (!feature.getVehicleManager().getPlayersInVehicle().containsKey(p) && !p.isPreviewingNametag()) return null;
|
||||
Location l = ((Player)p.getPlayer()).getLocation();
|
||||
return l.getX()+l.getY()+l.getZ(); //less cpu usage than literal Location#toString() and then .equals() when comparing last value
|
||||
});
|
||||
addUsedPlaceholders(Collections.singletonList("%location0%")); //making sure it's not the same one as in WitherBossBar
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(TabPlayer p, boolean force) {
|
||||
if (feature.getVehicleManager().getPlayersInVehicle().containsKey(p)) {
|
||||
feature.getVehicleManager().processPassengers((Entity) p.getPlayer());
|
||||
}
|
||||
if (p.isPreviewingNametag()) {
|
||||
p.getArmorStandManager().teleport(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-23
@@ -1,10 +1,6 @@
|
||||
package me.neznamy.tab.platforms.bukkit.features.unlimitedtags;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -42,11 +38,11 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
|
||||
//bukkit event listener
|
||||
private final EventListener eventListener = new EventListener(this);
|
||||
|
||||
private final List<TabPlayer> playersInDisabledUnlimitedWorlds = new ArrayList<>();
|
||||
private final Set<TabPlayer> playersInDisabledUnlimitedWorlds = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private final String[] disabledUnlimitedWorldsArray = disabledUnlimitedWorlds.toArray(new String[0]);
|
||||
private final boolean unlimitedWorldWhitelistMode = disabledUnlimitedWorlds.contains("WHITELIST");
|
||||
|
||||
private final List<TabPlayer> playersDisabledWithAPI = new ArrayList<>();
|
||||
private final Set<TabPlayer> playersDisabledWithAPI = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
|
||||
private final VehicleRefresher vehicleManager = new VehicleRefresher(this);
|
||||
|
||||
@@ -57,9 +53,8 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
|
||||
public NameTagX(JavaPlugin plugin) {
|
||||
Collections.reverse(dynamicLines);
|
||||
Bukkit.getPluginManager().registerEvents(eventListener, plugin);
|
||||
TAB.getInstance().getFeatureManager().registerFeature("NameTagX-packet", new PacketListener(this));
|
||||
TAB.getInstance().getFeatureManager().registerFeature("NameTagX-vehicle", vehicleManager);
|
||||
TAB.getInstance().getFeatureManager().registerFeature("NameTagX-location", new LocationRefresher(this));
|
||||
TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS_PACKET_LISTENER, new PacketListener(this));
|
||||
TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS_VEHICLE_REFRESHER, vehicleManager);
|
||||
TAB.getInstance().debug(String.format("Loaded Unlimited NameTag feature with parameters markerFor18x=%s, disableOnBoats=%s, spaceBetweenLines=%s, disabledUnlimitedWorlds=%s",
|
||||
markerFor18x, disableOnBoats, spaceBetweenLines, disabledUnlimitedWorlds));
|
||||
}
|
||||
@@ -84,10 +79,10 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
|
||||
}
|
||||
|
||||
private void startVisibilityRefreshTask() {
|
||||
TAB.getInstance().getCPUManager().startRepeatingMeasuredTask(500, "refreshing NameTag visibility", this, TabConstants.CpuUsageCategory.REFRESHING_NAMETAG_VISIBILITY, () -> {
|
||||
TAB.getInstance().getCPUManager().startRepeatingMeasuredTask(500, "refreshing NameTag visibility", this, TabConstants.CpuUsageCategory.REFRESHING_NAME_TAG_VISIBILITY, () -> {
|
||||
|
||||
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (!p.isLoaded() || isPlayerDisabled(p)) continue;
|
||||
if (isPlayerDisabled(p)) continue;
|
||||
p.getArmorStandManager().updateVisibility(false);
|
||||
}
|
||||
});
|
||||
@@ -105,7 +100,7 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
|
||||
|
||||
@Override
|
||||
public void onJoin(TabPlayer connectedPlayer) {
|
||||
if (isDisabled(connectedPlayer.getWorld()) && !playersInDisabledUnlimitedWorlds.contains(connectedPlayer))
|
||||
if (isDisabled(connectedPlayer.getWorld()))
|
||||
playersInDisabledUnlimitedWorlds.add(connectedPlayer);
|
||||
super.onJoin(connectedPlayer);
|
||||
getEntityIdMap().put(((Player) connectedPlayer.getPlayer()).getEntityId(), connectedPlayer);
|
||||
@@ -135,9 +130,7 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (all.getArmorStandManager() != null) all.getArmorStandManager().unregisterPlayer(disconnectedPlayer);
|
||||
}
|
||||
getEntityIdMap().remove(((Player) disconnectedPlayer.getPlayer()).getEntityId());
|
||||
playersInDisabledUnlimitedWorlds.remove(disconnectedPlayer);
|
||||
playersDisabledWithAPI.remove(disconnectedPlayer);
|
||||
entityIdMap.remove(((Player) disconnectedPlayer.getPlayer()).getEntityId());
|
||||
if (disconnectedPlayer.getArmorStandManager() != null) { //player was not loaded yet
|
||||
disconnectedPlayer.getArmorStandManager().destroy();
|
||||
TAB.getInstance().getCPUManager().runTaskLater(500, "processing onQuit", this, TabConstants.CpuUsageCategory.PLAYER_QUIT, () -> disconnectedPlayer.getArmorStandManager().destroy());
|
||||
@@ -231,16 +224,18 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
|
||||
* @param p - player to update
|
||||
*/
|
||||
@Override
|
||||
public void updateProperties(TabPlayer p) {
|
||||
super.updateProperties(p);
|
||||
p.loadPropertyFromConfig(this, TabConstants.Property.CUSTOMTAGNAME, p.getName());
|
||||
p.setProperty(this, TabConstants.Property.NAMETAG, p.getProperty(TabConstants.Property.TAGPREFIX).getCurrentRawValue() + p.getProperty(TabConstants.Property.CUSTOMTAGNAME).getCurrentRawValue() + p.getProperty(TabConstants.Property.TAGSUFFIX).getCurrentRawValue());
|
||||
public boolean updateProperties(TabPlayer p) {
|
||||
boolean changed = super.updateProperties(p);
|
||||
if (p.loadPropertyFromConfig(this, TabConstants.Property.CUSTOMTAGNAME, p.getName())) changed = true;
|
||||
if (p.setProperty(this, TabConstants.Property.NAMETAG, p.getProperty(TabConstants.Property.TAGPREFIX).getCurrentRawValue() +
|
||||
p.getProperty(TabConstants.Property.CUSTOMTAGNAME).getCurrentRawValue() + p.getProperty(TabConstants.Property.TAGSUFFIX).getCurrentRawValue())) changed = true;
|
||||
for (String property : dynamicLines) {
|
||||
if (!property.equals(TabConstants.Property.NAMETAG)) p.loadPropertyFromConfig(this, property);
|
||||
if (!property.equals(TabConstants.Property.NAMETAG) && p.loadPropertyFromConfig(this, property)) changed = true;
|
||||
}
|
||||
for (String property : staticLines.keySet()) {
|
||||
if (!property.equals(TabConstants.Property.NAMETAG)) p.loadPropertyFromConfig(this, property);
|
||||
if (!property.equals(TabConstants.Property.NAMETAG) && p.loadPropertyFromConfig(this, property)) changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -273,7 +268,7 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
|
||||
return markerFor18x;
|
||||
}
|
||||
|
||||
public List<TabPlayer> getPlayersInDisabledUnlimitedWorlds() {
|
||||
public Set<TabPlayer> getPlayersInDisabledUnlimitedWorlds() {
|
||||
return playersInDisabledUnlimitedWorlds;
|
||||
}
|
||||
|
||||
|
||||
+33
-12
@@ -3,6 +3,7 @@ package me.neznamy.tab.platforms.bukkit.features.unlimitedtags;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -13,24 +14,50 @@ import me.neznamy.tab.shared.TAB;
|
||||
|
||||
public class VehicleRefresher extends TabFeature {
|
||||
|
||||
//list of players currently in a vehicle
|
||||
private final Map<TabPlayer, Entity> playersInVehicle = new ConcurrentHashMap<>();
|
||||
//map of players currently in a vehicle
|
||||
private final WeakHashMap<TabPlayer, Entity> playersInVehicle = new WeakHashMap<>();
|
||||
|
||||
//map of vehicles carrying players
|
||||
private final Map<Integer, List<Entity>> vehicles = new ConcurrentHashMap<>();
|
||||
|
||||
//list of players currently on boats
|
||||
private final List<TabPlayer> playersOnBoats = new ArrayList<>();
|
||||
//set of players currently on boats
|
||||
private final Set<TabPlayer> playersOnBoats = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
|
||||
private final NameTagX feature;
|
||||
|
||||
public VehicleRefresher(NameTagX feature) {
|
||||
super(feature.getFeatureName(), "Refreshing vehicles");
|
||||
this.feature = feature;
|
||||
TAB.getInstance().getCPUManager().startRepeatingMeasuredTask(50, "processing player movement",
|
||||
this, TabConstants.CpuUsageCategory.PROCESSING_PLAYER_MOVEMENT, () -> {
|
||||
for (TabPlayer inVehicle : playersInVehicle.keySet()) {
|
||||
inVehicle.getArmorStandManager().teleport();
|
||||
// feature.getVehicleManager().processPassengers((Entity) inVehicle.getPlayer());
|
||||
}
|
||||
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (p.isPreviewingNametag()) {
|
||||
p.getArmorStandManager().teleport(p);
|
||||
}
|
||||
}
|
||||
});
|
||||
addUsedPlaceholders(Collections.singletonList("%vehicle%"));
|
||||
TAB.getInstance().getPlaceholderManager().registerPlayerPlaceholder("%vehicle%", 100, p -> ((Player)p.getPlayer()).getVehicle());
|
||||
TAB.getInstance().getPlaceholderManager().registerPlayerPlaceholder("%vehicle%", 100, p -> ((Player)p.getPlayer()).getVehicle() == null ? "" : ((Player)p.getPlayer()).getVehicle());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
|
||||
Entity vehicle = ((Player)p.getPlayer()).getVehicle();
|
||||
if (vehicle != null) {
|
||||
vehicles.put(vehicle.getEntityId(), getPassengers(vehicle));
|
||||
playersInVehicle.put(p, vehicle);
|
||||
if (feature.isDisableOnBoats() && vehicle.getType() == EntityType.BOAT) {
|
||||
playersOnBoats.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(TabPlayer p, boolean force) {
|
||||
if (feature.isPlayerDisabled(p)) return;
|
||||
@@ -64,8 +91,6 @@ public class VehicleRefresher extends TabFeature {
|
||||
@Override
|
||||
public void onQuit(TabPlayer disconnectedPlayer) {
|
||||
if (playersInVehicle.containsKey(disconnectedPlayer)) vehicles.remove(playersInVehicle.get(disconnectedPlayer).getEntityId());
|
||||
playersInVehicle.remove(disconnectedPlayer);
|
||||
playersOnBoats.remove(disconnectedPlayer);
|
||||
}
|
||||
|
||||
public Map<Integer, List<Entity>> getVehicles() {
|
||||
@@ -112,8 +137,4 @@ public class VehicleRefresher extends TabFeature {
|
||||
processPassengers(passenger);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<TabPlayer, Entity> getPlayersInVehicle() {
|
||||
return playersInVehicle;
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ public final class NMSStorage {
|
||||
|
||||
//another field due to fabric which uses 1.16 package on 1.17 server
|
||||
private final ProtocolVersion serverVersion = ProtocolVersion.fromFriendlyName(Bukkit.getBukkitVersion().split("-")[0]);
|
||||
|
||||
|
||||
//base
|
||||
private final Class<?> Packet = getNMSClass("net.minecraft.network.protocol.Packet", "Packet");
|
||||
public final Class<?> EnumChatFormat = getNMSClass("net.minecraft.EnumChatFormat", "EnumChatFormat");
|
||||
@@ -227,6 +227,7 @@ public final class NMSStorage {
|
||||
* If any class, field or method fails to load
|
||||
*/
|
||||
public NMSStorage() throws ReflectiveOperationException {
|
||||
ProtocolVersion.UNKNOWN.setMinorVersion(minorVersion); //fixing compatibility with forks that set version field value to "Unknown"
|
||||
Class<?> NetworkManager = getNMSClass("net.minecraft.network.NetworkManager", "NetworkManager");
|
||||
if (minorVersion >= 7) {
|
||||
NETWORK_MANAGER = getFields(PlayerConnection, NetworkManager).get(0);
|
||||
@@ -460,8 +461,8 @@ public final class NMSStorage {
|
||||
PacketPlayOutScoreboardTeam_NAME = getFields(PacketPlayOutScoreboardTeam, String.class).get(0);
|
||||
PacketPlayOutScoreboardTeam_PLAYERS = getFields(PacketPlayOutScoreboardTeam, Collection.class).get(0);
|
||||
ScoreboardTeam_getPlayerNameSet = getMethods(ScoreboardTeam, Collection.class).get(0);
|
||||
ScoreboardTeam_setAllowFriendlyFire = getMethod(ScoreboardTeam, new String[]{"setAllowFriendlyFire", "a"}, boolean.class);
|
||||
ScoreboardTeam_setCanSeeFriendlyInvisibles = getMethod(ScoreboardTeam, new String[]{"setCanSeeFriendlyInvisibles", "b"}, boolean.class);
|
||||
ScoreboardTeam_setAllowFriendlyFire = getMethod(ScoreboardTeam, new String[]{"setAllowFriendlyFire", "a", "func_96660_a"}, boolean.class);
|
||||
ScoreboardTeam_setCanSeeFriendlyInvisibles = getMethod(ScoreboardTeam, new String[]{"setCanSeeFriendlyInvisibles", "b", "func_98300_b"}, boolean.class);
|
||||
if (minorVersion >= 8) {
|
||||
Class<?> EnumNameTagVisibility = getNMSClass("net.minecraft.world.scores.ScoreboardTeamBase$EnumNameTagVisibility", "ScoreboardTeamBase$EnumNameTagVisibility", "EnumNameTagVisibility");
|
||||
EnumNameTagVisibility_values = getEnumValues(EnumNameTagVisibility);
|
||||
@@ -549,7 +550,21 @@ public final class NMSStorage {
|
||||
//not the first method in array
|
||||
}
|
||||
}
|
||||
throw new NoSuchMethodException("No method found with possible names " + Arrays.toString(names) + " with parameters " + Arrays.toString(parameterTypes) + " in class " + clazz.getName());
|
||||
List<String> list = new ArrayList<>();
|
||||
for (Method m : clazz.getMethods()) {
|
||||
if (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.getName());
|
||||
}
|
||||
throw new NoSuchMethodException("No method found with possible names " + Arrays.toString(names) + " with parameters " +
|
||||
Arrays.toString(parameterTypes) + " in class " + clazz.getName() + ". Methods with matching parameters: " + list);
|
||||
}
|
||||
|
||||
private Method getMethod(Class<?> clazz, String name, Class<?>... parameterTypes) throws NoSuchMethodException {
|
||||
|
||||
@@ -131,7 +131,7 @@ scoreboard:
|
||||
- "* &eOnline&7: &f%online%&7/&4%maxplayers%"
|
||||
- "* &eCurrent World&7: &f%worldonline%"
|
||||
- "* &eStaff&7: &f%staffonline%"
|
||||
- ""
|
||||
- " "
|
||||
- "&6Server Info:"
|
||||
- "* &bTPS&7: %tps%"
|
||||
- "* &bUptime&7: &f%server_uptime%"
|
||||
@@ -145,9 +145,9 @@ scoreboard:
|
||||
- "* &eKills&7: &f%statistic_player_kills%"
|
||||
- "* &eDeaths&7: &f%statistic_deaths%"
|
||||
- "* &eHealth&7: &f%health%"
|
||||
- ""
|
||||
- " "
|
||||
- "&6Personal Info:"
|
||||
- "* &bRank&7: &f%rank%"
|
||||
- "* &bRank&7: &f%group%"
|
||||
- "* &bPing&7: &f%ping%&7ms"
|
||||
- "* &bWorld&7: &f%world%"
|
||||
- "%animation:MyAnimation1%"
|
||||
@@ -163,9 +163,6 @@ placeholders:
|
||||
date-format: "dd.MM.yyyy"
|
||||
time-format: "[HH:mm:ss / h:mm a]"
|
||||
time-offset: 0
|
||||
remove-strings:
|
||||
- "[]"
|
||||
- "< >"
|
||||
|
||||
placeholder-output-replacements:
|
||||
"%essentials_vanished%":
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
name: @name@
|
||||
name: TAB
|
||||
version: @version@
|
||||
author: NEZNAMY
|
||||
main: me.neznamy.tab.platforms.bukkit.Main
|
||||
api-version: 1.13
|
||||
softdepend: [PlaceholderAPI, Vault, UltraPermissions, LuckPerms, Essentials, LibsDisguises, ProtocolSupport, ViaVersion]
|
||||
softdepend: [PlaceholderAPI, Vault, UltraPermissions, LuckPerms, Essentials, LibsDisguises, ProtocolSupport, ViaVersion, floodgate]
|
||||
website: "https://github.com/NEZNAMY/TAB"
|
||||
description: @description@
|
||||
commands:
|
||||
tab:
|
||||
description: Plugin's main command
|
||||
+11
-16
@@ -1,34 +1,27 @@
|
||||
package me.neznamy.tab.platforms.bungeecord;
|
||||
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.features.PluginMessageHandler;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ChatEvent;
|
||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
|
||||
/**
|
||||
* The core for BungeeCord forwarding events into all enabled features
|
||||
*/
|
||||
public class BungeeEventListener implements Listener {
|
||||
|
||||
private final PluginMessageHandler plm;
|
||||
|
||||
public BungeeEventListener(PluginMessageHandler plm) {
|
||||
this.plm = plm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect event listener to forward the event to all features
|
||||
* @param e - disconnect event
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
@EventHandler
|
||||
public void onQuit(PlayerDisconnectEvent e){
|
||||
if (TAB.getInstance().isDisabled()) return;
|
||||
TAB.getInstance().getFeatureManager().onQuit(TAB.getInstance().getPlayer(e.getPlayer().getUniqueId()));
|
||||
TAB.getInstance().getCPUManager().runTask("processing PlayerDisconnectEvent", () ->
|
||||
TAB.getInstance().getFeatureManager().onQuit(TAB.getInstance().getPlayer(e.getPlayer().getUniqueId())));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,14 +29,16 @@ public class BungeeEventListener implements Listener {
|
||||
* @param e
|
||||
* switch event
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
@EventHandler
|
||||
public void onSwitch(ServerSwitchEvent e){
|
||||
if (TAB.getInstance().isDisabled()) return;
|
||||
if (TAB.getInstance().getPlayer(e.getPlayer().getUniqueId()) == null) {
|
||||
TAB.getInstance().getFeatureManager().onJoin(new BungeeTabPlayer(e.getPlayer()));
|
||||
} else {
|
||||
TAB.getInstance().getFeatureManager().onServerChange(e.getPlayer().getUniqueId(), e.getPlayer().getServer().getInfo().getName());
|
||||
}
|
||||
TAB.getInstance().getCPUManager().runTask("processing ServerSwitchEvent", () -> {
|
||||
if (TAB.getInstance().getPlayer(e.getPlayer().getUniqueId()) == null) {
|
||||
TAB.getInstance().getFeatureManager().onJoin(new BungeeTabPlayer(e.getPlayer()));
|
||||
} else {
|
||||
TAB.getInstance().getFeatureManager().onServerChange(e.getPlayer().getUniqueId(), e.getPlayer().getServer().getInfo().getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -62,7 +62,7 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
public void write(ChannelHandlerContext context, Object packet, ChannelPromise channelPromise) {
|
||||
long time = System.nanoTime();
|
||||
Object modifiedPacket = packet instanceof ByteBuf && byteBufDeserialization ? deserialize((ByteBuf) packet) : packet;
|
||||
TAB.getInstance().getCPUManager().addTime("Packet deserializing", TabConstants.CpuUsageCategory.BYTEBUF, System.nanoTime()-time);
|
||||
TAB.getInstance().getCPUManager().addTime("Packet deserializing", TabConstants.CpuUsageCategory.BYTE_BUF, System.nanoTime()-time);
|
||||
try {
|
||||
switch(modifiedPacket.getClass().getSimpleName()) {
|
||||
case "PlayerListItem":
|
||||
@@ -112,7 +112,7 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
col.remove(getName(p));
|
||||
}
|
||||
}
|
||||
RedisBungeeSupport redis = (RedisBungeeSupport) TAB.getInstance().getFeatureManager().getFeature("redisbungee");
|
||||
RedisBungeeSupport redis = (RedisBungeeSupport) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.REDIS_BUNGEE);
|
||||
if (redis != null) {
|
||||
for (RedisPlayer p : redis.getRedisPlayers().values()) {
|
||||
if (col.contains(p.getName()) && !packet.getName().equals(p.getTeamName())) {
|
||||
@@ -126,7 +126,7 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
}
|
||||
|
||||
private String getName(TabPlayer p) {
|
||||
NickCompatibility nick = (NickCompatibility) TAB.getInstance().getFeatureManager().getFeature("nick");
|
||||
NickCompatibility nick = (NickCompatibility) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.NICK_COMPATIBILITY);
|
||||
if (nick != null) {
|
||||
return nick.getNickname(p);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package me.neznamy.tab.platforms.bungeecord;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.api.protocol.PacketBuilder;
|
||||
@@ -10,6 +11,7 @@ import me.neznamy.tab.platforms.bungeecord.event.TabLoadEvent;
|
||||
import me.neznamy.tab.platforms.bungeecord.event.TabPlayerLoadEvent;
|
||||
import me.neznamy.tab.platforms.bungeecord.redisbungee.RedisBungeeSupport;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.features.PluginMessageHandler;
|
||||
import me.neznamy.tab.shared.permission.LuckPerms;
|
||||
import me.neznamy.tab.shared.permission.PermissionPlugin;
|
||||
@@ -56,11 +58,16 @@ public class BungeePlatform extends ProxyPlatform {
|
||||
@Override
|
||||
public void loadFeatures() {
|
||||
TAB tab = TAB.getInstance();
|
||||
if (tab.getConfiguration().isPipelineInjection()) tab.getFeatureManager().registerFeature("injection", new BungeePipelineInjector());
|
||||
if (tab.getConfiguration().isPipelineInjection())
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.PIPELINE_INJECTION, new BungeePipelineInjector());
|
||||
new BungeePlaceholderRegistry().registerPlaceholders(tab.getPlaceholderManager());
|
||||
super.loadFeatures();
|
||||
if (ProxyServer.getInstance().getPluginManager().getPlugin("RedisBungee") != null) {
|
||||
tab.getFeatureManager().registerFeature("redisbungee", new RedisBungeeSupport(plugin));
|
||||
if (RedisBungeeAPI.getRedisBungeeApi() != null) {
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.REDIS_BUNGEE, new RedisBungeeSupport(plugin));
|
||||
} else {
|
||||
TAB.getInstance().getErrorManager().criticalError("RedisBungee plugin was detected, but it returned null API instance. Disabling hook.", null);
|
||||
}
|
||||
}
|
||||
for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) {
|
||||
tab.addPlayer(new BungeeTabPlayer(p));
|
||||
|
||||
+8
-7
@@ -33,14 +33,15 @@ public class BungeePluginMessageHandler extends PluginMessageHandler implements
|
||||
*/
|
||||
@EventHandler
|
||||
public void on(PluginMessageEvent event){
|
||||
if (!event.getTag().equalsIgnoreCase(channelName)) return;
|
||||
if (!event.getTag().equals(channelName)) return;
|
||||
if (event.getReceiver() instanceof ProxiedPlayer) {
|
||||
long time = System.nanoTime();
|
||||
BungeeTabPlayer receiver = (BungeeTabPlayer) TAB.getInstance().getPlayer(((ProxiedPlayer) event.getReceiver()).getUniqueId());
|
||||
if (receiver == null) return;
|
||||
onPluginMessage(receiver, ByteStreams.newDataInput(event.getData()));
|
||||
event.setCancelled(true);
|
||||
TAB.getInstance().getCPUManager().addTime("Plugin message handling", TabConstants.CpuUsageCategory.PLUGIN_MESSAGE, System.nanoTime()-time);
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask("processing PluginMessageEvent", "Plugin message handling",
|
||||
TabConstants.CpuUsageCategory.PLUGIN_MESSAGE, () -> {
|
||||
BungeeTabPlayer receiver = (BungeeTabPlayer) TAB.getInstance().getPlayer(((ProxiedPlayer) event.getReceiver()).getUniqueId());
|
||||
if (receiver == null) return;
|
||||
onPluginMessage(receiver, ByteStreams.newDataInput(event.getData()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +49,6 @@ public class BungeePluginMessageHandler extends PluginMessageHandler implements
|
||||
public void sendPluginMessage(TabPlayer player, byte[] message) {
|
||||
if (((ProxiedPlayer) player.getPlayer()).getServer() == null) return; //not connected to any server yet
|
||||
((ProxiedPlayer) player.getPlayer()).getServer().sendData(channelName, message);
|
||||
TAB.getInstance().getCPUManager().packetSent("Plugin Message");
|
||||
TAB.getInstance().getCPUManager().packetSent("Plugin Message (" + new String(message) + ")");
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import java.lang.reflect.Method;
|
||||
import de.myzelyam.api.vanish.BungeeVanishAPI;
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.features.PluginMessageHandler;
|
||||
import me.neznamy.tab.shared.proxy.ProxyTabPlayer;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
|
||||
@@ -32,12 +32,12 @@ public class Main extends Plugin {
|
||||
}
|
||||
PluginMessageHandler plm = new BungeePluginMessageHandler(this);
|
||||
TAB.setInstance(new TAB(new BungeePlatform(this, plm), ProtocolVersion.PROXY));
|
||||
getProxy().getPluginManager().registerListener(this, new BungeeEventListener(plm));
|
||||
getProxy().getPluginManager().registerListener(this, new BungeeEventListener());
|
||||
getProxy().getPluginManager().registerCommand(this, new BTABCommand());
|
||||
TAB.getInstance().load();
|
||||
Metrics metrics = new Metrics(this, 10535);
|
||||
metrics.addCustomChart(new SimplePie("permission_system", () -> TAB.getInstance().getGroupManager().getPlugin().getName()));
|
||||
metrics.addCustomChart(new SimplePie("global_playerlist_enabled", () -> TAB.getInstance().getFeatureManager().isFeatureEnabled("globalplayerlist") ? "Yes" : "No"));
|
||||
metrics.addCustomChart(new SimplePie("global_playerlist_enabled", () -> TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.GLOBAL_PLAYER_LIST) ? "Yes" : "No"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-1
@@ -5,7 +5,10 @@ import net.md_5.bungee.api.plugin.Event;
|
||||
/**
|
||||
* Bungee event that is called each time TAB fully loads. This includes server startup, reload and
|
||||
* /btab reload
|
||||
*
|
||||
* @deprecated for removal, use {@link me.neznamy.tab.api.event.plugin.TabLoadEvent}
|
||||
*/
|
||||
@Deprecated
|
||||
public class TabLoadEvent extends Event {
|
||||
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -5,7 +5,10 @@ import net.md_5.bungee.api.plugin.Event;
|
||||
|
||||
/**
|
||||
* BungeeCord event that is called when player is successfully loaded after joining. This also includes plugin reloading.
|
||||
*
|
||||
* @deprecated for removal, use {@link me.neznamy.tab.api.event.player.PlayerLoadEvent}
|
||||
*/
|
||||
@Deprecated
|
||||
public class TabPlayerLoadEvent extends Event {
|
||||
|
||||
private final TabPlayer player;
|
||||
@@ -17,4 +20,4 @@ public class TabPlayerLoadEvent extends Event {
|
||||
public TabPlayer getPlayer() {
|
||||
return player;
|
||||
}
|
||||
}
|
||||
}
|
||||
+129
-129
@@ -39,20 +39,15 @@ public class RedisBungeeSupport extends TabFeature implements RedisSupport, List
|
||||
private static final String CHANNEL_NAME = "TAB";
|
||||
|
||||
private final Map<String, RedisPlayer> redisPlayers = new ConcurrentHashMap<>();
|
||||
private final GlobalPlayerList global = (GlobalPlayerList) TAB.getInstance().getFeatureManager().getFeature("globalplayerlist");
|
||||
private final PlayerList playerlist = (PlayerList) TAB.getInstance().getFeatureManager().getFeature("playerlist");
|
||||
private final NameTag nametags = (NameTag) TAB.getInstance().getFeatureManager().getFeature("nametag16");
|
||||
private final GlobalPlayerList global = (GlobalPlayerList) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.GLOBAL_PLAYER_LIST);
|
||||
private final PlayerList playerlist = (PlayerList) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.PLAYER_LIST);
|
||||
private final NameTag nametags = (NameTag) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.NAME_TAGS);
|
||||
private final UUID proxy = UUID.randomUUID();
|
||||
|
||||
public RedisBungeeSupport(Plugin plugin) {
|
||||
super("RedisBungee", null);
|
||||
RedisBungeeAPI api = RedisBungeeAPI.getRedisBungeeApi();
|
||||
if (api == null) {
|
||||
TAB.getInstance().getErrorManager().criticalError("RedisBungee plugin was detected, but it returned null API instance. Disabling hook.", null);
|
||||
return;
|
||||
}
|
||||
ProxyServer.getInstance().getPluginManager().registerListener(plugin, this);
|
||||
api.registerPubSubChannels(CHANNEL_NAME);
|
||||
RedisBungeeAPI.getRedisBungeeApi().registerPubSubChannels(CHANNEL_NAME);
|
||||
overridePlaceholders();
|
||||
}
|
||||
|
||||
@@ -107,120 +102,124 @@ public class RedisBungeeSupport extends TabFeature implements RedisSupport, List
|
||||
@EventHandler
|
||||
public void onMessage(PubSubMessageEvent e) {
|
||||
if (!e.getChannel().equals(CHANNEL_NAME)) return;
|
||||
JSONObject message;
|
||||
try {
|
||||
message = (JSONObject) new JSONParser().parse(e.getMessage());
|
||||
} catch (ParseException ex) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to parse json message \"" + e.getMessage() + "\"", ex);
|
||||
return;
|
||||
}
|
||||
if (message.get("proxy").equals(proxy.toString())) return; //message coming from current proxy
|
||||
String action = (String) message.get("action");
|
||||
UUID id = UUID.fromString((String) message.getOrDefault("UUID", proxy.toString()));
|
||||
RedisPlayer target;
|
||||
switch(action) {
|
||||
case "loadrequest":
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("proxy", proxy.toString());
|
||||
json.put("action", "load");
|
||||
List<JSONObject> players = new ArrayList<>();
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
players.add(RedisPlayer.toJson(this, all));
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask("processing PubSubMessageEvent", this, TabConstants.CpuUsageCategory.REDIS_BUNGEE_MESSAGE, () -> {
|
||||
JSONObject message;
|
||||
try {
|
||||
message = (JSONObject) new JSONParser().parse(e.getMessage());
|
||||
} catch (ParseException ex) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to parse json message \"" + e.getMessage() + "\"", ex);
|
||||
return;
|
||||
}
|
||||
json.put("players", players);
|
||||
RedisBungeeAPI.getRedisBungeeApi().sendChannelMessage(CHANNEL_NAME, json.toString());
|
||||
break;
|
||||
case "load":
|
||||
List<JSONObject> players1 = (List<JSONObject>) message.get("players");
|
||||
for (JSONObject obj : players1) {
|
||||
RedisPlayer p = RedisPlayer.fromJson(this, obj);
|
||||
if (!redisPlayers.containsKey(p.getUniqueId().toString())) {
|
||||
redisPlayers.put(p.getUniqueId().toString(), p);
|
||||
join(p);
|
||||
}
|
||||
if (message.get("proxy").equals(proxy.toString())) return; //message coming from current proxy
|
||||
String action = (String) message.get("action");
|
||||
UUID id = UUID.fromString((String) message.getOrDefault("UUID", proxy.toString()));
|
||||
RedisPlayer target;
|
||||
switch(action) {
|
||||
case "loadrequest":
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("proxy", proxy.toString());
|
||||
json.put("action", "load");
|
||||
List<JSONObject> players = new ArrayList<>();
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
players.add(RedisPlayer.toJson(this, all));
|
||||
}
|
||||
json.put("players", players);
|
||||
RedisBungeeAPI.getRedisBungeeApi().sendChannelMessage(CHANNEL_NAME, json.toString());
|
||||
break;
|
||||
case "load":
|
||||
List<JSONObject> players1 = (List<JSONObject>) message.get("players");
|
||||
for (JSONObject obj : players1) {
|
||||
RedisPlayer p = RedisPlayer.fromJson(this, obj);
|
||||
if (!redisPlayers.containsKey(p.getUniqueId().toString())) {
|
||||
redisPlayers.put(p.getUniqueId().toString(), p);
|
||||
join(p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "join":
|
||||
target = RedisPlayer.fromJson(this, message);
|
||||
redisPlayers.put(id.toString(), target);
|
||||
join(target);
|
||||
break;
|
||||
case "server":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break;
|
||||
String server = (String) message.get("server");
|
||||
if (global == null) {
|
||||
target.setServer(server);
|
||||
return;
|
||||
}
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (viewer.getVersion().getMinorVersion() < 8) continue;
|
||||
boolean before = shouldSee(viewer, target.getServer(), target.isVanished());
|
||||
boolean after = shouldSee(viewer, server, target.isVanished());
|
||||
if (!before && after) {
|
||||
viewer.sendCustomPacket(target.getAddPacket(), this);
|
||||
}
|
||||
if (before && !after) {
|
||||
viewer.sendCustomPacket(target.getRemovePacket(), this);
|
||||
}
|
||||
}
|
||||
target.setServer(server);
|
||||
break;
|
||||
case "tabformat":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break;
|
||||
target.setTabFormat((String) message.get("tabformat"));
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (viewer.getVersion().getMinorVersion() >= 8) viewer.sendCustomPacket(target.getUpdatePacket(), this);
|
||||
}
|
||||
break;
|
||||
case "nametag":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break;
|
||||
target.setTagPrefix((String) message.get(TabConstants.Property.TAGPREFIX));
|
||||
target.setTagSuffix((String) message.get(TabConstants.Property.TAGSUFFIX));
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.sendCustomPacket(target.getUpdateTeamPacket(), this);
|
||||
}
|
||||
break;
|
||||
case "belowname":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break;
|
||||
target.setBelowName((String) message.get("belowname"));
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.sendCustomPacket(target.getBelowNameUpdatePacket(), this);
|
||||
}
|
||||
break;
|
||||
case "yellow-number":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break;
|
||||
target.setYellowNumber((String) message.get("yellow-number"));
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.sendCustomPacket(target.getYellowNumberUpdatePacket(), this);
|
||||
}
|
||||
break;
|
||||
case "team":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break;
|
||||
PacketPlayOutScoreboardTeam unregister = target.getUnregisterTeamPacket();
|
||||
target.setTeamName((String) message.get("to"));
|
||||
PacketPlayOutScoreboardTeam register = target.getRegisterTeamPacket();
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.sendCustomPacket(unregister, this);
|
||||
viewer.sendCustomPacket(register, this);
|
||||
}
|
||||
break;
|
||||
case "quit":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break; //player left current proxy and was unloaded from memory, therefore null check didn't pass
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
all.sendCustomPacket(target.getUnregisterTeamPacket(), this);
|
||||
if (all.getVersion().getMinorVersion() < 8) continue;
|
||||
all.sendCustomPacket(target.getRemovePacket(), this);
|
||||
}
|
||||
redisPlayers.remove(id.toString());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "join":
|
||||
target = RedisPlayer.fromJson(this, message);
|
||||
redisPlayers.put(id.toString(), target);
|
||||
join(target);
|
||||
break;
|
||||
case "server":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break;
|
||||
String server = (String) message.get("server");
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (viewer.getVersion().getMinorVersion() < 8) continue;
|
||||
boolean before = shouldSee(viewer, target.getServer(), target.isVanished());
|
||||
boolean after = shouldSee(viewer, server, target.isVanished());
|
||||
if (!before && after) {
|
||||
viewer.sendCustomPacket(target.getAddPacket(), this);
|
||||
}
|
||||
if (before && !after) {
|
||||
viewer.sendCustomPacket(target.getRemovePacket(), this);
|
||||
}
|
||||
}
|
||||
target.setServer(server);
|
||||
break;
|
||||
case "tabformat":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break;
|
||||
target.setTabFormat((String) message.get("tabformat"));
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (viewer.getVersion().getMinorVersion() >= 8) viewer.sendCustomPacket(target.getUpdatePacket(), this);
|
||||
}
|
||||
break;
|
||||
case "nametag":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break;
|
||||
target.setTagPrefix((String) message.get(TabConstants.Property.TAGPREFIX));
|
||||
target.setTagSuffix((String) message.get(TabConstants.Property.TAGSUFFIX));
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.sendCustomPacket(target.getUpdateTeamPacket(), this);
|
||||
}
|
||||
break;
|
||||
case "belowname":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break;
|
||||
target.setBelowName((String) message.get("belowname"));
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.sendCustomPacket(target.getBelowNameUpdatePacket(), this);
|
||||
}
|
||||
break;
|
||||
case "yellow-number":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break;
|
||||
target.setYellowNumber((String) message.get("yellow-number"));
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.sendCustomPacket(target.getYellowNumberUpdatePacket(), this);
|
||||
}
|
||||
break;
|
||||
case "team":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break;
|
||||
PacketPlayOutScoreboardTeam unregister = target.getUnregisterTeamPacket();
|
||||
target.setTeamName((String) message.get("to"));
|
||||
PacketPlayOutScoreboardTeam register = target.getRegisterTeamPacket();
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.sendCustomPacket(unregister, this);
|
||||
viewer.sendCustomPacket(register, this);
|
||||
}
|
||||
break;
|
||||
case "quit":
|
||||
target = redisPlayers.get(id.toString());
|
||||
if (target == null) break; //player left current proxy and was unloaded from memory, therefore null check didn't pass
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (all.getVersion().getMinorVersion() < 8) continue;
|
||||
all.sendCustomPacket(target.getUnregisterTeamPacket(), this);
|
||||
if (shouldSee(all, target.getServer(), target.isVanished()) && !all.getServer().equals(target.getServer())) {
|
||||
all.sendCustomPacket(target.getRemovePacket(), this);
|
||||
}
|
||||
}
|
||||
redisPlayers.remove(id.toString());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void join(RedisPlayer target) {
|
||||
@@ -229,6 +228,10 @@ public class RedisBungeeSupport extends TabFeature implements RedisSupport, List
|
||||
all.sendCustomPacket(target.getBelowNameUpdatePacket(), this);
|
||||
all.sendCustomPacket(target.getYellowNumberUpdatePacket(), this);
|
||||
if (all.getVersion().getMinorVersion() < 8) continue;
|
||||
if (global == null) {
|
||||
if (all.getServer().equals(target.getServer())) all.sendCustomPacket(target.getUpdatePacket(), this);
|
||||
continue;
|
||||
}
|
||||
if (shouldSee(all, target.getServer(), target.isVanished())) {
|
||||
if (!all.getServer().equals(target.getServer())) {
|
||||
all.sendCustomPacket(target.getAddPacket(), this);
|
||||
@@ -245,12 +248,8 @@ public class RedisBungeeSupport extends TabFeature implements RedisSupport, List
|
||||
|
||||
private boolean shouldSee(TabPlayer viewer, String viewerServer, String server, boolean targetVanished) {
|
||||
if (targetVanished && !viewer.hasPermission(TabConstants.Permission.GLOBAL_PLAYERLIST_SEE_VANISHED)) return false;
|
||||
if (global != null) {
|
||||
if (global.getSpyServers().contains(viewerServer)) return true;
|
||||
return global.getServerGroup(viewerServer).equals(global.getServerGroup(server));
|
||||
} else {
|
||||
return viewerServer.equals(server);
|
||||
}
|
||||
if (global.getSpyServers().contains(viewerServer)) return true;
|
||||
return global.getServerGroup(viewerServer).equals(global.getServerGroup(server));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -262,6 +261,7 @@ public class RedisBungeeSupport extends TabFeature implements RedisSupport, List
|
||||
p.sendCustomPacket(redis.getRegisterTeamPacket(), this);
|
||||
p.sendCustomPacket(redis.getBelowNameUpdatePacket(), this);
|
||||
p.sendCustomPacket(redis.getYellowNumberUpdatePacket(), this);
|
||||
if (global == null) continue;
|
||||
if (shouldSee(p, redis.getServer(), redis.isVanished())) {
|
||||
if (!p.getServer().equals(redis.getServer())) {
|
||||
p.sendCustomPacket(redis.getAddPacket(), this);
|
||||
@@ -280,7 +280,7 @@ public class RedisBungeeSupport extends TabFeature implements RedisSupport, List
|
||||
json.put("UUID", p.getTablistUUID().toString());
|
||||
json.put("server", to);
|
||||
RedisBungeeAPI.getRedisBungeeApi().sendChannelMessage(CHANNEL_NAME, json.toString());
|
||||
if (p.getVersion().getMinorVersion() < 8) return;
|
||||
if (p.getVersion().getMinorVersion() < 8 || global == null) return;
|
||||
for (RedisPlayer redis : redisPlayers.values()) {
|
||||
boolean before = shouldSee(p, from, redis.getServer(), redis.isVanished());
|
||||
boolean after = shouldSee(p, to, redis.getServer(), redis.isVanished());
|
||||
@@ -355,7 +355,7 @@ public class RedisBungeeSupport extends TabFeature implements RedisSupport, List
|
||||
|
||||
@Override
|
||||
public void onPlayerInfo(TabPlayer receiver, PacketPlayOutPlayerInfo info) {
|
||||
if (info.getAction() == EnumPlayerInfoAction.REMOVE_PLAYER) {
|
||||
if (info.getAction() == EnumPlayerInfoAction.REMOVE_PLAYER && global != null) {
|
||||
for (PlayerInfoData playerInfoData : info.getEntries()) {
|
||||
RedisPlayer packetPlayer = redisPlayers.get(playerInfoData.getUniqueId().toString());
|
||||
if (packetPlayer != null && (playerInfoData.getName() == null || playerInfoData.getName().length() == 0) && !packetPlayer.isVanished()) {
|
||||
|
||||
+3
-3
@@ -85,7 +85,7 @@ public class RedisPlayer {
|
||||
if (p.getProperty(TabConstants.Property.TAGPREFIX) != null) {
|
||||
json.put(TabConstants.Property.TAGPREFIX, p.getProperty(TabConstants.Property.TAGPREFIX).get());
|
||||
json.put(TabConstants.Property.TAGSUFFIX, p.getProperty(TabConstants.Property.TAGSUFFIX).get());
|
||||
json.put("namevisibility", ((NameTag)TAB.getInstance().getFeatureManager().getFeature("nametag16")).getTeamVisibility(p, p));
|
||||
json.put("namevisibility", ((NameTag)TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.NAME_TAGS)).getTeamVisibility(p, p));
|
||||
} else {
|
||||
json.put(TabConstants.Property.TAGPREFIX, "");
|
||||
json.put(TabConstants.Property.TAGSUFFIX, "");
|
||||
@@ -140,12 +140,12 @@ public class RedisPlayer {
|
||||
|
||||
public PacketPlayOutScoreboardScore getBelowNameUpdatePacket() {
|
||||
if (belowName == null) return null;
|
||||
return new PacketPlayOutScoreboardScore(Action.CHANGE, BelowName.OBJECTIVE_NAME, name, TAB.getInstance().getErrorManager().parseInteger(belowName, 0, "belowname number"));
|
||||
return new PacketPlayOutScoreboardScore(Action.CHANGE, BelowName.OBJECTIVE_NAME, name, TAB.getInstance().getErrorManager().parseInteger(belowName, 0));
|
||||
}
|
||||
|
||||
public PacketPlayOutScoreboardScore getYellowNumberUpdatePacket() {
|
||||
if (yellowNumber == null) return null;
|
||||
return new PacketPlayOutScoreboardScore(Action.CHANGE, YellowNumber.OBJECTIVE_NAME, name, TAB.getInstance().getErrorManager().parseInteger(yellowNumber, 0, "yellow number"));
|
||||
return new PacketPlayOutScoreboardScore(Action.CHANGE, YellowNumber.OBJECTIVE_NAME, name, TAB.getInstance().getErrorManager().parseInteger(yellowNumber, 0));
|
||||
}
|
||||
|
||||
public String getServer() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: @name@
|
||||
name: TAB
|
||||
main: me.neznamy.tab.platforms.bungeecord.Main
|
||||
version: @version@
|
||||
author: NEZNAMY
|
||||
|
||||
@@ -16,7 +16,7 @@ header-footer:
|
||||
footer:
|
||||
- "%animation:MyAnimation1%"
|
||||
- "%animation:time%"
|
||||
- "%animation:ping-tps%"
|
||||
- "&2Ping: %ping%"
|
||||
- "&7&l Used memory: %memory-used% MB / %memory-max% MB"
|
||||
- ""
|
||||
- "&7Visit our webpage %animation:web%"
|
||||
@@ -132,7 +132,7 @@ scoreboard:
|
||||
- "* &eOnline&7: &f%online%&7/&4%maxplayers%"
|
||||
- "* &eCurrent World&7: &f%worldonline%"
|
||||
- "* &eStaff&7: &f%staffonline%"
|
||||
- ""
|
||||
- " "
|
||||
- "&6Server Info:"
|
||||
- "* &bTPS&7: %tps%"
|
||||
- "* &bUptime&7: &f%server_uptime%"
|
||||
@@ -146,9 +146,9 @@ scoreboard:
|
||||
- "* &eKills&7: &f%statistic_player_kills%"
|
||||
- "* &eDeaths&7: &f%statistic_deaths%"
|
||||
- "* &eHealth&7: &f%health%"
|
||||
- ""
|
||||
- " "
|
||||
- "&6Personal Info:"
|
||||
- "* &bRank&7: &f%rank%"
|
||||
- "* &bRank&7: &f%group%"
|
||||
- "* &bPing&7: &f%ping%&7ms"
|
||||
- "* &bWorld&7: &f%world%"
|
||||
- "%animation:MyAnimation1%"
|
||||
@@ -161,9 +161,6 @@ placeholders:
|
||||
date-format: "dd.MM.yyyy"
|
||||
time-format: "[HH:mm:ss / h:mm a]"
|
||||
time-offset: 0
|
||||
remove-strings:
|
||||
- "[]"
|
||||
- "< >"
|
||||
|
||||
placeholder-output-replacements:
|
||||
"%essentials_vanished%":
|
||||
|
||||
+1
-1
@@ -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.0.1
|
||||
projectVersion=3.0.2
|
||||
|
||||
# Gradle properties
|
||||
org.gradle.daemon=true
|
||||
|
||||
@@ -3,22 +3,23 @@ metadata.format.version = "1.1"
|
||||
[versions]
|
||||
|
||||
# API
|
||||
netty = "4.1.63.Final"
|
||||
netty = "4.1.72.Final"
|
||||
jsonSimple = "1.1.1"
|
||||
snakeyaml = "1.28"
|
||||
snakeyaml = "1.30"
|
||||
yamlAssist = "1.0.5"
|
||||
gson = "2.8.7"
|
||||
gson = "2.8.9"
|
||||
|
||||
# General
|
||||
luckperms = "5.2"
|
||||
guava = "30.1.1-jre"
|
||||
floodgate = "2.0-SNAPSHOT"
|
||||
kotlin = "1.6.0"
|
||||
event = "3.0.0"
|
||||
|
||||
# Platforms
|
||||
bukkit = "1.16.5-R0.1-SNAPSHOT"
|
||||
bungeecord = "1.18-R0.1-SNAPSHOT"
|
||||
krypton = "0.58"
|
||||
krypton = "0.59.2"
|
||||
velocity = "1.1.0"
|
||||
|
||||
# Platform extras
|
||||
@@ -27,8 +28,8 @@ vault = "1.7"
|
||||
via = "4.0.0"
|
||||
authlib = "1.11"
|
||||
bstats = "2.2.1"
|
||||
libsDisguises = "10.0.26-SNAPSHOT"
|
||||
essentials = "2.19.0"
|
||||
libsDisguises = "10.0.26"
|
||||
essentials = "2.19.2"
|
||||
premiumVanish = "2.0.3"
|
||||
redisBungee = "0.6.5-SNAPSHOT"
|
||||
|
||||
@@ -46,9 +47,10 @@ luckperms = { group = "net.luckperms", name = "api", version.ref = "luckperms" }
|
||||
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
|
||||
floodgate = { group = "org.geysermc.floodgate", name = "api", version.ref = "floodgate" }
|
||||
kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
|
||||
event = { group = "net.kyori", name = "event-method", version.ref = "event" }
|
||||
|
||||
# Platforms
|
||||
bukkit = { group = "net.pl3x.purpur", name = "purpur-api", version.ref = "bukkit" }
|
||||
bukkit = { group = "com.destroystokyo.paper", name = "paper-api", version.ref = "bukkit" }
|
||||
bungeecord = { group = "net.md-5", name = "bungeecord-proxy", version.ref = "bungeecord" }
|
||||
krypton-api = { group = "org.kryptonmc", name = "krypton-api", version.ref = "krypton" }
|
||||
krypton-server = { group = "org.kryptonmc", name = "krypton-server", version.ref = "krypton" }
|
||||
|
||||
@@ -17,7 +17,6 @@ class KryptonPlaceholderRegistry(private val plugin: Main) : PlaceholderRegistry
|
||||
override fun registerPlaceholders(manager: PlaceholderManager) {
|
||||
// Built-in stuff
|
||||
manager.registerPlayerPlaceholder("%displayname%", 500) { (it.player as Player).displayName }
|
||||
manager.registerPlayerPlaceholder("%vanished%", 1000, TabPlayer::isVanished)
|
||||
manager.registerPlayerPlaceholder("%health%", 100) { ceil((it.player as Player).health) }
|
||||
|
||||
// TPS
|
||||
|
||||
@@ -2,12 +2,11 @@ package me.neznamy.tab.platforms.krypton
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer
|
||||
import me.neznamy.tab.api.protocol.PacketBuilder
|
||||
import me.neznamy.tab.platforms.krypton.event.TabLoadEvent
|
||||
import me.neznamy.tab.platforms.krypton.event.TabPlayerLoadEvent
|
||||
import me.neznamy.tab.platforms.krypton.features.PerWorldPlayerList
|
||||
import me.neznamy.tab.platforms.krypton.features.unlimitedtags.NameTagX
|
||||
import me.neznamy.tab.shared.Platform
|
||||
import me.neznamy.tab.shared.TAB
|
||||
import me.neznamy.tab.shared.TabConstants
|
||||
import me.neznamy.tab.shared.features.bossbar.BossBarManagerImpl
|
||||
import me.neznamy.tab.shared.features.nametags.NameTag
|
||||
import me.neznamy.tab.shared.permission.LuckPerms
|
||||
@@ -33,7 +32,7 @@ class KryptonPlatform(
|
||||
|
||||
override fun loadFeatures() {
|
||||
if (TAB.getInstance().configuration.isPipelineInjection) {
|
||||
TAB.getInstance().featureManager.registerFeature("injection", KryptonPipelineInjector())
|
||||
TAB.getInstance().featureManager.registerFeature(TabConstants.Feature.PIPELINE_INJECTION, KryptonPipelineInjector())
|
||||
}
|
||||
|
||||
// Placeholders
|
||||
@@ -44,10 +43,10 @@ class KryptonPlatform(
|
||||
loadNametagFeature()
|
||||
TAB.getInstance().loadUniversalFeatures()
|
||||
if (TAB.getInstance().config.getBoolean("bossbar.enabled", false)) {
|
||||
TAB.getInstance().featureManager.registerFeature("bossbar", BossBarManagerImpl())
|
||||
TAB.getInstance().featureManager.registerFeature(TabConstants.Feature.BOSS_BAR, BossBarManagerImpl())
|
||||
}
|
||||
if (TAB.getInstance().config.getBoolean("per-world-playerlist.enabled", false)) {
|
||||
TAB.getInstance().featureManager.registerFeature("pwp", PerWorldPlayerList(plugin))
|
||||
TAB.getInstance().featureManager.registerFeature(TabConstants.Feature.PER_WORLD_PLAYER_LIST, PerWorldPlayerList(plugin))
|
||||
}
|
||||
server.players.forEach { TAB.getInstance().addPlayer(KryptonTabPlayer(it, plugin.protocolVersion(it))) }
|
||||
}
|
||||
@@ -82,11 +81,11 @@ class KryptonPlatform(
|
||||
override fun getDataFolder(): File = folder
|
||||
|
||||
override fun callLoadEvent() {
|
||||
server.eventManager.fireAndForget(TabLoadEvent)
|
||||
// do nothing here, this will be removed
|
||||
}
|
||||
|
||||
override fun callLoadEvent(player: TabPlayer) {
|
||||
server.eventManager.fireAndForget(TabPlayerLoadEvent(player))
|
||||
// do nothing here, this will be removed
|
||||
}
|
||||
|
||||
override fun getMaxPlayers(): Int = server.maxPlayers
|
||||
@@ -104,9 +103,9 @@ class KryptonPlatform(
|
||||
private fun loadNametagFeature() {
|
||||
if (!TAB.getInstance().config.getBoolean("scoreboard-teams.enabled", true)) return
|
||||
if (TAB.getInstance().config.getBoolean("scoreboard-teams.unlimited-nametag-mode.enabled", false)) {
|
||||
TAB.getInstance().featureManager.registerFeature("nametagx", NameTagX(plugin))
|
||||
TAB.getInstance().featureManager.registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS, NameTagX(plugin))
|
||||
} else {
|
||||
TAB.getInstance().featureManager.registerFeature("nametag16", NameTag())
|
||||
TAB.getInstance().featureManager.registerFeature(TabConstants.Feature.NAME_TAGS, NameTag())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package me.neznamy.tab.platforms.krypton.event
|
||||
|
||||
/**
|
||||
* Krypton event that is called each time TAB fully loads. This includes server
|
||||
* startup and /tab reload
|
||||
*/
|
||||
object TabLoadEvent {
|
||||
|
||||
override fun toString(): String = "TabLoadEvent"
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package me.neznamy.tab.platforms.krypton.event
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer
|
||||
|
||||
/**
|
||||
* Krypton event that is called when player is successfully loaded after
|
||||
* joining. This also includes plugin reloading.
|
||||
*/
|
||||
// Thanks kapt...
|
||||
//@JvmRecord
|
||||
data class TabPlayerLoadEvent(val player: TabPlayer)
|
||||
+2
-3
@@ -21,7 +21,6 @@ import org.kryptonmc.krypton.packet.out.play.PacketOutMetadata
|
||||
import org.kryptonmc.krypton.packet.out.play.PacketOutSpawnLivingEntity
|
||||
import org.spongepowered.math.vector.Vector2f
|
||||
import org.spongepowered.math.vector.Vector3d
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
@@ -32,7 +31,7 @@ class KryptonArmorStand(
|
||||
private val staticOffset: Boolean
|
||||
) : ArmorStand {
|
||||
|
||||
private val manager = TAB.getInstance().featureManager.getFeature("nametagx") as NameTagX
|
||||
private val manager = TAB.getInstance().featureManager.getFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS) as NameTagX
|
||||
private val player = owner.player as Player
|
||||
private val entityId = ID_COUNTER.incrementAndGet()
|
||||
private val uuid = UUID.randomUUID()
|
||||
@@ -171,7 +170,7 @@ class KryptonArmorStand(
|
||||
var flags = 32 // invisible
|
||||
if (sneaking) flags += 2
|
||||
holder[MetadataKeys.FLAGS] = flags.toByte()
|
||||
holder[MetadataKeys.CUSTOM_NAME] = Optional.of(KryptonPacketBuilder.toComponent(displayName, viewer.version))
|
||||
holder[MetadataKeys.CUSTOM_NAME] = KryptonPacketBuilder.toComponent(displayName, viewer.version)
|
||||
|
||||
if (isNameVisibilityEmpty(displayName) || !viewerPlayer.canSee(player) || manager.hasHiddenNametag(owner, viewer)) {
|
||||
holder[MetadataKeys.CUSTOM_NAME_VISIBILITY] = false
|
||||
|
||||
+6
-5
@@ -54,9 +54,9 @@ class NameTagX(plugin: Main) : NameTag(), UnlimitedNametagManager {
|
||||
init {
|
||||
dynamicLines.reverse()
|
||||
plugin.server.eventManager.register(plugin, eventListener)
|
||||
TAB.getInstance().featureManager.registerFeature("nametagx-packet", PacketListener(this))
|
||||
TAB.getInstance().featureManager.registerFeature("nametagx-vehicle", vehicleManager)
|
||||
TAB.getInstance().featureManager.registerFeature("nametagx-location", LocationRefresher(this))
|
||||
TAB.getInstance().featureManager.registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS_PACKET_LISTENER, PacketListener(this))
|
||||
TAB.getInstance().featureManager.registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS_VEHICLE_REFRESHER, vehicleManager)
|
||||
TAB.getInstance().featureManager.registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS_LOCATION_REFRESHER, LocationRefresher(this))
|
||||
TAB.getInstance().debug("Loaded Unlimited nametag featured with parameters markerFor18x=$markerFor18x, disableOnBoats=$disableOnBoats, " +
|
||||
"spaceBetweenLines=$spaceBetweenLines, disabledUnlimitedWorlds=$disabledUnlimitedWorlds")
|
||||
}
|
||||
@@ -136,12 +136,13 @@ class NameTagX(plugin: Main) : NameTag(), UnlimitedNametagManager {
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateProperties(player: TabPlayer) {
|
||||
override fun updateProperties(player: TabPlayer): Boolean {
|
||||
super.updateProperties(player)
|
||||
player.loadPropertyFromConfig(this, TabConstants.Property.CUSTOMTAGNAME, player.name)
|
||||
rebuildNametagLine(player)
|
||||
dynamicLines.forEach { if (it != TabConstants.Property.NAMETAG) player.loadPropertyFromConfig(this, it) }
|
||||
staticLines.keys.forEach { if (it != TabConstants.Property.NAMETAG) player.loadPropertyFromConfig(this, it) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getFeatureName(): String = "Unlimited Nametags"
|
||||
@@ -248,7 +249,7 @@ class NameTagX(plugin: Main) : NameTag(), UnlimitedNametagManager {
|
||||
500,
|
||||
"refreshing nametag visibility",
|
||||
this,
|
||||
TabConstants.CpuUsageCategory.REFRESHING_NAMETAG_VISIBILITY
|
||||
TabConstants.CpuUsageCategory.REFRESHING_NAME_TAG_VISIBILITY
|
||||
) {
|
||||
TAB.getInstance().onlinePlayers.forEach {
|
||||
if (!it.isLoaded || isPlayerDisabled(it)) return@forEach
|
||||
|
||||
@@ -182,9 +182,6 @@ placeholders:
|
||||
date-format: "dd.MM.yyyy"
|
||||
time-format: "[HH:mm:ss / h:mm a]"
|
||||
time-offset: 0
|
||||
remove-strings:
|
||||
- "[]"
|
||||
- "< >"
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Placeholder-output-replacements-(premium-only)
|
||||
placeholder-output-replacements:
|
||||
|
||||
+2
-1
@@ -5,10 +5,10 @@ dependencyResolutionManagement {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://jitpack.io")
|
||||
maven("https://repo.pl3x.net/")
|
||||
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
|
||||
maven("https://repo.viaversion.com/")
|
||||
maven("https://repo.aikar.co/content/groups/aikar/")
|
||||
maven("https://repo.md-5.net/content/groups/public/")
|
||||
maven("https://ci.lucko.me/plugin/repository/everything/")
|
||||
maven("https://repo.essentialsx.net/releases/")
|
||||
maven("https://repo.codemc.org/repository/maven-public")
|
||||
@@ -17,6 +17,7 @@ dependencyResolutionManagement {
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||
maven("https://nexus.velocitypowered.com/repository/maven-public/")
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/")
|
||||
maven("https://papermc.io/repo/repository/maven-public/")
|
||||
}
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,10 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
api(projects.api)
|
||||
api(libs.event) {
|
||||
exclude("com.google.guava", "guava")
|
||||
exclude("org.checkerframework", "checker-qual")
|
||||
}
|
||||
compileOnlyApi(libs.luckperms)
|
||||
compileOnlyApi(libs.guava)
|
||||
compileOnlyApi(libs.floodgate)
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
@@ -42,8 +41,12 @@ public class CpuManager implements ThreadManager {
|
||||
//packets sent in the previous 10 seconds
|
||||
private Map<String, AtomicInteger> packetsPrevious = new ConcurrentHashMap<>();
|
||||
|
||||
//thread pool
|
||||
private ThreadPoolExecutor exe = (ThreadPoolExecutor) Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("TAB - Thread %d").build());
|
||||
//thread pools
|
||||
private ExecutorService thread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("TAB Processing Thread").build());
|
||||
private final ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
|
||||
private final Map<Runnable, String> taskQueue = new HashMap<>();
|
||||
private boolean enabled = false;
|
||||
|
||||
//error manager
|
||||
private final ErrorManager errorManager;
|
||||
@@ -76,26 +79,30 @@ public class CpuManager implements ThreadManager {
|
||||
TAB.getInstance().getPlaceholderManager().addUsedPlaceholders(Collections.singletonList("%cpu%"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns amount of active and total threads
|
||||
* @return active and total threads from this thread pool
|
||||
*/
|
||||
public String getThreadCount() {
|
||||
return exe.getActiveCount() + "/" + exe.getPoolSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels all tasks, new instance is set to avoid errors when starting tasks on shutdown (such as packet readers)
|
||||
*/
|
||||
public void cancelAllTasks() {
|
||||
//preventing errors when tasks are inserted while shutting down
|
||||
ExecutorService old = exe;
|
||||
exe = (ThreadPoolExecutor) Executors.newCachedThreadPool();
|
||||
ExecutorService old = thread;
|
||||
thread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("TAB Processing Thread").build());
|
||||
old.shutdownNow();
|
||||
threadPool.shutdownNow();
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
enabled = true;
|
||||
taskQueue.forEach((r, e) -> submit(e, r));
|
||||
taskQueue.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> runMeasuredTask(String errorDescription, TabFeature feature, String type, Runnable task) {
|
||||
return runMeasuredTask(errorDescription, feature.getFeatureName(), type, task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> runMeasuredTask(String errorDescription, String feature, String type, Runnable task) {
|
||||
return submit(errorDescription, () -> {
|
||||
long time = System.nanoTime();
|
||||
task.run();
|
||||
@@ -110,34 +117,27 @@ public class CpuManager implements ThreadManager {
|
||||
|
||||
@Override
|
||||
public RepeatingTask startRepeatingMeasuredTask(int intervalMilliseconds, String errorDescription, TabFeature feature, String type, Runnable task) {
|
||||
return new TabRepeatingTask(exe, task, errorDescription, feature, type, intervalMilliseconds);
|
||||
return new TabRepeatingTask(threadPool, task, errorDescription, feature, type, intervalMilliseconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> runTaskLater(int delayMilliseconds, String errorDescription, TabFeature feature, String type, Runnable task) {
|
||||
return runTaskLater(delayMilliseconds, errorDescription, feature.getFeatureName(), type, task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> runTaskLater(int delayMilliseconds, String errorDescription, String feature, String type, Runnable task) {
|
||||
return submit(errorDescription, () -> {
|
||||
public Future<?> runTaskLater(int delayMilliseconds, String errorDescription, TabFeature feature, String type, Runnable task) {
|
||||
return threadPool.submit(() -> {
|
||||
try {
|
||||
Thread.sleep(delayMilliseconds);
|
||||
long time = System.nanoTime();
|
||||
task.run();
|
||||
addTime(feature, type, System.nanoTime()-time);
|
||||
runMeasuredTask(errorDescription, feature, type, task);
|
||||
} catch (InterruptedException pluginDisabled) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Future<Void> runTaskLater(int delayMilliseconds, String errorDescription, Runnable task) {
|
||||
return submit(errorDescription, () -> {
|
||||
public Future<?> runTaskLater(int delayMilliseconds, String errorDescription, Runnable task) {
|
||||
return threadPool.submit(() -> {
|
||||
try {
|
||||
Thread.sleep(delayMilliseconds);
|
||||
task.run();
|
||||
submit(errorDescription, task);
|
||||
} catch (InterruptedException pluginDisabled) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
@@ -146,10 +146,14 @@ public class CpuManager implements ThreadManager {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Future<Void> submit(String errorDescription, Runnable task) {
|
||||
return (Future<Void>) exe.submit(() -> {
|
||||
if (!enabled) {
|
||||
taskQueue.put(task, errorDescription);
|
||||
return null;
|
||||
}
|
||||
return (Future<Void>) thread.submit(() -> {
|
||||
try {
|
||||
task.run();
|
||||
} catch (Exception | NoClassDefFoundError e) {
|
||||
} catch (Exception | LinkageError e) {
|
||||
errorManager.printError("An error occurred when " + errorDescription, e);
|
||||
}
|
||||
});
|
||||
@@ -254,7 +258,10 @@ public class CpuManager implements ThreadManager {
|
||||
* @return sorted map
|
||||
*/
|
||||
private <K, V extends Comparable<V>> Map<K, V> sortByValue(Map<K, V> map) {
|
||||
Comparator<K> valueComparator = (k1, k2) -> map.get(k2).compareTo(map.get(k1));
|
||||
Comparator<K> valueComparator = (k1, k2) -> {
|
||||
int diff = map.get(k2).compareTo(map.get(k1));
|
||||
return diff == 0 ? 1 : diff; //otherwise, entries with duplicate values are lost
|
||||
};
|
||||
Map<K, V> sortedByValues = new TreeMap<>(valueComparator);
|
||||
sortedByValues.putAll(map);
|
||||
return sortedByValues;
|
||||
@@ -267,7 +274,10 @@ public class CpuManager implements ThreadManager {
|
||||
* @return sorted map
|
||||
*/
|
||||
private <K> Map<K, AtomicInteger> sortByValue1(Map<K, AtomicInteger> map) {
|
||||
Comparator<K> valueComparator = (k1, k2) -> ((Comparable<Integer>)map.get(k2).get()).compareTo(map.get(k1).get());
|
||||
Comparator<K> valueComparator = (k1, k2) -> {
|
||||
int diff = map.get(k2).get() - map.get(k1).get();
|
||||
return diff == 0 ? 1 : diff; //otherwise, entries with duplicate values are lost
|
||||
};
|
||||
Map<K, AtomicInteger> sortedByValues = new TreeMap<>(valueComparator);
|
||||
sortedByValues.putAll(map);
|
||||
return sortedByValues;
|
||||
|
||||
@@ -21,29 +21,18 @@ public class ErrorManager {
|
||||
//date format used in error messages
|
||||
private final SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy - HH:mm:ss - ");
|
||||
|
||||
//one time messages already sent into console, so they are not sent again
|
||||
private final List<String> oneTimeMessages = new ArrayList<>();
|
||||
|
||||
//amount of logged startup warns
|
||||
private int startupWarns = 0;
|
||||
|
||||
//error logs
|
||||
private final File errorLog;
|
||||
private final File antiOverrideLog;
|
||||
private final File placeholderErrorLog;
|
||||
|
||||
//plugin instance
|
||||
private final TAB tab;
|
||||
|
||||
/**
|
||||
* Constructs new instance
|
||||
* @param tab - tab instance
|
||||
*/
|
||||
public ErrorManager(TAB tab) {
|
||||
this.tab = tab;
|
||||
errorLog = new File(tab.getPlatform().getDataFolder(), "errors.log");
|
||||
antiOverrideLog = new File(tab.getPlatform().getDataFolder(), "anti-override.log");
|
||||
placeholderErrorLog = new File(tab.getPlatform().getDataFolder(), "placeholder-errors.log");
|
||||
public ErrorManager() {
|
||||
errorLog = new File(TAB.getInstance().getPlatform().getDataFolder(), "errors.log");
|
||||
antiOverrideLog = new File(TAB.getInstance().getPlatform().getDataFolder(), "anti-override.log");
|
||||
placeholderErrorLog = new File(TAB.getInstance().getPlatform().getDataFolder(), "placeholder-errors.log");
|
||||
if (getErrorLog().exists() && getErrorLog().length() > 10) {
|
||||
startupWarn("File &e" + getErrorLog().getPath() + "&c exists and is not empty. Take a look at the error messages and try to resolve them. After you do, delete the file.");
|
||||
}
|
||||
@@ -99,16 +88,16 @@ public class ErrorManager {
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
tab.getPlatform().sendConsoleMessage("&c[TAB] An error occurred when printing error message into file", true);
|
||||
tab.getPlatform().sendConsoleMessage(ex.getClass().getName() + ": " + ex.getMessage(), true);
|
||||
TAB.getInstance().getPlatform().sendConsoleMessage("&c[TAB] An error occurred when printing error message into file", true);
|
||||
TAB.getInstance().getPlatform().sendConsoleMessage(ex.getClass().getName() + ": " + ex.getMessage(), true);
|
||||
for (StackTraceElement e : ex.getStackTrace()) {
|
||||
tab.getPlatform().sendConsoleMessage("\t" + e.toString(), true);
|
||||
TAB.getInstance().getPlatform().sendConsoleMessage("\t" + e.toString(), true);
|
||||
}
|
||||
tab.getPlatform().sendConsoleMessage("&c[TAB] Original error: " + message, true);
|
||||
TAB.getInstance().getPlatform().sendConsoleMessage("&c[TAB] Original error: " + message, true);
|
||||
if (error != null) {
|
||||
tab.getPlatform().sendConsoleMessage(error.getClass().getName() + ": " + error.getMessage(), true);
|
||||
TAB.getInstance().getPlatform().sendConsoleMessage(error.getClass().getName() + ": " + error.getMessage(), true);
|
||||
for (StackTraceElement e : error.getStackTrace()) {
|
||||
tab.getPlatform().sendConsoleMessage("\t" + e.toString(), true);
|
||||
TAB.getInstance().getPlatform().sendConsoleMessage("\t" + e.toString(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,7 +118,7 @@ public class ErrorManager {
|
||||
try {
|
||||
return file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
tab.getPlatform().sendConsoleMessage("&c[TAB] Failed to create file " + file.getPath() + ": " + e.getMessage(), true);
|
||||
TAB.getInstance().getPlatform().sendConsoleMessage("&c[TAB] Failed to create file " + file.getPath() + ": " + e.getMessage(), true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -142,45 +131,24 @@ public class ErrorManager {
|
||||
* @throws IOException - if IO writer operation fails
|
||||
*/
|
||||
private void write(BufferedWriter buf, String prefix, String message, boolean forceConsole) throws IOException {
|
||||
buf.write(getCurrentTime() + IChatBaseComponent.fromColoredText(prefix).toRawText() + message + System.getProperty("line.separator"));
|
||||
if (tab.isDebugMode() || forceConsole) tab.getPlatform().sendConsoleMessage(EnumChatFormat.color(prefix) + message, false);
|
||||
buf.write(dateFormat.format(new Date()) + IChatBaseComponent.fromColoredText(prefix).toRawText() + message + System.getProperty("line.separator"));
|
||||
if (TAB.getInstance().isDebugMode() || forceConsole) TAB.getInstance().getPlatform().sendConsoleMessage(EnumChatFormat.color(prefix) + message, false);
|
||||
}
|
||||
|
||||
public void criticalError(String message, Throwable t) {
|
||||
printError(message, t, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends message into console once
|
||||
* @param message - message to send
|
||||
*/
|
||||
public void oneTimeConsoleError(String message) {
|
||||
if (oneTimeMessages.contains(message)) return;
|
||||
oneTimeMessages.add(message);
|
||||
printError(message, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current formatted time
|
||||
* @return current formatted time
|
||||
*/
|
||||
private String getCurrentTime() {
|
||||
return dateFormat.format(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses integer in given string, returns second argument if string is not valid
|
||||
* @param string - string to parse
|
||||
* @param defaultValue - value to return if string is not valid
|
||||
* @param place - used in error message
|
||||
* @return parsed integer
|
||||
*/
|
||||
public int parseInteger(String string, int defaultValue, String place) {
|
||||
if (string == null || string.length() == 0) return 0; //preventing error message on bungee with papi placeholders due to them not being initialized yet
|
||||
public int parseInteger(String string, int defaultValue) {
|
||||
try {
|
||||
return (int) Math.round(Double.parseDouble(string));
|
||||
} catch (NumberFormatException e) {
|
||||
oneTimeConsoleError(formatNumberError(place, string));
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -190,14 +158,12 @@ public class ErrorManager {
|
||||
* Parses float in given string, returns second argument if string is not valid
|
||||
* @param string - string to parse
|
||||
* @param defaultValue - value to return if string is not valid
|
||||
* @param place - used in error message
|
||||
* @return parsed float
|
||||
*/
|
||||
public float parseFloat(String string, float defaultValue, String place) {
|
||||
public float parseFloat(String string, float defaultValue) {
|
||||
try {
|
||||
return Float.parseFloat(string);
|
||||
} catch (NumberFormatException e) {
|
||||
oneTimeConsoleError(formatNumberError(place, string));
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -206,35 +172,26 @@ public class ErrorManager {
|
||||
* Parses double in given string, returns second argument if string is not valid
|
||||
* @param string - string to parse
|
||||
* @param defaultValue - value to return if string is not valid
|
||||
* @param place - used in error message
|
||||
* @return parsed double
|
||||
*/
|
||||
public double parseDouble(String string, double defaultValue, String place) {
|
||||
if (string == null || string.length() == 0) return 0; //preventing error message on bungee with papi placeholders due to them not being initialized yet
|
||||
public double parseDouble(String string, double defaultValue) {
|
||||
try {
|
||||
return Double.parseDouble(string);
|
||||
} catch (NumberFormatException e) {
|
||||
oneTimeConsoleError(formatNumberError(place, string));
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
private String formatNumberError(String place, String value) {
|
||||
return String.format("%s only accepts numeric values! (Attempted to use \"%s\")", place, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses bar color in given string, returns second argument if string is not valid
|
||||
* @param string - string to parse
|
||||
* @param defaultValue - value to return if string is not valid
|
||||
* @param place - used in error message
|
||||
* @return parsed bar color
|
||||
*/
|
||||
public BarColor parseColor(String string, BarColor defaultValue, String place) {
|
||||
public BarColor parseColor(String string, BarColor defaultValue) {
|
||||
try {
|
||||
return BarColor.valueOf(string);
|
||||
} catch (IllegalArgumentException e) {
|
||||
oneTimeConsoleError(String.format("%s only accepts one of the defined colors! (Attempted to use \"%s\")", place, string));
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -243,14 +200,12 @@ public class ErrorManager {
|
||||
* Parses bar style in given string, returns second argument if string is not valid
|
||||
* @param string - string to parse
|
||||
* @param defaultValue - value to return if string is not valid
|
||||
* @param place - used in error message
|
||||
* @return parsed bar style
|
||||
*/
|
||||
public BarStyle parseStyle(String string, BarStyle defaultValue, String place) {
|
||||
public BarStyle parseStyle(String string, BarStyle defaultValue) {
|
||||
try {
|
||||
return BarStyle.valueOf(string);
|
||||
} catch (IllegalArgumentException e) {
|
||||
oneTimeConsoleError(String.format("%s only accepts one of the defined styles! (Attempted to use \"%s\")", place, string));
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -294,10 +249,7 @@ public class ErrorManager {
|
||||
}
|
||||
|
||||
public void startupWarn(String message) {
|
||||
if (oneTimeMessages.contains(message)) return;
|
||||
oneTimeMessages.add(message);
|
||||
tab.getPlatform().sendConsoleMessage("&c[TAB] " + message, true);
|
||||
startupWarns++;
|
||||
TAB.getInstance().getPlatform().sendConsoleMessage("&c[TAB] " + message, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,19 +262,6 @@ public class ErrorManager {
|
||||
startupWarn(objectType + " \"&e" + objectName + "&c\" is missing \"&e" + attribute + "&c\" attribute!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints amount of startup warns into console if more than 0
|
||||
*/
|
||||
public void printConsoleWarnCount() {
|
||||
if (startupWarns > 0) {
|
||||
if (startupWarns == 1) {
|
||||
tab.getPlatform().sendConsoleMessage("&e[TAB] There was 1 startup warning.", true);
|
||||
} else {
|
||||
tab.getPlatform().sendConsoleMessage("&e[TAB] There were " + startupWarns + " startup warnings.", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public File getAntiOverrideLog() {
|
||||
return antiOverrideLog;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
//list of registered features
|
||||
private final Map<String, TabFeature> features = new LinkedHashMap<>();
|
||||
|
||||
private TabFeature[] values;
|
||||
private TabFeature[] values = new TabFeature[0];
|
||||
|
||||
@Override
|
||||
public void registerFeature(String featureName, TabFeature featureHandler) {
|
||||
@@ -111,6 +111,7 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
*/
|
||||
public void onQuit(TabPlayer disconnectedPlayer) {
|
||||
if (disconnectedPlayer == null) return;
|
||||
long millis = System.currentTimeMillis();
|
||||
for (TabFeature f : values) {
|
||||
if (!f.overridesMethod("onQuit")) continue;
|
||||
long time = System.nanoTime();
|
||||
@@ -118,14 +119,7 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
TAB.getInstance().getCPUManager().addTime(f, TabConstants.CpuUsageCategory.PLAYER_QUIT, System.nanoTime()-time);
|
||||
}
|
||||
TAB.getInstance().removePlayer(disconnectedPlayer);
|
||||
PlayerPlaceholder online = (PlayerPlaceholder) TAB.getInstance().getPlaceholderManager().getPlaceholder("%online%");
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (all.isLoaded()) online.updateValue(all, online.request(all));
|
||||
}
|
||||
if (TAB.getInstance().getConfiguration().getUsers() instanceof MySQLUserConfiguration) {
|
||||
MySQLUserConfiguration users = (MySQLUserConfiguration) TAB.getInstance().getConfiguration().getUsers();
|
||||
users.unload(disconnectedPlayer);
|
||||
}
|
||||
TAB.getInstance().debug("Player quit of " + disconnectedPlayer.getName() + " processed in " + (System.currentTimeMillis()-millis) + "ms");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,13 +139,10 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
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();
|
||||
((ITabPlayer)connectedPlayer).markAsLoaded(true);
|
||||
TAB.getInstance().debug("Player join of " + connectedPlayer.getName() + " processed in " + (System.currentTimeMillis()-millis) + "ms");
|
||||
PlayerPlaceholder online = (PlayerPlaceholder) TAB.getInstance().getPlaceholderManager().getPlaceholder("%online%");
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (all.isLoaded()) online.updateValue(all, online.request(all));
|
||||
}
|
||||
if (TAB.getInstance().getConfiguration().getUsers() instanceof MySQLUserConfiguration) {
|
||||
MySQLUserConfiguration users = (MySQLUserConfiguration) TAB.getInstance().getConfiguration().getUsers();
|
||||
users.load(connectedPlayer);
|
||||
@@ -166,10 +157,7 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
*/
|
||||
public void onWorldChange(UUID playerUUID, String to) {
|
||||
TabPlayer changed = TAB.getInstance().getPlayer(playerUUID);
|
||||
if (changed == null || !changed.isLoaded()) {
|
||||
TAB.getInstance().getCPUManager().runTaskLater(100, "processing delayed world/server switch", "Other", "Player world switch", () -> onWorldChange(playerUUID, to));
|
||||
return;
|
||||
}
|
||||
if (changed == null) return;
|
||||
String from = changed.getWorld();
|
||||
((ITabPlayer)changed).setWorld(to);
|
||||
for (TabFeature f : values) {
|
||||
@@ -179,8 +167,6 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
TAB.getInstance().getCPUManager().addTime(f, TabConstants.CpuUsageCategory.WORLD_SWITCH, System.nanoTime()-time);
|
||||
}
|
||||
((PlayerPlaceholder)TAB.getInstance().getPlaceholderManager().getPlaceholder("%world%")).updateValue(changed, to);
|
||||
PlayerPlaceholder worldOnline = (PlayerPlaceholder) TAB.getInstance().getPlaceholderManager().getPlaceholder("%worldonline%");
|
||||
worldOnline.updateValue(changed, worldOnline.request(changed));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,13 +180,12 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
String from = changed.getServer();
|
||||
((ITabPlayer)changed).setServer(to);
|
||||
for (TabFeature f : values) {
|
||||
if (!f.overridesMethod("onServerChange")) continue;
|
||||
long time = System.nanoTime();
|
||||
f.onServerChange(changed, from, to);
|
||||
TAB.getInstance().getCPUManager().addTime(f, TabConstants.CpuUsageCategory.SERVER_SWITCH, System.nanoTime()-time);
|
||||
}
|
||||
((PlayerPlaceholder)TAB.getInstance().getPlaceholderManager().getPlaceholder("%server%")).updateValue(changed, to);
|
||||
PlayerPlaceholder serverOnline = (PlayerPlaceholder) TAB.getInstance().getPlaceholderManager().getPlaceholder("%serveronline%");
|
||||
serverOnline.updateValue(changed, serverOnline.request(changed));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,7 +253,7 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
* @param packetReceiver - player who received the packet
|
||||
*/
|
||||
public void onLoginPacket(TabPlayer packetReceiver) {
|
||||
((ITabPlayer)packetReceiver).clearRegisteredTeams();
|
||||
((ITabPlayer)packetReceiver).clearRegisteredObjectives();
|
||||
for (TabFeature f : values) {
|
||||
if (!f.overridesMethod("onLoginPacket")) continue;
|
||||
long time = System.nanoTime();
|
||||
|
||||
@@ -54,18 +54,19 @@ public class GroupManager extends TabFeature {
|
||||
luckPermsSub2 = LuckPermsProvider.get().getEventBus().subscribe(GroupDataRecalculateEvent.class, this::updateGroup);
|
||||
}
|
||||
|
||||
//synchronized because LP spams the event
|
||||
private synchronized void updatePlayer(UserDataRecalculateEvent event) {
|
||||
long time = System.nanoTime();
|
||||
TabPlayer p = TAB.getInstance().getPlayer(event.getUser().getUniqueId());
|
||||
if (p == null) return; //server still starting up and users connecting already (LP loading them)
|
||||
refresh(p, false);
|
||||
TAB.getInstance().getCPUManager().addTime("Permission group refreshing", TabConstants.CpuUsageCategory.LUCKPERMS_RECALCULATE_EVENT, System.nanoTime()-time);
|
||||
groupPlaceholder.updateValue(p, p.getGroup());
|
||||
private void updatePlayer(UserDataRecalculateEvent event) {
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask("Processing UserDataRecalculateEvent", this, "Processing UserDataRecalculateEvent", () -> {
|
||||
long time = System.nanoTime();
|
||||
TabPlayer p = TAB.getInstance().getPlayer(event.getUser().getUniqueId());
|
||||
if (p == null) return; //server still starting up and users connecting already (LP loading them)
|
||||
refresh(p, false);
|
||||
TAB.getInstance().getCPUManager().addTime("Permission group refreshing", TabConstants.CpuUsageCategory.LUCKPERMS_RECALCULATE_EVENT, System.nanoTime()-time);
|
||||
groupPlaceholder.updateValue(p, p.getGroup());
|
||||
});
|
||||
}
|
||||
|
||||
private synchronized void updateGroup(GroupDataRecalculateEvent event) {
|
||||
TAB.getInstance().getCPUManager().runTaskLater(50, "Processing GroupDataRecalculateEvent", () -> {
|
||||
private void updateGroup(GroupDataRecalculateEvent event) {
|
||||
TAB.getInstance().getCPUManager().runTaskLater(50, "Processing GroupDataRecalculateEvent", this, "Processing GroupDataRecalculateEvent", () -> {
|
||||
long time = System.nanoTime();
|
||||
for (TabPlayer player : TAB.getInstance().getOnlinePlayers()) {
|
||||
refresh(player, false);
|
||||
|
||||
@@ -2,9 +2,6 @@ package me.neznamy.tab.shared;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardTeam;
|
||||
import org.geysermc.floodgate.api.FloodgateApi;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import me.neznamy.tab.api.ArmorStandManager;
|
||||
import me.neznamy.tab.api.Property;
|
||||
@@ -12,10 +9,11 @@ import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutChat;
|
||||
import me.neznamy.tab.api.protocol.*;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutChat.ChatMessageType;
|
||||
import me.neznamy.tab.api.protocol.TabPacket;
|
||||
import me.neznamy.tab.api.team.TeamManager;
|
||||
import me.neznamy.tab.shared.event.impl.PlayerLoadEventImpl;
|
||||
import org.geysermc.floodgate.api.FloodgateApi;
|
||||
|
||||
/**
|
||||
* The core class for player
|
||||
@@ -42,6 +40,7 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
private boolean onJoinFinished;
|
||||
|
||||
private final List<String> registeredTeams = new ArrayList<>();
|
||||
private final List<String> registeredObjectives = new ArrayList<>();
|
||||
|
||||
protected ITabPlayer(Object player, UUID uniqueId, String name, String server, String world) {
|
||||
this.player = player;
|
||||
@@ -49,7 +48,7 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
this.name = name;
|
||||
this.server = server;
|
||||
this.world = world;
|
||||
bedrockPlayer = TAB.getInstance().isFloodgateInstalled() && FloodgateApi.getInstance().isFloodgatePlayer(uniqueId);
|
||||
bedrockPlayer = TAB.getInstance().isFloodgateInstalled() && FloodgateApi.getInstance() != null && FloodgateApi.getInstance().isFloodgatePlayer(uniqueId);
|
||||
setGroup(TAB.getInstance().getGroupManager().detectPermissionGroup(this), false);
|
||||
}
|
||||
|
||||
@@ -106,18 +105,44 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCustomPacket(TabPacket packet) {
|
||||
public synchronized void sendCustomPacket(TabPacket packet) {
|
||||
if (packet == null) return;
|
||||
//avoiding BungeeCord bug kicking all players
|
||||
if (packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
String team = ((PacketPlayOutScoreboardTeam) packet).getName();
|
||||
if (((PacketPlayOutScoreboardTeam) packet).getMethod() == 0) {
|
||||
int method = ((PacketPlayOutScoreboardTeam) packet).getMethod();
|
||||
if (method == 0) {
|
||||
if (registeredTeams.contains(team)) {
|
||||
TAB.getInstance().getErrorManager().printError("Tried to register duplicated team " + team + " to player " + getName());
|
||||
return;
|
||||
}
|
||||
registeredTeams.add(team);
|
||||
} else if (((PacketPlayOutScoreboardTeam) packet).getMethod() == 1) {
|
||||
registeredTeams.remove(((PacketPlayOutScoreboardTeam) packet).getName());
|
||||
} else if (method == 1) {
|
||||
registeredTeams.remove(team);
|
||||
}
|
||||
}
|
||||
//avoiding BungeeCord bug kicking all players
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
String objective = ((PacketPlayOutScoreboardObjective) packet).getObjectiveName();
|
||||
int method = ((PacketPlayOutScoreboardObjective) packet).getMethod();
|
||||
if (method == 0) {
|
||||
if (registeredObjectives.contains(objective)) {
|
||||
TAB.getInstance().getErrorManager().printError("Tried to register duplicated objective " + objective + " to player " + getName());
|
||||
return;
|
||||
}
|
||||
registeredObjectives.add(objective);
|
||||
} else if (method == 1) {
|
||||
registeredObjectives.remove(objective);
|
||||
}
|
||||
}
|
||||
//avoiding console spam from geyser
|
||||
if (packet instanceof PacketPlayOutScoreboardScore) {
|
||||
String objective = ((PacketPlayOutScoreboardScore) packet).getObjectiveName();
|
||||
String player = ((PacketPlayOutScoreboardScore) packet).getPlayer();
|
||||
if (!registeredObjectives.contains(objective)) {
|
||||
TAB.getInstance().getErrorManager().printError("Tried to update score (" + player + ") without the existence of its requested objective '" +
|
||||
objective + "' to player " + getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
@@ -190,12 +215,12 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadPropertyFromConfig(TabFeature feature, String property) {
|
||||
loadPropertyFromConfig(feature, property, "");
|
||||
public boolean loadPropertyFromConfig(TabFeature feature, String property) {
|
||||
return loadPropertyFromConfig(feature, property, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadPropertyFromConfig(TabFeature feature, String property, String ifNotSet) {
|
||||
public boolean loadPropertyFromConfig(TabFeature feature, String property, String ifNotSet) {
|
||||
String[] value = TAB.getInstance().getConfiguration().getUsers().getProperty(getName(), property, server, world);
|
||||
if (value.length == 0) {
|
||||
value = TAB.getInstance().getConfiguration().getUsers().getProperty(getUniqueId().toString(), property, server, world);
|
||||
@@ -204,10 +229,9 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
value = TAB.getInstance().getConfiguration().getGroups().getProperty(getGroup(), property, server, world);
|
||||
}
|
||||
if (value.length > 0) {
|
||||
setProperty(feature, property, value[0], value[1]);
|
||||
return;
|
||||
return setProperty(feature, property, value[0], value[1]);
|
||||
}
|
||||
setProperty(feature, property, ifNotSet, "None");
|
||||
return setProperty(feature, property, ifNotSet, "None");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -265,8 +289,9 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
teamName = name;
|
||||
}
|
||||
|
||||
public void markAsLoaded() {
|
||||
public void markAsLoaded(boolean join) {
|
||||
onJoinFinished = true;
|
||||
if (TAB.getInstance().getEventBus() != null) TAB.getInstance().getEventBus().fire(new PlayerLoadEventImpl(this, join));
|
||||
TAB.getInstance().getPlatform().callLoadEvent(this);
|
||||
}
|
||||
|
||||
@@ -290,8 +315,9 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
server = name;
|
||||
}
|
||||
|
||||
public void clearRegisteredTeams() {
|
||||
public void clearRegisteredObjectives() {
|
||||
registeredTeams.clear();
|
||||
registeredObjectives.clear();
|
||||
}
|
||||
|
||||
public void setTemporaryGroup(String group) {
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package me.neznamy.tab.shared;
|
||||
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardDisplayObjective;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardObjective;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardObjective.EnumScoreboardHealthDisplay;
|
||||
|
||||
/**
|
||||
* Soon to be removed assistant for easier packet creating
|
||||
*/
|
||||
public class PacketAPI {
|
||||
|
||||
private PacketAPI() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers scoreboard objective with given properties but sends unregister packet first unless disabled to avoid BungeeCord kick
|
||||
* @param to - player to send the packet to
|
||||
* @param objectiveName - name of the objective
|
||||
* @param title - title
|
||||
* @param position - objective position (0 = PlayerList, 1 = Sidebar, 2 = BelowName)
|
||||
* @param displayType - display type of the value (only supported in PlayerList)
|
||||
*/
|
||||
public static synchronized void registerScoreboardObjective(TabPlayer to, String objectiveName, String title, int position, EnumScoreboardHealthDisplay displayType, TabFeature feature) {
|
||||
registerScoreboardObjective(to, objectiveName, title, position, displayType, feature.getFeatureName());
|
||||
}
|
||||
|
||||
public static synchronized void registerScoreboardObjective(TabPlayer to, String objectiveName, String title, int position, EnumScoreboardHealthDisplay displayType, String feature) {
|
||||
if (to.getVersion().getMinorVersion() >= 8 && TAB.getInstance().getConfiguration().isUnregisterBeforeRegister()) {
|
||||
to.sendCustomPacket(new PacketPlayOutScoreboardObjective(objectiveName), feature);
|
||||
}
|
||||
to.sendCustomPacket(new PacketPlayOutScoreboardObjective(0, objectiveName, title, displayType), feature);
|
||||
to.sendCustomPacket(new PacketPlayOutScoreboardDisplayObjective(position, objectiveName), feature);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package me.neznamy.tab.shared;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Formatter;
|
||||
import java.util.List;
|
||||
|
||||
import me.neznamy.tab.api.Property;
|
||||
@@ -42,9 +41,6 @@ public class PropertyImpl implements Property {
|
||||
|
||||
//used relational placeholders in current raw value
|
||||
private String[] relPlaceholders;
|
||||
|
||||
private final StringBuilder formatBuffer = new StringBuilder();
|
||||
private final Formatter formatter = new Formatter(formatBuffer);
|
||||
|
||||
public PropertyImpl(TabFeature listener, TabPlayer owner, String rawValue) {
|
||||
this(listener, owner, rawValue, null);
|
||||
@@ -56,7 +52,6 @@ public class PropertyImpl implements Property {
|
||||
this.source = source;
|
||||
this.rawValue = (rawValue == null ? "" : rawValue);
|
||||
analyze(this.rawValue);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,11 +67,11 @@ public class PropertyImpl implements Property {
|
||||
relPlaceholders0.add(identifier);
|
||||
}
|
||||
}
|
||||
String rawFormattedValue0 = RGBUtils.getInstance().applyFormats(value, true);
|
||||
String rawFormattedValue0 = value;
|
||||
for (String placeholder : placeholders0) {
|
||||
rawFormattedValue0 = rawFormattedValue0.replace(placeholder, "%s");
|
||||
}
|
||||
if (rawFormattedValue0.contains("%")) {
|
||||
if (placeholders0.size() > 0 && rawFormattedValue0.contains("%")) {
|
||||
int index = rawFormattedValue0.lastIndexOf('%');
|
||||
if (rawFormattedValue0.length() == index+1 || rawFormattedValue0.charAt(index+1) != 's') {
|
||||
StringBuilder sb = new StringBuilder(rawFormattedValue0);
|
||||
@@ -84,13 +79,15 @@ public class PropertyImpl implements Property {
|
||||
rawFormattedValue0 = sb.toString();
|
||||
}
|
||||
}
|
||||
rawFormattedValue0 = RGBUtils.getInstance().applyFormats(rawFormattedValue0, true);
|
||||
rawFormattedValue = EnumChatFormat.color(rawFormattedValue0);
|
||||
placeholders = placeholders0.toArray(new String[0]);
|
||||
relPlaceholders = relPlaceholders0.toArray(new String[0]);
|
||||
rawFormattedValue0 = EnumChatFormat.color(rawFormattedValue0);
|
||||
rawFormattedValue = applyRemoveStrings(rawFormattedValue0); //this should never be needed
|
||||
if (listener != null) {
|
||||
listener.addUsedPlaceholders(placeholders0);
|
||||
}
|
||||
lastReplacedValue = rawFormattedValue;
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,7 +99,6 @@ public class PropertyImpl implements Property {
|
||||
this.temporaryValue = null;
|
||||
analyze(rawValue);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -111,7 +107,6 @@ public class PropertyImpl implements Property {
|
||||
rawValue = newValue;
|
||||
if (temporaryValue == null) {
|
||||
analyze(rawValue);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,24 +149,20 @@ public class PropertyImpl implements Property {
|
||||
|
||||
@Override
|
||||
public boolean update() {
|
||||
if (placeholders.length == 0) return false;
|
||||
long time = System.nanoTime();
|
||||
String string;
|
||||
if (placeholders.length > 0) {
|
||||
if ("%s".equals(rawFormattedValue)) {
|
||||
string = TAB.getInstance().getPlaceholderManager().getPlaceholder(placeholders[0]).set(placeholders[0], owner);
|
||||
} else {
|
||||
String[] values = new String[placeholders.length];
|
||||
for (int i=0; i<placeholders.length; i++) {
|
||||
values[i] = TAB.getInstance().getPlaceholderManager().getPlaceholder(placeholders[i]).set(placeholders[i], owner);
|
||||
}
|
||||
string = formatter.format(rawFormattedValue, (Object[]) values).toString();
|
||||
formatBuffer.setLength(0);
|
||||
}
|
||||
string = applyRemoveStrings(EnumChatFormat.color(string));
|
||||
if ("%s".equals(rawFormattedValue)) {
|
||||
string = TAB.getInstance().getPlaceholderManager().getPlaceholder(placeholders[0]).set(placeholders[0], owner);
|
||||
} else {
|
||||
string = rawFormattedValue;
|
||||
Object[] values = new String[placeholders.length];
|
||||
for (int i=0; i<placeholders.length; i++) {
|
||||
values[i] = TAB.getInstance().getPlaceholderManager().getPlaceholder(placeholders[i]).set(placeholders[i], owner);
|
||||
}
|
||||
string = String.format(rawFormattedValue, values);
|
||||
}
|
||||
if (lastReplacedValue == null || !lastReplacedValue.equals(string)) {
|
||||
string = EnumChatFormat.color(string);
|
||||
if (!lastReplacedValue.equals(string)) {
|
||||
lastReplacedValue = string;
|
||||
TAB.getInstance().getCPUManager().addMethodTime("Property#update", System.nanoTime()-time);
|
||||
return true;
|
||||
@@ -179,19 +170,7 @@ public class PropertyImpl implements Property {
|
||||
TAB.getInstance().getCPUManager().addMethodTime("Property#update", System.nanoTime()-time);
|
||||
return false;
|
||||
}
|
||||
|
||||
private String applyRemoveStrings(String text) {
|
||||
if (TAB.getInstance().getConfiguration().getRemoveStrings().length == 0) return text;
|
||||
String reformatted = text;
|
||||
for (String removed : TAB.getInstance().getConfiguration().getRemoveStrings()) {
|
||||
if (removed.startsWith("CONTAINS:") && reformatted.contains(removed.substring(9))) return "";
|
||||
if (removed.startsWith("STARTS:") && reformatted.startsWith(removed.substring(7))) return "";
|
||||
if (removed.startsWith("ENDS:") && reformatted.endsWith(removed.substring(5))) return "";
|
||||
if (reformatted.contains(removed)) reformatted = reformatted.replace(removed, "");
|
||||
}
|
||||
return reformatted;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
return lastReplacedValue;
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import me.neznamy.tab.shared.event.EventBusImpl;
|
||||
import me.neznamy.tab.shared.event.impl.TabLoadEventImpl;
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
|
||||
import me.neznamy.tab.api.HeaderFooterManager;
|
||||
@@ -33,7 +35,6 @@ import me.neznamy.tab.shared.features.layout.LayoutManager;
|
||||
import me.neznamy.tab.shared.features.nametags.NameTag;
|
||||
import me.neznamy.tab.shared.features.scoreboard.ScoreboardManagerImpl;
|
||||
import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
import me.neznamy.tab.shared.proxy.ProxyTabPlayer;
|
||||
|
||||
/**
|
||||
* Universal variable and method storage
|
||||
@@ -48,6 +49,7 @@ public class TAB extends TabAPI {
|
||||
|
||||
//player data
|
||||
private final Map<UUID, TabPlayer> data = new ConcurrentHashMap<>();
|
||||
private final Map<UUID, TabPlayer> playersByTablistId = new ConcurrentHashMap<>();
|
||||
|
||||
//player array to reduce memory allocation when iterating
|
||||
private TabPlayer[] players = new TabPlayer[0];
|
||||
@@ -64,6 +66,8 @@ public class TAB extends TabAPI {
|
||||
//cpu manager
|
||||
private CpuManager cpu;
|
||||
|
||||
private EventBusImpl eventBus;
|
||||
|
||||
//error manager
|
||||
private ErrorManager errorManager;
|
||||
|
||||
@@ -92,9 +96,14 @@ public class TAB extends TabAPI {
|
||||
try {
|
||||
Class.forName("org.geysermc.floodgate.api.FloodgateApi");
|
||||
floodgate = true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
} catch (ClassNotFoundException | IllegalStateException e) {
|
||||
//plugin not installed
|
||||
}
|
||||
try {
|
||||
eventBus = new EventBusImpl();
|
||||
} catch (NoSuchMethodError e) {
|
||||
//1.7.10 or lower
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,15 +112,12 @@ public class TAB extends TabAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns player by TabList UUID. This is required due to Velocity as player uuid and TabList uuid do ont match there
|
||||
* Returns player by TabList UUID. This is required due to Velocity as player uuid and TabList uuid do not match there
|
||||
* @param tabListId - TabList id of player
|
||||
* @return the player or null if not found
|
||||
*/
|
||||
public TabPlayer getPlayerByTablistUUID(UUID tabListId) {
|
||||
for (TabPlayer p : data.values()) {
|
||||
if (p.getTablistUUID().equals(tabListId)) return p;
|
||||
}
|
||||
return null;
|
||||
return playersByTablistId.get(tabListId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,32 +144,33 @@ public class TAB extends TabAPI {
|
||||
public String load() {
|
||||
try {
|
||||
long time = System.currentTimeMillis();
|
||||
this.errorManager = new ErrorManager(this);
|
||||
this.errorManager = new ErrorManager();
|
||||
cpu = new CpuManager(errorManager);
|
||||
featureManager = new FeatureManagerImpl();
|
||||
configuration = new Configs(this);
|
||||
configuration.loadFiles();
|
||||
placeholderManager = new PlaceholderManagerImpl();
|
||||
cpu.registerPlaceholder();
|
||||
featureManager.registerFeature("placeholders", placeholderManager);
|
||||
featureManager.registerFeature(TabConstants.Feature.PLACEHOLDER_MANAGER, placeholderManager);
|
||||
groupManager = new GroupManager(platform.detectPermissionPlugin());
|
||||
featureManager.registerFeature("groups", groupManager);
|
||||
featureManager.registerFeature(TabConstants.Feature.GROUP_MANAGER, groupManager);
|
||||
platform.loadFeatures();
|
||||
command = new TabCommand(this);
|
||||
featureManager.load();
|
||||
for (TabPlayer p : players) ((ITabPlayer)p).markAsLoaded();
|
||||
errorManager.printConsoleWarnCount();
|
||||
print('a', "Enabled in " + (System.currentTimeMillis()-time) + "ms");
|
||||
for (TabPlayer p : players) ((ITabPlayer)p).markAsLoaded(false);
|
||||
cpu.enable();
|
||||
if (eventBus != null) eventBus.fire(TabLoadEventImpl.getInstance());
|
||||
platform.callLoadEvent();
|
||||
disabled = false;
|
||||
print('a', "Enabled in " + (System.currentTimeMillis()-time) + "ms");
|
||||
return configuration.getMessages().getReloadSuccess();
|
||||
} catch (YAMLException e) {
|
||||
print('c', "Did not enable due to a broken configuration file.");
|
||||
disabled = true;
|
||||
kill();
|
||||
return configuration.getReloadFailedMessage().replace("%file%", "-"); //recode soon
|
||||
} catch (Exception e) {
|
||||
errorManager.criticalError("Failed to enable. Did you just invent a new way to break the plugin by misconfiguring it?", e);
|
||||
disabled = true;
|
||||
kill();
|
||||
return "&cFailed to enable due to an internal plugin error. Check console for more info.";
|
||||
}
|
||||
}
|
||||
@@ -173,60 +180,68 @@ public class TAB extends TabAPI {
|
||||
*/
|
||||
public void unload() {
|
||||
if (disabled) return;
|
||||
disabled = true;
|
||||
try {
|
||||
long time = System.currentTimeMillis();
|
||||
cpu.cancelAllTasks();
|
||||
if (configuration.getMysql() != null) configuration.getMysql().closeConnection();
|
||||
featureManager.unload();
|
||||
data.clear();
|
||||
platform.sendConsoleMessage("&a[TAB] Disabled in " + (System.currentTimeMillis()-time) + "ms", true);
|
||||
} catch (Exception e) {
|
||||
data.clear();
|
||||
errorManager.criticalError("Failed to disable", e);
|
||||
}
|
||||
kill();
|
||||
}
|
||||
|
||||
private void kill() {
|
||||
disabled = true;
|
||||
data.clear();
|
||||
players = new TabPlayer[0];
|
||||
cpu.cancelAllTasks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads universal features present on all platforms with the same configuration
|
||||
*/
|
||||
public void loadUniversalFeatures() {
|
||||
if (configuration.getConfig().getBoolean("header-footer.enabled", true)) featureManager.registerFeature("headerfooter", new HeaderFooter());
|
||||
if (configuration.isRemoveGhostPlayers()) featureManager.registerFeature("ghostplayerfix", new GhostPlayerFix());
|
||||
if (configuration.getConfig().getBoolean("header-footer.enabled", true))
|
||||
featureManager.registerFeature(TabConstants.Feature.HEADER_FOOTER, new HeaderFooter());
|
||||
if (configuration.isRemoveGhostPlayers())
|
||||
featureManager.registerFeature(TabConstants.Feature.GHOST_PLAYER_FIX, new GhostPlayerFix());
|
||||
if (serverVersion.getMinorVersion() >= 8 && configuration.getConfig().getBoolean("tablist-name-formatting.enabled", true)) {
|
||||
if (configuration.getConfig().getBoolean("tablist-name-formatting.align-tabsuffix-on-the-right", false)) {
|
||||
featureManager.registerFeature("playerlist", new AlignedPlayerList());
|
||||
featureManager.registerFeature(TabConstants.Feature.PLAYER_LIST, new AlignedPlayerList());
|
||||
} else {
|
||||
featureManager.registerFeature("playerlist", new PlayerList());
|
||||
featureManager.registerFeature(TabConstants.Feature.PLAYER_LIST, new PlayerList());
|
||||
}
|
||||
}
|
||||
if (configuration.getConfig().getBoolean("ping-spoof.enabled", false)) featureManager.registerFeature("pingspoof", new PingSpoof());
|
||||
if (configuration.getConfig().getBoolean("yellow-number-in-tablist.enabled", true)) featureManager.registerFeature("tabobjective", new YellowNumber());
|
||||
if (configuration.getConfig().getBoolean("prevent-spectator-effect.enabled", false)) featureManager.registerFeature("spectatorfix", new SpectatorFix());
|
||||
if (configuration.getConfig().getBoolean("belowname-objective.enabled", true)) featureManager.registerFeature("belowname", new BelowName());
|
||||
if (configuration.getConfig().getBoolean("scoreboard.enabled", false)) featureManager.registerFeature("scoreboard", new ScoreboardManagerImpl());
|
||||
if (configuration.getConfig().getBoolean("ping-spoof.enabled", false))
|
||||
featureManager.registerFeature(TabConstants.Feature.PING_SPOOF, new PingSpoof());
|
||||
if (configuration.getConfig().getBoolean("yellow-number-in-tablist.enabled", true))
|
||||
featureManager.registerFeature(TabConstants.Feature.YELLOW_NUMBER, new YellowNumber());
|
||||
if (configuration.getConfig().getBoolean("prevent-spectator-effect.enabled", false))
|
||||
featureManager.registerFeature(TabConstants.Feature.SPECTATOR_FIX, new SpectatorFix());
|
||||
if (configuration.getConfig().getBoolean("belowname-objective.enabled", true))
|
||||
featureManager.registerFeature(TabConstants.Feature.BELOW_NAME, new BelowName());
|
||||
if (configuration.getConfig().getBoolean("scoreboard.enabled", false))
|
||||
featureManager.registerFeature(TabConstants.Feature.SCOREBOARD, new ScoreboardManagerImpl());
|
||||
if (serverVersion.getMinorVersion() >= 8 && configuration.getLayout().getBoolean("enabled", false)) {
|
||||
if (getTeamManager() == null) {
|
||||
//sorting is disabled, but layout needs team names
|
||||
featureManager.registerFeature("sorting", new Sorting(null));
|
||||
}
|
||||
featureManager.registerFeature("layout", new LayoutManager());
|
||||
}
|
||||
featureManager.registerFeature("nick", new NickCompatibility());
|
||||
if (platform.isProxy()) {
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
((ProxyTabPlayer)all).getPluginMessageHandler().requestAttribute(all, "world");
|
||||
featureManager.registerFeature(TabConstants.Feature.SORTING, new Sorting(null));
|
||||
}
|
||||
featureManager.registerFeature(TabConstants.Feature.LAYOUT, new LayoutManager());
|
||||
}
|
||||
featureManager.registerFeature(TabConstants.Feature.NICK_COMPATIBILITY, new NickCompatibility());
|
||||
}
|
||||
|
||||
public void addPlayer(TabPlayer player) {
|
||||
data.put(player.getUniqueId(), player);
|
||||
playersByTablistId.put(player.getTablistUUID(), player);
|
||||
players = data.values().toArray(new TabPlayer[0]);
|
||||
}
|
||||
|
||||
public void removePlayer(TabPlayer player) {
|
||||
data.remove(player.getUniqueId());
|
||||
playersByTablistId.remove(player.getTablistUUID());
|
||||
players = data.values().toArray(new TabPlayer[0]);
|
||||
}
|
||||
|
||||
@@ -251,6 +266,11 @@ public class TAB extends TabAPI {
|
||||
return cpu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBusImpl getEventBus() {
|
||||
return eventBus;
|
||||
}
|
||||
|
||||
public ErrorManager getErrorManager() {
|
||||
return errorManager;
|
||||
}
|
||||
@@ -286,18 +306,18 @@ public class TAB extends TabAPI {
|
||||
|
||||
@Override
|
||||
public BossBarManager getBossBarManager() {
|
||||
return (BossBarManager) featureManager.getFeature("bossbar");
|
||||
return (BossBarManager) featureManager.getFeature(TabConstants.Feature.BOSS_BAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoreboardManager getScoreboardManager() {
|
||||
return (ScoreboardManager) featureManager.getFeature("scoreboard");
|
||||
return (ScoreboardManager) featureManager.getFeature(TabConstants.Feature.SCOREBOARD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeamManager getTeamManager() {
|
||||
if (featureManager.isFeatureEnabled("nametag16")) return (NameTag) featureManager.getFeature("nametag16");
|
||||
return (NameTag) featureManager.getFeature("nametagx");
|
||||
if (featureManager.isFeatureEnabled(TabConstants.Feature.NAME_TAGS)) return (NameTag) featureManager.getFeature(TabConstants.Feature.NAME_TAGS);
|
||||
return (NameTag) featureManager.getFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -325,7 +345,7 @@ public class TAB extends TabAPI {
|
||||
|
||||
@Override
|
||||
public HeaderFooterManager getHeaderFooterManager() {
|
||||
return (HeaderFooterManager) featureManager.getFeature("headerfooter");
|
||||
return (HeaderFooterManager) featureManager.getFeature(TabConstants.Feature.HEADER_FOOTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -368,6 +388,6 @@ public class TAB extends TabAPI {
|
||||
|
||||
@Override
|
||||
public TablistFormatManager getTablistFormatManager() {
|
||||
return (TablistFormatManager) featureManager.getFeature("playerlist");
|
||||
return (TablistFormatManager) featureManager.getFeature(TabConstants.Feature.PLAYER_LIST);
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,12 @@ public class TabConstants {
|
||||
public static final String PLAYER_SNEAK = "Player Sneak";
|
||||
public static final String PLAYER_RESPAWN = "Player Respawn";
|
||||
public static final String PLUGIN_MESSAGE = "PluginMessageEvent";
|
||||
public static final String REDIS_BUNGEE_MESSAGE = "PubSubMessageEvent";
|
||||
public static final String LUCKPERMS_RECALCULATE_EVENT = "UserDataRecalculateEvent";
|
||||
|
||||
public static final String ANTI_OVERRIDE = "Anti override";
|
||||
|
||||
public static final String BYTEBUF = "ByteBuf";
|
||||
public static final String BYTE_BUF = "ByteBuf";
|
||||
public static final String PACKET_PLAYER_INFO = "PacketPlayOutPlayerInfo";
|
||||
public static final String PACKET_DISPLAY_OBJECTIVE = "PacketPlayOutScoreboardDisplayObjective";
|
||||
public static final String PACKET_OBJECTIVE = "PacketPlayOutScoreboardObjective";
|
||||
@@ -33,12 +34,9 @@ public class TabConstants {
|
||||
public static final String PLACEHOLDER_REFRESHING = "Refreshing placeholders";
|
||||
|
||||
public static final String V1_8_0_BUG_COMPENSATION = "Compensating for 1.8.0 bugs";
|
||||
public static final String REFRESHING_NAMETAG_VISIBILITY = "Refreshing nametag visibility";
|
||||
public static final String TICKING_VEHICLES = "Ticking vehicles";
|
||||
public static final String TELEPORTING_WITHER = "Teleporting Wither entity";
|
||||
public static final String REFRESHING_NAME_TAG_VISIBILITY = "Refreshing NameTag visibility";
|
||||
public static final String SCOREBOARD_PACKET_CHECK = "Checking for other plugins";
|
||||
public static final String REFRESHING_TEAM_NAMES = "Refreshing team names";
|
||||
public static final String REFRESHING_GROUPS = "Refreshing player groups";
|
||||
public static final String PROCESSING_PLAYER_MOVEMENT = "Processing player movement";
|
||||
|
||||
private CpuUsageCategory() {}
|
||||
}
|
||||
@@ -50,26 +48,25 @@ public class TabConstants {
|
||||
public static final String BOSSBAR_TEXT = "BossBar (Text)";
|
||||
public static final String BOSSBAR_WITHER_TELEPORT = "BossBar (Teleporting Wither)";
|
||||
|
||||
public static final String GLOBAL_PLAYERLIST_LATENCY = "Global Playerlist (Updating latency)";
|
||||
public static final String GLOBAL_PLAYERLIST_VANISH = "Global Playerlist (Vanishing)";
|
||||
public static final String GLOBAL_PLAYERLIST_LATENCY = "Global PlayerList (Updating latency)";
|
||||
public static final String GLOBAL_PLAYERLIST_VANISH = "Global PlayerList (Vanishing)";
|
||||
|
||||
public static final String LAYOUT_FIXED_SLOTS = "Layout (Fixed slots)";
|
||||
public static final String LAYOUT_LATENCY = "Layout (Updating latency)";
|
||||
public static final String LAYOUT_PLAYER_SLOTS = "Layout (Player slots)";
|
||||
|
||||
public static final String NAMETAGS_TEAM_REGISTER = "Nametags (Team register)";
|
||||
public static final String NAMETAGS_TEAM_UNREGISTER = "Nametags (Team unregister)";
|
||||
public static final String NAMETAGS_TEAM_UPDATE = "Nametags (Team update)";
|
||||
public static final String NAMETAGS_TEAM_REGISTER = "NameTags (Team register)";
|
||||
public static final String NAMETAGS_TEAM_UNREGISTER = "NameTags (Team unregister)";
|
||||
public static final String NAMETAGS_TEAM_UPDATE = "NameTags (Team update)";
|
||||
|
||||
public static final String SCOREBOARD_TITLE = "Scoreboard (Title)";
|
||||
public static final String SCOREBOARD_LINES = "Scoreboard (Lines)";
|
||||
|
||||
public static final String UNLIMITED_NAMETAGS_OFFSET_CHANGE = "Unlimited Nametags (Changing offset)";
|
||||
public static final String UNLIMITED_NAMETAGS_SPAWN = "Unlimited Nametags (Spawning)";
|
||||
public static final String UNLIMITED_NAMETAGS_DESPAWN = "Unlimited Nametags (Despawning)";
|
||||
public static final String UNLIMITED_NAMETAGS_TELEPORT = "Unlimited Nametags (Teleporting)";
|
||||
public static final String UNLIMITED_NAMETAGS_SNEAK = "Unlimited Nametags (Sneaking)";
|
||||
public static final String UNLIMITED_NAMETAGS_METADATA = "Unlimited Nametags (Metadata)";
|
||||
public static final String UNLIMITED_NAMETAGS_OFFSET_CHANGE = "Unlimited NameTags (Changing offset)";
|
||||
public static final String UNLIMITED_NAMETAGS_SPAWN = "Unlimited NameTags (Spawning)";
|
||||
public static final String UNLIMITED_NAMETAGS_DESPAWN = "Unlimited NameTags (Despawning)";
|
||||
public static final String UNLIMITED_NAMETAGS_TELEPORT = "Unlimited NameTags (Teleporting)";
|
||||
public static final String UNLIMITED_NAMETAGS_SNEAK = "Unlimited NameTags (Sneaking)";
|
||||
public static final String UNLIMITED_NAMETAGS_METADATA = "Unlimited NameTags (Metadata)";
|
||||
|
||||
private PacketCategory() {}
|
||||
}
|
||||
@@ -162,4 +159,74 @@ public class TabConstants {
|
||||
return scoreboard + "-" + lineNumber + "-suffix";
|
||||
}
|
||||
}
|
||||
|
||||
public static class Feature {
|
||||
|
||||
//universal features
|
||||
public static final String HEADER_FOOTER = "HeaderFooter";
|
||||
public static final String GHOST_PLAYER_FIX = "GhostPlayerFix";
|
||||
public static final String PLAYER_LIST = "PlayerList";
|
||||
public static final String SPECTATOR_FIX = "SpectatorFix";
|
||||
public static final String YELLOW_NUMBER = "YellowNumber";
|
||||
public static final String BELOW_NAME = "BelowName";
|
||||
public static final String BELOW_NAME_TEXT = "BelowNameText";
|
||||
public static final String SCOREBOARD = "ScoreBoard";
|
||||
public static final String PING_SPOOF = "PingSpoof";
|
||||
public static final String SORTING = "sorting";
|
||||
public static final String LAYOUT = "layout";
|
||||
public static final String LAYOUT_VANISH = "layout-vanish";
|
||||
public static final String NICK_COMPATIBILITY = "nick";
|
||||
public static final String PIPELINE_INJECTION = "injection";
|
||||
public static final String BOSS_BAR = "BossBar";
|
||||
public static final String NAME_TAGS = "NameTag16";
|
||||
public static final String NAME_TAGS_COLLISION = "NameTagCollision";
|
||||
public static final String NAME_TAGS_VISIBILITY = "NameTagVisibility";
|
||||
public static final String GROUP_MANAGER = "GroupManager";
|
||||
public static final String PLACEHOLDER_MANAGER = "PlaceholderManager";
|
||||
|
||||
//Bukkit only
|
||||
public static final String PER_WORLD_PLAYER_LIST = "PerWorldPlayerList";
|
||||
public static final String PET_FIX = "PetFix";
|
||||
public static final String UNLIMITED_NAME_TAGS = "NameTagX";
|
||||
public static final String UNLIMITED_NAME_TAGS_PACKET_LISTENER = "nametagx-packet";
|
||||
public static final String UNLIMITED_NAME_TAGS_VEHICLE_REFRESHER = "nametagx-vehicle";
|
||||
public static final String UNLIMITED_NAME_TAGS_LOCATION_REFRESHER = "nametagx-location";
|
||||
|
||||
//BungeeCord only
|
||||
public static final String REDIS_BUNGEE = "RedisBungee";
|
||||
public static final String GLOBAL_PLAYER_LIST = "GlobalPlayerList";
|
||||
public static final String GLOBAL_PLAYER_LIST_LATENCY = "GlobalPlayerList-Latency";
|
||||
public static final String GLOBAL_PLAYER_LIST_VANISH = "GlobalPlayerList-Vanish";
|
||||
|
||||
private Feature(){
|
||||
}
|
||||
|
||||
public static String scoreboardLine(String line) {
|
||||
return "scoreboard-" + line;
|
||||
}
|
||||
|
||||
public static String layout(String name) {
|
||||
return "layout-" + name;
|
||||
}
|
||||
|
||||
public static String layoutSlot(String layout, int slot) {
|
||||
return "layout-" + layout + "-slot-" + slot;
|
||||
}
|
||||
|
||||
public static String bossBarTitle(String name) {
|
||||
return "BossBar-title-" + name;
|
||||
}
|
||||
|
||||
public static String bossBarProgress(String name) {
|
||||
return "BossBar-progress-" + name;
|
||||
}
|
||||
|
||||
public static String bossBarColorStyle(String name) {
|
||||
return "BossBar-color-style-" + name;
|
||||
}
|
||||
|
||||
public static String scoreboardLine(String scoreboard, int index) {
|
||||
return "scoreboard-score-" + scoreboard + "-" + index;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +1,46 @@
|
||||
package me.neznamy.tab.shared;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.task.RepeatingTask;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class TabRepeatingTask implements RepeatingTask {
|
||||
|
||||
private Future<Void> task;
|
||||
private final ThreadPoolExecutor executor;
|
||||
private final ExecutorService exe;
|
||||
private Runnable runnable;
|
||||
private final String errorDescription;
|
||||
private final TabFeature feature;
|
||||
private final String type;
|
||||
private int interval;
|
||||
private Future<?> task;
|
||||
|
||||
public TabRepeatingTask(ThreadPoolExecutor executor, Runnable runnable, String errorDescription, TabFeature feature, String type, int interval) {
|
||||
public TabRepeatingTask(ExecutorService exe, Runnable runnable, String errorDescription, TabFeature feature, String type, int interval) {
|
||||
if (interval < 0) throw new IllegalArgumentException("Interval cannot be negative");
|
||||
this.executor = executor;
|
||||
this.exe = exe;
|
||||
this.runnable = runnable;
|
||||
this.errorDescription = errorDescription;
|
||||
this.feature = feature;
|
||||
this.type = type;
|
||||
this.interval = interval;
|
||||
this.task = createTask();
|
||||
createTask();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Future<Void> createTask() {
|
||||
return (Future<Void>)executor.submit(() -> {
|
||||
long nextLoop = System.currentTimeMillis() - interval;
|
||||
|
||||
private void createTask() {
|
||||
task = exe.submit(() -> {
|
||||
long nextLoop = System.currentTimeMillis();
|
||||
while (true) {
|
||||
try {
|
||||
nextLoop += interval;
|
||||
long sleep = nextLoop - System.currentTimeMillis();
|
||||
if (sleep > interval) sleep = interval; //time travelers who travel back in time
|
||||
if (sleep > interval) sleep = interval; //servers who travel back in time
|
||||
if (sleep > 0) Thread.sleep(sleep);
|
||||
long time = System.nanoTime();
|
||||
runnable.run();
|
||||
TAB.getInstance().getCPUManager().addTime(feature, type, System.nanoTime() - time);
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask(errorDescription, feature, type, runnable);
|
||||
} catch (InterruptedException pluginDisabled) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
} catch (Exception | NoClassDefFoundError e) {
|
||||
} catch (Exception | LinkageError e) {
|
||||
TAB.getInstance().getErrorManager().printError("An error occurred when " + errorDescription, e);
|
||||
}
|
||||
}
|
||||
@@ -60,7 +57,7 @@ public class TabRepeatingTask implements RepeatingTask {
|
||||
if (interval < 0) throw new IllegalArgumentException("Interval cannot be negative");
|
||||
cancel();
|
||||
this.interval = interval;
|
||||
task = createTask();
|
||||
createTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,7 +19,7 @@ public class BossBarCommand extends SubCommand {
|
||||
|
||||
@Override
|
||||
public void execute(TabPlayer sender, String[] args) {
|
||||
BossBarManager bossBar = (BossBarManager) TAB.getInstance().getFeatureManager().getFeature("bossbar");
|
||||
BossBarManager bossBar = (BossBarManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.BOSS_BAR);
|
||||
if (bossBar == null) {
|
||||
sendMessage(sender, getMessages().getBossBarNotEnabled());
|
||||
return;
|
||||
|
||||
@@ -67,7 +67,6 @@ public class CpuCommand extends SubCommand {
|
||||
sendToConsole(features);
|
||||
}
|
||||
sendMessage(sender, SEPARATOR);
|
||||
sendMessage(sender, String.format("&8&l%s &7Threads created by the plugin (active/total): &7%s", LINE_CHAR, tab.getCPUManager().getThreadCount()));
|
||||
if (sender != null) {
|
||||
sendPacketCountToPlayer(sender);
|
||||
} else {
|
||||
|
||||
@@ -66,8 +66,8 @@ public class DebugCommand extends SubCommand {
|
||||
sendMessage(sender, getGroup(analyzed));
|
||||
sendMessage(sender, getTeamName(analyzed));
|
||||
sendMessage(sender, getTeamNameNote(analyzed));
|
||||
if (tab.getFeatureManager().isFeatureEnabled("playerlist")) {
|
||||
PlayerList playerlist = (PlayerList) tab.getFeatureManager().getFeature("playerlist");
|
||||
if (tab.getFeatureManager().isFeatureEnabled(TabConstants.Feature.PLAYER_LIST)) {
|
||||
PlayerList playerlist = (PlayerList) tab.getFeatureManager().getFeature(TabConstants.Feature.PLAYER_LIST);
|
||||
boolean disabledPlayerlist = playerlist.isDisabled(analyzed.getServer(), analyzed.getWorld());
|
||||
showProperty(sender, analyzed, TabConstants.Property.TABPREFIX, disabledPlayerlist);
|
||||
showProperty(sender, analyzed, TabConstants.Property.TABSUFFIX, disabledPlayerlist);
|
||||
@@ -164,7 +164,7 @@ public class DebugCommand extends SubCommand {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Object> getExtraLines(){
|
||||
if (!TAB.getInstance().getFeatureManager().isFeatureEnabled("nametagx")) return new ArrayList<>();
|
||||
if (!TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.UNLIMITED_NAME_TAGS)) return new ArrayList<>();
|
||||
List<Object> lines = Lists.newArrayList((List<Object>) TAB.getInstance().getConfiguration().getConfig().getObject("scoreboard-teams.unlimited-nametag-mode.dynamic-lines"));
|
||||
lines.addAll(TAB.getInstance().getConfiguration().getConfig().getConfigurationSection("scoreboard-teams.unlimited-nametag-mode.static-lines").keySet());
|
||||
lines.remove(TabConstants.Property.NAMETAG);
|
||||
|
||||
@@ -27,7 +27,20 @@ public class GroupCommand extends PropertyCommand {
|
||||
}
|
||||
String group = args[0];
|
||||
String type = args[1].toLowerCase();
|
||||
String value = buildArgument(Arrays.copyOfRange(args, 2, args.length));
|
||||
String value = String.join(" ", Arrays.copyOfRange(args, 2, args.length));
|
||||
String world = null;
|
||||
String server = null;
|
||||
if (args[args.length-2].equals("-w")) {
|
||||
world = args[args.length-1];
|
||||
value = value.substring(0, value.length()-world.length()-4);
|
||||
}
|
||||
if (args[args.length-2].equals("-s")) {
|
||||
server = args[args.length-1];
|
||||
value = value.substring(0, value.length()-server.length()-4);
|
||||
}
|
||||
if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
|
||||
value = value.substring(1, value.length()-1);
|
||||
}
|
||||
if ("remove".equals(type)) {
|
||||
if (hasPermission(sender, TabConstants.Permission.COMMAND_DATA_REMOVE)) {
|
||||
TAB.getInstance().getConfiguration().getGroups().remove(group);
|
||||
@@ -45,8 +58,8 @@ public class GroupCommand extends PropertyCommand {
|
||||
for (String property : getAllProperties()) {
|
||||
if (type.equals(property)) {
|
||||
if (hasPermission(sender, TabConstants.Permission.COMMAND_PROPERTY_CHANGE_PREFIX + property)) {
|
||||
saveGroup(sender, group, type, value);
|
||||
if (extraProperties.contains(property) && !TAB.getInstance().getFeatureManager().isFeatureEnabled("nametagx")) {
|
||||
saveGroup(sender, group, type, value, server, world);
|
||||
if (extraProperties.contains(property) && !TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.UNLIMITED_NAME_TAGS)) {
|
||||
sendMessage(sender, getMessages().getUnlimitedNametagModeNotEnabled());
|
||||
}
|
||||
} else {
|
||||
@@ -65,15 +78,15 @@ public class GroupCommand extends PropertyCommand {
|
||||
* @param type - property type
|
||||
* @param value - new value
|
||||
*/
|
||||
private void saveGroup(TabPlayer sender, String group, String type, String value){
|
||||
private void saveGroup(TabPlayer sender, String group, String type, String value, String server, String world){
|
||||
if (value.length() > 0){
|
||||
sendMessage(sender, getMessages().getGroupValueAssigned(type, value, group));
|
||||
} else {
|
||||
sendMessage(sender, getMessages().getGroupValueRemoved(type, group));
|
||||
}
|
||||
String[] property = TAB.getInstance().getConfiguration().getGroups().getProperty(group, type, null, null);
|
||||
String[] property = TAB.getInstance().getConfiguration().getGroups().getProperty(group, type, server, world);
|
||||
if (property.length > 0 && String.valueOf(value.length() == 0 ? null : value).equals(String.valueOf(property[0]))) return;
|
||||
TAB.getInstance().getConfiguration().getGroups().setProperty(group, type, null, null, value.length() == 0 ? null : value);
|
||||
TAB.getInstance().getConfiguration().getGroups().setProperty(group, type, server, world, value.length() == 0 ? null : value);
|
||||
for (TabPlayer pl : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (pl.getGroup().equals(group) || "_DEFAULT_".equals(group)){
|
||||
pl.forceRefresh();
|
||||
|
||||
@@ -18,7 +18,7 @@ public class NTPreviewCommand extends SubCommand{
|
||||
|
||||
@Override
|
||||
public void execute(TabPlayer sender, String[] args) {
|
||||
if ((TAB.getInstance().getFeatureManager().getFeature("nametagx")) != null) {
|
||||
if ((TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS)) != null) {
|
||||
if (sender != null) {
|
||||
sender.toggleNametagPreview();
|
||||
} else {
|
||||
|
||||
@@ -3,10 +3,12 @@ package me.neznamy.tab.shared.command;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.api.placeholder.Placeholder;
|
||||
import me.neznamy.tab.shared.PropertyImpl;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
@@ -60,9 +62,15 @@ public class ParseCommand extends SubCommand {
|
||||
|
||||
@Override
|
||||
public List<String> complete(TabPlayer sender, String[] arguments) {
|
||||
if (arguments.length != 1) return new ArrayList<>();
|
||||
List<String> suggestions = getOnlinePlayers(arguments[0]);
|
||||
if ("me".startsWith(arguments[0].toLowerCase())) suggestions.add("me");
|
||||
return suggestions;
|
||||
if (arguments.length == 1) {
|
||||
List<String> suggestions = getOnlinePlayers(arguments[0]);
|
||||
if ("me".startsWith(arguments[0].toLowerCase())) suggestions.add("me");
|
||||
return suggestions;
|
||||
}
|
||||
if (arguments.length == 2) {
|
||||
return TAB.getInstance().getPlaceholderManager().getAllPlaceholders().stream().map(Placeholder::getIdentifier)
|
||||
.filter(placeholder -> placeholder.toLowerCase().startsWith(arguments[1].toLowerCase())).collect(Collectors.toList());
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,20 @@ public class PlayerCommand extends PropertyCommand {
|
||||
}
|
||||
String player = args[0];
|
||||
String type = args[1].toLowerCase();
|
||||
String value = buildArgument(Arrays.copyOfRange(args, 2, args.length));
|
||||
String value = String.join(" ", Arrays.copyOfRange(args, 2, args.length));
|
||||
String world = null;
|
||||
String server = null;
|
||||
if (args[args.length-2].equals("-w")) {
|
||||
world = args[args.length-1];
|
||||
value = value.substring(0, value.length()-world.length()-4);
|
||||
}
|
||||
if (args[args.length-2].equals("-s")) {
|
||||
server = args[args.length-1];
|
||||
value = value.substring(0, value.length()-server.length()-4);
|
||||
}
|
||||
if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
|
||||
value = value.substring(1, value.length()-1);
|
||||
}
|
||||
if ("remove".equals(type)) {
|
||||
if (hasPermission(sender, TabConstants.Permission.COMMAND_DATA_REMOVE)) {
|
||||
TAB.getInstance().getConfiguration().getUsers().remove(player);
|
||||
@@ -45,8 +58,8 @@ public class PlayerCommand extends PropertyCommand {
|
||||
for (String property : getAllProperties()) {
|
||||
if (type.equals(property)) {
|
||||
if (hasPermission(sender, TabConstants.Permission.COMMAND_PROPERTY_CHANGE_PREFIX + property)) {
|
||||
savePlayer(sender, player, type, value);
|
||||
if (extraProperties.contains(property) && !TAB.getInstance().getFeatureManager().isFeatureEnabled("nametagx")) {
|
||||
savePlayer(sender, player, type, value, server, world);
|
||||
if (extraProperties.contains(property) && !TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.UNLIMITED_NAME_TAGS)) {
|
||||
sendMessage(sender, getMessages().getUnlimitedNametagModeNotEnabled());
|
||||
}
|
||||
} else {
|
||||
@@ -65,15 +78,15 @@ public class PlayerCommand extends PropertyCommand {
|
||||
* @param type - property type
|
||||
* @param value - new value
|
||||
*/
|
||||
public void savePlayer(TabPlayer sender, String player, String type, String value){
|
||||
public void savePlayer(TabPlayer sender, String player, String type, String value, String server, String world){
|
||||
if (value.length() > 0){
|
||||
sendMessage(sender, getMessages().getPlayerValueAssigned(type, value, player));
|
||||
} else {
|
||||
sendMessage(sender, getMessages().getPlayerValueRemoved(type, player));
|
||||
}
|
||||
String[] property = TAB.getInstance().getConfiguration().getUsers().getProperty(player, type, null, null);
|
||||
String[] property = TAB.getInstance().getConfiguration().getUsers().getProperty(player, type, server, world);
|
||||
if (property.length > 0 && String.valueOf(value.length() == 0 ? null : value).equals(String.valueOf(property[0]))) return;
|
||||
TAB.getInstance().getConfiguration().getUsers().setProperty(player, type, null, null, value.length() == 0 ? null : value);
|
||||
TAB.getInstance().getConfiguration().getUsers().setProperty(player, type, server, world, value.length() == 0 ? null : value);
|
||||
TabPlayer pl = TAB.getInstance().getPlayer(player);
|
||||
if (pl != null) {
|
||||
pl.forceRefresh();
|
||||
|
||||
@@ -33,7 +33,20 @@ public class PlayerUUIDCommand extends PropertyCommand {
|
||||
return;
|
||||
}
|
||||
String type = args[1].toLowerCase();
|
||||
String value = buildArgument(Arrays.copyOfRange(args, 2, args.length));
|
||||
String value = String.join(" ", Arrays.copyOfRange(args, 2, args.length));
|
||||
String world = null;
|
||||
String server = null;
|
||||
if (args[args.length-2].equals("-w")) {
|
||||
world = args[args.length-1];
|
||||
value = value.substring(0, value.length()-world.length()-4);
|
||||
}
|
||||
if (args[args.length-2].equals("-s")) {
|
||||
server = args[args.length-1];
|
||||
value = value.substring(0, value.length()-server.length()-4);
|
||||
}
|
||||
if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
|
||||
value = value.substring(1, value.length()-1);
|
||||
}
|
||||
if ("remove".equals(type)) {
|
||||
if (hasPermission(sender, TabConstants.Permission.COMMAND_DATA_REMOVE)) {
|
||||
TAB.getInstance().getConfiguration().getUsers().remove(changed.getUniqueId().toString());
|
||||
@@ -47,8 +60,8 @@ public class PlayerUUIDCommand extends PropertyCommand {
|
||||
for (String property : getAllProperties()) {
|
||||
if (type.equals(property)) {
|
||||
if (hasPermission(sender, TabConstants.Permission.COMMAND_PROPERTY_CHANGE_PREFIX + property)) {
|
||||
savePlayer(sender, changed, type, value);
|
||||
if (extraProperties.contains(property) && !TAB.getInstance().getFeatureManager().isFeatureEnabled("nametagx")) {
|
||||
savePlayer(sender, changed, type, value, server, world);
|
||||
if (extraProperties.contains(property) && !TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.UNLIMITED_NAME_TAGS)) {
|
||||
sendMessage(sender, getMessages().getUnlimitedNametagModeNotEnabled());
|
||||
}
|
||||
} else {
|
||||
@@ -67,15 +80,15 @@ public class PlayerUUIDCommand extends PropertyCommand {
|
||||
* @param type - property type
|
||||
* @param value - new value
|
||||
*/
|
||||
public void savePlayer(TabPlayer sender, TabPlayer player, String type, String value){
|
||||
public void savePlayer(TabPlayer sender, TabPlayer player, String type, String value, String server, String world){
|
||||
if (value.length() > 0){
|
||||
sendMessage(sender, getMessages().getPlayerValueAssigned(type, value, player.getName() + "(" + player.getUniqueId().toString() + ")"));
|
||||
} else {
|
||||
sendMessage(sender, getMessages().getPlayerValueRemoved(type, player.getName() + "(" + player.getUniqueId().toString() + ")"));
|
||||
}
|
||||
String[] property = TAB.getInstance().getConfiguration().getUsers().getProperty(player.getUniqueId().toString(), type, null, null);
|
||||
String[] property = TAB.getInstance().getConfiguration().getUsers().getProperty(player.getUniqueId().toString(), type, server, world);
|
||||
if (property.length > 0 && String.valueOf(value.length() == 0 ? null : value).equals(String.valueOf(property[0]))) return;
|
||||
TAB.getInstance().getConfiguration().getUsers().setProperty(player.getUniqueId().toString(), type, null, null, value.length() == 0 ? null : value);
|
||||
TAB.getInstance().getConfiguration().getUsers().setProperty(player.getUniqueId().toString(), type, server, world, value.length() == 0 ? null : value);
|
||||
player.forceRefresh();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,20 +42,18 @@ public class ScoreboardCommand extends SubCommand {
|
||||
TabPlayer p = getTarget(sender, args);
|
||||
if (scoreboard.getOtherPluginScoreboards().containsKey(p)) return; //not overriding other plugins
|
||||
boolean silent = args.length >= 3 && args[2].equals("-s");
|
||||
if (args.length >= 1) {
|
||||
switch(args[0]) {
|
||||
case "on":
|
||||
scoreboard.setScoreboardVisible(p, true, !silent);
|
||||
break;
|
||||
case "off":
|
||||
scoreboard.setScoreboardVisible(p, false, !silent);
|
||||
break;
|
||||
case "toggle":
|
||||
scoreboard.toggleScoreboard(p, !silent);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch(args[0]) {
|
||||
case "on":
|
||||
scoreboard.setScoreboardVisible(p, true, !silent);
|
||||
break;
|
||||
case "off":
|
||||
scoreboard.setScoreboardVisible(p, false, !silent);
|
||||
break;
|
||||
case "toggle":
|
||||
scoreboard.toggleScoreboard(p, !silent);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +72,10 @@ public class ScoreboardCommand extends SubCommand {
|
||||
}
|
||||
|
||||
private void show(TabPlayer sender, String[] args) {
|
||||
if (args.length < 2) {
|
||||
sendMessage(sender, getMessages().getScoreboardShowUsage());
|
||||
return;
|
||||
}
|
||||
ScoreboardManagerImpl scoreboard = getScoreboardManager();
|
||||
Scoreboard sb = scoreboard.getRegisteredScoreboards().get(args[1]);
|
||||
if (sb == null) {
|
||||
@@ -88,7 +90,7 @@ public class ScoreboardCommand extends SubCommand {
|
||||
}
|
||||
target = sender;
|
||||
} else {
|
||||
if (!hasPermission(sender,TabConstants.Permission.COMMAND_SCOREBOARD_SHOW)) {
|
||||
if (!hasPermission(sender,TabConstants.Permission.COMMAND_SCOREBOARD_SHOW_OTHER)) {
|
||||
sendMessage(sender, getMessages().getNoPermission());
|
||||
return;
|
||||
}
|
||||
@@ -114,7 +116,7 @@ public class ScoreboardCommand extends SubCommand {
|
||||
}
|
||||
|
||||
private ScoreboardManagerImpl getScoreboardManager() {
|
||||
return (ScoreboardManagerImpl) TAB.getInstance().getFeatureManager().getFeature("scoreboard");
|
||||
return (ScoreboardManagerImpl) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SCOREBOARD);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -151,19 +151,6 @@ public abstract class SubCommand {
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string array into a single string with "" and '' support for spaces
|
||||
* @param args - array of arguments
|
||||
* @return argument from array
|
||||
*/
|
||||
public String buildArgument(String[] args) {
|
||||
String value = String.join(" ", args);
|
||||
if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
|
||||
value = value.substring(1, value.length()-1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public MessageFile getMessages() {
|
||||
return TAB.getInstance().getConfiguration().getMessages();
|
||||
|
||||
@@ -82,26 +82,10 @@ public class TabCommand extends SubCommand {
|
||||
} else {
|
||||
tab.getPlatform().sendConsoleMessage("&3TAB v" + TAB.PLUGIN_VERSION, true);
|
||||
}
|
||||
String command = !tab.getPlatform().isProxy() ? "/tab" : "/btab";
|
||||
String prefix = " &8>> &3&l";
|
||||
sendMessage(sender, "&m ");
|
||||
sendMessage(sender, prefix + command + " reload");
|
||||
sendMessage(sender, " - &7Reloads plugin and config");
|
||||
sendMessage(sender, prefix + command + " &9group&3/&9player &3<name> &9<property> &3<value...>");
|
||||
sendMessage(sender, " - &7Do &8/tab group/player &7to show properties");
|
||||
sendMessage(sender, prefix + command + " ntpreview");
|
||||
sendMessage(sender, " - &7Shows your nametag for yourself, for testing purposes");
|
||||
sendMessage(sender, prefix + command + " announce bar &3<name> &9<seconds>");
|
||||
sendMessage(sender, " - &7Temporarily displays bossbar to all players");
|
||||
sendMessage(sender, prefix + command + " parse <player> <placeholder> ");
|
||||
sendMessage(sender, " - &7Test if a placeholder works");
|
||||
sendMessage(sender, prefix + command + " debug [player]");
|
||||
sendMessage(sender, " - &7displays debug information about player");
|
||||
sendMessage(sender, prefix + command + " cpu");
|
||||
sendMessage(sender, " - &7shows CPU usage of the plugin");
|
||||
sendMessage(sender, prefix + command + " group/player <name> remove");
|
||||
sendMessage(sender, " - &7Clears all data about player/group");
|
||||
sendMessage(sender, "&m ");
|
||||
for (String message : getMessages().getHelpMenu()) {
|
||||
if (tab.getPlatform().isProxy()) message = message.replace("/tab", "/btab");
|
||||
sendMessage(sender, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import me.neznamy.tab.api.bossbar.BossBarManager;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.command.SubCommand;
|
||||
import me.neznamy.tab.shared.features.bossbar.BossBarLine;
|
||||
|
||||
/**
|
||||
* Handler for "/tab announce bar" subcommand
|
||||
@@ -25,7 +26,7 @@ public class AnnounceBarCommand extends SubCommand {
|
||||
|
||||
@Override
|
||||
public void execute(TabPlayer sender, String[] args) {
|
||||
BossBarManager feature = (BossBarManager) TAB.getInstance().getFeatureManager().getFeature("bossbar");
|
||||
BossBarManager feature = (BossBarManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.BOSS_BAR);
|
||||
if (feature == null) {
|
||||
sendMessage(sender, getMessages().getBossBarNotEnabled());
|
||||
return;
|
||||
@@ -47,16 +48,21 @@ public class AnnounceBarCommand extends SubCommand {
|
||||
sendMessage(sender, getMessages().getBossBarNotFound(barName));
|
||||
return;
|
||||
}
|
||||
if (!((BossBarLine)bar).isAnnouncementOnly()) {
|
||||
sendMessage(sender, getMessages().getBossBarNotMarkedAsAnnouncement());
|
||||
return;
|
||||
}
|
||||
if (feature.getAnnouncedBossBars().contains(bar)) {
|
||||
sendMessage(sender, getMessages().getBossBarAlreadyAnnounced());
|
||||
return;
|
||||
}
|
||||
feature.announceBossBar(bar.getName(), duration);
|
||||
sendMessage(sender, getMessages().getBossBarAnnouncementSuccess(bar.getName(), duration));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> complete(TabPlayer sender, String[] arguments) {
|
||||
BossBarManager b = (BossBarManager) TAB.getInstance().getFeatureManager().getFeature("bossbar");
|
||||
BossBarManager b = (BossBarManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.BOSS_BAR);
|
||||
if (b == null) return new ArrayList<>();
|
||||
List<String> suggestions = new ArrayList<>();
|
||||
if (arguments.length == 1) {
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@ public class AnnounceScoreboardCommand extends SubCommand {
|
||||
|
||||
@Override
|
||||
public void execute(TabPlayer sender, String[] args) {
|
||||
ScoreboardManager feature = (ScoreboardManager) TAB.getInstance().getFeatureManager().getFeature("scoreboard");
|
||||
ScoreboardManager feature = (ScoreboardManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SCOREBOARD);
|
||||
if (feature == null) {
|
||||
sendMessage(sender, getMessages().getScoreboardFeatureNotEnabled());
|
||||
return;
|
||||
@@ -52,7 +52,7 @@ public class AnnounceScoreboardCommand extends SubCommand {
|
||||
|
||||
@Override
|
||||
public List<String> complete(TabPlayer sender, String[] arguments) {
|
||||
ScoreboardManager s = (ScoreboardManager) TAB.getInstance().getFeatureManager().getFeature("scoreboard");
|
||||
ScoreboardManager s = (ScoreboardManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SCOREBOARD);
|
||||
if (s == null) return new ArrayList<>();
|
||||
List<String> suggestions = new ArrayList<>();
|
||||
if (arguments.length == 1) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import me.neznamy.tab.api.bossbar.BossBarManager;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.command.SubCommand;
|
||||
import me.neznamy.tab.shared.features.bossbar.BossBarLine;
|
||||
|
||||
/**
|
||||
* Handler for "/tab announce bar" subcommand
|
||||
@@ -25,7 +26,7 @@ public class SendBarCommand extends SubCommand {
|
||||
|
||||
@Override
|
||||
public void execute(TabPlayer sender, String[] args) {
|
||||
BossBarManager feature = (BossBarManager) TAB.getInstance().getFeatureManager().getFeature("bossbar");
|
||||
BossBarManager feature = (BossBarManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.BOSS_BAR);
|
||||
if (feature == null) {
|
||||
sendMessage(sender, getMessages().getBossBarNotEnabled());
|
||||
return;
|
||||
@@ -52,12 +53,17 @@ public class SendBarCommand extends SubCommand {
|
||||
sendMessage(sender, getMessages().getBossBarNotFound(barName));
|
||||
return;
|
||||
}
|
||||
if (!((BossBarLine)bar).isAnnouncementOnly()) {
|
||||
sendMessage(sender, getMessages().getBossBarNotMarkedAsAnnouncement());
|
||||
return;
|
||||
}
|
||||
feature.sendBossBarTemporarily(target, bar.getName(), duration);
|
||||
sendMessage(sender, getMessages().getBossBarSendSuccess(target.getName(), bar.getName(), duration));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> complete(TabPlayer sender, String[] arguments) {
|
||||
BossBarManager b = (BossBarManager) TAB.getInstance().getFeatureManager().getFeature("bossbar");
|
||||
BossBarManager b = (BossBarManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.BOSS_BAR);
|
||||
if (b == null) return new ArrayList<>();
|
||||
if (arguments.length == 1) return getOnlinePlayers(arguments[0]);
|
||||
if (arguments.length == 2) return getStartingArgument(b.getRegisteredBossBars().keySet(), arguments[1]);
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
package me.neznamy.tab.shared.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
|
||||
import me.neznamy.tab.api.PropertyConfiguration;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.api.config.ConfigurationFile;
|
||||
import me.neznamy.tab.api.config.YamlConfigurationFile;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.config.file.YamlPropertyConfigurationFile;
|
||||
import me.neznamy.tab.shared.config.mysql.MySQLGroupConfiguration;
|
||||
import me.neznamy.tab.shared.config.mysql.MySQLUserConfiguration;
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Core of loading configuration files
|
||||
@@ -28,10 +21,11 @@ public class Configs {
|
||||
|
||||
private final TAB tab;
|
||||
|
||||
private final Converter converter = new Converter();
|
||||
|
||||
//config.yml file
|
||||
private ConfigurationFile config;
|
||||
|
||||
private String[] removeStrings;
|
||||
private boolean bukkitPermissions;
|
||||
|
||||
//hidden config options
|
||||
@@ -59,9 +53,6 @@ public class Configs {
|
||||
private PropertyConfiguration userFile;
|
||||
|
||||
private MySQL mysql;
|
||||
|
||||
private final List<String> disabledWorld = Collections.singletonList("disabledworld");
|
||||
private final List<String> disabledServer = Collections.singletonList("disabledServer");
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameter
|
||||
@@ -82,12 +73,7 @@ public class Configs {
|
||||
ClassLoader loader = Configs.class.getClassLoader();
|
||||
loadConfig();
|
||||
animation = new YamlConfigurationFile(loader.getResourceAsStream("animations.yml"), new File(tab.getPlatform().getDataFolder(), "animations.yml"));
|
||||
Map<String, Object> values = animation.getValues();
|
||||
if (values.size() == 1 && values.containsKey("animations")) {
|
||||
animation.setValues(animation.getConfigurationSection("animations"));
|
||||
animation.save();
|
||||
TAB.getInstance().print('2', "Converted animations.yml to new format.");
|
||||
}
|
||||
converter.convertAnimationFile(animation);
|
||||
messages = new MessageFile();
|
||||
layout = new YamlConfigurationFile(loader.getResourceAsStream("layout.yml"), new File(tab.getPlatform().getDataFolder(), "layout.yml"));
|
||||
reloadFailed = messages.getReloadFailBrokenFile();
|
||||
@@ -102,19 +88,15 @@ public class Configs {
|
||||
*/
|
||||
public void loadConfig() throws YAMLException, IOException {
|
||||
config = new YamlConfigurationFile(Configs.class.getClassLoader().getResourceAsStream(tab.getPlatform().getConfigName()), new File(tab.getPlatform().getDataFolder(), "config.yml"));
|
||||
if (!config.hasConfigOption("mysql"))
|
||||
convertToV3();
|
||||
List<String> list = config.getStringList("placeholders.remove-strings", Arrays.asList("[] ", "< > "));
|
||||
removeStrings = new String[list.size()];
|
||||
for (int i=0; i<list.size(); i++) {
|
||||
removeStrings[i] = EnumChatFormat.color(list.get(i));
|
||||
}
|
||||
converter.convertToV3(config);
|
||||
converter.removeOldOptions(config);
|
||||
tab.setDebugMode(getConfig().getBoolean("debug", false));
|
||||
if (tab.getPlatform().isProxy()) {
|
||||
bukkitPermissions = getConfig().getBoolean("use-bukkit-permissions-manager", false);
|
||||
} else {
|
||||
unregisterBeforeRegister = (boolean) getSecretOption("unregister-before-register", true);
|
||||
armorStandsAlwaysVisible = (boolean) getSecretOption("scoreboard-teams.unlimited-nametag-mode.always-visible", false);
|
||||
}
|
||||
unregisterBeforeRegister = (boolean) getSecretOption("unregister-before-register", true);
|
||||
armorStandsAlwaysVisible = (boolean) getSecretOption("unlimited-nametag-prefix-suffix-mode.always-visible", false);
|
||||
removeGhostPlayers = (boolean) getSecretOption("remove-ghost-players", false);
|
||||
pipelineInjection = (boolean) getSecretOption("pipeline-injection", true) && tab.getServerVersion().getMinorVersion() >= 8;
|
||||
if (config.getBoolean("mysql.enabled", false)) {
|
||||
@@ -144,10 +126,6 @@ public class Configs {
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
public String[] getRemoveStrings() {
|
||||
return removeStrings;
|
||||
}
|
||||
|
||||
public boolean isUnregisterBeforeRegister() {
|
||||
return unregisterBeforeRegister;
|
||||
}
|
||||
@@ -227,260 +205,4 @@ public class Configs {
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
public void convertToV3() throws YAMLException, IOException {
|
||||
config.setValues(new HashMap<>());
|
||||
Map<String, ConfigurationFile> yamls = new HashMap<>();
|
||||
File folder = tab.getPlatform().getDataFolder();
|
||||
String path = folder.getPath();
|
||||
File premiumcfg = new File(tab.getPlatform().getDataFolder(), "premiumconfig.yml");
|
||||
if (!premiumcfg.exists()) {
|
||||
Files.copy(Configs.class.getClassLoader().getResourceAsStream("premiumconfig.yml"), premiumcfg.toPath());
|
||||
}
|
||||
for (File file : folder.listFiles()) if (!checkFiles(file,yamls)) return;
|
||||
|
||||
Files.createFile(Paths.get(path+File.separator+"config.yml"));
|
||||
if (!Files.exists(Paths.get(path+File.separator+"groups.yml")))
|
||||
Files.createFile(Paths.get(path+File.separator+"groups.yml"));
|
||||
if (!Files.exists(Paths.get(path+File.separator+"users.yml")))
|
||||
Files.createFile(Paths.get(path+File.separator+"users.yml"));
|
||||
yamls.put("finalConfig", new YamlConfigurationFile(null, new File(path+File.separator+"config.yml")));
|
||||
yamls.put("groups.yml", new YamlConfigurationFile(null, new File(path+File.separator+"groups.yml")));
|
||||
yamls.put("users.yml", new YamlConfigurationFile(null, new File(path+File.separator+"users.yml")));
|
||||
config = yamls.get("finalConfig");
|
||||
|
||||
createConfigYml(yamls);
|
||||
}
|
||||
|
||||
public boolean checkFiles(File file, Map<String,ConfigurationFile> yamls) {
|
||||
if (!file.getName().equals("config.yml") && !file.getName().equals("premiumconfig.yml") && !file.getName().equals("bossbar.yml") && !file.getName().equals("translation.yml"))
|
||||
return true;
|
||||
|
||||
try {
|
||||
File oldFolder = new File(file.getParent()+File.separator+"old_configs");
|
||||
if (!oldFolder.exists()) oldFolder.mkdir();
|
||||
|
||||
Path oldConfig = Paths.get(file.getParent()+File.separator+"old_configs"+File.separator+file.getName());
|
||||
Files.copy(file.toPath(), oldConfig, StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
yamls.put(file.getName(), new YamlConfigurationFile(null,file));
|
||||
|
||||
Files.delete(file.toPath());
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void createConfigYml(Map<String, ConfigurationFile> yamls) throws YAMLException, IOException {
|
||||
tab.sendConsoleMessage("&e[TAB] --------------------------------------------------------------",true);
|
||||
tab.sendConsoleMessage("&e[TAB] Performing configuration conversion from 2.9.2 to 3.0.0",true);
|
||||
tab.sendConsoleMessage("&e[TAB] Please note that this may not be 100% accurate",true);
|
||||
tab.sendConsoleMessage("&e[TAB] Review your configuration and verify everything is as you want it to be",true);
|
||||
tab.sendConsoleMessage("&e[TAB] --------------------------------------------------------------",true);
|
||||
String worldOrServer = tab.getPlatform().isProxy() ? "server" : "world";
|
||||
boolean isProxy = "server".equals(worldOrServer);
|
||||
|
||||
ConfigurationFile premium = yamls.get("premiumconfig.yml");
|
||||
ConfigurationFile bossbar = yamls.get("bossbar.yml");
|
||||
ConfigurationFile config = yamls.get("config.yml");
|
||||
ConfigurationFile finalCfg = yamls.get("finalConfig");
|
||||
|
||||
finalCfg.set("scoreboard-teams.enabled",config.getBoolean("change-nametag-prefix-suffix",true));
|
||||
finalCfg.set("scoreboard-teams.invisible-nametags",config.getBoolean("invisible-nametags",false));
|
||||
finalCfg.set("scoreboard-teams.anti-override",config.getBoolean("anti-override.scoreboard-teams",true));
|
||||
finalCfg.set("scoreboard-teams.enable-collision",config.getBoolean("enable-collision",true));
|
||||
|
||||
List<String> sortingtypes = new ArrayList<>();
|
||||
String sortingtype = premium.getString("sorting-type");
|
||||
if (sortingtype == null)
|
||||
sortingtypes = Arrays.asList("GROUPS:owner,admin,mod,helper,builder,vip,default","PLACEHOLDER_A_TO_Z:%player%");
|
||||
else {
|
||||
for (String type : sortingtype.split("_THEN_")) {
|
||||
if (type.equalsIgnoreCase("GROUPS") || type.equalsIgnoreCase("GROUP_PERMISSIONS")) {
|
||||
List<String> sortinglist = config.getStringList("group-sorting-priority-list", Arrays.asList("owner", "admin", "mod", "helper", "builder", "premium", "player", "default"));
|
||||
|
||||
StringBuilder groups = new StringBuilder(("GROUP_PERMISSIONS".equals(type) ? "PERMISSIONS" : "GROUPS") + ":");
|
||||
for (String group : sortinglist) {
|
||||
groups.append(("GROUP_PERMISSIONS".equals(type) ? "tab.sort." : ""));
|
||||
groups.append(group.replace(" ", "|"));
|
||||
if (sortinglist.indexOf(group) != sortinglist.size() - 1)
|
||||
groups.append(",");
|
||||
}
|
||||
sortingtypes.add(groups.toString());
|
||||
}
|
||||
else if (type.equalsIgnoreCase("PLACEHOLDER")) {
|
||||
List<String> sortinglist = config.getStringList("placeholder-order", Arrays.asList("value1", "value2"));
|
||||
String placeholder = premium.getString("sorting-placeholder", "%some_level_maybe?%");
|
||||
|
||||
StringBuilder groups = new StringBuilder("PLACEHOLDER:"+placeholder+":");
|
||||
for (String group : sortinglist) {
|
||||
groups.append(group);
|
||||
if (sortinglist.indexOf(group) != sortinglist.size() - 1)
|
||||
groups.append(",");
|
||||
}
|
||||
sortingtypes.add(groups.toString());
|
||||
}
|
||||
else {
|
||||
String placeholder = premium.getString("sorting-placeholder", "%some_level_maybe?%");
|
||||
if (!placeholder.equalsIgnoreCase("%some_level_maybe?%"))
|
||||
sortingtypes.add(type+":"+placeholder);
|
||||
}
|
||||
}
|
||||
}
|
||||
sortingtypes.add("PLACEHOLDER_A_TO_Z:%player%");
|
||||
finalCfg.set("scoreboard-teams.sorting-types",sortingtypes);
|
||||
|
||||
finalCfg.set("scoreboard-teams.case-sensitive-sorting",premium.getBoolean("case-sensitive-sorting",true));
|
||||
finalCfg.set("scoreboard-teams.disable-in-worlds",config.getStringList("disable-features-in-worlds.nametag",disabledWorld));
|
||||
if (isProxy)
|
||||
finalCfg.set("scoreboard-teams.disable-in-servers",config.getStringList("disable-features-in-servers.nametag",disabledServer));
|
||||
finalCfg.set("scoreboard-teams.unlimited-nametag-mode.enabled",config.getBoolean("unlimited-nametag-prefix-suffix-mode.enabled",false));
|
||||
finalCfg.set("scoreboard-teams.unlimited-nametag-mode.use-marker-tag-for-1-8-x-clients",config.getBoolean("unlimited-nametag-prefix-suffix-mode.use-marker-tag-for-1-8-x-clients",false));
|
||||
finalCfg.set("scoreboard-teams.unlimited-nametag-mode.disable-on-boats",config.getBoolean("unlimited-nametag-prefix-suffix-mode.disable-on-boats",true));
|
||||
finalCfg.set("scoreboard-teams.unlimited-nametag-mode.space-between-lines",config.getBoolean("unlimited-nametag-prefix-suffix-mode.space-between-lines",true));
|
||||
finalCfg.set("scoreboard-teams.unlimited-nametag-mode.disable-in-worlds",config.getStringList("disable-features-in-worlds.unlimited-nametags",disabledWorld));
|
||||
finalCfg.set("scoreboard-teams.unlimited-nametag-mode.dynamic-lines",premium.getStringList("unlimited-nametag-mode-dynamic-lines",Arrays.asList("abovename","nametag","belowname","another")));
|
||||
finalCfg.set("scoreboard-teams.unlimited-nametag-mode.static-lines",premium.getConfigurationSection("unlimited-nametag-mode-static-lines"));
|
||||
|
||||
finalCfg.set("tablist-name-formatting.enabled", config.getBoolean("change-tablist-prefix-suffix",true));
|
||||
finalCfg.set("tablist-name-formatting.align-tabsuffix-on-the-right", premium.getBoolean("align-tabsuffix-on-the-right",false));
|
||||
finalCfg.set("tablist-name-formatting.character-width-overrides", premium.getConfigurationSection("character-width-overrides"));
|
||||
finalCfg.set("tablist-name-formatting.anti-override", config.getBoolean("anti-override.tablist-names",true));
|
||||
finalCfg.set("tablist-name-formatting.disable-in-worlds", config.getStringList("disable-features-in-worlds.tablist-names",disabledWorld));
|
||||
if (isProxy)
|
||||
finalCfg.set("tablist-name-formatting.disable-in-servers",config.getStringList("disable-features-in-servers.tablist-names",disabledServer));
|
||||
|
||||
finalCfg.set("header-footer.enabled", config.getBoolean("enable-header-footer",true));
|
||||
finalCfg.set("header-footer.disable-in-worlds", config.getStringList("disable-features-in-worlds.header-footer",disabledWorld));
|
||||
if (isProxy)
|
||||
finalCfg.set("header-footer.disable-in-servers",premium.getStringList("disable-features-in-servers.header-footer",disabledServer));
|
||||
finalCfg.set("header-footer.header", config.getStringList("header"));
|
||||
finalCfg.set("header-footer.footer", config.getStringList("footer"));
|
||||
|
||||
finalCfg.set("yellow-number-in-tablist.enabled", !config.getString("yellow-number-in-tablist","%ping%").equals(""));
|
||||
finalCfg.set("yellow-number-in-tablist.value", config.getString("yellow-number-in-tablist","%ping%"));
|
||||
finalCfg.set("yellow-number-in-tablist.disable-in-worlds", config.getStringList("disable-features-in-worlds.yellow-number",disabledWorld));
|
||||
if (isProxy)
|
||||
finalCfg.set("yellow-number.disable-in-servers",config.getStringList("disable-features-in-servers.yellow-number",disabledServer));
|
||||
|
||||
finalCfg.set("belowname-objective", config.getConfigurationSection("classic-vanilla-belowname"));
|
||||
finalCfg.set("belowname-objective.disable-in-worlds", config.getStringList("disable-features-in-worlds.belowname",disabledWorld));
|
||||
if (isProxy)
|
||||
finalCfg.set("belowname-objective.disable-in-servers",config.getStringList("disable-features-in-servers.belowname",disabledServer));
|
||||
|
||||
finalCfg.set("prevent-spectator-effect.enabled", config.getBoolean("do-not-move-spectators",false));
|
||||
|
||||
finalCfg.set("bossbar.enabled", bossbar.getBoolean("bossbar-enabled",false));
|
||||
finalCfg.set("bossbar.toggle-command", bossbar.getString("bossbar-toggle-command","/bossbar"));
|
||||
finalCfg.set("bossbar.remember-toggle-choice", bossbar.getBoolean("remember-toggle-choice",false));
|
||||
finalCfg.set("bossbar.hidden-by-default", bossbar.getBoolean("hidden-by-default",false));
|
||||
finalCfg.set("bossbar.default-bars", bossbar.getStringList("default-bars",Arrays.asList("ServerInfo","tpsbar")));
|
||||
finalCfg.set("bossbar.disable-in-worlds", bossbar.getObject("disable-features-in-worlds.bossbar"));
|
||||
if (isProxy)
|
||||
finalCfg.set("bossbar.disable-in-servers",config.getStringList("disable-features-in-servers.bossbar",disabledServer));
|
||||
|
||||
Map<String,Map<String,String>> bossbars = bossbar.getConfigurationSection("bars");
|
||||
Map<String,List<String>> perworldBossbars = bossbar.getConfigurationSection("per-world");
|
||||
if (perworldBossbars != null) {
|
||||
for (Entry<String, List<String>> entry : perworldBossbars.entrySet()) {
|
||||
String world = entry.getKey();
|
||||
for (String bar : entry.getValue()) {
|
||||
if (!bossbars.containsKey(bar)) continue;
|
||||
if (bossbars.get(bar).containsKey("display-condition"))
|
||||
bossbars.get(bar).put("display-condition", bossbars.get(bar).get("display-condition")+";%"+worldOrServer+"%="+world);
|
||||
else bossbars.get(bar).put("display-condition", "%"+worldOrServer+"%="+world);
|
||||
}
|
||||
}
|
||||
}
|
||||
finalCfg.set("bossbar.bars", bossbars);
|
||||
|
||||
if (!isProxy)
|
||||
finalCfg.set("per-world-playerlist", config.getConfigurationSection("per-world-playerlist"));
|
||||
|
||||
finalCfg.set("scoreboard", premium.getObject("scoreboard"));
|
||||
finalCfg.set("scoreboard.permission-required-to-toggle", null);
|
||||
Map<String,Map<String,Object>> scoreboards = premium.getConfigurationSection("scoreboards");
|
||||
Map<String,String> perworldScoreboards = premium.getConfigurationSection("scoreboard.per-world");
|
||||
finalCfg.set("scoreboard.default-scoreboard", null);
|
||||
finalCfg.set("scoreboard.per-world", null);
|
||||
if (perworldScoreboards != null)
|
||||
perworldScoreboards.forEach((world,sb)->{
|
||||
if (!scoreboards.containsKey(sb)) return;
|
||||
if (scoreboards.get(sb).containsKey("display-condition"))
|
||||
scoreboards.get(sb).put("display-condition", scoreboards.get(sb).get("display-condition")+";%"+worldOrServer+"%="+world);
|
||||
else scoreboards.get(sb).put("display-condition", "%"+worldOrServer+"%="+world);
|
||||
});
|
||||
finalCfg.set("scoreboard.scoreboards", scoreboards);
|
||||
|
||||
finalCfg.set("ping-spoof", config.getConfigurationSection("ping-spoof"));
|
||||
|
||||
finalCfg.set("fix-pet-names.enabled", config.getBoolean("fix-pet-names",false));
|
||||
|
||||
Map<String,Object> placeholders = config.getConfigurationSection("placeholders");
|
||||
String afkyes = placeholders.remove("afk-yes")+"";
|
||||
String afkno = placeholders.remove("afk-no")+"";
|
||||
finalCfg.set("placeholders", placeholders);
|
||||
|
||||
finalCfg.set("placeholder-output-replacements", premium.getConfigurationSection("placeholder-output-replacements"));
|
||||
finalCfg.set("placeholder-output-replacements.%afk%.true", afkyes);
|
||||
finalCfg.set("placeholder-output-replacements.%afk%.false", afkno);
|
||||
|
||||
finalCfg.set("conditions",premium.getConfigurationSection("conditions"));
|
||||
|
||||
finalCfg.set("placeholderapi-refresh-intervals", config.getConfigurationSection("placeholderapi-refresh-intervals"));
|
||||
finalCfg.set("assign-groups-by-permissions", config.getBoolean("assign-groups-by-permissions",false));
|
||||
finalCfg.set("primary-group-finding-list", config.getStringList("primary-group-finding-list",Arrays.asList("Owner","Admin","Mod","Helper","default")));
|
||||
|
||||
finalCfg.set("debug", config.getBoolean("debug", false));
|
||||
|
||||
finalCfg.set("mysql.enabled", false);
|
||||
finalCfg.set("mysql.host", "127.0.0.1");
|
||||
finalCfg.set("mysql.port", 3306);
|
||||
finalCfg.set("mysql.database", "tab");
|
||||
finalCfg.set("mysql.username", "user");
|
||||
finalCfg.set("mysql.password", "password");
|
||||
|
||||
ConfigurationFile groups = yamls.get("groups.yml");
|
||||
ConfigurationFile users = yamls.get("users.yml");
|
||||
groups.setValues(config.getConfigurationSection("Groups"));
|
||||
users.setValues(config.getConfigurationSection("Users"));
|
||||
|
||||
Map<String,Map<String,Object>> perworldsettings = config.getConfigurationSection("per-"+worldOrServer+"-settings");
|
||||
Map<String,Object> groupMap = new HashMap<>();
|
||||
Map<String,Object> userMap = new HashMap<>();
|
||||
Map<String,Object> headerFooterMap = new HashMap<>();
|
||||
if (perworldsettings != null) {
|
||||
Map<String,Map<String,Object>> worldMap = new HashMap<>(perworldsettings);
|
||||
for (Entry<String, Map<String, Object>> entry : worldMap.entrySet()) {
|
||||
String world = entry.getKey();
|
||||
Map<String, Object> map = new HashMap<>(entry.getValue());
|
||||
Map<String,Object> headerFooter = new HashMap<>();
|
||||
for (Entry<String, Object> entry2 : map.entrySet()) {
|
||||
String value = entry2.getKey();
|
||||
if (value.equalsIgnoreCase("Groups"))
|
||||
groupMap.put(world,entry2.getValue());
|
||||
else if (value.equalsIgnoreCase("Users"))
|
||||
userMap.put(world,entry2.getValue());
|
||||
else if (value.equalsIgnoreCase("header") || value.equalsIgnoreCase("footer"))
|
||||
headerFooter.put(value,entry2.getValue());
|
||||
}
|
||||
headerFooterMap.put(world,headerFooter);
|
||||
if (entry.getValue().isEmpty())
|
||||
perworldsettings.remove(world);
|
||||
}
|
||||
}
|
||||
groups.set("per-"+worldOrServer, groupMap);
|
||||
groups.set("_DEFAULT_",groups.getConfigurationSection("_OTHER_"));
|
||||
groups.set("_OTHER_",null);
|
||||
users.set("per-"+worldOrServer, userMap);
|
||||
for (Object world : groups.getConfigurationSection("per-"+worldOrServer).keySet()) {
|
||||
String gPath = "per-"+worldOrServer+"."+world;
|
||||
if (!groups.hasConfigOption(gPath+"._OTHER_")) continue;
|
||||
groups.set(gPath+"._DEFAULT_",groups.getObject(gPath+"._OTHER_"));
|
||||
groups.set(gPath+"._OTHER_",null);
|
||||
}
|
||||
finalCfg.set("header-footer.per-"+worldOrServer, headerFooterMap);
|
||||
Files.delete(premium.getFile().toPath());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
package me.neznamy.tab.shared.config;
|
||||
|
||||
import me.neznamy.tab.api.config.ConfigurationFile;
|
||||
import me.neznamy.tab.api.config.YamlConfigurationFile;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Configuration converter that converts configuration files from practically
|
||||
* any previous version of TAB to the current format.
|
||||
*/
|
||||
public class Converter {
|
||||
|
||||
/**
|
||||
* Creates new instance of this class
|
||||
*/
|
||||
public Converter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts animation file from old format with everything under "animations" key
|
||||
* to new format which does not use the redundant key anymore.
|
||||
* <p>
|
||||
* The method contains a check if the conversion is necessary, so it is always safe
|
||||
* to call this method, even if conversion is not needed.
|
||||
* <p>
|
||||
* This change was made from 2.8.10 -> 2.9.0
|
||||
* @param animations
|
||||
* animation file to convert
|
||||
*/
|
||||
public void convertAnimationFile(ConfigurationFile animations) {
|
||||
if (animations.getValues().size() == 1 && animations.getValues().containsKey("animations")) {
|
||||
animations.setValues(animations.getConfigurationSection("animations"));
|
||||
animations.save();
|
||||
TAB.getInstance().getPlatform().sendConsoleMessage("&2[TAB] Converted animations.yml to new format.", true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all configuration files from 2.9.2 into new 3.0.0 format and saves a copy
|
||||
* of old files into a new "old_configs" folder.
|
||||
* @param currentConfig
|
||||
* currently detected config.yml file
|
||||
* @throws IOException
|
||||
* if an I/O operation with the files fails
|
||||
*/
|
||||
public void convertToV3(ConfigurationFile currentConfig) throws IOException {
|
||||
if (currentConfig.hasConfigOption("mysql")) return;
|
||||
TAB.getInstance().sendConsoleMessage("&e[TAB] --------------------------------------------------------------",true);
|
||||
TAB.getInstance().sendConsoleMessage("&e[TAB] Performing configuration conversion from 2.9.2 to 3.0.0",true);
|
||||
TAB.getInstance().sendConsoleMessage("&e[TAB] Please note that this may not be 100% accurate",true);
|
||||
TAB.getInstance().sendConsoleMessage("&e[TAB] Review your configuration and verify everything is as you want it to be",true);
|
||||
TAB.getInstance().sendConsoleMessage("&e[TAB] --------------------------------------------------------------",true);
|
||||
|
||||
File folder = TAB.getInstance().getPlatform().getDataFolder();
|
||||
moveOldFiles();
|
||||
Files.createFile(new File(folder, "groups.yml").toPath());
|
||||
Files.createFile(new File(folder, "users.yml").toPath());
|
||||
Files.createFile(new File(folder, "config.yml").toPath());
|
||||
ConfigurationFile groups = new YamlConfigurationFile(null, new File(folder, "groups.yml"));
|
||||
ConfigurationFile users = new YamlConfigurationFile(null, new File(folder, "users.yml"));
|
||||
File oldConfigsFolder = new File(folder, "old_configs");
|
||||
Files.copy(new File(oldConfigsFolder, "animations.yml").toPath(), new File(folder, "animations.yml").toPath());
|
||||
File premiumFile = new File(oldConfigsFolder, "premiumconfig.yml");
|
||||
ConfigurationFile premiumConfig = premiumFile.exists() ? new YamlConfigurationFile(null, premiumFile) : null;
|
||||
File bossBarFile = new File(oldConfigsFolder, "bossbar.yml");
|
||||
if (!bossBarFile.exists()) throw new IllegalStateException("Failed to convert configuration to v3: File bossbar.yml does not exist");
|
||||
ConfigurationFile bossBar = new YamlConfigurationFile(null, bossBarFile);
|
||||
ConfigurationFile oldConfig = new YamlConfigurationFile(null, new File(oldConfigsFolder, "config.yml"));
|
||||
ConfigurationFile newConfig = new YamlConfigurationFile(null, new File(folder, "config.yml"));
|
||||
|
||||
convertHeaderFooter(oldConfig, newConfig);
|
||||
convertTabListFormatting(oldConfig, newConfig, premiumConfig);
|
||||
convertTeamOptions(oldConfig, newConfig, premiumConfig);
|
||||
convertYellowNumber(oldConfig, newConfig);
|
||||
convertBelowName(oldConfig, newConfig);
|
||||
convertBossBar(bossBar, oldConfig, newConfig);
|
||||
if (premiumConfig != null) {
|
||||
convertScoreboard(newConfig, premiumConfig);
|
||||
} else {
|
||||
createDefaultScoreboard(newConfig);
|
||||
}
|
||||
convertOtherOptions(oldConfig, newConfig, premiumConfig);
|
||||
convertGroupsAndUsers(oldConfig, groups, users);
|
||||
currentConfig.setValues(newConfig.getValues());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new "old_configs" folder and moves all files in TAB's folder into it.
|
||||
* @throws IOException
|
||||
* if thrown by file move operation
|
||||
*/
|
||||
private void moveOldFiles() throws IOException {
|
||||
File folder = TAB.getInstance().getPlatform().getDataFolder();
|
||||
File oldFolder = new File(folder, "old_configs");
|
||||
if (!oldFolder.exists() && !oldFolder.mkdirs()) throw new RuntimeException("Failed to convert configuration to v3: Failed to create old_configs folder");
|
||||
File[] files = folder.listFiles();
|
||||
if (files == null) throw new IllegalStateException("Failed to convert configuration to v3: old_configs is not a folder");
|
||||
for (File file : files) {
|
||||
if (!file.isFile()) continue; //old_configs folder
|
||||
Files.move(file.toPath(), new File(folder.getPath() +
|
||||
File.separator + "old_configs" + File.separator + file.getName()).toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
||||
private void convertTeamOptions(ConfigurationFile oldConfig, ConfigurationFile newConfig, ConfigurationFile premiumConfig) {
|
||||
newConfig.set("scoreboard-teams.enabled", oldConfig.getBoolean("change-nametag-prefix-suffix", true));
|
||||
newConfig.set("scoreboard-teams.invisible-nametags", oldConfig.getBoolean("invisible-nametags", false));
|
||||
newConfig.set("scoreboard-teams.anti-override", oldConfig.getBoolean("anti-override.scoreboard-teams", true));
|
||||
newConfig.set("scoreboard-teams.enable-collision", oldConfig.getBoolean("enable-collision", true));
|
||||
newConfig.set("scoreboard-teams.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.nametag", Collections.singletonList("disabledworld")));
|
||||
if (TAB.getInstance().getPlatform().isProxy()) {
|
||||
newConfig.set("scoreboard-teams.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.nametag", Collections.singletonList("disabledserver")));
|
||||
} else {
|
||||
newConfig.set("scoreboard-teams.unlimited-nametag-mode.enabled", oldConfig.getBoolean("unlimited-nametag-prefix-suffix-mode.enabled", false));
|
||||
newConfig.set("scoreboard-teams.unlimited-nametag-mode.use-marker-tag-for-1-8-x-clients", oldConfig.getBoolean("unlimited-nametag-prefix-suffix-mode.use-marker-tag-for-1-8-x-clients", false));
|
||||
newConfig.set("scoreboard-teams.unlimited-nametag-mode.disable-on-boats", oldConfig.getBoolean("unlimited-nametag-prefix-suffix-mode.disable-on-boats", true));
|
||||
newConfig.set("scoreboard-teams.unlimited-nametag-mode.space-between-lines", oldConfig.getBoolean("unlimited-nametag-prefix-suffix-mode.space-between-lines", true));
|
||||
newConfig.set("scoreboard-teams.unlimited-nametag-mode.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.unlimited-nametags", Collections.singletonList("disabledworld")));
|
||||
}
|
||||
String sortingType;
|
||||
String sortingPlaceholder;
|
||||
List<String> placeholderOrder = new ArrayList<>();
|
||||
if (premiumConfig != null) {
|
||||
newConfig.set("scoreboard-teams.case-sensitive-sorting", premiumConfig.getBoolean("case-sensitive-sorting", true));
|
||||
newConfig.set("scoreboard-teams.unlimited-nametag-mode.dynamic-lines", premiumConfig.getStringList("unlimited-nametag-mode-dynamic-lines", Arrays.asList("abovename","nametag","belowname","another")));
|
||||
newConfig.set("scoreboard-teams.unlimited-nametag-mode.static-lines", premiumConfig.getConfigurationSection("unlimited-nametag-mode-static-lines"));
|
||||
sortingType = premiumConfig.getString("sorting-type", "GROUPS");
|
||||
sortingPlaceholder = premiumConfig.getString("sorting-placeholder", "%some_level_maybe?%");
|
||||
placeholderOrder = premiumConfig.getStringList("placeholder-order", Arrays.asList("value1", "value2"));
|
||||
} else {
|
||||
newConfig.set("scoreboard-teams.case-sensitive-sorting", true);
|
||||
newConfig.set("scoreboard-teams.unlimited-nametag-mode.dynamic-lines", Arrays.asList("abovename","nametag","belowname","another"));
|
||||
newConfig.set("scoreboard-teams.unlimited-nametag-mode.static-lines", new HashMap<String, Object>(){{put("myCustomLine", 0.66);}});
|
||||
sortingType = oldConfig.getBoolean("sort-players-by-permissions", false) ? "GROUP_PERMISSIONS" : "GROUPS";
|
||||
sortingPlaceholder = "";
|
||||
}
|
||||
|
||||
List<String> sortingTypes = new ArrayList<>();
|
||||
for (String type : sortingType.split("_THEN_")) {
|
||||
if (type.equalsIgnoreCase("GROUPS") || type.equalsIgnoreCase("GROUP_PERMISSIONS")) {
|
||||
List<String> sortingList = oldConfig.getStringList("group-sorting-priority-list", Arrays.asList("owner", "admin", "mod", "helper", "builder", "premium", "player", "default"));
|
||||
StringBuilder groups = new StringBuilder(("GROUP_PERMISSIONS".equals(type) ? "PERMISSIONS" : "GROUPS") + ":");
|
||||
for (String group : sortingList) {
|
||||
groups.append(("GROUP_PERMISSIONS".equals(type) ? "tab.sort." : ""));
|
||||
groups.append(group.replace(" ", "|"));
|
||||
if (sortingList.indexOf(group) != sortingList.size() - 1)
|
||||
groups.append(",");
|
||||
}
|
||||
sortingTypes.add(groups.toString());
|
||||
} else if (type.equalsIgnoreCase("PLACEHOLDER")) {
|
||||
sortingTypes.add("PLACEHOLDER:" + sortingPlaceholder + ":" + String.join(",", placeholderOrder));
|
||||
} else {
|
||||
sortingTypes.add(type + ":" + sortingPlaceholder);
|
||||
}
|
||||
}
|
||||
sortingTypes.add("PLACEHOLDER_A_TO_Z:%player%");
|
||||
newConfig.set("scoreboard-teams.sorting-types", sortingTypes);
|
||||
}
|
||||
|
||||
private void convertTabListFormatting(ConfigurationFile oldConfig, ConfigurationFile newConfig, ConfigurationFile premiumConfig) {
|
||||
newConfig.set("tablist-name-formatting.enabled", oldConfig.getBoolean("change-tablist-prefix-suffix", true));
|
||||
newConfig.set("tablist-name-formatting.anti-override", oldConfig.getBoolean("anti-override.tablist-names", true));
|
||||
newConfig.set("tablist-name-formatting.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.tablist-names", Collections.singletonList("disabledworld")));
|
||||
if (TAB.getInstance().getPlatform().isProxy())
|
||||
newConfig.set("tablist-name-formatting.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.tablist-names", Collections.singletonList("disabledserver")));
|
||||
if (premiumConfig != null) {
|
||||
newConfig.set("tablist-name-formatting.align-tabsuffix-on-the-right", premiumConfig.getBoolean("align-tabsuffix-on-the-right", false));
|
||||
newConfig.set("tablist-name-formatting.character-width-overrides", premiumConfig.getConfigurationSection("character-width-overrides"));
|
||||
} else {
|
||||
newConfig.set("tablist-name-formatting.align-tabsuffix-on-the-right", false);
|
||||
newConfig.set("tablist-name-formatting.character-width-overrides", new HashMap<Integer, Integer>());
|
||||
}
|
||||
}
|
||||
|
||||
private void convertYellowNumber(ConfigurationFile oldConfig, ConfigurationFile newConfig) {
|
||||
newConfig.set("yellow-number-in-tablist.enabled", !oldConfig.getString("yellow-number-in-tablist","%ping%").equals(""));
|
||||
newConfig.set("yellow-number-in-tablist.value", oldConfig.getString("yellow-number-in-tablist","%ping%"));
|
||||
newConfig.set("yellow-number-in-tablist.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.yellow-number", Collections.singletonList("disabledworld")));
|
||||
if (TAB.getInstance().getPlatform().isProxy())
|
||||
newConfig.set("yellow-number.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.yellow-number", Collections.singletonList("disabledserver")));
|
||||
}
|
||||
|
||||
private void convertBelowName(ConfigurationFile oldConfig, ConfigurationFile newConfig) {
|
||||
newConfig.set("belowname-objective", oldConfig.getConfigurationSection("classic-vanilla-belowname"));
|
||||
newConfig.set("belowname-objective.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.belowname", Collections.singletonList("disabledworld")));
|
||||
if (TAB.getInstance().getPlatform().isProxy())
|
||||
newConfig.set("belowname-objective.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.belowname", Collections.singletonList("disabledserver")));
|
||||
}
|
||||
|
||||
private void convertBossBar(ConfigurationFile bossBar, ConfigurationFile oldConfig, ConfigurationFile newConfig) {
|
||||
newConfig.set("bossbar.enabled", bossBar.getBoolean("bossbar-enabled", false));
|
||||
newConfig.set("bossbar.toggle-command", bossBar.getString("bossbar-toggle-command", "/bossbar"));
|
||||
newConfig.set("bossbar.remember-toggle-choice", bossBar.getBoolean("remember-toggle-choice", false));
|
||||
newConfig.set("bossbar.hidden-by-default", bossBar.getBoolean("hidden-by-default", false));
|
||||
newConfig.set("bossbar.disable-in-worlds", bossBar.getObject("disable-features-in-worlds.bossbar"));
|
||||
if (TAB.getInstance().getPlatform().isProxy())
|
||||
newConfig.set("bossbar.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.bossbar", Collections.singletonList("disabledserver")));
|
||||
Map<String, Map<String, Object>> bars = bossBar.getConfigurationSection("bars");
|
||||
Map<String, List<String>> perWorldBossBars = bossBar.getConfigurationSection("per-world");
|
||||
List<String> activeBossBars = new ArrayList<>(bossBar.getStringList("default-bars", new ArrayList<>()));
|
||||
String separator = TAB.getInstance().getPlatform().isProxy() ? "server" : "world";
|
||||
if (perWorldBossBars != null) {
|
||||
for (Map.Entry<String, List<String>> entry : perWorldBossBars.entrySet()) {
|
||||
for (String bar : entry.getValue()) {
|
||||
if (!bars.containsKey(bar)) continue;
|
||||
activeBossBars.add(bar);
|
||||
if (bars.get(bar).containsKey("display-condition")){
|
||||
bars.get(bar).put("display-condition", bars.get(bar).get("display-condition") + ";%" + separator + "%=" + entry.getKey());
|
||||
} else {
|
||||
bars.get(bar).put("display-condition", "%" + separator + "%=" + entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (String definedBossBar : bars.keySet()) {
|
||||
bars.get(definedBossBar).put("announcement-bar", !activeBossBars.contains(definedBossBar));
|
||||
}
|
||||
newConfig.set("bossbar.bars", bars);
|
||||
}
|
||||
|
||||
private void convertScoreboard(ConfigurationFile newConfig, ConfigurationFile premiumConfig) {
|
||||
String separator = TAB.getInstance().getPlatform().isProxy() ? "server" : "world";
|
||||
newConfig.set("scoreboard", premiumConfig.getObject("scoreboard"));
|
||||
newConfig.set("scoreboard.permission-required-to-toggle", null);
|
||||
Map<String, Map<String,Object>> scoreboards = premiumConfig.getConfigurationSection("scoreboards");
|
||||
Map<String, String> perWorldScoreboards = premiumConfig.getConfigurationSection("scoreboard.per-world");
|
||||
newConfig.set("scoreboard.default-scoreboard", null);
|
||||
newConfig.set("scoreboard.per-world", null);
|
||||
for (Map.Entry<String, String> entry : perWorldScoreboards.entrySet()) {
|
||||
String world = entry.getKey();
|
||||
String sb = entry.getValue();
|
||||
if (!scoreboards.containsKey(sb)) continue;
|
||||
Map<String, Object> scoreboard = scoreboards.get(sb);
|
||||
if (scoreboard.containsKey("display-condition")) {
|
||||
scoreboard.put("display-condition", scoreboards.get(sb).get("display-condition") + ";%" + separator + "%=" + world);
|
||||
} else {
|
||||
scoreboard.put("display-condition", "%" + separator + "%=" + world);
|
||||
//move to the top, so it's actually displayed with new priority system
|
||||
scoreboards.remove(sb);
|
||||
Map<String, Map<String, Object>> reordered = new HashMap<>();
|
||||
reordered.put(sb, scoreboard);
|
||||
reordered.putAll(scoreboards);
|
||||
scoreboards = reordered;
|
||||
}
|
||||
}
|
||||
newConfig.set("scoreboard.scoreboards", scoreboards);
|
||||
}
|
||||
|
||||
private void createDefaultScoreboard(ConfigurationFile newConfig) {
|
||||
newConfig.set("scoreboard.enabled", false);
|
||||
newConfig.set("scoreboard.toggle-command", "/sb");
|
||||
newConfig.set("scoreboard.remember-toggle-choice", false);
|
||||
newConfig.set("scoreboard.hidden-by-default", false);
|
||||
newConfig.set("scoreboard.use-numbers", false);
|
||||
newConfig.set("scoreboard.static-number", 0);
|
||||
newConfig.set("scoreboard.delay-on-join-milliseconds", 0);
|
||||
newConfig.set("scoreboard.respect-other-plugins", true);
|
||||
newConfig.set("scoreboard.disable-in-worlds", Collections.singletonList("disabledworld"));
|
||||
if (TAB.getInstance().getPlatform().isProxy()) {
|
||||
newConfig.set("scoreboard.disable-in-servers", Collections.singletonList("disabledserver"));
|
||||
}
|
||||
newConfig.set("scoreboard.scoreboards.admin.display-condition", "permission:tab.scoreboard.admin");
|
||||
newConfig.set("scoreboard.scoreboards.admin.title", "Admin scoreboard");
|
||||
newConfig.set("scoreboard.scoreboards.admin.lines", Arrays.asList("%animation:MyAnimation1%", "&6Online:", "* &eOnline&7: &f%online%&7/&4%maxplayers%",
|
||||
"* &eCurrent World&7: &f%worldonline%", "* &eStaff&7: &f%staffonline%", " ", "&6Server Info:", "* &bTPS&7: %tps%",
|
||||
"* &bUptime&7: &f%server_uptime%", "* &bMemory&7: &f%memory-used%&7/&4%memory-max%", "%animation:MyAnimation1%"));
|
||||
newConfig.set("scoreboard.scoreboards.scoreboard1.title", "Default");
|
||||
newConfig.set("scoreboard.scoreboards.scoreboard1.lines", Arrays.asList("%animation:MyAnimation1%", "&6My Stats:", "* &eKills&7: &f%statistic_player_kills%",
|
||||
"* &eDeaths&7: &f%statistic_deaths%", "* &eHealth&7: &f%health%", " ", "&6Personal Info:", "* &bRank&7: &f%group%",
|
||||
"* &bPing&7: &f%ping%&7ms", "* &bWorld&7: &f%world%", "%animation:MyAnimation1%"));
|
||||
}
|
||||
|
||||
private void convertHeaderFooter(ConfigurationFile oldConfig, ConfigurationFile newConfig) {
|
||||
newConfig.set("header-footer.enabled", oldConfig.getBoolean("enable-header-footer", true));
|
||||
newConfig.set("header-footer.header", oldConfig.getStringList("header"));
|
||||
newConfig.set("header-footer.footer", oldConfig.getStringList("footer"));
|
||||
newConfig.set("header-footer.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.header-footer", Collections.singletonList("disabledworld")));
|
||||
if (TAB.getInstance().getPlatform().isProxy())
|
||||
newConfig.set("header-footer.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.header-footer", Collections.singletonList("disabledserver")));
|
||||
|
||||
String separator = TAB.getInstance().getPlatform().isProxy() ? "server" : "world";
|
||||
Map<String, Map<String, Object>> perWorldSettings = oldConfig.getConfigurationSection("per-" + separator + "-settings");
|
||||
Map<String, Object> headerFooterMap = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, Map<String, Object>> worldEntry : new LinkedHashMap<>(perWorldSettings).entrySet()) {
|
||||
Map<String, Object> headerFooter = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, Object> propertyValueEntry : new LinkedHashMap<>(worldEntry.getValue()).entrySet()) {
|
||||
if (propertyValueEntry.getKey().equalsIgnoreCase("header") || propertyValueEntry.getKey().equalsIgnoreCase("footer"))
|
||||
headerFooter.put(propertyValueEntry.getKey(), propertyValueEntry.getValue());
|
||||
}
|
||||
headerFooterMap.put(translateWorldGroup(oldConfig, worldEntry.getKey()), headerFooter);
|
||||
}
|
||||
newConfig.set("header-footer.per-" + separator, headerFooterMap);
|
||||
}
|
||||
|
||||
private void convertOtherOptions(ConfigurationFile oldConfig, ConfigurationFile newConfig, ConfigurationFile premiumConfig) {
|
||||
newConfig.set("ping-spoof", oldConfig.getConfigurationSection("ping-spoof"));
|
||||
newConfig.set("prevent-spectator-effect.enabled", oldConfig.getBoolean("do-not-move-spectators",false));
|
||||
|
||||
Map<String,Object> placeholders = oldConfig.getConfigurationSection("placeholders");
|
||||
if (premiumConfig != null) {
|
||||
newConfig.set("placeholder-output-replacements", premiumConfig.getConfigurationSection("placeholder-output-replacements"));
|
||||
newConfig.set("conditions", premiumConfig.getConfigurationSection("conditions"));
|
||||
} else {
|
||||
newConfig.set("placeholder-output-replacements.%essentials_vanished%.yes", "&7| Vanished");
|
||||
newConfig.set("placeholder-output-replacements.%essentials_vanished%.no", "");
|
||||
newConfig.set("conditions.nick.conditions", Collections.singletonList("%player%=%essentials_nickname%"));
|
||||
newConfig.set("conditions.nick.yes", "%player%");
|
||||
newConfig.set("conditions.nick.no", "~%essentials_nickname%");
|
||||
}
|
||||
if (!TAB.getInstance().getPlatform().isProxy()) {
|
||||
newConfig.set("placeholder-output-replacements.%afk%.true", placeholders.remove("afk-yes"));
|
||||
newConfig.set("placeholder-output-replacements.%afk%.false", placeholders.remove("afk-no"));
|
||||
}
|
||||
|
||||
newConfig.set("placeholders", placeholders);
|
||||
newConfig.set("placeholderapi-refresh-intervals", oldConfig.getConfigurationSection("placeholderapi-refresh-intervals"));
|
||||
newConfig.set("assign-groups-by-permissions", oldConfig.getBoolean("assign-groups-by-permissions", false));
|
||||
newConfig.set("primary-group-finding-list", oldConfig.getStringList("primary-group-finding-list", Arrays.asList("Owner","Admin","Mod","Helper","default")));
|
||||
|
||||
newConfig.set("debug", oldConfig.getBoolean("debug", false));
|
||||
|
||||
newConfig.set("mysql.enabled", false);
|
||||
newConfig.set("mysql.host", "127.0.0.1");
|
||||
newConfig.set("mysql.port", 3306);
|
||||
newConfig.set("mysql.database", "tab");
|
||||
newConfig.set("mysql.username", "user");
|
||||
newConfig.set("mysql.password", "password");
|
||||
|
||||
if (TAB.getInstance().getPlatform().isProxy()) {
|
||||
newConfig.set("global-playerlist", oldConfig.getConfigurationSection("global-playerlist"));
|
||||
newConfig.set("global-playerlist.update-latency", false);
|
||||
newConfig.set("use-bukkit-permissions-manager", false);
|
||||
} else {
|
||||
newConfig.set("per-world-playerlist", oldConfig.getConfigurationSection("per-world-playerlist"));
|
||||
newConfig.set("fix-pet-names.enabled", oldConfig.getBoolean("fix-pet-names", false));
|
||||
}
|
||||
}
|
||||
|
||||
private void convertGroupsAndUsers(ConfigurationFile oldConfig, ConfigurationFile groups, ConfigurationFile users) {
|
||||
groups.setValues(oldConfig.getConfigurationSection("Groups"));
|
||||
users.setValues(oldConfig.getConfigurationSection("Users"));
|
||||
|
||||
String separator = TAB.getInstance().getPlatform().isProxy() ? "server" : "world";
|
||||
Map<String,Map<String,Object>> perWorldSettings = oldConfig.getConfigurationSection("per-" + separator + "-settings");
|
||||
Map<String,Object> groupMap = new LinkedHashMap<>();
|
||||
Map<String,Object> userMap = new LinkedHashMap<>();
|
||||
Map<String,Map<String,Object>> worldMap = new LinkedHashMap<>(perWorldSettings);
|
||||
for (Map.Entry<String, Map<String, Object>> worldEntry : worldMap.entrySet()) {
|
||||
for (Map.Entry<String, Object> entry2 : new LinkedHashMap<>(worldEntry.getValue()).entrySet()) {
|
||||
if (entry2.getKey().equalsIgnoreCase("Groups"))
|
||||
groupMap.put(translateWorldGroup(oldConfig, worldEntry.getKey()),entry2.getValue());
|
||||
else if (entry2.getKey().equalsIgnoreCase("Users"))
|
||||
userMap.put(translateWorldGroup(oldConfig, worldEntry.getKey()),entry2.getValue());
|
||||
}
|
||||
}
|
||||
groups.set("per-" + separator, groupMap);
|
||||
groups.set("_DEFAULT_", groups.getConfigurationSection("_OTHER_"));
|
||||
groups.set("_OTHER_", null);
|
||||
users.set("per-" + separator, userMap);
|
||||
for (Object world : groups.getConfigurationSection("per-" + separator).keySet()) {
|
||||
String gPath = "per-" + separator + "." + world;
|
||||
if (!groups.hasConfigOption(gPath + "._OTHER_")) continue;
|
||||
groups.set(gPath + "._DEFAULT_", groups.getObject(gPath + "._OTHER_"));
|
||||
groups.set(gPath + "._OTHER_", null);
|
||||
}
|
||||
}
|
||||
|
||||
private String translateWorldGroup(ConfigurationFile oldConfig, String group) {
|
||||
String oldSeparator = oldConfig.hasConfigOption("multi-world-separator") ? oldConfig.getString("multi-world-separator") : "-";
|
||||
return group.replace(oldSeparator, ";");
|
||||
}
|
||||
|
||||
public void removeOldOptions(ConfigurationFile config) {
|
||||
if (config.hasConfigOption("placeholders.remove-strings")) {
|
||||
config.set("placeholders.remove-strings", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,151 +2,190 @@ package me.neznamy.tab.shared.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
|
||||
import me.neznamy.tab.api.config.ConfigurationFile;
|
||||
import me.neznamy.tab.api.config.YamlConfigurationFile;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
|
||||
public class MessageFile {
|
||||
public class MessageFile extends YamlConfigurationFile {
|
||||
|
||||
private final ConfigurationFile file;
|
||||
|
||||
public MessageFile() throws YAMLException, IOException {
|
||||
file = new YamlConfigurationFile(getClass().getClassLoader().getResourceAsStream("messages.yml"), new File(TAB.getInstance().getPlatform().getDataFolder(), "messages.yml"));
|
||||
super(MessageFile.class.getClassLoader().getResourceAsStream("messages.yml"), new File(TAB.getInstance().getPlatform().getDataFolder(), "messages.yml"));
|
||||
}
|
||||
|
||||
|
||||
public String getAnnounceCommandUsage() {
|
||||
return file.getString("announce-command-usage", "Usage: /tab announce <type> <name> <length>\nCurrently supported types: &lbar, scoreboard");
|
||||
return getString("announce-command-usage", "Usage: /tab announce <type> <name> <length>\nCurrently supported types: &lbar, scoreboard");
|
||||
}
|
||||
|
||||
|
||||
public String getBossBarNotEnabled() {
|
||||
return file.getString("bossbar-feature-not-enabled", "&cThis command requires the bossbar feature to be enabled.");
|
||||
return getString("bossbar-feature-not-enabled", "&cThis command requires the bossbar feature to be enabled.");
|
||||
}
|
||||
|
||||
|
||||
public String getBossBarAnnounceCommandUsage() {
|
||||
return file.getString("bossbar-announce-command-usage", "Usage: /tab announce bar <bar name> <length>");
|
||||
return getString("bossbar-announce-command-usage", "Usage: /tab announce bar <bar name> <length>");
|
||||
}
|
||||
|
||||
|
||||
public String getBossBarNotFound(String name) {
|
||||
return file.getString("bossbar-not-found", "&cNo bossbar found with the name \"%name%\"").replace("%name%", name);
|
||||
return getString("bossbar-not-found", "&cNo bossbar found with the name \"%name%\"").replace("%name%", name);
|
||||
}
|
||||
|
||||
|
||||
public String getBossBarAlreadyAnnounced() {
|
||||
return file.getString("bossbar-already-announced", "&cThis bossbar is already being announced");
|
||||
return getString("bossbar-already-announced", "&cThis bossbar is already being announced");
|
||||
}
|
||||
|
||||
|
||||
public String getGroupDataRemoved(String group) {
|
||||
return file.getString("group-data-removed", "&3[TAB] All data has been successfully removed from group &e%group%").replace("%group%", group);
|
||||
return getString("group-data-removed", "&3[TAB] All data has been successfully removed from group &e%group%").replace("%group%", group);
|
||||
}
|
||||
|
||||
|
||||
public String getGroupValueAssigned(String property, String value, String group) {
|
||||
return file.getString("group-value-assigned", "&3[TAB] %property% '&r%value%&r&3' has been successfully assigned to group &e%group%")
|
||||
return getString("group-value-assigned", "&3[TAB] %property% '&r%value%&r&3' has been successfully assigned to group &e%group%")
|
||||
.replace("%property%", property).replace("%value%", value).replace("%group%", group);
|
||||
}
|
||||
|
||||
|
||||
public String getGroupValueRemoved(String property, String group) {
|
||||
return file.getString("group-value-removed", "&3[TAB] %property% has been successfully removed from group &e%group%")
|
||||
return getString("group-value-removed", "&3[TAB] %property% has been successfully removed from group &e%group%")
|
||||
.replace("%property%", property).replace("%group%", group);
|
||||
}
|
||||
|
||||
|
||||
public String getPlayerDataRemoved(String player) {
|
||||
return file.getString("user-data-removed", "&3[TAB] All data has been successfully removed from player &e%player%").replace("%player%", player);
|
||||
return getString("user-data-removed", "&3[TAB] All data has been successfully removed from player &e%player%").replace("%player%", player);
|
||||
}
|
||||
|
||||
|
||||
public String getPlayerValueAssigned(String property, String value, String player) {
|
||||
return file.getString("user-value-assigned", "&3[TAB] %property% '&r%value%&r&3' has been successfully assigned to player &e%player%")
|
||||
return getString("user-value-assigned", "&3[TAB] %property% '&r%value%&r&3' has been successfully assigned to player &e%player%")
|
||||
.replace("%property%", property).replace("%value%", value).replace("%player%", player);
|
||||
}
|
||||
|
||||
|
||||
public String getPlayerValueRemoved(String property, String player) {
|
||||
return file.getString("user-value-removed", "&3[TAB] %property% has been successfully removed from player &e%player%")
|
||||
return getString("user-value-removed", "&3[TAB] %property% has been successfully removed from player &e%player%")
|
||||
.replace("%property%", property).replace("%player%", player);
|
||||
}
|
||||
|
||||
|
||||
public String getParseCommandUsage() {
|
||||
return file.getString("parse-command-usage", "Usage: /tab parse <player> <placeholder>");
|
||||
return getString("parse-command-usage", "Usage: /tab parse <player> <placeholder>");
|
||||
}
|
||||
|
||||
|
||||
public String getSendCommandUsage() {
|
||||
return file.getString("send-command-usage", "Usage: /tab send <type> <player> <bar name> <length>\nCurrently supported types: &lbar");
|
||||
return getString("send-command-usage", "Usage: /tab send <type> <player> <bar name> <length>\nCurrently supported types: &lbar");
|
||||
}
|
||||
|
||||
|
||||
public String getSendBarCommandUsage() {
|
||||
return file.getString("send-bar-command-usage", "Usage: /tab send bar <player> <bar name> <length>");
|
||||
return getString("send-bar-command-usage", "Usage: /tab send bar <player> <bar name> <length>");
|
||||
}
|
||||
|
||||
|
||||
public String getTeamFeatureRequired() {
|
||||
return file.getString("team-feature-required", "This command requires scoreboard teams feature enabled");
|
||||
return getString("team-feature-required", "This command requires scoreboard teams feature enabled");
|
||||
}
|
||||
|
||||
|
||||
public String getCollisionCommandUsage() {
|
||||
return file.getString("collision-command-ussage", "Usage: /tab setcollision <player> <true/false>");
|
||||
return getString("collision-command-ussage", "Usage: /tab setcollision <player> <true/false>");
|
||||
}
|
||||
|
||||
|
||||
public String getNoPermission() {
|
||||
return file.getString("no-permission", "&cI'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error.");
|
||||
return getString("no-permission", "&cI'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error.");
|
||||
}
|
||||
|
||||
|
||||
public String getCommandOnlyFromGame() {
|
||||
return file.getString("command-only-from-game", "&cThis command must be ran from the game");
|
||||
return getString("command-only-from-game", "&cThis command must be ran from the game");
|
||||
}
|
||||
|
||||
|
||||
public String getPlayerNotFound(String name) {
|
||||
return file.getString("player-not-online", "&cNo online player found with the name \"%player%\"").replace("%player%", name);
|
||||
return getString("player-not-online", "&cNo online player found with the name \"%player%\"").replace("%player%", name);
|
||||
}
|
||||
|
||||
|
||||
public String getUnlimitedNametagModeNotEnabled() {
|
||||
return file.getString("unlimited-nametag-mode-not-enabled", "&c[TAB] Warning! To make this feature work, you need to enable unlimited-nametag-mode in the config!");
|
||||
return getString("unlimited-nametag-mode-not-enabled", "&c[TAB] Warning! To make this feature work, you need to enable unlimited-nametag-mode in the config!");
|
||||
}
|
||||
|
||||
|
||||
public String getInvalidNumber(String input) {
|
||||
return file.getString("invalid-number", "\"%input%\" is not a number!").replace("%input%", input);
|
||||
return getString("invalid-number", "\"%input%\" is not a number!").replace("%input%", input);
|
||||
}
|
||||
|
||||
|
||||
public String getScoreboardFeatureNotEnabled() {
|
||||
return file.getString("scoreboard-feature-not-enabled", "&4This command requires the scoreboard feature to be enabled.");
|
||||
return getString("scoreboard-feature-not-enabled", "&4This command requires the scoreboard feature to be enabled.");
|
||||
}
|
||||
|
||||
|
||||
public String getScoreboardAnnounceCommandUsage() {
|
||||
return file.getString("scoreboard-announce-command-usage", "Usage: /tab announce scoreboard <scoreboard name> <length>");
|
||||
return getString("scoreboard-announce-command-usage", "Usage: /tab announce scoreboard <scoreboard name> <length>");
|
||||
}
|
||||
|
||||
|
||||
public String getScoreboardNotFound(String name) {
|
||||
return file.getString("scoreboard-not-found", "&cNo scoreboard found with the name \"%name%\"").replace("%name%", name);
|
||||
return getString("scoreboard-not-found", "&cNo scoreboard found with the name \"%name%\"").replace("%name%", name);
|
||||
}
|
||||
|
||||
|
||||
public String getNametagPreviewOn() {
|
||||
return file.getString("nametag-preview-on", "&7Preview mode &aactivated&7.");
|
||||
return getString("nametag-preview-on", "&7Preview mode &aactivated&7.");
|
||||
}
|
||||
|
||||
|
||||
public String getNametagPreviewOff() {
|
||||
return file.getString("nametag-preview-of", "&7Preview mode &3deactivated&7.");
|
||||
return getString("nametag-preview-of", "&7Preview mode &3deactivated&7.");
|
||||
}
|
||||
|
||||
|
||||
public String getReloadSuccess() {
|
||||
return file.getString("reload-success", "&3[TAB] Successfully reloaded");
|
||||
return getString("reload-success", "&3[TAB] Successfully reloaded");
|
||||
}
|
||||
|
||||
|
||||
//keeping %file% to replace later since message file may not be available
|
||||
public String getReloadFailBrokenFile() {
|
||||
return file.getString("reload-fail-file", "&3[TAB] &4Failed to reload, file %file% has broken syntax. Check console for more info.");
|
||||
return getString("reload-fail-file", "&3[TAB] &4Failed to reload, file %file% has broken syntax. Check console for more info.");
|
||||
}
|
||||
|
||||
|
||||
public String getScoreboardOn() {
|
||||
return file.getString("scoreboard-toggle-on", "&2Scoreboard enabled");
|
||||
return getString("scoreboard-toggle-on", "&2Scoreboard enabled");
|
||||
}
|
||||
|
||||
|
||||
public String getScoreboardOff() {
|
||||
return file.getString("scoreboard-toggle-off", "&7Scoreboard disabled");
|
||||
return getString("scoreboard-toggle-off", "&7Scoreboard disabled");
|
||||
}
|
||||
|
||||
|
||||
public String getBossBarOn() {
|
||||
return file.getString("bossbar-toggle-on", "&2Bossbar is now visible");
|
||||
return getString("bossbar-toggle-on", "&2Bossbar is now visible");
|
||||
}
|
||||
|
||||
public String getBossBarOff() {
|
||||
return getString("bossbar-toggle-off", "&7Bossbar is no longer visible. Magic!");
|
||||
}
|
||||
|
||||
public String getScoreboardShowUsage() {
|
||||
return getString("scoreboard-show-usage", "Usage: /tab scoreboard show <scoreboard> [player]");
|
||||
}
|
||||
|
||||
public String getBossBarNotMarkedAsAnnouncement() {
|
||||
return getString("bossbar-not-marked-as-announcement", "&cThis bossbar is not marked as an announcement bar and is therefore " +
|
||||
"already displayed permanently (if display condition is met)");
|
||||
}
|
||||
|
||||
public String getBossBarOff() {
|
||||
return file.getString("bossbar-toggle-off", "&7Bossbar is no longer visible. Magic!");
|
||||
public String getBossBarAnnouncementSuccess(String bar, int length) {
|
||||
return getString("bossbar-announcement-success", "&aAnnouncing bossbar &6%bossbar% &afor %length% seconds.")
|
||||
.replace("%bossbar%", bar).replace("%length%", String.valueOf(length));
|
||||
}
|
||||
|
||||
public String getBossBarSendSuccess(String player, String bar, int length) {
|
||||
return getString("bossbar-send-success", "&aSending bossbar &6%bossbar% &ato player &6%player% &afor %length% seconds.")
|
||||
.replace("%player%", player).replace("%bossbar%", bar).replace("%length%", String.valueOf(length));
|
||||
}
|
||||
|
||||
public List<String> getHelpMenu() {
|
||||
return getStringList("help-menu", Arrays.asList("&m "
|
||||
," &8>> &3&l/tab reload"
|
||||
," &7Reloads plugin and config"
|
||||
," &8>> &3&l/tab &9group&3/&9player &3<name> &9<property> &3<value...>"
|
||||
," &7Do &8/tab group/player &7to show properties"
|
||||
," &8>> &3&l/tab ntpreview"
|
||||
," &7Shows your nametag for yourself, for testing purposes"
|
||||
," &8>> &3&l/tab announce bar &3<name> &9<seconds>"
|
||||
," &7Temporarily displays bossbar to all players"
|
||||
," &8>> &3&l/tab parse <player> <placeholder> "
|
||||
," &7Test if a placeholder works"
|
||||
," &8>> &3&l/tab debug [player]"
|
||||
," &7displays debug information about player"
|
||||
," &8>> &3&l/tab cpu"
|
||||
," &7shows CPU usage of the plugin"
|
||||
," &8>> &3&l/tab group/player <name> remove"
|
||||
," &7Clears all data about player/group"
|
||||
,"&m "));
|
||||
}
|
||||
}
|
||||
@@ -56,18 +56,13 @@ public class MySQL {
|
||||
}
|
||||
|
||||
public void execute(String query, Object... vars) throws SQLException {
|
||||
if (isConnected()) {
|
||||
openConnection();
|
||||
}
|
||||
try (PreparedStatement ps = prepareStatement(query, vars)){
|
||||
ps.execute();
|
||||
}
|
||||
}
|
||||
|
||||
private PreparedStatement prepareStatement(String query, Object... vars) throws SQLException {
|
||||
if (isConnected()) {
|
||||
openConnection();
|
||||
}
|
||||
if (!isConnected()) openConnection();
|
||||
PreparedStatement ps = con.prepareStatement(query);
|
||||
int i = 0;
|
||||
if (query.contains("?") && vars.length != 0) {
|
||||
@@ -80,9 +75,6 @@ public class MySQL {
|
||||
}
|
||||
|
||||
public CachedRowSet getCRS(String query, Object... vars) throws SQLException {
|
||||
if (isConnected()) {
|
||||
openConnection();
|
||||
}
|
||||
PreparedStatement ps = prepareStatement(query, vars);
|
||||
ResultSet rs = ps.executeQuery();
|
||||
CachedRowSet crs;
|
||||
|
||||
+48
-25
@@ -3,6 +3,8 @@ package me.neznamy.tab.shared.config.mysql;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import javax.sql.rowset.CachedRowSet;
|
||||
|
||||
@@ -15,9 +17,9 @@ public class MySQLUserConfiguration implements PropertyConfiguration {
|
||||
|
||||
private final MySQL mysql;
|
||||
|
||||
private final Map<String, Map<String, String>> values = new HashMap<>();
|
||||
private final Map<String, Map<String, Map<String, String>>> perWorld = new HashMap<>();
|
||||
private final Map<String, Map<String, Map<String, String>>> perServer = new HashMap<>();
|
||||
private final WeakHashMap<TabPlayer, Map<String, String>> values = new WeakHashMap<>();
|
||||
private final Map<String, WeakHashMap<TabPlayer, Map<String, String>>> perWorld = new HashMap<>();
|
||||
private final Map<String, WeakHashMap<TabPlayer, Map<String, String>>> perServer = new HashMap<>();
|
||||
|
||||
public MySQLUserConfiguration(MySQL mysql) throws SQLException {
|
||||
this.mysql = mysql;
|
||||
@@ -26,12 +28,13 @@ public class MySQLUserConfiguration implements PropertyConfiguration {
|
||||
|
||||
@Override
|
||||
public void setProperty(String user, String property, String server, String world, String value) {
|
||||
TabPlayer p = getPlayer(user);
|
||||
user = user.toLowerCase();
|
||||
try {
|
||||
if (getProperty(user, property, server, world) != null) {
|
||||
mysql.execute("delete from `tab_users` where `user` = ? and `property` = ? and world " + querySymbol(world == null) + " ? and server " + querySymbol(server == null) + " ?", user, property, world, server);
|
||||
}
|
||||
setProperty0(user, property, server, world, value);
|
||||
if (p != null) setProperty0(p, property, server, world, value);
|
||||
if (value != null) mysql.execute("insert into `tab_users` (`user`, `property`, `value`, `world`, `server`) values (?, ?, ?, ?, ?)", user, property, value, world, server);
|
||||
} catch (SQLException e) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to execute MySQL query", e);
|
||||
@@ -42,12 +45,11 @@ public class MySQLUserConfiguration implements PropertyConfiguration {
|
||||
return isNull ? "is" : "=";
|
||||
}
|
||||
|
||||
private void setProperty0(String user, String property, String server, String world, String value) {
|
||||
user = user.toLowerCase();
|
||||
private void setProperty0(TabPlayer user, String property, String server, String world, String value) {
|
||||
if (server != null) {
|
||||
perServer.computeIfAbsent(server, s -> new HashMap<>()).computeIfAbsent(user, g -> new HashMap<>()).put(property, value);
|
||||
perServer.computeIfAbsent(server, s -> new WeakHashMap<>()).computeIfAbsent(user, g -> new HashMap<>()).put(property, value);
|
||||
} else if (world != null) {
|
||||
perWorld.computeIfAbsent(world, w -> new HashMap<>()).computeIfAbsent(user, g -> new HashMap<>()).put(property, value);
|
||||
perWorld.computeIfAbsent(world, w -> new WeakHashMap<>()).computeIfAbsent(user, g -> new HashMap<>()).put(property, value);
|
||||
} else {
|
||||
values.computeIfAbsent(user, g -> new HashMap<>()).put(property, value);
|
||||
}
|
||||
@@ -55,15 +57,15 @@ public class MySQLUserConfiguration implements PropertyConfiguration {
|
||||
|
||||
@Override
|
||||
public String[] getProperty(String user, String property, String server, String world) {
|
||||
user = user.toLowerCase();
|
||||
TabPlayer p = getPlayer(user);
|
||||
String value;
|
||||
if ((value = perServer.getOrDefault(server, new HashMap<>()).getOrDefault(user, new HashMap<>()).get(property)) != null) {
|
||||
if ((value = perServer.getOrDefault(server, new WeakHashMap<>()).getOrDefault(p, new HashMap<>()).get(property)) != null) {
|
||||
return new String[] {value, String.format("user=%s,server=%s", user, server)};
|
||||
}
|
||||
if ((value = perWorld.getOrDefault(world, new HashMap<>()).getOrDefault(user, new HashMap<>()).get(property)) != null) {
|
||||
if ((value = perWorld.getOrDefault(world, new WeakHashMap<>()).getOrDefault(p, new HashMap<>()).get(property)) != null) {
|
||||
return new String[] {value, String.format("user=%s,world=%s", user, world)};
|
||||
}
|
||||
if ((value = values.getOrDefault(user, new HashMap<>()).get(property)) != null) {
|
||||
if ((value = values.getOrDefault(p, new HashMap<>()).get(property)) != null) {
|
||||
return new String[] {value, String.format("user=%s", user)};
|
||||
}
|
||||
return new String[0];
|
||||
@@ -71,10 +73,28 @@ public class MySQLUserConfiguration implements PropertyConfiguration {
|
||||
|
||||
@Override
|
||||
public void remove(String player) {
|
||||
final String user = player.toLowerCase();
|
||||
values.getOrDefault(user, new HashMap<>()).keySet().forEach(property -> setProperty(user, property, null, null, null));
|
||||
perWorld.keySet().forEach(world -> perWorld.get(world).getOrDefault(user, new HashMap<>()).keySet().forEach(property -> setProperty(user, property, null, world, null)));
|
||||
perServer.keySet().forEach(server -> perServer.get(server).getOrDefault(user, new HashMap<>()).keySet().forEach(property -> setProperty(user, property, server, null, null)));
|
||||
try {
|
||||
mysql.execute("delete from `tab_users` where `user` = ?", player);
|
||||
} catch (SQLException e) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to execute MySQL query", e);
|
||||
}
|
||||
TabPlayer user = getPlayer(player);
|
||||
if (user == null) return;
|
||||
values.remove(user);
|
||||
perWorld.keySet().forEach(world -> perWorld.get(world).remove(user));
|
||||
perServer.keySet().forEach(server -> perServer.get(server).remove(user));
|
||||
}
|
||||
|
||||
private TabPlayer getPlayer(String string) {
|
||||
TabPlayer p = TAB.getInstance().getPlayer(string);
|
||||
if (p == null) {
|
||||
try {
|
||||
p = TAB.getInstance().getPlayer(UUID.fromString(string));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
//not a valid uuid
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
public void load(TabPlayer player) {
|
||||
@@ -89,10 +109,20 @@ public class MySQLUserConfiguration implements PropertyConfiguration {
|
||||
String world = crs.getString("world");
|
||||
String server = crs.getString("server");
|
||||
TAB.getInstance().debug("Loaded user line: " + String.format("%s, %s, %s, %s, %s", user, property, value, world, server));
|
||||
setProperty0(user, property, server, world, value);
|
||||
setProperty0(player, property, server, world, value);
|
||||
}
|
||||
CachedRowSet crs2 = mysql.getCRS("select * from `tab_users` where `user` = ?", player.getUniqueId().toString());
|
||||
while (crs2.next()) {
|
||||
String user = crs2.getString("user");
|
||||
String property = crs2.getString("property");
|
||||
String value = crs2.getString("value");
|
||||
String world = crs2.getString("world");
|
||||
String server = crs2.getString("server");
|
||||
TAB.getInstance().debug("Loaded user line: " + String.format("%s, %s, %s, %s, %s", user, property, value, world, server));
|
||||
setProperty0(player, property, server, world, value);
|
||||
}
|
||||
TAB.getInstance().debug("Loaded MySQL data of " + player.getName());
|
||||
if (crs.size() > 0) {
|
||||
if (crs.size() > 0 || crs2.size() > 0) {
|
||||
player.forceRefresh();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
@@ -100,11 +130,4 @@ public class MySQLUserConfiguration implements PropertyConfiguration {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void unload(TabPlayer player) {
|
||||
values.remove(player.getName().toLowerCase());
|
||||
perWorld.keySet().forEach(world -> perWorld.get(world).remove(player.getName().toLowerCase()));
|
||||
perServer.keySet().forEach(server -> perServer.get(server).remove(player.getName().toLowerCase()));
|
||||
TAB.getInstance().debug("Unloaded MySQL data of " + player.getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package me.neznamy.tab.shared.event;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import me.neznamy.tab.api.event.EventBus;
|
||||
import me.neznamy.tab.api.event.EventHandler;
|
||||
import me.neznamy.tab.api.event.Subscribe;
|
||||
import me.neznamy.tab.api.event.TabEvent;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import net.kyori.event.EventSubscriber;
|
||||
import net.kyori.event.PostOrders;
|
||||
import net.kyori.event.PostResult;
|
||||
import net.kyori.event.SimpleEventBus;
|
||||
import net.kyori.event.method.MethodHandleEventExecutorFactory;
|
||||
import net.kyori.event.method.MethodScanner;
|
||||
import net.kyori.event.method.MethodSubscriptionAdapter;
|
||||
import net.kyori.event.method.SimpleMethodSubscriptionAdapter;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public final class EventBusImpl implements EventBus {
|
||||
|
||||
private final SimpleEventBus<TabEvent> bus;
|
||||
private final MethodSubscriptionAdapter<Object> methodAdapter;
|
||||
|
||||
public EventBusImpl() {
|
||||
this.bus = new SimpleEventBus<TabEvent>(TabEvent.class) {
|
||||
|
||||
@Override
|
||||
protected boolean shouldPost(@NonNull TabEvent event, @NonNull EventSubscriber subscriber) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
this.methodAdapter = new SimpleMethodSubscriptionAdapter<>(bus, new MethodHandleEventExecutorFactory<>(), new TabMethodScanner());
|
||||
}
|
||||
|
||||
public <E extends TabEvent> void fire(final E event) {
|
||||
if (!bus.hasSubscribers(event.getClass())) return;
|
||||
final PostResult result = bus.post(event);
|
||||
if (result.exceptions().isEmpty()) return;
|
||||
|
||||
TAB.getInstance().getErrorManager().printError("Some errors occurred whilst trying to fire event " + event);
|
||||
int i = 0;
|
||||
for (final Throwable exception : result.exceptions().values()) {
|
||||
TAB.getInstance().getErrorManager().printError("#" + i++ + ": \n", exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Object listener) {
|
||||
methodAdapter.register(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E extends TabEvent> void register(Class<E> type, EventHandler<E> handler) {
|
||||
bus.register(type, new HandlerWrapper<>(handler));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(Object listener) {
|
||||
methodAdapter.unregister(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E extends TabEvent> void unregister(EventHandler<E> handler) {
|
||||
bus.unregister(subscriber -> subscriber instanceof HandlerWrapper && ((HandlerWrapper<?>) subscriber).handler == handler);
|
||||
}
|
||||
|
||||
private static final class TabMethodScanner implements MethodScanner<Object> {
|
||||
|
||||
@Override
|
||||
public boolean shouldRegister(@NonNull Object listener, @NonNull Method method) {
|
||||
return method.isAnnotationPresent(Subscribe.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int postOrder(@NonNull Object listener, @NonNull Method method) {
|
||||
return PostOrders.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean consumeCancelledEvents(@NonNull Object listener, @NonNull Method method) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class HandlerWrapper<E> implements EventSubscriber<E> {
|
||||
|
||||
private final EventHandler<E> handler;
|
||||
|
||||
public HandlerWrapper(final EventHandler<E> handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NonNull E event) {
|
||||
handler.handle(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package me.neznamy.tab.shared.event.impl;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.event.player.PlayerLoadEvent;
|
||||
|
||||
public final class PlayerLoadEventImpl implements PlayerLoadEvent {
|
||||
|
||||
private final TabPlayer player;
|
||||
private final boolean join;
|
||||
|
||||
public PlayerLoadEventImpl(TabPlayer player, boolean join) {
|
||||
this.player = player;
|
||||
this.join = join;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabPlayer getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJoin() {
|
||||
return join;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package me.neznamy.tab.shared.event.impl;
|
||||
|
||||
import me.neznamy.tab.api.event.plugin.TabLoadEvent;
|
||||
|
||||
public final class TabLoadEventImpl implements TabLoadEvent {
|
||||
|
||||
private static final TabLoadEvent INSTANCE = new TabLoadEventImpl();
|
||||
|
||||
public static TabLoadEvent getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private TabLoadEventImpl() {
|
||||
}
|
||||
}
|
||||
Loaded 100 of 153 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user