diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4788b4b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,113 @@
+# User-specific stuff
+.idea/
+
+*.iml
+*.ipr
+*.iws
+
+# IntelliJ
+out/
+
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+# Windows thumbnail cache files
+Thumbs.db
+Thumbs.db:encryptable
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+target/
+
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
+.flattened-pom.xml
+
+# Common working directory
+run/
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..6a9a135
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,171 @@
+
+
+ 4.0.0
+
+ dev.qv7_
+ SnakeHub
+ 1.2.0-HOTFIX
+ jar
+
+ SnakeHub
+
+
+ 1.8
+ UTF-8
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ ${java.version}
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.2.4
+
+
+ package
+
+ shade
+
+
+ false
+
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+
+
+ spigotmc-repo
+ https://hub.spigotmc.org/nexus/content/repositories/snapshots/
+
+
+ dmulloy2-repo
+ https://repo.dmulloy2.net/repository/public/
+
+
+ jitpack.io
+ https://jitpack.io/
+
+
+
+ placeholderapi
+ http://repo.extendedclip.com/content/repositories/placeholderapi/
+
+
+
+ viaversion-repo
+ https://repo.viaversion.com/
+
+
+ sonatype
+ https://oss.sonatype.org/content/groups/public/
+
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.22
+ provided
+
+
+ org.spigotmc
+ spigot-api
+ 1.8.8-R0.1-SNAPSHOT
+ provided
+
+
+ com.viaversion
+ viaversion
+ 4.2.0-SNAPSHOT
+ provided
+
+
+ com.spigot
+ Spigot
+ LATEST
+ system
+ ${project.basedir}/depends/Spigot1.8.jar
+
+
+ net.hylist.spigot
+ Spigot
+ LATEST
+ system
+ ${project.basedir}/depends/spigot.jar
+
+
+ com.comphenix.protocol
+ ProtocolLib
+ 4.7.0
+
+
+ dev.alex.net.utilities.command
+ Spigot-Utilities-Command
+ 1.0
+ system
+ ${project.basedir}/depends/Spigot-Utilities-Command-1.0.jar
+
+
+ net.milkbowl.vault
+ Vault
+ 1.2.27
+ system
+ ${project.basedir}/depends/Vault.jar
+
+
+ aqua
+ aqua
+ LATEST
+ system
+ ${project.basedir}/depends/DL-AquaCore_2.6.20-Cracked_2.jar
+
+
+ net.lunarclient
+ LunarClient
+ LATEST
+ system
+ ${project.basedir}/depends/LunarAPI.jar
+
+
+ placeholder
+ Placeholder
+ LATEST
+ system
+ ${project.basedir}/depends/PlaceholderAPI.jar
+
+
+ net.luckperms
+ api
+ 5.0
+ provided
+
+
+ me.signatured.ezqueuespigot
+ EzqueueSpigot
+ 1.6.5
+ system
+ ${project.basedir}/depends/EzQueueSpigot.jar
+
+
+
diff --git a/src/main/java/dev/aapy/SnakeHub.java b/src/main/java/dev/aapy/SnakeHub.java
new file mode 100644
index 0000000..0a1b88e
--- /dev/null
+++ b/src/main/java/dev/aapy/SnakeHub.java
@@ -0,0 +1,82 @@
+package dev.aapy;
+
+import dev.aapy.file.Config;
+import dev.aapy.file.Message;
+import dev.aapy.file.Scoreboard;
+import dev.aapy.file.Tablist;
+import dev.aapy.listeners.hotbar.PvPListener;
+import dev.aapy.manager.Manager;
+import dev.aapy.manager.managers.PermissionManager;
+import dev.aapy.tablist.Tab;
+import dev.aapy.tablist.provider.TablistProvider;
+import dev.aapy.util.CC;
+import lombok.Getter;
+import org.bukkit.Bukkit;
+import org.bukkit.World;
+import org.bukkit.plugin.java.JavaPlugin;
+
+@Getter
+public class SnakeHub extends JavaPlugin {
+
+ private static SnakeHub plugin;
+ private PermissionManager permission;
+ private Manager manager;
+ private PvPListener pvpListener;
+
+ @Override
+ public void onEnable() {
+ plugin = this;
+
+ this.manager = new Manager(this);
+ this.manager.enable();
+ CC.log("&cSnakeHub &f" + this.manager.getManagers().size() + " &amanagers have been registered");
+
+ CC.log("&f");
+ this.permission = new PermissionManager(this);
+ this.permission.loadHook();
+
+ Bukkit.getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
+ CC.log("&aBungeeCoord connecting!");
+
+ Message.getConfig().load();
+ Scoreboard.getConfig().load();
+ Tablist.getConfig().load();
+ Config.getConfig().load();
+
+ CC.log("&7&m=========================");
+ CC.log("");
+ CC.log("&cPlugin Name: &fSnakeHub");
+ CC.log("&cVersion: &f1.2.0-HOTFIX");
+ CC.log("&cAuthor: &fAapy#0001");
+ CC.log("");
+ CC.log("&7&m=========================");
+
+ for (World world : Bukkit.getWorlds()) {
+ world.setGameRuleValue("doDaylightCycle", "false");
+ world.setGameRuleValue("doMobSpawning", "false");
+ world.setTime(6000L);
+ }
+
+ if (Config.getConfig().getBoolean("BOOLEANS.TABLIST")) {
+ new Tab(this, new TablistProvider());
+ }
+
+ Message.getConfig().save();
+ Scoreboard.getConfig().save();
+ Tablist.getConfig().save();
+ Config.getConfig().save();
+ }
+
+ @Override
+ public void onDisable() {
+ this.manager.disable();
+ Message.getConfig().save();
+ Scoreboard.getConfig().save();
+ Tablist.getConfig().save();
+ Config.getConfig().save();
+ }
+
+ public static SnakeHub getInst() {
+ return plugin;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/commands/plugin/HubCore.java b/src/main/java/dev/aapy/commands/plugin/HubCore.java
new file mode 100644
index 0000000..5bfc9d1
--- /dev/null
+++ b/src/main/java/dev/aapy/commands/plugin/HubCore.java
@@ -0,0 +1,17 @@
+package dev.aapy.commands.plugin;
+
+import dev.alex.net.utilities.command.command.CommandExecutor;
+
+/**
+ * @author 7qv_ and Alexito2060 on 19/2/2022.
+ * @project SnakeHub
+ */
+
+public class HubCore extends CommandExecutor {
+
+ public HubCore() {
+ super("HubCore", "HubCore command");
+ registerArgument(new HubInfo());
+ registerArgument(new HubReload());
+ }
+}
diff --git a/src/main/java/dev/aapy/commands/plugin/HubInfo.java b/src/main/java/dev/aapy/commands/plugin/HubInfo.java
new file mode 100644
index 0000000..57796eb
--- /dev/null
+++ b/src/main/java/dev/aapy/commands/plugin/HubInfo.java
@@ -0,0 +1,30 @@
+package dev.aapy.commands.plugin;
+
+import dev.alex.net.utilities.command.command.CommandArgument;
+import dev.aapy.util.CC;
+import org.bukkit.command.CommandSender;
+
+/**
+ * @author 7qv_ and Alexito2060 on 19/2/2022.
+ * @project SnakeHub
+ */
+public class HubInfo extends CommandArgument {
+
+ public HubInfo() { super("info", "See SnakeHub information"); }
+
+ @Override
+ public String getUsage(String s) { return getName(); }
+
+ @Override
+ public boolean onCommand(CommandSender sender, String label, String[] args) {
+ sender.sendMessage(CC.translate("&7&m----------------------------"));
+ sender.sendMessage("");
+ sender.sendMessage(CC.translate("&bSnakeHub &7- &7[&fHubCore&7]"));
+ sender.sendMessage("");
+ sender.sendMessage(CC.translate("&7» &cVersion&7: &f1.0.3-RECODE"));
+ sender.sendMessage(CC.translate("&7» &cAuthor&7: &f7qv_"));
+ sender.sendMessage("");
+ sender.sendMessage(CC.translate("&7&m----------------------------"));
+ return false;
+ }
+}
diff --git a/src/main/java/dev/aapy/commands/plugin/HubReload.java b/src/main/java/dev/aapy/commands/plugin/HubReload.java
new file mode 100644
index 0000000..9007b27
--- /dev/null
+++ b/src/main/java/dev/aapy/commands/plugin/HubReload.java
@@ -0,0 +1,33 @@
+package dev.aapy.commands.plugin;
+
+import dev.alex.net.utilities.command.command.CommandArgument;
+import dev.aapy.file.Config;
+import dev.aapy.file.Message;
+import dev.aapy.file.Scoreboard;
+import dev.aapy.file.Tablist;
+import dev.aapy.util.CC;
+import org.bukkit.command.CommandSender;
+
+/**
+ * @author 7qv_ and Alexito2060 on 19/2/2022.
+ * @project SnakeHub
+ */
+public class HubReload extends CommandArgument {
+
+ public HubReload() { super("reload", "Reload configs file", "hub.reload"); }
+
+ @Override
+ public String getUsage(String s) { return getName(); }
+
+ @Override
+ public boolean onCommand(CommandSender sender, String label, String[] args) {
+ Config.getConfig().reload();
+ Message.getConfig().reload();
+ Scoreboard.getConfig().reload();
+ Tablist.getConfig().reload();
+
+ sender.sendMessage(CC.translate("&aAll files has been successfully reloaded."));
+
+ return true;
+ }
+}
diff --git a/src/main/java/dev/aapy/commands/social/Discord.java b/src/main/java/dev/aapy/commands/social/Discord.java
new file mode 100644
index 0000000..ca1c054
--- /dev/null
+++ b/src/main/java/dev/aapy/commands/social/Discord.java
@@ -0,0 +1,28 @@
+package dev.aapy.commands.social;
+
+import dev.alex.net.utilities.command.command.CommandExecutor;
+import dev.aapy.file.Config;
+import dev.aapy.file.Message;
+import dev.aapy.util.CC;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+/**
+ * @author 7qv_ and Alexito2060 on 19/2/2022.
+ * @project SnakeHub
+ */
+public class Discord extends CommandExecutor {
+
+ public Discord() {
+ super("discord", "Discord command", "hubcore.discord.command", new String[]{"dc"});
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ Message.getConfig().getStringList("SOCIAL.DISCORD").forEach((s) -> {
+ sender.sendMessage(CC.translate(s.replace("{discord}", Config.getConfig().getString("SOCIAL.DISCORD"))));
+ });
+ return true;
+ }
+}
+
diff --git a/src/main/java/dev/aapy/commands/social/Store.java b/src/main/java/dev/aapy/commands/social/Store.java
new file mode 100644
index 0000000..d9df459
--- /dev/null
+++ b/src/main/java/dev/aapy/commands/social/Store.java
@@ -0,0 +1,27 @@
+package dev.aapy.commands.social;
+
+import dev.alex.net.utilities.command.command.CommandExecutor;
+import dev.aapy.file.Config;
+import dev.aapy.file.Message;
+import dev.aapy.util.CC;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+/**
+ * @author 7qv_ and Alexito2060 on 19/2/2022.
+ * @project SnakeHub
+ */
+public class Store extends CommandExecutor {
+
+ public Store() {
+ super("store", "Store Command", "hubcore.store.command");
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ Message.getConfig().getStringList("SOCIAL.STORE").forEach((s) -> {
+ sender.sendMessage(CC.translate(s.replace("{store}", Config.getConfig().getString("SOCIAL.STORE"))));
+ });
+ return true;
+ }
+}
diff --git a/src/main/java/dev/aapy/commands/social/TeamSpeak.java b/src/main/java/dev/aapy/commands/social/TeamSpeak.java
new file mode 100644
index 0000000..ed8b69b
--- /dev/null
+++ b/src/main/java/dev/aapy/commands/social/TeamSpeak.java
@@ -0,0 +1,27 @@
+package dev.aapy.commands.social;
+
+import dev.alex.net.utilities.command.command.CommandExecutor;
+import dev.aapy.file.Config;
+import dev.aapy.file.Message;
+import dev.aapy.util.CC;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+/**
+ * @author 7qv_ and Alexito2060 on 19/2/2022.
+ * @project SnakeHub
+ */
+public class TeamSpeak extends CommandExecutor {
+
+ public TeamSpeak() {
+ super("teamspeak", "TeamSpeak Command", "hubcore.teamspeak.command", new String[]{"ts"});
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ Message.getConfig().getStringList("SOCIAL.TEAMSPEAK").forEach((s) -> {
+ sender.sendMessage(CC.translate(s.replace("{team-speak}", Config.getConfig().getString("SOCIAL.TEAMSPEAK"))));
+ });
+ return true;
+ }
+}
diff --git a/src/main/java/dev/aapy/commands/social/Twitter.java b/src/main/java/dev/aapy/commands/social/Twitter.java
new file mode 100644
index 0000000..f622de8
--- /dev/null
+++ b/src/main/java/dev/aapy/commands/social/Twitter.java
@@ -0,0 +1,27 @@
+package dev.aapy.commands.social;
+
+import dev.alex.net.utilities.command.command.CommandExecutor;
+import dev.aapy.file.Config;
+import dev.aapy.file.Message;
+import dev.aapy.util.CC;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+/**
+ * @author 7qv_ and Alexito2060 on 19/2/2022.
+ * @project SnakeHub
+ */
+public class Twitter extends CommandExecutor {
+
+ public Twitter() {
+ super("twitter", "Twitter Command", "hubcore.twitter.command");
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ Message.getConfig().getStringList("SOCIAL.TWITTER").forEach((s) -> {
+ sender.sendMessage(CC.translate(s.replace("{twitter}", Config.getConfig().getString("SOCIAL.TWITTER"))));
+ });
+ return true;
+ }
+}
diff --git a/src/main/java/dev/aapy/commands/social/WebSite.java b/src/main/java/dev/aapy/commands/social/WebSite.java
new file mode 100644
index 0000000..7ff7567
--- /dev/null
+++ b/src/main/java/dev/aapy/commands/social/WebSite.java
@@ -0,0 +1,27 @@
+package dev.aapy.commands.social;
+
+import dev.alex.net.utilities.command.command.CommandExecutor;
+import dev.aapy.file.Config;
+import dev.aapy.file.Message;
+import dev.aapy.util.CC;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+/**
+ * @author 7qv_ and Alexito2060 on 19/2/2022.
+ * @project SnakeHub
+ */
+public class WebSite extends CommandExecutor {
+
+ public WebSite() {
+ super("website", "WebSite Command","hubcore.website.command");
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ Message.getConfig().getStringList("SOCIAL.WEBSITE").forEach((s) -> {
+ sender.sendMessage(CC.translate(s.replace("{website}", Config.getConfig().getString("SOCIAL.WEBSITE"))));
+ });
+ return true;
+ }
+}
diff --git a/src/main/java/dev/aapy/file/Config.java b/src/main/java/dev/aapy/file/Config.java
new file mode 100644
index 0000000..b7a29b2
--- /dev/null
+++ b/src/main/java/dev/aapy/file/Config.java
@@ -0,0 +1,61 @@
+package dev.aapy.file;
+
+import dev.aapy.SnakeHub;
+import org.bukkit.configuration.file.*;
+import org.bukkit.plugin.*;
+
+import java.io.File;
+
+/**
+ * @author 7qv_ on 8/2/2022.
+ * @project SnakeHub
+ */
+public class Config extends YamlConfiguration
+{
+ private static Config config;
+ private Plugin plugin;
+ private File configFile;
+
+ public static Config getConfig() {
+ if (Config.config == null) {
+ Config.config = new Config();
+ }
+ return Config.config;
+ }
+
+ private Plugin main() {
+ return (Plugin) SnakeHub.getInst();
+ }
+
+ public Config() {
+ this.plugin = this.main();
+ this.configFile = new File(this.plugin.getDataFolder(), "config.yml");
+ if (!this.configFile.exists()) {
+ this.plugin.saveResource("config.yml", false);
+ }
+ this.reload();
+ }
+
+ public void reload() {
+ try {
+ super.load(this.configFile);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void load() {
+ try {
+ super.save(this.configFile);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void save() {
+ this.load();
+ this.reload();
+ }
+}
diff --git a/src/main/java/dev/aapy/file/Message.java b/src/main/java/dev/aapy/file/Message.java
new file mode 100644
index 0000000..bf12f94
--- /dev/null
+++ b/src/main/java/dev/aapy/file/Message.java
@@ -0,0 +1,60 @@
+package dev.aapy.file;
+import dev.aapy.SnakeHub;
+import org.bukkit.configuration.file.*;
+import org.bukkit.plugin.*;
+
+import java.io.File;
+
+/**
+ * @author 7qv_ on 9/2/2022.
+ * @project SnakeHub
+ */
+public class Message extends YamlConfiguration
+{
+ private static Message config;
+ private Plugin plugin;
+ private File configFile;
+
+ public static Message getConfig() {
+ if (Message.config == null) {
+ Message.config = new Message();
+ }
+ return Message.config;
+ }
+
+ private Plugin main() {
+ return (Plugin) SnakeHub.getInst();
+ }
+
+ public Message() {
+ this.plugin = this.main();
+ this.configFile = new File(this.plugin.getDataFolder(), "lang.yml");
+ if (!this.configFile.exists()) {
+ this.plugin.saveResource("lang.yml", false);
+ }
+ this.reload();
+ }
+
+ public void reload() {
+ try {
+ super.load(this.configFile);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void load() {
+ try {
+ super.save(this.configFile);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void save() {
+ this.load();
+ this.reload();
+ }
+}
diff --git a/src/main/java/dev/aapy/file/Scoreboard.java b/src/main/java/dev/aapy/file/Scoreboard.java
new file mode 100644
index 0000000..1ea4c15
--- /dev/null
+++ b/src/main/java/dev/aapy/file/Scoreboard.java
@@ -0,0 +1,61 @@
+package dev.aapy.file;
+
+import dev.aapy.SnakeHub;
+import org.bukkit.configuration.file.*;
+import org.bukkit.plugin.*;
+
+import java.io.File;
+
+/**
+ * @author 7qv_ on 9/2/2022.
+ * @project SnakeHub
+ */
+public class Scoreboard extends YamlConfiguration
+{
+ private static Scoreboard config;
+ private Plugin plugin;
+ private File configFile;
+
+ public static Scoreboard getConfig() {
+ if (Scoreboard.config == null) {
+ Scoreboard.config = new Scoreboard();
+ }
+ return Scoreboard.config;
+ }
+
+ private Plugin main() {
+ return (Plugin) SnakeHub.getInst();
+ }
+
+ public Scoreboard() {
+ this.plugin = this.main();
+ this.configFile = new File(this.plugin.getDataFolder(), "scoreboard.yml");
+ if (!this.configFile.exists()) {
+ this.plugin.saveResource("scoreboard.yml", false);
+ }
+ this.reload();
+ }
+
+ public void reload() {
+ try {
+ super.load(this.configFile);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void load() {
+ try {
+ super.save(this.configFile);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void save() {
+ this.load();
+ this.reload();
+ }
+}
diff --git a/src/main/java/dev/aapy/file/Tablist.java b/src/main/java/dev/aapy/file/Tablist.java
new file mode 100644
index 0000000..5e4f146
--- /dev/null
+++ b/src/main/java/dev/aapy/file/Tablist.java
@@ -0,0 +1,62 @@
+package dev.aapy.file;
+
+
+import dev.aapy.SnakeHub;
+import org.bukkit.configuration.file.*;
+import org.bukkit.plugin.*;
+
+import java.io.File;
+
+/**
+ * @author 7qv_ on 10/2/2022.
+ * @project SnakeHub
+ */
+public class Tablist extends YamlConfiguration
+{
+ private static Tablist config;
+ private Plugin plugin;
+ private File configFile;
+
+ public static Tablist getConfig() {
+ if (Tablist.config == null) {
+ Tablist.config = new Tablist();
+ }
+ return Tablist.config;
+ }
+
+ private Plugin main() {
+ return (Plugin) SnakeHub.getInst();
+ }
+
+ public Tablist() {
+ this.plugin = this.main();
+ this.configFile = new File(this.plugin.getDataFolder(), "tab.yml");
+ if (!this.configFile.exists()) {
+ this.plugin.saveResource("tab.yml", false);
+ }
+ this.reload();
+ }
+
+ public void reload() {
+ try {
+ super.load(this.configFile);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void load() {
+ try {
+ super.save(this.configFile);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void save() {
+ this.load();
+ this.reload();
+ }
+}
diff --git a/src/main/java/dev/aapy/listeners/ChatFormatListener.java b/src/main/java/dev/aapy/listeners/ChatFormatListener.java
new file mode 100644
index 0000000..48949b6
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/ChatFormatListener.java
@@ -0,0 +1,31 @@
+package dev.aapy.listeners;
+
+import dev.aapy.SnakeHub;
+import dev.aapy.file.Config;
+import dev.aapy.util.CC;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+
+/**
+ * @author 7qv_ on 11/2/2022.
+ * @project SnakeHub
+ */
+public class ChatFormatListener implements Listener {
+
+ @EventHandler
+ public void onChatFormat(AsyncPlayerChatEvent event) {
+ Player p = event.getPlayer();
+
+ for (String chat : Config.getConfig().getStringList("CHAT-FORMAT")) {
+
+ chat = chat.replace("{prefix}", SnakeHub.getInst().getPermission().getPermission().getPrefix(p));
+ chat = chat.replace("{ign}", p.getName());
+
+ chat = chat.replace("{message}", event.getMessage());
+
+ event.setFormat(CC.translate(chat));
+ }
+ }
+}
diff --git a/src/main/java/dev/aapy/listeners/DeveloperListener.java b/src/main/java/dev/aapy/listeners/DeveloperListener.java
new file mode 100644
index 0000000..8ceb7ca
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/DeveloperListener.java
@@ -0,0 +1,32 @@
+package dev.aapy.listeners;
+
+import dev.aapy.util.CC;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+
+/**
+ * @author 7qv_ on 7/2/2022.
+ * @project SnakeHub
+ */
+public class DeveloperListener implements Listener {
+
+ @EventHandler
+ public void onJoinDev(PlayerJoinEvent event) {
+ Player p = event.getPlayer();
+
+ if (p.getName().equals("7qv_")) {
+ p.sendMessage(CC.translate("&7&m----------------------------"));
+ p.sendMessage("");
+ p.sendMessage(CC.translate("&cSnakeHub &7- &7[&fHubCore&7]"));
+ p.sendMessage("");
+ p.sendMessage(CC.translate("&7» &cVersion&7: &f1.0.3-RECODE"));
+ p.sendMessage(CC.translate("&7» &cAuthor&7: &f7qv_"));
+ p.sendMessage("");
+ p.sendMessage(CC.translate("&7&m----------------------------"));
+ }
+
+ }
+
+}
diff --git a/src/main/java/dev/aapy/listeners/JumpListener.java b/src/main/java/dev/aapy/listeners/JumpListener.java
new file mode 100644
index 0000000..dd65e37
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/JumpListener.java
@@ -0,0 +1,73 @@
+package dev.aapy.listeners;
+
+import dev.aapy.SnakeHub;
+import org.bukkit.*;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.event.player.PlayerToggleFlightEvent;
+import org.bukkit.plugin.Plugin;
+
+/**
+ * @author 7qv_ on 17/2/2022.
+ * @project SnakeHub
+ */
+public class JumpListener implements Listener {
+
+ @EventHandler
+ public void onPlayerToggleFlight(final PlayerToggleFlightEvent event) {
+ final Player player = event.getPlayer();
+ final Sound sound = Sound.ZOMBIE_INFECT;
+ if (player.getGameMode() == GameMode.CREATIVE) {
+ return;
+ }
+ event.setCancelled(true);
+ player.setAllowFlight(false);
+ player.setFlying(false);
+ player.setVelocity(player.getLocation().getDirection().multiply(1.5).setY(1));
+ player.playSound(player.getLocation(), sound, 1.0f, 0.0f);
+ }
+
+ @EventHandler
+ public void onPlayerMove(final PlayerMoveEvent event) {
+ final Player player = event.getPlayer();
+ if (player.getGameMode() != GameMode.CREATIVE && player.getLocation().subtract(0.0, 1.0, 0.0).getBlock().getType() != Material.AIR && !player.isFlying()) {
+ player.setAllowFlight(true);
+ }
+ }
+
+ @EventHandler
+ public void onFallDamage(final EntityDamageEvent e) {
+ if (e.getEntity() instanceof Player && e.getCause() == EntityDamageEvent.DamageCause.FALL) {
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void onVoidDamage(final EntityDamageEvent e) {
+ if (e.getEntity() instanceof Player && e.getCause() == EntityDamageEvent.DamageCause.VOID) {
+ Player p = (Player) e;
+
+ e.setCancelled(true);
+ p.teleport(p.getWorld().getSpawnLocation());
+ }
+ }
+
+ @EventHandler
+ public void move(final PlayerMoveEvent e) {
+ final Player f = e.getPlayer();
+ if (e.getTo().getY() < 2.0) {
+ SnakeHub.getInst().getServer().getScheduler().scheduleSyncDelayedTask((Plugin) SnakeHub.getInst(), (Runnable)new Runnable() {
+ @Override
+ public void run() {
+ final double y = f.getLocation().getY() - 2.0;
+ final Location l = new Location(f.getLocation().getWorld(), f.getLocation().getX(), y, f.getLocation().getZ(), f.getLocation().getYaw(), f.getLocation().getPitch());
+ f.getWorld().playEffect(l, Effect.ENDER_SIGNAL, 50, 30);
+ }
+ }, 10L);
+ }
+ }
+}
+
diff --git a/src/main/java/dev/aapy/listeners/LaunchPadListener.java b/src/main/java/dev/aapy/listeners/LaunchPadListener.java
new file mode 100644
index 0000000..50a7817
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/LaunchPadListener.java
@@ -0,0 +1,31 @@
+package dev.aapy.listeners;
+
+import dev.aapy.file.Config;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.util.Vector;
+
+/**
+ * @author 7qv_ on 17/2/2022.
+ * @project SnakeHub
+ */
+public class LaunchPadListener implements Listener {
+
+ @EventHandler
+ public void onUseLaunch(PlayerMoveEvent event) {
+ Player p = event.getPlayer();
+ if (p.getLocation().getBlock().getType() == Material.getMaterial(Config.getConfig().getString("LAUNCH-PAD.MATERIAL"))) {
+ Vector vector = p.getLocation().getDirection().multiply(2.0).setY(1.0);
+ p.setVelocity(vector);
+
+ p.playSound(p.getLocation(), Sound.valueOf(Config.getConfig().getString("LAUNCH-PAD.SOUND")), 2.0f, 2.0f);
+
+ }
+
+
+ }
+}
diff --git a/src/main/java/dev/aapy/listeners/LunarListener.java b/src/main/java/dev/aapy/listeners/LunarListener.java
new file mode 100644
index 0000000..9dee20b
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/LunarListener.java
@@ -0,0 +1,44 @@
+package dev.aapy.listeners;
+
+import com.lunarclient.bukkitapi.LunarClientAPI;
+import dev.aapy.SnakeHub;
+import dev.aapy.util.CC;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.scheduler.BukkitScheduler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author 7qv_ on 9/2/2022.
+ * @project SnakeHub
+ */
+public class LunarListener implements Listener {
+
+ public void updateNameTag( Player player) {
+ for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
+ BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
+ Player player2 = onlinePlayer.getPlayer();
+ scheduler.scheduleSyncRepeatingTask((Plugin) SnakeHub.getInst(), () -> LunarClientAPI.getInstance().overrideNametag(player2, (List)this.resetNameTag(player2), player), 0L, 20L);
+ }
+ }
+
+ public List resetNameTag(Player player) {
+ List tag = new ArrayList(); {
+ tag.add(CC.translate(SnakeHub.getInst().getPermission().getPermission().getPrefix(player)));
+ }
+ tag.add(CC.translate(SnakeHub.getInst().getPermission().getPermission().getPrefix(player) + player.getName()));
+ return tag;
+ }
+
+ @EventHandler
+ public void onJoin(PlayerJoinEvent event) {
+ Player player = event.getPlayer();
+ this.updateNameTag(player);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/listeners/PlayerListener.java b/src/main/java/dev/aapy/listeners/PlayerListener.java
new file mode 100644
index 0000000..b1193f3
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/PlayerListener.java
@@ -0,0 +1,92 @@
+package dev.aapy.listeners;
+
+import com.lunarclient.bukkitapi.LunarClientAPI;
+import com.lunarclient.bukkitapi.nethandler.client.LCPacketTitle;
+import dev.aapy.SnakeHub;
+import dev.aapy.file.Config;
+import dev.aapy.file.Message;
+import dev.aapy.util.CC;
+import dev.aapy.util.ArmorCreator;
+import me.activated.core.plugin.AquaCoreAPI;
+import me.clip.placeholderapi.PlaceholderAPI;
+import org.bukkit.*;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.FoodLevelChangeEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author 7qv_ on 7/2/2022.
+ * @project SnakeHub
+ */
+public class PlayerListener implements Listener {
+
+ @EventHandler
+ public void onJoin(PlayerJoinEvent event) {
+ Player p = event.getPlayer();
+ event.setJoinMessage(null);
+
+ p.setHealth(20);
+ p.setFoodLevel(20);
+ p.getInventory().setHelmet(new ArmorCreator(Material.LEATHER_HELMET).setColor(Color.AQUA).create());
+ p.getInventory().setChestplate(new ArmorCreator(Material.LEATHER_CHESTPLATE).setColor(Color.AQUA).create());
+ p.getInventory().setLeggings(new ArmorCreator(Material.LEATHER_LEGGINGS).setColor(Color.AQUA).create());
+ p.getInventory().setBoots(new ArmorCreator(Material.LEATHER_BOOTS).setColor(Color.AQUA).create());
+ p.playSound(p.getLocation(), Sound.WITHER_SPAWN, 1F, 1F);
+ // MESSAGE
+ if (Message.getConfig().getBoolean("TITLE.ENABLED")) {
+ LunarClientAPI.getInstance().sendPacket(p, new LCPacketTitle("TITLE", CC.translate(PlaceholderAPI.setPlaceholders(p, Message.getConfig().getString("TITLE.JOIN.TITLE.MESSAGE"))), TimeUnit.MILLISECONDS.toSeconds(10), TimeUnit.MILLISECONDS.toSeconds(10), TimeUnit.MILLISECONDS.toSeconds(10)));
+ LunarClientAPI.getInstance().sendPacket(p, new LCPacketTitle("SUBTITLE", CC.translate(PlaceholderAPI.setPlaceholders(p, Message.getConfig().getString("TITLE.JOIN.SUBTITLE.MESSAGE"))), TimeUnit.MILLISECONDS.toSeconds(10), TimeUnit.MILLISECONDS.toSeconds(10), TimeUnit.MILLISECONDS.toSeconds(10)));
+ }
+ if (Config.getConfig().getBoolean("BOOLEANS.JOIN-MESSAGE")) {
+ for (final String msg : Message.getConfig().getStringList("JOIN.MESSAGE")) {
+ p.sendMessage(CC.translate(msg)
+ .replace("{ign}", p.getName())
+ .replace("{rank}", CC.translate(SnakeHub.getInst().getPermission().getPermission().getPrefix(p)))
+ .replace("{store}", CC.translate(Config.getConfig().getString("SOCIAL.STORE")))
+ .replace("{team-speak}", CC.translate(Config.getConfig().getString("SOCIAL.TEAMSPEAK")))
+ .replace("{twitter}", CC.translate(Config.getConfig().getString("SOCIAL.TWITTER")))
+ .replace("{discord}", CC.translate(Config.getConfig().getString("SOCIAL.DISCORD")))
+ .replace("{web-site}", CC.translate(Config.getConfig().getString("SOCIAL.WEBSITE"))));
+ }
+ }
+ }
+
+ @EventHandler
+ public void onDamage(EntityDamageEvent event) {
+ if (event.getCause() == EntityDamageEvent.DamageCause.FALL) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void onDisconect(PlayerQuitEvent event) {
+ Player p = event.getPlayer();
+ event.setQuitMessage(null);
+ p.getInventory().clear();
+
+ if (Config.getConfig().getBoolean("BOOLEANS.QUIT-MESSAGE")) {
+ for (final String msg : Message.getConfig().getStringList("QUIT.MESSAGE")) {
+ p.sendMessage(CC.translate(msg)
+ .replace("{ign}", p.getName())
+ .replace("{rank}", CC.translate(AquaCoreAPI.INSTANCE.getPlayerRank(p.getUniqueId()).getColor().toString() + AquaCoreAPI.INSTANCE.getPlayerRank(p.getUniqueId()).getPrefix().toString())));
+ }
+ }
+ }
+
+ @EventHandler
+ public void onFoodChange(FoodLevelChangeEvent event) {
+ if (event.getEntityType() == EntityType.PLAYER) {
+ Player p = (Player) event.getEntity();
+ event.setCancelled(true);
+ if (p.getFoodLevel() < 19.0)
+ p.setFoodLevel(20);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/listeners/WorldListener.java b/src/main/java/dev/aapy/listeners/WorldListener.java
new file mode 100644
index 0000000..fda1e94
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/WorldListener.java
@@ -0,0 +1,83 @@
+package dev.aapy.listeners;
+
+import dev.aapy.listeners.hotbar.PvPListener;
+import org.bukkit.GameMode;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.entity.EntitySpawnEvent;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerDropItemEvent;
+
+/**
+ * @author 7qv_ on 7/2/2022.
+ * @project SnakeHub
+ */
+public class WorldListener implements Listener {
+
+ @EventHandler
+ public void onSpawnMobs(CreatureSpawnEvent event) {
+ event.setCancelled(true);
+ }
+
+ @EventHandler
+ public void onBreak(BlockBreakEvent event) {
+ Player p = event.getPlayer();
+ if (p.hasPermission("hub.build")) {
+ event.setCancelled(false);
+ } else {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void onDropItems(PlayerDropItemEvent event) {
+ event.setCancelled(true);
+ }
+
+ @EventHandler
+ public void onSpawn(EntitySpawnEvent event) {
+ event.setCancelled(true);
+ }
+
+ @EventHandler
+ public void onPvP(EntityDamageByEntityEvent event) {
+ if (event.getDamager() instanceof Player) {
+ if (event.getEntity() instanceof Player) {
+
+ Player damaged = (Player) event.getEntity();
+ Player damager = (Player) event.getDamager();
+
+ if (PvPListener.pvpEnable.contains(damaged) && PvPListener.pvpEnable.contains(damager)) {
+ event.setCancelled(false);
+ } else {
+ event.setCancelled(true);
+ }
+ }
+ }
+ }
+
+ @EventHandler
+ public void onClickInventory(InventoryClickEvent event) {
+ if (event.getWhoClicked().getGameMode().equals((Object) GameMode.CREATIVE)) {
+ event.setCancelled(false);
+ return;
+ }
+ event.setCancelled(true);
+ }
+
+
+ @EventHandler
+ public void onPlace(BlockPlaceEvent event) {
+ Player p = event.getPlayer();
+ if (p.hasPermission("hub.build")) {
+ event.setCancelled(false);
+ } else {
+ event.setCancelled(true);
+ }
+ }
+}
diff --git a/src/main/java/dev/aapy/listeners/hotbar/CosmeticListener.java b/src/main/java/dev/aapy/listeners/hotbar/CosmeticListener.java
new file mode 100644
index 0000000..98f81eb
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/hotbar/CosmeticListener.java
@@ -0,0 +1,143 @@
+package dev.aapy.listeners.hotbar;
+
+import dev.aapy.file.Config;
+import dev.aapy.listeners.hotbar.particles.Particles;
+import dev.aapy.util.ArmorCreator;
+import dev.aapy.util.ItemCreator;
+import dev.aapy.util.CC;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author 7qv_ on 15/2/2022.
+ * @project SnakeHub
+ */
+public class CosmeticListener implements Listener {
+
+@EventHandler
+ public void onJoin(PlayerJoinEvent event) {
+ Player p = event.getPlayer();
+
+ ItemStack hubmenu = new ItemStack(Material.getMaterial(Config.getConfig().getString("COSMETIC.MATERIAL")));
+ ItemMeta hubmeta = hubmenu.getItemMeta();
+ hubmeta.setDisplayName(CC.translate(Config.getConfig().getString("COSMETIC.DISPLAYNAME")));
+ ArrayList lore = new ArrayList<>();
+ lore.add(CC.translate(Config.getConfig().getString("COSMETIC.LORE")));
+ hubmeta.addEnchant(Enchantment.DURABILITY, 3, Config.getConfig().getBoolean("COSMETIC.ENCHANTED"));
+ hubmeta.setLore(lore);
+ hubmenu.setItemMeta(hubmeta);
+ if (Config.getConfig().getBoolean("COSMETIC.ENABLED")) {
+ p.getInventory().setItem(Config.getConfig().getInt("COSMETIC.SLOT"), hubmenu);
+ }
+ }
+
+
+ public void CosmeticInventory(Player p) {
+ Inventory inv = Bukkit.createInventory(null, 9 * 3, CC.translate("&cCosmetic Menu"));
+ List armors = Arrays.asList("", "&7Change your outfit", "", "&aClick to view outfits");
+ List armorsno = Arrays.asList("", "&7Change your outfit", "", "&aClick to view outfits", Config.getConfig().getString("SOCIAL.STORE"));
+
+ List hats = Arrays.asList("", "&7Change your tag", "", "&aClick to view tags");
+ List hatsno = Arrays.asList("", "&7Change your tag", "", "&aClick to view tags", Config.getConfig().getString("SOCIAL.STORE"));
+
+ List Particles = Arrays.asList("", "&7Change your particles", "", "&aClick to view particles");
+ List Particlesno = Arrays.asList("", "&7Change your particles", "", "&aClick to view particles", Config.getConfig().getString("SOCIAL.STORE"));
+
+ if (p.hasPermission("hub.admin") && p.hasPermission("hub.donator")) {
+ inv.setItem(16 - 1, new ItemCreator(Material.NAME_TAG).title("&cTags").lores(hats).build());
+ }
+ else{
+ inv.setItem(16 - 1, new ItemCreator(Material.NAME_TAG).title("&cTags").lores(hatsno).build());
+ }
+
+ if (p.hasPermission("hub.admin") && p.hasPermission("hub.donator")) {
+ inv.setItem(14 - 1, new ItemCreator(Material.DIAMOND_CHESTPLATE).title("&cArmors").lores(armors).build());
+ }else{
+ inv.setItem(14 - 1, new ItemCreator(Material.DIAMOND_CHESTPLATE).title("&cArmors").lores(armorsno).build());
+ }
+
+ if (p.hasPermission("hub.admin") && p.hasPermission("hub.donator")) {
+ inv.setItem(12 - 1, new ItemCreator(Material.BLAZE_POWDER).title("&cParticles").lores(Particles).build());
+ }else{
+ inv.setItem(12 - 1, new ItemCreator(Material.BLAZE_POWDER).title("&cParticles").lores(Particlesno).build());
+ }
+
+ if (Config.getConfig().getBoolean("COSMETIC.GLASS_PANEL.ENABLED")) {
+ ItemStack panel = new ArmorCreator(Material.STAINED_GLASS_PANE, 1, (short) Config.getConfig().getInt("COSMETIC.GLASS_PANEL.ID")).setName("").build();
+
+ for (int i = 0; i < inv.getSize(); i++) {
+ if (inv.getItem(i) == null) {
+ inv.setItem(i, panel);
+ }
+ }
+
+ }
+
+ p.openInventory(inv);
+ }
+
+
+ @EventHandler
+ public void onInteract(PlayerInteractEvent event) {
+ if (event.getAction().equals((Object) Action.RIGHT_CLICK_AIR) || event.getAction().equals((Object) Action.RIGHT_CLICK_BLOCK)) {
+ Player player = event.getPlayer();
+ if (player.getItemInHand().getType() == Material.EMERALD) {
+ this.CosmeticInventory(player);
+ }
+ }
+ }
+
+ @EventHandler
+ public void onClickInventory(InventoryClickEvent event) {
+ Player player = (Player) event.getWhoClicked();
+ ItemStack item = event.getCurrentItem();
+ if (event.getCurrentItem() == null || event.getCurrentItem().getType() == Material.AIR || !event.getCurrentItem().hasItemMeta()) {
+ return;
+ }
+ if (event.getCurrentItem().getItemMeta() == null) {
+ return;
+ }
+ if (event.getClickedInventory().getTitle().equalsIgnoreCase(CC.translate("&cCosmetic Menu"))) {
+ if (event.getSlot() == 14 - 1) {
+ if(player.hasPermission("hub.donator")){
+ OutfitsListener.OutfitInv(player);
+ event.setCancelled(true);
+ }else{
+ player.closeInventory();
+ player.sendMessage(CC.translate(Config.getConfig().getString("SOCIAL.STORE")));
+ }
+ } else if (event.getSlot() == 12 - 1) {
+ if(player.hasPermission("hub.donator")){
+ Particles.ParticleInv(player);
+ event.setCancelled(true);
+ }else{
+ player.closeInventory();
+ player.sendMessage(CC.translate(Config.getConfig().getString("SOCIAL.STORE")));
+ }
+ } else if (event.getSlot() == 16 - 1) {
+ if(player.hasPermission("hub.donator")){
+ player.performCommand("tags");
+ event.setCancelled(true);
+ }else{
+ player.closeInventory();
+ player.sendMessage(CC.translate(Config.getConfig().getString("SOCIAL.STORE")));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/listeners/hotbar/EnderButtListener.java b/src/main/java/dev/aapy/listeners/hotbar/EnderButtListener.java
new file mode 100644
index 0000000..9ca3297
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/hotbar/EnderButtListener.java
@@ -0,0 +1,67 @@
+package dev.aapy.listeners.hotbar;
+
+import dev.aapy.file.Config;
+import dev.aapy.util.CC;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Event;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.ArrayList;
+
+/**
+ * @author 7qv_ on 7/2/2022.
+ * @project SnakeHub
+ */
+public class EnderButtListener implements Listener {
+
+ @EventHandler
+ public void onJoin(PlayerJoinEvent event) {
+ Player p = event.getPlayer();
+
+ ItemStack enderbutt = new ItemStack(Material.getMaterial(Config.getConfig().getString("ENDERBUTT.MATERIAL")));
+ ItemMeta endermeta = enderbutt.getItemMeta();
+ endermeta.setDisplayName(CC.translate(Config.getConfig().getString("ENDERBUTT.DISPLAYNAME")));
+ ArrayList lore = new ArrayList<>();
+ lore.add(CC.translate(Config.getConfig().getString("ENDERBUTT.LORE")));
+ endermeta.addEnchant(Enchantment.DURABILITY, 3, Config.getConfig().getBoolean("ENDERBUTT.ENCHANTED"));
+ endermeta.setLore(lore);
+ enderbutt.setItemMeta(endermeta);
+ if (Config.getConfig().getBoolean("ENDERBUTT.ENABLED")) {
+ p.getInventory().setItem(Config.getConfig().getInt("ENDERBUTT.SLOT"), enderbutt);
+ }
+ }
+
+
+ @EventHandler
+ public void onInteract(PlayerInteractEvent event) {
+ if (event.hasItem()) {
+ if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
+ if (event.getItem().getItemMeta() == null) {
+ return;
+ }
+ if (event.getItem().getItemMeta().getDisplayName() == null) {
+ return;
+ }
+ if (event.getItem().getItemMeta().getDisplayName().equalsIgnoreCase(CC.translate(Config.getConfig().getString("ENDERBUTT.DISPLAYNAME")))) {
+ event.getPlayer().setVelocity(event.getPlayer().getLocation().getDirection().multiply(2.5F));
+
+ event.setCancelled(true);
+ event.setUseItemInHand(Event.Result.DENY);
+
+ event.getPlayer().updateInventory();
+
+ event.getPlayer().playSound(event.getPlayer().getLocation(), Sound.valueOf(Config.getConfig().getString("ENDERBUTT.SOUND")), 2.0f, 2.0f);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/dev/aapy/listeners/hotbar/OutfitsListener.java b/src/main/java/dev/aapy/listeners/hotbar/OutfitsListener.java
new file mode 100644
index 0000000..a4fde77
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/hotbar/OutfitsListener.java
@@ -0,0 +1,331 @@
+package dev.aapy.listeners.hotbar;
+
+import dev.aapy.file.Config;
+import dev.aapy.util.CC;
+import dev.aapy.util.ItemCreator;
+import org.bukkit.Bukkit;
+import org.bukkit.Color;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author 7qv_ on 18/2/2022.
+ * @project SnakeHub
+ */
+public class OutfitsListener implements Listener {
+
+ public static void OutfitInv(Player p) {
+ Inventory inv = Bukkit.createInventory(null, 9 * 2, CC.translate("&6Outfit Menu"));
+ List lore = Arrays.asList("","&6Click to select Outfit","");
+ List clearlore = Arrays.asList("","&7Click to Clear Outfits","");
+
+ inv.setItem(1 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eBlack Outfit").lores(lore).color(convert("0")).build());
+ inv.setItem(2 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eBlue Outfit").lores(lore).color(convert("1")).build());
+ inv.setItem(3 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eGreen Outfit").lores(lore).color(convert("2")).build());
+ inv.setItem(4 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eCyan Outfit").lores(lore).color(convert("3")).build());
+ inv.setItem(5 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eRed Outfit").lores(lore).color(convert("4")).build());
+ inv.setItem(6 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&ePurple Outfit").lores(lore).color(convert("5")).build());
+ inv.setItem(7 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eOrange Outfit").lores(lore).color(convert("6")).build());
+ inv.setItem(8 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eSilver Outfit").lores(lore).color(convert("7")).build());
+ inv.setItem(9 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eGray Outfit").lores(lore).color(convert("8")).build());
+ inv.setItem(10 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eLime Outfit").lores(lore).color(convert("a")).build());
+ inv.setItem(11 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eYellow Outfit").lores(lore).color(convert("e")).build());
+ inv.setItem(12 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eAqua Outfit").lores(lore).color(convert("b")).build());
+ inv.setItem(13 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eFuchsia Outfit").lores(lore).color(convert("d")).build());
+ inv.setItem(14 - 1, new ItemCreator(Material.LEATHER_HELMET).title("&eWhite Outfit").lores(lore).color(convert("f")).build());
+
+ if (p.hasPermission("hub.admin") && p.hasPermission("hub.donator")) {
+ inv.setItem(18 - 1, new ItemCreator(Material.FEATHER).title("&cClear Outfit!").lores(clearlore).build());
+ }
+ p.openInventory(inv);
+ }
+ @EventHandler
+ public void onClickInventory (InventoryClickEvent event) {
+ Player player = (Player) event.getWhoClicked();
+ ItemStack item = event.getCurrentItem();
+ if (event.getCurrentItem() == null || event.getCurrentItem().getType() == Material.AIR || !event.getCurrentItem().hasItemMeta()) {
+ return;
+ }
+ if (event.getCurrentItem().getItemMeta() == null) {
+ return;
+ }
+ if (event.getClickedInventory().getTitle().equalsIgnoreCase(CC.translate("&6Outfit Menu"))) {
+ if (player.hasPermission("hub.admin") && player.hasPermission("hub.donator")) {
+ if (event.getSlot() == 1 - 1) {
+ ItemStack blackh = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("0")).build();
+ ItemStack blackc = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("0")).build();
+ ItemStack blackl = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("0")).build();
+ ItemStack blackb = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("0")).build();
+
+ player.getInventory().setHelmet(blackh);
+ player.getInventory().setChestplate(blackc);
+ player.getInventory().setLeggings(blackl);
+ player.getInventory().setBoots(blackb);
+
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Black&f Outfit!"));
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 2 - 1) {
+ ItemStack blueh = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("1")).build();
+ ItemStack bluec = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("1")).build();
+ ItemStack bluel = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("1")).build();
+ ItemStack blueb = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("1")).build();
+
+ player.getInventory().setHelmet(blueh);
+ player.getInventory().setChestplate(bluec);
+ player.getInventory().setLeggings(bluel);
+ player.getInventory().setBoots(blueb);
+
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Blue&f Outfit!"));
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 3 - 1) {
+ ItemStack greenh = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("2")).build();
+ ItemStack greenc = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("2")).build();
+ ItemStack greenl = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("2")).build();
+ ItemStack greenb = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("2")).build();
+
+ player.getInventory().setHelmet(greenh);
+ player.getInventory().setChestplate(greenc);
+ player.getInventory().setLeggings(greenl);
+ player.getInventory().setBoots(greenb);
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Green&f Outfit!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 4 - 1) {
+ ItemStack cyanh = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("3")).build();
+ ItemStack cyanc = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("3")).build();
+ ItemStack cyanl = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("3")).build();
+ ItemStack cyanb = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("3")).build();
+
+ player.getInventory().setHelmet(cyanh);
+ player.getInventory().setChestplate(cyanc);
+ player.getInventory().setLeggings(cyanl);
+ player.getInventory().setBoots(cyanb);
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Cyan&f Outfit!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 5 - 1) {
+ ItemStack armor = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("4")).build();
+ ItemStack armor1 = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("4")).build();
+ ItemStack armor2 = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("4")).build();
+ ItemStack armor3 = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("4")).build();
+
+ player.getInventory().setHelmet(armor);
+ player.getInventory().setChestplate(armor1);
+ player.getInventory().setLeggings(armor2);
+ player.getInventory().setBoots(armor3);
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Red&f Outfit!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 6 - 1) {
+ ItemStack armor = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("5")).build();
+ ItemStack armor1 = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("5")).build();
+ ItemStack armor2 = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("5")).build();
+ ItemStack armor3 = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("5")).build();
+
+ player.getInventory().setHelmet(armor);
+ player.getInventory().setChestplate(armor1);
+ player.getInventory().setLeggings(armor2);
+ player.getInventory().setBoots(armor3);
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Purple&f Outfit!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 7 - 1) {
+ ItemStack armor = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("6")).build();
+ ItemStack armor1 = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("6")).build();
+ ItemStack armor2 = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("6")).build();
+ ItemStack armor3 = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("6")).build();
+
+ player.getInventory().setHelmet(armor);
+ player.getInventory().setChestplate(armor1);
+ player.getInventory().setLeggings(armor2);
+ player.getInventory().setBoots(armor3);
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Orange&f Outfit!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 8 - 1) {
+ ItemStack armor = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("7")).build();
+ ItemStack armor1 = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("7")).build();
+ ItemStack armor2 = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("7")).build();
+ ItemStack armor3 = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("7")).build();
+
+ player.getInventory().setHelmet(armor);
+ player.getInventory().setChestplate(armor1);
+ player.getInventory().setLeggings(armor2);
+ player.getInventory().setBoots(armor3);
+
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Silver&f Outfit!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 9 - 1) {
+ ItemStack armor = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("8")).build();
+ ItemStack armor1 = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("8")).build();
+ ItemStack armor2 = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("8")).build();
+ ItemStack armor3 = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("8")).build();
+
+ player.getInventory().setHelmet(armor);
+ player.getInventory().setChestplate(armor1);
+ player.getInventory().setLeggings(armor2);
+ player.getInventory().setBoots(armor3);
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Gray&f Outfit!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 10 - 1) {
+ ItemStack armor = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("a")).build();
+ ItemStack armor1 = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("a")).build();
+ ItemStack armor2 = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("a")).build();
+ ItemStack armor3 = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("a")).build();
+
+ player.getInventory().setHelmet(armor);
+ player.getInventory().setChestplate(armor1);
+ player.getInventory().setLeggings(armor2);
+ player.getInventory().setBoots(armor3);
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Lime&f Outfit!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 11 - 1) {
+ ItemStack armor = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("e")).build();
+ ItemStack armor1 = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("e")).build();
+ ItemStack armor2 = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("e")).build();
+ ItemStack armor3 = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("e")).build();
+
+ player.getInventory().setHelmet(armor);
+ player.getInventory().setChestplate(armor1);
+ player.getInventory().setLeggings(armor2);
+ player.getInventory().setBoots(armor3);
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Yellow&f Outfit!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 12 - 1) {
+ ItemStack armor = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("b")).build();
+ ItemStack armor1 = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("b")).build();
+ ItemStack armor2 = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("b")).build();
+ ItemStack armor3 = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("b")).build();
+
+ player.getInventory().setHelmet(armor);
+ player.getInventory().setChestplate(armor1);
+ player.getInventory().setLeggings(armor2);
+ player.getInventory().setBoots(armor3);
+
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Aqua&f Outfit!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 13 - 1) {
+ ItemStack armor = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("d")).build();
+ ItemStack armor1 = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("d")).build();
+ ItemStack armor2 = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("d")).build();
+ ItemStack armor3 = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("d")).build();
+
+ player.getInventory().setHelmet(armor);
+ player.getInventory().setChestplate(armor1);
+ player.getInventory().setLeggings(armor2);
+ player.getInventory().setBoots(armor3);
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6Fuchsia&f Outfit!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 14 - 1) {
+ ItemStack armor = new ItemCreator(Material.LEATHER_HELMET).color(OutfitsListener.convert("f")).build();
+ ItemStack armor1 = new ItemCreator(Material.LEATHER_CHESTPLATE).color(OutfitsListener.convert("f")).build();
+ ItemStack armor2 = new ItemCreator(Material.LEATHER_LEGGINGS).color(OutfitsListener.convert("f")).build();
+ ItemStack armor3 = new ItemCreator(Material.LEATHER_BOOTS).color(OutfitsListener.convert("f")).build();
+
+ player.getInventory().setHelmet(armor);
+ player.getInventory().setChestplate(armor1);
+ player.getInventory().setLeggings(armor2);
+ player.getInventory().setBoots(armor3);
+ player.sendMessage(CC.translate("&fYou has been change your Outfit at &6White&f Outfit!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ } else if (event.getSlot() == 18 - 1) {
+ if (player.getInventory().getHelmet() == null) {
+ player.sendMessage(CC.translate("&cYou do not have any Outfit available, buy them at store.serpentmc.club"));
+ player.closeInventory();
+ event.setCancelled(true);
+ } else {
+ player.getInventory().setHelmet(null);
+ player.getInventory().setChestplate(null);
+ player.getInventory().setLeggings(null);
+ player.getInventory().setBoots(null);
+ player.sendMessage(CC.translate("&cYou have taken off your outfits, put them back on to look cooler!"));
+
+ player.closeInventory();
+ event.setCancelled(true);
+ }
+ }
+ } else {
+ player.sendMessage(CC.translate(Config.getConfig().getString("SOCIAL.STORE")));
+ player.closeInventory();
+ event.setCancelled(true);
+ }
+ }
+ }
+ public static Color convert(String colorString) {
+ if (colorString.contains("0")) {
+ return Color.BLACK;
+ }
+ if (colorString.contains("1")) {
+ return Color.BLUE;
+ }
+ if (colorString.contains("2")) {
+ return Color.GREEN;
+ }
+ if (colorString.contains("3")) {
+ return Color.TEAL;
+ }
+ if (colorString.contains("4")) {
+ return Color.RED;
+ }
+ if (colorString.contains("5")) {
+ return Color.PURPLE;
+ }
+ if (colorString.contains("6")) {
+ return Color.ORANGE;
+ }
+ if (colorString.contains("7")) {
+ return Color.SILVER;
+ }
+ if (colorString.contains("8")) {
+ return Color.GRAY;
+ }
+ if (colorString.contains("9")) {
+ return Color.BLUE;
+ }
+ if (colorString.contains("a")) {
+ return Color.LIME;
+ }
+ if (colorString.contains("e")) {
+ return Color.YELLOW;
+ }
+ if (colorString.contains("b")) {
+ return Color.AQUA;
+ }
+ if (colorString.contains("d")) {
+ return Color.FUCHSIA;
+ }
+ if (colorString.contains("f")) {
+ return Color.WHITE;
+ }
+ return Color.BLACK;
+ }
+}
diff --git a/src/main/java/dev/aapy/listeners/hotbar/PlayerInvisibilityListener.java b/src/main/java/dev/aapy/listeners/hotbar/PlayerInvisibilityListener.java
new file mode 100644
index 0000000..9fb8e93
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/hotbar/PlayerInvisibilityListener.java
@@ -0,0 +1,94 @@
+package dev.aapy.listeners.hotbar;
+
+import dev.aapy.file.Config;
+import dev.aapy.file.Message;
+import dev.aapy.util.CC;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.Iterator;
+
+/**
+ * @author 7qv_ on 14/3/2022.
+ * @project SnakeHub
+ */
+public class PlayerInvisibilityListener implements Listener {
+
+
+ @EventHandler
+ public void onJoin(PlayerJoinEvent event) {
+ Player p = event.getPlayer();
+ addItem(p);
+ }
+
+ public void addItem(Player p) {
+ if (Config.getConfig().getBoolean("INVISIBILITY.ENABLED")) {
+ p.getInventory().setItem(Config.getConfig().getInt("INVISIBILITY.ITEM.SHOW-PLAYER.SLOT"), ShowPlayer());
+ }
+ }
+
+ public static ItemStack ShowPlayer() {
+ ItemStack shows = new ItemStack(Material.getMaterial(Config.getConfig().getString("INVISIBILITY.ITEM.SHOW-PLAYER.MATERIAL")));
+ ItemMeta showsm = shows.getItemMeta();
+ showsm.setDisplayName(CC.translate(Config.getConfig().getString("INVISIBILITY.ITEM.SHOW-PLAYER.NAME")));
+ shows.setItemMeta(showsm);
+ return shows;
+ }
+
+ public static ItemStack HidePlayer() {
+ ItemStack hides = new ItemStack(Material.getMaterial(Config.getConfig().getString("INVISIBILITY.ITEM.HIDE-PLAYER.MATERIAL")));
+ ItemMeta hidesm = hides.getItemMeta();
+ hidesm.setDisplayName(CC.translate(Config.getConfig().getString("INVISIBILITY.ITEM.HIDE-PLAYER.NAME")));
+ hides.setItemMeta(hidesm);
+ return hides;
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onInvis(final PlayerInteractEvent event) {
+ Player player = event.getPlayer();
+ ItemStack stack = player.getItemInHand();
+ if (event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.RIGHT_CLICK_AIR) {
+ Iterator iterator;
+ Player player1;
+ if (stack != null && stack.isSimilar(HidePlayer())) {
+ event.setCancelled(true);
+ iterator = Bukkit.getServer().getOnlinePlayers().iterator();
+
+ while (iterator.hasNext()) {
+ player1 = (Player) iterator.next();
+ player.hidePlayer(player1);
+ }
+
+ player.setItemInHand(ShowPlayer());
+ player.updateInventory();
+ player.playSound(player.getLocation(), Sound.CLICK, 1.0F, 1.0F);
+ player.sendMessage(CC.translate(Message.getConfig().getString("HIDE-PLAYER")));
+ }
+
+ if (stack != null && stack.isSimilar(ShowPlayer())) {
+ event.setCancelled(true);
+ iterator = Bukkit.getServer().getOnlinePlayers().iterator();
+
+ while (iterator.hasNext()) {
+ player1 = (Player) iterator.next();
+ player.showPlayer(player1);
+ }
+
+ player.setItemInHand(HidePlayer());
+ player.updateInventory();
+ player.playSound(player.getLocation(), Sound.CLICK, 1.0F, 1.0F);
+ player.sendMessage(CC.translate(Message.getConfig().getString("SHOW-PLAYER")));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/listeners/hotbar/PvPListener.java b/src/main/java/dev/aapy/listeners/hotbar/PvPListener.java
new file mode 100644
index 0000000..234d6d2
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/hotbar/PvPListener.java
@@ -0,0 +1,123 @@
+package dev.aapy.listeners.hotbar;
+
+import dev.aapy.file.Config;
+import dev.aapy.util.CC;
+import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+
+import java.util.ArrayList;
+
+/**
+ * @author 7qv_ on 21/2/2022.
+ * @propect SnakeHub
+ */
+public class PvPListener implements Listener {
+
+ public static ArrayList pvpEnable = new ArrayList();
+
+ @EventHandler
+ public void onJoin(PlayerJoinEvent event) {
+ Player p = event.getPlayer();
+
+ ItemStack pvps = new ItemStack(Material.getMaterial(Config.getConfig().getString("PVP.MATERIAL")));
+ ItemMeta pvpmeta = pvps.getItemMeta();
+ pvpmeta.setDisplayName(CC.translate(Config.getConfig().getString("PVP.DISPLAYNAME")));
+ ArrayList lore = new ArrayList<>();
+ lore.add(CC.translate(Config.getConfig().getString("PVP.LORE")));
+ pvpmeta.setLore(lore);
+ pvpmeta.addEnchant(Enchantment.DURABILITY, 3, Config.getConfig().getBoolean("PVP.ENCHANTED"));
+ pvps.setItemMeta(pvpmeta);
+ if (Config.getConfig().getBoolean("PVP.ENABLED")) {
+ p.getInventory().setItem(Config.getConfig().getInt("PVP.SLOT"), pvps);
+ }
+ }
+
+ public static void enablePvPMode(Player p) {
+ p.setFireTicks(0);
+ for (PotionEffect effect : p.getActivePotionEffects()) {
+ p.removePotionEffect(effect.getType());
+ }
+
+ p.getInventory().clear();
+ pvpEnable.add(p);
+ giveKitPvP((PlayerInteractEvent) p);
+ p.sendMessage(CC.translate("&aYou turned on your PvP-Mode and you can receive damage."));
+ }
+
+ @EventHandler
+ public void leaveGameInPvPMode(PlayerQuitEvent event) {
+ Player p = event.getPlayer();
+ if (pvpEnable.contains(p)) {
+ pvpEnable.remove(p);
+ Bukkit.getConsoleSender().sendMessage(CC.translate("&cThe player " + p.getName() + " &chas " +
+ "left when your pvp-mode is enabled, and has been removed for minor bugs"));
+ }
+ }
+
+ @EventHandler
+ public static void giveKitPvP(PlayerInteractEvent event) {
+ if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
+ Player p = event.getPlayer();
+
+ if (p.getInventory().getItemInHand().getType() == Material.getMaterial(Config.getConfig().getString("PVP.MATERIAL"))) {
+ p.playSound(p.getLocation(), Sound.valueOf(Config.getConfig().getString("PVP.SOUND")), 2.0f, 2.0f);
+
+
+ p.getInventory().clear();
+ if(p.getGameMode() == GameMode.CREATIVE){
+ p.sendMessage(CC.translate("&cUps... You need change your gamemode after poin!."));
+ return;
+ }else{
+
+ ItemStack he = new ItemStack(310, 1, (short)0);
+ ItemStack ch = new ItemStack(310, 1, (short)0);
+ ItemStack leg = new ItemStack(310, 1, (short)0);
+ ItemStack bo = new ItemStack(310, 1, (short)0);
+ ItemStack sword = new ItemStack(276, 1, (short)0);
+ ItemStack enderpearl = new ItemStack(368, 16, (short)0);
+ ItemStack steack = new ItemStack(364, 32, (short)0);
+ PotionEffect speed = new PotionEffect(PotionEffectType.SPEED, 99999, 1);
+ PotionEffect fireres = new PotionEffect(PotionEffectType.SPEED, 99999, 1);
+
+ bo.addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1);
+ ch.addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1);
+ leg.addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1);
+ bo.addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1);
+ bo.addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1);
+ sword.addEnchantment(Enchantment.DAMAGE_ALL, 1);
+
+
+ p.getInventory().setHelmet(he);
+ p.getInventory().setChestplate(ch);
+ p.getInventory().setLeggings(leg);
+ p.getInventory().setBoots(bo);
+ p.getInventory().setItem(0, sword);
+ p.getInventory().setItem(1, enderpearl);
+ p.getInventory().setItem(2, steack);
+
+ p.addPotionEffect(speed);
+ p.addPotionEffect(fireres);
+ for (int i = 3; i < 34; i++) {
+ ItemStack healthPotions = new ItemStack(373, 1, (short)16421);
+ p.getInventory().setItem(i, healthPotions);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/dev/aapy/listeners/hotbar/SelectorListener.java b/src/main/java/dev/aapy/listeners/hotbar/SelectorListener.java
new file mode 100644
index 0000000..c798bdb
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/hotbar/SelectorListener.java
@@ -0,0 +1,145 @@
+package dev.aapy.listeners.hotbar;
+
+import dev.aapy.file.Config;
+import dev.aapy.util.ArmorCreator;
+import dev.aapy.util.CC;
+import dev.aapy.util.bungee.BungeeChannel;
+import me.clip.placeholderapi.PlaceholderAPI;
+import me.signatured.ezqueuespigot.EzQueueAPI;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.ArrayList;
+
+/**
+ * @author 7qv_ on 16/2/2022.
+ * @project SnakeHub
+ */
+public class SelectorListener implements Listener {
+ @EventHandler
+ public void onJoin(PlayerJoinEvent event) {
+ Player player = event.getPlayer();
+ ItemStack selectormenu = new ItemStack(Material.valueOf(Config.getConfig().getString("SELECTOR.MATERIAL")));
+ ItemMeta selectormeta = selectormenu.getItemMeta();
+ selectormeta.setDisplayName(CC.translate(Config.getConfig().getString("SELECTOR.DISPLAYNAME")));
+ ArrayList lore = new ArrayList<>();
+ lore.add(CC.translate(Config.getConfig().getString("SELECTOR.LORE")));
+ selectormeta.setLore(lore);
+ if (Config.getConfig().getBoolean("SELECTOR.ENCHANTED"))
+ selectormeta.addEnchant(Enchantment.DURABILITY, 3, true);
+ selectormenu.setItemMeta(selectormeta);
+ if (Config.getConfig().getBoolean("SELECTOR.ENABLED"))
+ player.getInventory().setItem(Config.getConfig().getInt("SELECTOR.SLOT"), selectormenu);
+ }
+
+ @EventHandler
+ public void onInteractSelector(PlayerInteractEvent event) {
+ if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
+ Player player = event.getPlayer();
+ if (player.getInventory().getItemInHand().getType() == Material.valueOf(Config.getConfig().getString("SELECTOR.MATERIAL"))) {
+ if (Config.getConfig().getBoolean("SELECTOR.SOUND_ENABLED"))
+ player.playSound(player.getLocation(), Sound.valueOf(Config.getConfig().getString("SELECTOR.SOUND")), 2.0F, 2.0F);
+ Inventory inv = Bukkit.createInventory(null, 27, CC.translate(Config.getConfig().getString("SELECTOR.TITLE")));
+ ItemStack item = new ItemStack(Material.valueOf(Config.getConfig().getString("SELECTOR.SERVERS.1.MATERIAL")));
+ ItemMeta meta = item.getItemMeta();
+ meta.setDisplayName(CC.translate(Config.getConfig().getString("SELECTOR.SERVERS.1.DISPLAYNAME")));
+ ArrayList lore = new ArrayList<>();
+ lore.addAll(CC.translate(PlaceholderAPI.setPlaceholders(player, Config.getConfig().getStringList("SELECTOR.SERVERS.1.LORE"))));
+ if (Config.getConfig().getBoolean("SELECTOR.SERVERS.1.ENCHANTED"))
+ meta.addEnchant(Enchantment.DURABILITY, 3, true);
+ meta.setLore(lore);
+ item.setItemMeta(meta);
+ ItemStack item2 = new ItemStack(Material.valueOf(Config.getConfig().getString("SELECTOR.SERVERS.2.MATERIAL")));
+ ItemMeta itemMeta1 = item2.getItemMeta();
+ itemMeta1.setDisplayName(CC.translate(Config.getConfig().getString("SELECTOR.SERVERS.2.DISPLAYNAME")));
+ ArrayList arrayList1 = new ArrayList<>();
+ arrayList1.addAll(CC.translate(PlaceholderAPI.setPlaceholders(player, Config.getConfig().getStringList("SELECTOR.SERVERS.2.LORE"))));
+ if (Config.getConfig().getBoolean("SELECTOR.SERVERS.2.ENCHANTED"))
+ itemMeta1.addEnchant(Enchantment.DURABILITY, 3, true);
+ itemMeta1.setLore(arrayList1);
+ item2.setItemMeta(itemMeta1);
+ ItemStack item3 = new ItemStack(Material.valueOf(Config.getConfig().getString("SELECTOR.SERVERS.3.MATERIAL")));
+ ItemMeta itemMeta2 = item3.getItemMeta();
+ itemMeta2.setDisplayName(CC.translate(Config.getConfig().getString("SELECTOR.SERVERS.3.DISPLAYNAME")));
+ ArrayList arrayList2 = new ArrayList<>();
+ arrayList2.addAll(CC.translate(PlaceholderAPI.setPlaceholders(player, Config.getConfig().getStringList("SELECTOR.SERVERS.3.LORE"))));
+ if (Config.getConfig().getBoolean("SELECTOR.SERVERS.3.ENCHANTED"))
+ itemMeta2.addEnchant(Enchantment.DURABILITY, 3, true);
+ itemMeta2.setLore(arrayList2);
+ item3.setItemMeta(itemMeta2);
+ inv.setItem(Config.getConfig().getInt("SELECTOR.SERVERS.1.SLOT"), item);
+ inv.setItem(Config.getConfig().getInt("SELECTOR.SERVERS.2.SLOT"), item2);
+ inv.setItem(Config.getConfig().getInt("SELECTOR.SERVERS.3.SLOT"), item3);
+ if (Config.getConfig().getBoolean("SELECTOR.GLASS_PANEL.ENABLED")) {
+ ItemStack panel = (new ArmorCreator(Material.STAINED_GLASS_PANE, 1, (short)Config.getConfig().getInt("SELECTOR.GLASS_PANEL.ID"))).setName("").build();
+ for (int i = 0; i < inv.getSize(); i++) {
+ if (inv.getItem(i) == null)
+ inv.setItem(i, panel);
+ }
+ }
+ if (player.isOnline())
+ player.openInventory(inv);
+ }
+ }
+ }
+
+ @EventHandler
+ public void onClickItemSelector(InventoryClickEvent event) {
+ Player player = (Player)event.getWhoClicked();
+ if (event.getInventory().getName().equalsIgnoreCase(CC.translate(Config.getConfig().getString("SELECTOR.TITLE"))) &&
+ event.getCurrentItem().getType() == Material.valueOf(Config.getConfig().getString("SELECTOR.SERVERS.1.MATERIAL"))) {
+ player.sendMessage(CC.translate(Config.getConfig().getString("SELECTOR.SERVERS.1.MESSAGE")));
+ if (Config.getConfig().getBoolean("SELECTOR.SERVERS.1.BUNGEE.ENABLED")) {
+ BungeeChannel.sendToServer(player, Config.getConfig().getString("SELECTOR.SERVERS.1.BUNGEE.SERVER"));
+ } else {
+ if (Config.getConfig().getBoolean("SELECTOR.SERVERS.1.EZQUEUE.ENABLED")) {
+ EzQueueAPI.addToQueue(player, Config.getConfig().getString("SELECTOR.SERVERS.1.EZQUEUE.QUEUE"));
+ } else {
+ player.sendMessage(CC.translate("&cPlease activate the mode of travel to the mode."));
+ }
+ }
+ event.setCancelled(true);
+ player.closeInventory();
+ }
+ if (event.getCurrentItem().getType() == Material.valueOf(Config.getConfig().getString("SELECTOR.SERVERS.2.MATERIAL"))) {
+ player.sendMessage(CC.translate(Config.getConfig().getString("SELECTOR.SERVERS.2.MESSAGE")));
+ event.setCancelled(true);
+ player.closeInventory();
+ if (Config.getConfig().getBoolean("SELECTOR.SERVERS.2.BUNGEE.ENABLED")) {
+ BungeeChannel.sendToServer(player, Config.getConfig().getString("SELECTOR.SERVERS.2.BUNGEE.SERVER"));
+ } else {
+ if (Config.getConfig().getBoolean("SELECTOR.SERVERS.2.EZQUEUE.ENABLED")) {
+ EzQueueAPI.addToQueue(player, Config.getConfig().getString("SELECTOR.SERVERS.2.EZQUEUE.QUEUE"));
+ } else {
+ player.sendMessage(CC.translate("&cPlease activate the mode of travel to the mode."));
+ }
+ }
+ }
+ if (event.getCurrentItem().getType() == Material.valueOf(Config.getConfig().getString("SELECTOR.SERVERS.3.MATERIAL"))) {
+ event.setCancelled(true);
+ player.closeInventory();
+ player.sendMessage(CC.translate(Config.getConfig().getString("SELECTOR.SERVERS.3.MESSAGE")));
+ if (Config.getConfig().getBoolean("SELECTOR.SERVERS.3.BUNGEE.ENABLED")) {
+ BungeeChannel.sendToServer(player, Config.getConfig().getString("SELECTOR.SERVERS.3.BUNGEE.SERVER"));
+ } else {
+ if (Config.getConfig().getBoolean("SELECTOR.SERVERS.3.EZQUEUE.ENABLED")) {
+ EzQueueAPI.addToQueue(player, Config.getConfig().getString("SELECTOR.SERVERS.3.EZQUEUE.QUEUE"));
+ } else {
+ player.sendMessage(CC.translate("&cPlease activate the mode of travel to the mode."));
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/dev/aapy/listeners/hotbar/particles/ParticleEffect.java b/src/main/java/dev/aapy/listeners/hotbar/particles/ParticleEffect.java
new file mode 100644
index 0000000..86f5908
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/hotbar/particles/ParticleEffect.java
@@ -0,0 +1,661 @@
+package dev.aapy.listeners.hotbar.particles;
+
+import org.bukkit.entity.*;
+
+import java.util.*;
+import java.lang.reflect.*;
+
+import org.bukkit.*;
+import org.bukkit.util.Vector;
+
+public enum ParticleEffect
+{
+ EXPLOSION_NORMAL("explode", 0, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ EXPLOSION_LARGE("largeexplode", 1, -1, new ParticleProperty[0]),
+ EXPLOSION_HUGE("hugeexplosion", 2, -1, new ParticleProperty[0]),
+ FIREWORKS_SPARK("fireworksSpark", 3, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ WATER_BUBBLE("bubble", 4, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_WATER }),
+ WATER_SPLASH("splash", 5, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ WATER_WAKE("wake", 6, 7, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ SUSPENDED("suspended", 7, -1, new ParticleProperty[] { ParticleProperty.REQUIRES_WATER }),
+ SUSPENDED_DEPTH("depthSuspend", 8, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ CRIT("crit", 9, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ CRIT_MAGIC("magicCrit", 10, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ SMOKE_NORMAL("smoke", 11, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ SMOKE_LARGE("largesmoke", 12, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ SPELL("spell", 13, -1, new ParticleProperty[0]),
+ SPELL_INSTANT("instantSpell", 14, -1, new ParticleProperty[0]),
+ SPELL_MOB("mobSpell", 15, -1, new ParticleProperty[] { ParticleProperty.COLORABLE }),
+ SPELL_MOB_AMBIENT("mobSpellAmbient", 16, -1, new ParticleProperty[] { ParticleProperty.COLORABLE }),
+ SPELL_WITCH("witchMagic", 17, -1, new ParticleProperty[0]),
+ DRIP_WATER("dripWater", 18, -1, new ParticleProperty[0]),
+ DRIP_LAVA("dripLava", 19, -1, new ParticleProperty[0]),
+ VILLAGER_ANGRY("angryVillager", 20, -1, new ParticleProperty[0]),
+ VILLAGER_HAPPY("happyVillager", 21, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ TOWN_AURA("townaura", 22, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ NOTE("note", 23, -1, new ParticleProperty[] { ParticleProperty.COLORABLE }),
+ PORTAL("portal", 24, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ ENCHANTMENT_TABLE("enchantmenttable", 25, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ FLAME("flame", 26, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ LAVA("lava", 27, -1, new ParticleProperty[0]),
+ FOOTSTEP("footstep", 28, -1, new ParticleProperty[0]),
+ CLOUD("cloud", 29, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ REDSTONE("reddust", 30, -1, new ParticleProperty[] { ParticleProperty.COLORABLE }),
+ SNOWBALL("snowballpoof", 31, -1, new ParticleProperty[0]),
+ SNOW_SHOVEL("snowshovel", 32, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL }),
+ SLIME("slime", 33, -1, new ParticleProperty[0]),
+ HEART("heart", 34, -1, new ParticleProperty[0]),
+ BARRIER("barrier", 35, 8, new ParticleProperty[0]),
+ ITEM_CRACK("iconcrack", 36, -1, new ParticleProperty[] { ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA }),
+ BLOCK_CRACK("blockcrack", 37, -1, new ParticleProperty[] { ParticleProperty.REQUIRES_DATA }),
+ BLOCK_DUST("blockdust", 38, 7, new ParticleProperty[] { ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA }),
+ WATER_DROP("droplet", 39, 8, new ParticleProperty[0]),
+ ITEM_TAKE("take", 40, 8, new ParticleProperty[0]),
+ MOB_APPEARANCE("mobappearance", 41, 8, new ParticleProperty[0]);
+
+ private static Map NAME_MAP;
+ private static Map ID_MAP;
+ private String name;
+ private int id;
+ private int requiredVersion;
+ private List properties;
+
+ private ParticleEffect(String name, int id, int requiredVersion, ParticleProperty[] properties) {
+ this.name = name;
+ this.id = id;
+ this.requiredVersion = requiredVersion;
+ this.properties = Arrays.asList(properties);
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public int getId() {
+ return this.id;
+ }
+
+ public int getRequiredVersion() {
+ return this.requiredVersion;
+ }
+
+ public boolean hasProperty(ParticleProperty property) {
+ return this.properties.contains(property);
+ }
+
+ public boolean isSupported() {
+ return this.requiredVersion == -1 || ParticlePacket.getVersion() >= this.requiredVersion;
+ }
+
+ public static ParticleEffect fromName(String name) {
+ for (Map.Entry entry : ParticleEffect.NAME_MAP.entrySet()) {
+ if (!entry.getKey().equalsIgnoreCase(name)) {
+ continue;
+ }
+ return entry.getValue();
+ }
+ return null;
+ }
+
+ public static ParticleEffect fromId(int id) {
+ for (Map.Entry entry : ParticleEffect.ID_MAP.entrySet()) {
+ if (entry.getKey() != id) {
+ continue;
+ }
+ return entry.getValue();
+ }
+ return null;
+ }
+
+ private static boolean isWater(Location location) {
+ Material material = location.getBlock().getType();
+ return material == Material.WATER || material == Material.STATIONARY_WATER;
+ }
+
+ private static boolean isLongDistance(Location location, List players) {
+ String world = location.getWorld().getName();
+ for (Player player : players) {
+ Location playerLocation = player.getLocation();
+ if (world.equals(playerLocation.getWorld().getName())) {
+ if (playerLocation.distanceSquared(location) < 65536.0) {
+ continue;
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isDataCorrect(ParticleEffect effect, ParticleData data) {
+ return ((effect == ParticleEffect.BLOCK_CRACK || effect == ParticleEffect.BLOCK_DUST) && data instanceof BlockData) || (effect == ParticleEffect.ITEM_CRACK && data instanceof ItemData);
+ }
+
+ private static boolean isColorCorrect(ParticleEffect effect, ParticleColor color) {
+ return ((effect == ParticleEffect.SPELL_MOB || effect == ParticleEffect.SPELL_MOB_AMBIENT || effect == ParticleEffect.REDSTONE) && color instanceof OrdinaryColor) || (effect == ParticleEffect.NOTE && color instanceof NoteColor);
+ }
+
+ public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, double range) throws ParticleVersionException, ParticleDataException, IllegalArgumentException {
+ if (!this.isSupported()) {
+ throw new ParticleVersionException("This particle effect is not supported by your server version");
+ }
+ if (this.hasProperty(ParticleProperty.REQUIRES_DATA)) {
+ throw new ParticleDataException("This particle effect requires additional data");
+ }
+ if (this.hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) {
+ throw new IllegalArgumentException("There is no water at the center location");
+ }
+ new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, range > 256.0, null).sendTo(center, range);
+ }
+
+ public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, List players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException {
+ if (!this.isSupported()) {
+ throw new ParticleVersionException("This particle effect is not supported by your server version");
+ }
+ if (this.hasProperty(ParticleProperty.REQUIRES_DATA)) {
+ throw new ParticleDataException("This particle effect requires additional data");
+ }
+ if (this.hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) {
+ throw new IllegalArgumentException("There is no water at the center location");
+ }
+ new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, isLongDistance(center, players), null).sendTo(center, players);
+ }
+
+ public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, Player... players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException {
+ this.display(offsetX, offsetY, offsetZ, speed, amount, center, Arrays.asList(players));
+ }
+
+ public void display(Vector direction, float speed, Location center, double range) throws ParticleVersionException, ParticleDataException, IllegalArgumentException {
+ if (!this.isSupported()) {
+ throw new ParticleVersionException("This particle effect is not supported by your server version");
+ }
+ if (this.hasProperty(ParticleProperty.REQUIRES_DATA)) {
+ throw new ParticleDataException("This particle effect requires additional data");
+ }
+ if (!this.hasProperty(ParticleProperty.DIRECTIONAL)) {
+ throw new IllegalArgumentException("This particle effect is not directional");
+ }
+ if (this.hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) {
+ throw new IllegalArgumentException("There is no water at the center location");
+ }
+ new ParticlePacket(this, direction, speed, range > 256.0, null).sendTo(center, range);
+ }
+
+ public void display(Vector direction, float speed, Location center, List players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException {
+ if (!this.isSupported()) {
+ throw new ParticleVersionException("This particle effect is not supported by your server version");
+ }
+ if (this.hasProperty(ParticleProperty.REQUIRES_DATA)) {
+ throw new ParticleDataException("This particle effect requires additional data");
+ }
+ if (!this.hasProperty(ParticleProperty.DIRECTIONAL)) {
+ throw new IllegalArgumentException("This particle effect is not directional");
+ }
+ if (this.hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) {
+ throw new IllegalArgumentException("There is no water at the center location");
+ }
+ new ParticlePacket(this, direction, speed, isLongDistance(center, players), null).sendTo(center, players);
+ }
+
+ public void display(Vector direction, float speed, Location center, Player... players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException {
+ this.display(direction, speed, center, Arrays.asList(players));
+ }
+
+ public void display(ParticleColor color, Location center, double range) throws ParticleVersionException, ParticleColorException {
+ if (!this.isSupported()) {
+ throw new ParticleVersionException("This particle effect is not supported by your server version");
+ }
+ if (!this.hasProperty(ParticleProperty.COLORABLE)) {
+ throw new ParticleColorException("This particle effect is not colorable");
+ }
+ if (!isColorCorrect(this, color)) {
+ throw new ParticleColorException("The particle color type is incorrect");
+ }
+ new ParticlePacket(this, color, range > 256.0).sendTo(center, range);
+ }
+
+ public void display(ParticleColor color, Location center, List players) throws ParticleVersionException, ParticleColorException {
+ if (!this.isSupported()) {
+ throw new ParticleVersionException("This particle effect is not supported by your server version");
+ }
+ if (!this.hasProperty(ParticleProperty.COLORABLE)) {
+ throw new ParticleColorException("This particle effect is not colorable");
+ }
+ if (!isColorCorrect(this, color)) {
+ throw new ParticleColorException("The particle color type is incorrect");
+ }
+ new ParticlePacket(this, color, isLongDistance(center, players)).sendTo(center, players);
+ }
+
+ public void display(ParticleColor color, Location center, Player... players) throws ParticleVersionException, ParticleColorException {
+ this.display(color, center, Arrays.asList(players));
+ }
+
+ public void display(ParticleData data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, double range) throws ParticleVersionException, ParticleDataException {
+ if (!this.isSupported()) {
+ throw new ParticleVersionException("This particle effect is not supported by your server version");
+ }
+ if (!this.hasProperty(ParticleProperty.REQUIRES_DATA)) {
+ throw new ParticleDataException("This particle effect does not require additional data");
+ }
+ if (!isDataCorrect(this, data)) {
+ throw new ParticleDataException("The particle data type is incorrect");
+ }
+ new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, range > 256.0, data).sendTo(center, range);
+ }
+
+ public void display(ParticleData data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, List players) throws ParticleVersionException, ParticleDataException {
+ if (!this.isSupported()) {
+ throw new ParticleVersionException("This particle effect is not supported by your server version");
+ }
+ if (!this.hasProperty(ParticleProperty.REQUIRES_DATA)) {
+ throw new ParticleDataException("This particle effect does not require additional data");
+ }
+ if (!isDataCorrect(this, data)) {
+ throw new ParticleDataException("The particle data type is incorrect");
+ }
+ new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, isLongDistance(center, players), data).sendTo(center, players);
+ }
+
+ public void display(ParticleData data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, Player... players) throws ParticleVersionException, ParticleDataException {
+ this.display(data, offsetX, offsetY, offsetZ, speed, amount, center, Arrays.asList(players));
+ }
+
+ public void display(ParticleData data, Vector direction, float speed, Location center, double range) throws ParticleVersionException, ParticleDataException {
+ if (!this.isSupported()) {
+ throw new ParticleVersionException("This particle effect is not supported by your server version");
+ }
+ if (!this.hasProperty(ParticleProperty.REQUIRES_DATA)) {
+ throw new ParticleDataException("This particle effect does not require additional data");
+ }
+ if (!isDataCorrect(this, data)) {
+ throw new ParticleDataException("The particle data type is incorrect");
+ }
+ new ParticlePacket(this, direction, speed, range > 256.0, data).sendTo(center, range);
+ }
+
+ public void display(ParticleData data, Vector direction, float speed, Location center, List players) throws ParticleVersionException, ParticleDataException {
+ if (!this.isSupported()) {
+ throw new ParticleVersionException("This particle effect is not supported by your server version");
+ }
+ if (!this.hasProperty(ParticleProperty.REQUIRES_DATA)) {
+ throw new ParticleDataException("This particle effect does not require additional data");
+ }
+ if (!isDataCorrect(this, data)) {
+ throw new ParticleDataException("The particle data type is incorrect");
+ }
+ new ParticlePacket(this, direction, speed, isLongDistance(center, players), data).sendTo(center, players);
+ }
+
+ public void display(ParticleData data, Vector direction, float speed, Location center, Player... players) throws ParticleVersionException, ParticleDataException {
+ this.display(data, direction, speed, center, Arrays.asList(players));
+ }
+
+ static {
+ NAME_MAP = new HashMap();
+ ID_MAP = new HashMap();
+ for (ParticleEffect effect : values()) {
+ ParticleEffect.NAME_MAP.put(effect.name, effect);
+ ParticleEffect.ID_MAP.put(effect.id, effect);
+ }
+ }
+
+ public enum ParticleProperty
+ {
+ REQUIRES_WATER,
+ REQUIRES_DATA,
+ DIRECTIONAL,
+ COLORABLE;
+ }
+
+ public abstract static class ParticleData
+ {
+ private Material material;
+ private byte data;
+ private int[] packetData;
+
+ public ParticleData(Material material, byte data) {
+ this.material = material;
+ this.data = data;
+ this.packetData = new int[] { material.getId(), data };
+ }
+
+ public Material getMaterial() {
+ return this.material;
+ }
+
+ public byte getData() {
+ return this.data;
+ }
+
+ public int[] getPacketData() {
+ return this.packetData;
+ }
+
+ public String getPacketDataString() {
+ return "_" + this.packetData[0] + "_" + this.packetData[1];
+ }
+ }
+
+ public static class ItemData extends ParticleData
+ {
+ public ItemData(Material material, byte data) {
+ super(material, data);
+ }
+ }
+
+ public static class BlockData extends ParticleData
+ {
+ public BlockData(Material material, byte data) throws IllegalArgumentException {
+ super(material, data);
+ if (!material.isBlock()) {
+ throw new IllegalArgumentException("The material is not a block");
+ }
+ }
+ }
+
+ public abstract static class ParticleColor
+ {
+ public abstract float getValueX();
+
+ public abstract float getValueY();
+
+ public abstract float getValueZ();
+ }
+
+ public static class OrdinaryColor extends ParticleColor
+ {
+ private int red;
+ private int green;
+ private int blue;
+
+ public OrdinaryColor(int red, int green, int blue) throws IllegalArgumentException {
+ if (red < 0) {
+ throw new IllegalArgumentException("The red value is lower than 0");
+ }
+ if (red > 255) {
+ throw new IllegalArgumentException("The red value is higher than 255");
+ }
+ this.red = red;
+ if (green < 0) {
+ throw new IllegalArgumentException("The green value is lower than 0");
+ }
+ if (green > 255) {
+ throw new IllegalArgumentException("The green value is higher than 255");
+ }
+ this.green = green;
+ if (blue < 0) {
+ throw new IllegalArgumentException("The blue value is lower than 0");
+ }
+ if (blue > 255) {
+ throw new IllegalArgumentException("The blue value is higher than 255");
+ }
+ this.blue = blue;
+ }
+
+ public OrdinaryColor(Color color) {
+ this(color.getRed(), color.getGreen(), color.getBlue());
+ }
+
+ public int getRed() {
+ return this.red;
+ }
+
+ public int getGreen() {
+ return this.green;
+ }
+
+ public int getBlue() {
+ return this.blue;
+ }
+
+ @Override
+ public float getValueX() {
+ return this.red / 255.0f;
+ }
+
+ @Override
+ public float getValueY() {
+ return this.green / 255.0f;
+ }
+
+ @Override
+ public float getValueZ() {
+ return this.blue / 255.0f;
+ }
+ }
+
+ public static class NoteColor extends ParticleColor
+ {
+ private int note;
+
+ public NoteColor(int note) throws IllegalArgumentException {
+ if (note < 0) {
+ throw new IllegalArgumentException("The note value is lower than 0");
+ }
+ if (note > 24) {
+ throw new IllegalArgumentException("The note value is higher than 24");
+ }
+ this.note = note;
+ }
+
+ @Override
+ public float getValueX() {
+ return this.note / 24.0f;
+ }
+
+ @Override
+ public float getValueY() {
+ return 0.0f;
+ }
+
+ @Override
+ public float getValueZ() {
+ return 0.0f;
+ }
+ }
+
+ private static class ParticleDataException extends RuntimeException
+ {
+ private static long serialVersionUID = 3203085387160737484L;
+
+ public ParticleDataException(String message) {
+ super(message);
+ }
+ }
+
+ private static class ParticleColorException extends RuntimeException
+ {
+ private static long serialVersionUID = 3203085387160737484L;
+
+ public ParticleColorException(String message) {
+ super(message);
+ }
+ }
+
+ private static class ParticleVersionException extends RuntimeException
+ {
+ private static long serialVersionUID = 3203085387160737484L;
+
+ public ParticleVersionException(String message) {
+ super(message);
+ }
+ }
+
+ public static class ParticlePacket
+ {
+ private static int version;
+ private static Class> enumParticle;
+ private static Constructor> packetConstructor;
+ private static Method getHandle;
+ private static Field playerConnection;
+ private static Method sendPacket;
+ private static boolean initialized;
+ private ParticleEffect effect;
+ private float offsetX;
+ private float offsetY;
+ private float offsetZ;
+ private float speed;
+ private int amount;
+ private boolean longDistance;
+ private ParticleData data;
+ private Object packet;
+
+ public ParticlePacket(ParticleEffect effect, float offsetX, float offsetY, float offsetZ, float speed, int amount, boolean longDistance, ParticleData data) throws IllegalArgumentException {
+ initialize();
+ if (speed < 0.0f) {
+ throw new IllegalArgumentException("The speed is lower than 0");
+ }
+ if (amount < 0) {
+ throw new IllegalArgumentException("The amount is lower than 0");
+ }
+ this.effect = effect;
+ this.offsetX = offsetX;
+ this.offsetY = offsetY;
+ this.offsetZ = offsetZ;
+ this.speed = speed;
+ this.amount = amount;
+ this.longDistance = longDistance;
+ this.data = data;
+ }
+
+ public ParticlePacket(ParticleEffect effect, Vector direction, float speed, boolean longDistance, ParticleData data) throws IllegalArgumentException {
+ this(effect, (float)direction.getX(), (float)direction.getY(), (float)direction.getZ(), speed, 0, longDistance, data);
+ }
+
+ public ParticlePacket(ParticleEffect effect, ParticleColor color, boolean longDistance) {
+ this(effect, color.getValueX(), color.getValueY(), color.getValueZ(), 1.0f, 0, longDistance, null);
+ if (effect == ParticleEffect.REDSTONE && color instanceof OrdinaryColor && ((OrdinaryColor)color).getRed() == 0) {
+ this.offsetX = Float.MIN_NORMAL;
+ }
+ }
+
+ public static void initialize() throws VersionIncompatibleException {
+ if (ParticlePacket.initialized) {
+ return;
+ }
+ try {
+ ParticlePacket.version = Integer.parseInt(Character.toString(ReflectionUtils.PackageType.getServerVersion().charAt(3)));
+ if (ParticlePacket.version > 7) {
+ ParticlePacket.enumParticle = ReflectionUtils.PackageType.MINECRAFT_SERVER.getClass("EnumParticle");
+ }
+ Class> packetClass = ReflectionUtils.PackageType.MINECRAFT_SERVER.getClass((ParticlePacket.version < 7) ? "Packet63WorldParticles" : "PacketPlayOutWorldParticles");
+ ParticlePacket.packetConstructor = ReflectionUtils.getConstructor(packetClass, (Class>[])new Class[0]);
+ ParticlePacket.getHandle = ReflectionUtils.getMethod("CraftPlayer", ReflectionUtils.PackageType.CRAFTBUKKIT_ENTITY, "getHandle", (Class>[])new Class[0]);
+ ParticlePacket.playerConnection = ReflectionUtils.getField("EntityPlayer", ReflectionUtils.PackageType.MINECRAFT_SERVER, false, "playerConnection");
+ ParticlePacket.sendPacket = ReflectionUtils.getMethod(ParticlePacket.playerConnection.getType(), "sendPacket", ReflectionUtils.PackageType.MINECRAFT_SERVER.getClass("Packet"));
+ }
+ catch (Exception exception) {
+ throw new VersionIncompatibleException("Your current bukkit version seems to be incompatible with this library", exception);
+ }
+ ParticlePacket.initialized = true;
+ }
+
+ public static int getVersion() {
+ if (!ParticlePacket.initialized) {
+ initialize();
+ }
+ return ParticlePacket.version;
+ }
+
+ public static boolean isInitialized() {
+ return ParticlePacket.initialized;
+ }
+
+ private void initializePacket(Location center) throws PacketInstantiationException {
+ if (this.packet != null) {
+ return;
+ }
+ try {
+ this.packet = ParticlePacket.packetConstructor.newInstance(new Object[0]);
+ if (ParticlePacket.version < 8) {
+ String name = this.effect.getName();
+ if (this.data != null) {
+ name += this.data.getPacketDataString();
+ }
+ ReflectionUtils.setValue(this.packet, true, "a", name);
+ }
+ else {
+ ReflectionUtils.setValue(this.packet, true, "a", ParticlePacket.enumParticle.getEnumConstants()[this.effect.getId()]);
+ ReflectionUtils.setValue(this.packet, true, "j", this.longDistance);
+ if (this.data != null) {
+ int[] packetData = this.data.getPacketData();
+ ReflectionUtils.setValue(this.packet, true, "k", (this.effect == ParticleEffect.ITEM_CRACK) ? packetData : new int[] { packetData[0] | packetData[1] << 12 });
+ }
+ }
+ ReflectionUtils.setValue(this.packet, true, "b", (float)center.getX());
+ ReflectionUtils.setValue(this.packet, true, "c", (float)center.getY());
+ ReflectionUtils.setValue(this.packet, true, "d", (float)center.getZ());
+ ReflectionUtils.setValue(this.packet, true, "e", this.offsetX);
+ ReflectionUtils.setValue(this.packet, true, "f", this.offsetY);
+ ReflectionUtils.setValue(this.packet, true, "g", this.offsetZ);
+ ReflectionUtils.setValue(this.packet, true, "h", this.speed);
+ ReflectionUtils.setValue(this.packet, true, "i", this.amount);
+ }
+ catch (Exception exception) {
+ throw new PacketInstantiationException("Packet instantiation failed", exception);
+ }
+ }
+
+ public void sendTo(Location center, Player player) throws PacketInstantiationException, PacketSendingException {
+ this.initializePacket(center);
+ try {
+ ParticlePacket.sendPacket.invoke(ParticlePacket.playerConnection.get(ParticlePacket.getHandle.invoke(player, new Object[0])), this.packet);
+ }
+ catch (Exception exception) {
+ throw new PacketSendingException("Failed to send the packet to player '" + player.getName() + "'", exception);
+ }
+ }
+
+ public void sendTo(Location center, List players) throws IllegalArgumentException {
+ if (players.isEmpty()) {
+ throw new IllegalArgumentException("The player list is empty");
+ }
+ for (Player player : players) {
+ this.sendTo(center, player);
+ }
+ }
+
+ public void sendTo(Location center, double range) throws IllegalArgumentException {
+ if (range < 1.0) {
+ throw new IllegalArgumentException("The range is lower than 1");
+ }
+ String worldName = center.getWorld().getName();
+ double squared = range * range;
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ if (player.getWorld().getName().equals(worldName)) {
+ if (player.getLocation().distanceSquared(center) > squared) {
+ continue;
+ }
+ this.sendTo(center, player);
+ }
+ }
+ }
+
+ private static class VersionIncompatibleException extends RuntimeException
+ {
+ private static long serialVersionUID = 3203085387160737484L;
+
+ public VersionIncompatibleException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ private static class PacketInstantiationException extends RuntimeException
+ {
+ private static long serialVersionUID = 3203085387160737484L;
+
+ public PacketInstantiationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ private static class PacketSendingException extends RuntimeException
+ {
+ private static long serialVersionUID = 3203085387160737484L;
+
+ public PacketSendingException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+ }
+}
diff --git a/src/main/java/dev/aapy/listeners/hotbar/particles/ParticleParameter.java b/src/main/java/dev/aapy/listeners/hotbar/particles/ParticleParameter.java
new file mode 100644
index 0000000..e39fecf
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/hotbar/particles/ParticleParameter.java
@@ -0,0 +1,15 @@
+package dev.aapy.listeners.hotbar.particles;
+
+import org.bukkit.entity.Player;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ParticleParameter {
+
+ public static Map set;
+
+ static{
+ ParticleParameter.set =new HashMap();
+ }
+}
diff --git a/src/main/java/dev/aapy/listeners/hotbar/particles/Particles.java b/src/main/java/dev/aapy/listeners/hotbar/particles/Particles.java
new file mode 100644
index 0000000..0daec0b
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/hotbar/particles/Particles.java
@@ -0,0 +1,109 @@
+package dev.aapy.listeners.hotbar.particles;
+
+import dev.aapy.SnakeHub;
+import dev.aapy.file.Config;
+import dev.aapy.util.ArmorCreator;
+import dev.aapy.util.CC;
+import dev.aapy.util.ItemCreator;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.plugin.Plugin;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Particles implements Listener {
+
+ public static void ParticleInv(Player p) {
+ Inventory inv = Bukkit.createInventory(null, 9 * 4, CC.translate("&cParticle Menu"));
+ List clearparticles = Arrays.asList("","&6Click to clear particle","");
+
+ inv.setItem(12 - 1, new ItemCreator(Material.BLAZE_POWDER).title("&6Flame Particle").build());
+ inv.setItem(14 - 1, new ItemCreator(Material.TNT).title("&eExplosion Particle").build());
+ inv.setItem(16 - 1, new ItemCreator(Material.REDSTONE).title("&cHeart Particle").build());
+ inv.setItem(18 - 1, new ItemCreator(Material.WATER_BUCKET).title("&dWater Particle").build());
+
+ if (Config.getConfig().getBoolean("COSMETIC.GLASS_PANEL.ENABLED")) {
+ ItemStack panel = new ArmorCreator(Material.STAINED_GLASS_PANE, 1, (short) Config.getConfig().getInt("COSMETIC.GLASS_PANEL.ID")).setName("").build();
+
+ for (int i = 0; i < inv.getSize(); i++) {
+ if (inv.getItem(i) == null) {
+ inv.setItem(i, panel);
+ }
+ }
+ }
+
+ p.openInventory(inv);
+ }
+
+ @EventHandler
+ public void onClickInventory (InventoryClickEvent event) {
+ Player player = (Player) event.getWhoClicked();
+ ItemStack item = event.getCurrentItem();
+ if (event.getCurrentItem() == null || event.getCurrentItem().getType() == Material.AIR || !event.getCurrentItem().hasItemMeta()) {
+ return;
+ }
+ if (event.getCurrentItem().getItemMeta() == null) {
+ return;
+ }
+ if (event.getClickedInventory().getTitle().equalsIgnoreCase(CC.translate("&cParticle Menu"))) {
+ if (player.hasPermission("hub.admin") && player.hasPermission("hub.donator")) {
+ if (event.getSlot() == 12 - 1) {
+ if(ParticleParameter.set.containsKey(player)){
+ Bukkit.getScheduler().cancelTask((int)ParticleParameter.set.get(player));
+ ParticleParameter.set.replace(player, Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask((Plugin) SnakeHub.getInst(), () -> ParticleEffect.FLAME.display(10.0f, 15.0f, 0.0f, 0.0f, 0, player.getLocation().add(-0.0, 2.0, 0.0), 10.0), 0L, 0L));
+ player.sendMessage(CC.translate("&fYou has been Changed your &cParticle!"));
+ player.closeInventory();
+ }else {
+ ParticleParameter.set.put(player, Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask((Plugin) SnakeHub.getInst(), () -> ParticleEffect.FLAME.display(10.0f, 15.0f, 0.0f, 0.0f, 0, player.getLocation().add(-0.0, 2.0, 0.0), 10.0), 0L, 0L));
+ player.sendMessage(CC.translate("&fYou has been set &6Flame &fParticle!"));
+ player.closeInventory();
+ }
+ }else if(event.getSlot() == 14 - 1){
+ if(ParticleParameter.set.containsKey(player)){
+ Bukkit.getScheduler().cancelTask((int)ParticleParameter.set.get(player));
+ ParticleParameter.set.replace(player, Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask((Plugin) SnakeHub.getInst(), () -> ParticleEffect.EXPLOSION_NORMAL.display(10.0f, 15.0f, 0.0f, 0.0f, 0, player.getLocation().add(-0.0, 2.0, 0.0), 10.0), 0L, 0L));
+ player.sendMessage(CC.translate("&fYou has been Changed your &cParticle!"));
+ player.closeInventory();
+ }else {
+ ParticleParameter.set.put(player, Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask((Plugin) SnakeHub.getInst(), () -> ParticleEffect.EXPLOSION_NORMAL.display(10.0f, 15.0f, 0.0f, 0.0f, 0, player.getLocation().add(-0.0, 2.0, 0.0), 10.0), 0L, 0L));
+ player.sendMessage(CC.translate("&fYou has been set &eExplosion &fParticle!"));
+ player.closeInventory();
+ }
+ }else if(event.getSlot() == 16 - 1){
+ if(ParticleParameter.set.containsKey(player)){
+ Bukkit.getScheduler().cancelTask((int)ParticleParameter.set.get(player));
+ ParticleParameter.set.replace(player, Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask((Plugin) SnakeHub.getInst(), () -> ParticleEffect.HEART.display(10.0f, 15.0f, 0.0f, 0.0f, 0, player.getLocation().add(-0.0, 2.0, 0.0), 10.0), 0L, 0L));
+ player.sendMessage(CC.translate("&fYou has been Changed your &cParticle!"));
+ player.closeInventory();
+ }else {
+ ParticleParameter.set.put(player, Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask((Plugin) SnakeHub.getInst(), () -> ParticleEffect.HEART.display(10.0f, 15.0f, 0.0f, 0.0f, 0, player.getLocation().add(-0.0, 2.0, 0.0), 10.0), 0L, 0L));
+ player.sendMessage(CC.translate("&fYou has been set &cHeart &fParticle!"));
+ player.closeInventory();
+ }
+ }else if(event.getSlot() == 18 - 1) {
+ if (ParticleParameter.set.containsKey(player)) {
+ Bukkit.getScheduler().cancelTask((int) ParticleParameter.set.get(player));
+ ParticleParameter.set.replace(player, Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask((Plugin) SnakeHub.getInst(), () -> ParticleEffect.DRIP_WATER.display(10.0f, 15.0f, 0.0f, 0.0f, 0, player.getLocation().add(-0.0, 2.0, 0.0), 10.0), 0L, 0L));
+ player.sendMessage(CC.translate("&fYou has been Changed your &cParticle!"));
+ player.closeInventory();
+ } else {
+ ParticleParameter.set.put(player, Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask((Plugin) SnakeHub.getInst(), () -> ParticleEffect.DRIP_WATER.display(10.0f, 15.0f, 0.0f, 0.0f, 0, player.getLocation().add(-0.0, 2.0, 0.0), 10.0), 0L, 0L));
+ player.sendMessage(CC.translate("&fYou has been set &cWater &fParticle!"));
+ player.closeInventory();
+ }
+ }
+ } else {
+ player.sendMessage(CC.translate(Config.getConfig().getString("SOCIAL.STORE")));
+ player.closeInventory();
+ event.setCancelled(true);
+ }
+ }
+ }
+}
diff --git a/src/main/java/dev/aapy/listeners/hotbar/particles/ReflectionUtils.java b/src/main/java/dev/aapy/listeners/hotbar/particles/ReflectionUtils.java
new file mode 100644
index 0000000..a72c3a4
--- /dev/null
+++ b/src/main/java/dev/aapy/listeners/hotbar/particles/ReflectionUtils.java
@@ -0,0 +1,246 @@
+package dev.aapy.listeners.hotbar.particles;
+
+
+import java.lang.reflect.*;
+import org.bukkit.*;
+import java.util.*;
+
+public final class ReflectionUtils
+{
+ private ReflectionUtils() {
+ }
+
+ public static Constructor> getConstructor(final Class> clazz, final Class>... parameterTypes) throws NoSuchMethodException {
+ final Class>[] primitiveTypes = DataType.getPrimitive(parameterTypes);
+ for (final Constructor> constructor : clazz.getConstructors()) {
+ if (DataType.compare(DataType.getPrimitive(constructor.getParameterTypes()), primitiveTypes)) {
+ return constructor;
+ }
+ }
+ throw new NoSuchMethodException("There is no such constructor in this class with the specified parameter types");
+ }
+
+ public static Constructor> getConstructor(final String className, final PackageType packageType, final Class>... parameterTypes) throws NoSuchMethodException, ClassNotFoundException {
+ return getConstructor(packageType.getClass(className), parameterTypes);
+ }
+
+ public static Object instantiateObject(final Class> clazz, final Object... arguments) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return getConstructor(clazz, DataType.getPrimitive(arguments)).newInstance(arguments);
+ }
+
+ public static Object instantiateObject(final String className, final PackageType packageType, final Object... arguments) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
+ return instantiateObject(packageType.getClass(className), arguments);
+ }
+
+ public static Method getMethod(final Class> clazz, final String methodName, final Class>... parameterTypes) throws NoSuchMethodException {
+ final Class>[] primitiveTypes = DataType.getPrimitive(parameterTypes);
+ for (final Method method : clazz.getMethods()) {
+ if (method.getName().equals(methodName) && DataType.compare(DataType.getPrimitive(method.getParameterTypes()), primitiveTypes)) {
+ return method;
+ }
+ }
+ throw new NoSuchMethodException("There is no such method in this class with the specified name and parameter types");
+ }
+
+ public static Method getMethod(final String className, final PackageType packageType, final String methodName, final Class>... parameterTypes) throws NoSuchMethodException, ClassNotFoundException {
+ return getMethod(packageType.getClass(className), methodName, parameterTypes);
+ }
+
+ public static Object invokeMethod(final Object instance, final String methodName, final Object... arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return getMethod(instance.getClass(), methodName, DataType.getPrimitive(arguments)).invoke(instance, arguments);
+ }
+
+ public static Object invokeMethod(final Object instance, final Class> clazz, final String methodName, final Object... arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
+ return getMethod(clazz, methodName, DataType.getPrimitive(arguments)).invoke(instance, arguments);
+ }
+
+ public static Object invokeMethod(final Object instance, final String className, final PackageType packageType, final String methodName, final Object... arguments) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
+ return invokeMethod(instance, packageType.getClass(className), methodName, arguments);
+ }
+
+ public static Field getField(final Class> clazz, final boolean declared, final String fieldName) throws NoSuchFieldException, SecurityException {
+ final Field field = declared ? clazz.getDeclaredField(fieldName) : clazz.getField(fieldName);
+ field.setAccessible(true);
+ return field;
+ }
+
+ public static Field getField(final String className, final PackageType packageType, final boolean declared, final String fieldName) throws NoSuchFieldException, SecurityException, ClassNotFoundException {
+ return getField(packageType.getClass(className), declared, fieldName);
+ }
+
+ public static Object getValue(final Object instance, final Class> clazz, final boolean declared, final String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
+ return getField(clazz, declared, fieldName).get(instance);
+ }
+
+ public static Object getValue(final Object instance, final String className, final PackageType packageType, final boolean declared, final String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, ClassNotFoundException {
+ return getValue(instance, packageType.getClass(className), declared, fieldName);
+ }
+
+ public static Object getValue(final Object instance, final boolean declared, final String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
+ return getValue(instance, instance.getClass(), declared, fieldName);
+ }
+
+ public static void setValue(final Object instance, final Class> clazz, final boolean declared, final String fieldName, final Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
+ getField(clazz, declared, fieldName).set(instance, value);
+ }
+
+ public static void setValue(final Object instance, final String className, final PackageType packageType, final boolean declared, final String fieldName, final Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, ClassNotFoundException {
+ setValue(instance, packageType.getClass(className), declared, fieldName, value);
+ }
+
+ public static void setValue(final Object instance, final boolean declared, final String fieldName, final Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
+ setValue(instance, instance.getClass(), declared, fieldName, value);
+ }
+
+ public enum PackageType
+ {
+ MINECRAFT_SERVER("net.minecraft.server." + getServerVersion()),
+ CRAFTBUKKIT("org.bukkit.craftbukkit." + getServerVersion()),
+ CRAFTBUKKIT_BLOCK(PackageType.CRAFTBUKKIT, "block"),
+ CRAFTBUKKIT_CHUNKIO(PackageType.CRAFTBUKKIT, "chunkio"),
+ CRAFTBUKKIT_COMMAND(PackageType.CRAFTBUKKIT, "command"),
+ CRAFTBUKKIT_CONVERSATIONS(PackageType.CRAFTBUKKIT, "conversations"),
+ CRAFTBUKKIT_ENCHANTMENS(PackageType.CRAFTBUKKIT, "enchantments"),
+ CRAFTBUKKIT_ENTITY(PackageType.CRAFTBUKKIT, "entity"),
+ CRAFTBUKKIT_EVENT(PackageType.CRAFTBUKKIT, "event"),
+ CRAFTBUKKIT_GENERATOR(PackageType.CRAFTBUKKIT, "generator"),
+ CRAFTBUKKIT_HELP(PackageType.CRAFTBUKKIT, "help"),
+ CRAFTBUKKIT_INVENTORY(PackageType.CRAFTBUKKIT, "inventory"),
+ CRAFTBUKKIT_MAP(PackageType.CRAFTBUKKIT, "map"),
+ CRAFTBUKKIT_METADATA(PackageType.CRAFTBUKKIT, "metadata"),
+ CRAFTBUKKIT_POTION(PackageType.CRAFTBUKKIT, "potion"),
+ CRAFTBUKKIT_PROJECTILES(PackageType.CRAFTBUKKIT, "projectiles"),
+ CRAFTBUKKIT_SCHEDULER(PackageType.CRAFTBUKKIT, "scheduler"),
+ CRAFTBUKKIT_SCOREBOARD(PackageType.CRAFTBUKKIT, "scoreboard"),
+ CRAFTBUKKIT_UPDATER(PackageType.CRAFTBUKKIT, "updater"),
+ CRAFTBUKKIT_UTIL(PackageType.CRAFTBUKKIT, "util");
+
+ private final String path;
+
+ private PackageType(final String path) {
+ this.path = path;
+ }
+
+ private PackageType(final PackageType parent, final String path) {
+ this(parent + "." + path);
+ }
+
+ public String getPath() {
+ return this.path;
+ }
+
+ public Class> getClass(final String className) throws ClassNotFoundException {
+ return Class.forName(this + "." + className);
+ }
+
+ @Override
+ public String toString() {
+ return this.path;
+ }
+
+ public static String getServerVersion() {
+ return Bukkit.getServer().getClass().getPackage().getName().substring(23);
+ }
+ }
+
+ public enum DataType
+ {
+ BYTE((Class>)Byte.TYPE, (Class>)Byte.class),
+ SHORT((Class>)Short.TYPE, (Class>)Short.class),
+ INTEGER((Class>)Integer.TYPE, (Class>)Integer.class),
+ LONG((Class>)Long.TYPE, (Class>)Long.class),
+ CHARACTER((Class>)Character.TYPE, (Class>)Character.class),
+ FLOAT((Class>)Float.TYPE, (Class>)Float.class),
+ DOUBLE((Class>)Double.TYPE, (Class>)Double.class),
+ BOOLEAN((Class>)Boolean.TYPE, (Class>)Boolean.class);
+
+ private static final Map, DataType> CLASS_MAP;
+ private final Class> primitive;
+ private final Class> reference;
+
+ private DataType(final Class> primitive, final Class> reference) {
+ this.primitive = primitive;
+ this.reference = reference;
+ }
+
+ public Class> getPrimitive() {
+ return this.primitive;
+ }
+
+ public Class> getReference() {
+ return this.reference;
+ }
+
+ public static DataType fromClass(final Class> clazz) {
+ return DataType.CLASS_MAP.get(clazz);
+ }
+
+ public static Class> getPrimitive(final Class> clazz) {
+ final DataType type = fromClass(clazz);
+ return (type == null) ? clazz : type.getPrimitive();
+ }
+
+ public static Class> getReference(final Class> clazz) {
+ final DataType type = fromClass(clazz);
+ return (type == null) ? clazz : type.getReference();
+ }
+
+ public static Class>[] getPrimitive(final Class>[] classes) {
+ final int length = (classes == null) ? 0 : classes.length;
+ final Class>[] types = (Class>[])new Class[length];
+ for (int index = 0; index < length; ++index) {
+ types[index] = getPrimitive(classes[index]);
+ }
+ return types;
+ }
+
+ public static Class>[] getReference(final Class>[] classes) {
+ final int length = (classes == null) ? 0 : classes.length;
+ final Class>[] types = (Class>[])new Class[length];
+ for (int index = 0; index < length; ++index) {
+ types[index] = getReference(classes[index]);
+ }
+ return types;
+ }
+
+ public static Class>[] getPrimitive(final Object[] objects) {
+ final int length = (objects == null) ? 0 : objects.length;
+ final Class>[] types = (Class>[])new Class[length];
+ for (int index = 0; index < length; ++index) {
+ types[index] = getPrimitive(objects[index].getClass());
+ }
+ return types;
+ }
+
+ public static Class>[] getReference(final Object[] objects) {
+ final int length = (objects == null) ? 0 : objects.length;
+ final Class>[] types = (Class>[])new Class[length];
+ for (int index = 0; index < length; ++index) {
+ types[index] = getReference(objects[index].getClass());
+ }
+ return types;
+ }
+
+ public static boolean compare(final Class>[] primary, final Class>[] secondary) {
+ if (primary == null || secondary == null || primary.length != secondary.length) {
+ return false;
+ }
+ for (int index = 0; index < primary.length; ++index) {
+ final Class> primaryClass = primary[index];
+ final Class> secondaryClass = secondary[index];
+ if (!primaryClass.equals(secondaryClass) && !primaryClass.isAssignableFrom(secondaryClass)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static {
+ CLASS_MAP = new HashMap, DataType>();
+ for (final DataType type : values()) {
+ DataType.CLASS_MAP.put(type.primitive, type);
+ DataType.CLASS_MAP.put(type.reference, type);
+ }
+ }
+ }
+}
diff --git a/src/main/java/dev/aapy/manager/Manager.java b/src/main/java/dev/aapy/manager/Manager.java
new file mode 100644
index 0000000..e4e1d75
--- /dev/null
+++ b/src/main/java/dev/aapy/manager/Manager.java
@@ -0,0 +1,43 @@
+package dev.aapy.manager;
+
+import com.google.common.collect.Lists;
+import dev.aapy.SnakeHub;
+import dev.aapy.manager.handler.Handler;
+import dev.aapy.manager.managers.*;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author 7qv_ and Alexito2060 on 19/2/2022.
+ * @project SnakeHub
+ */
+
+@Getter
+public class Manager {
+
+ private final SnakeHub plugin;
+ private final List managers = Lists.newArrayList();
+
+ private ScoreBoardManager scoreboard;
+ private CommandManager command;
+ private ListenerManager listener;
+
+ public Manager(SnakeHub plugin) {
+ this.plugin = plugin;
+ }
+
+ public void enable() {
+ this.scoreboard = new ScoreBoardManager(this.plugin);
+ this.command = new CommandManager(this.plugin);
+ this.listener = new ListenerManager(this.plugin);
+ this.managers.addAll(Arrays.asList(this.scoreboard, this.command, this.listener));
+ this.managers.forEach(Handler::enable);
+ }
+
+ public void disable() {
+ this.managers.forEach(Handler::disable);
+ }
+
+}
diff --git a/src/main/java/dev/aapy/manager/handler/Handler.java b/src/main/java/dev/aapy/manager/handler/Handler.java
new file mode 100644
index 0000000..df8bd38
--- /dev/null
+++ b/src/main/java/dev/aapy/manager/handler/Handler.java
@@ -0,0 +1,22 @@
+package dev.aapy.manager.handler;
+
+import dev.aapy.SnakeHub;
+
+/**
+ * @author 7qv_ and Alexti2o600 on 19/2/2022.
+ * @project Snake
+ Hub
+ */
+
+public abstract class Handler {
+
+ private final SnakeHub plugin;
+
+ public Handler(SnakeHub plugin) { this.plugin = plugin; }
+
+ public void enable() { }
+
+ public void disable() { }
+
+ public SnakeHub getPlugin() { return plugin; }
+}
diff --git a/src/main/java/dev/aapy/manager/managers/CommandManager.java b/src/main/java/dev/aapy/manager/managers/CommandManager.java
new file mode 100644
index 0000000..0c56c87
--- /dev/null
+++ b/src/main/java/dev/aapy/manager/managers/CommandManager.java
@@ -0,0 +1,37 @@
+package dev.aapy.manager.managers;
+
+import dev.alex.net.utilities.command.Command;
+import dev.aapy.SnakeHub;
+import dev.aapy.commands.plugin.HubCore;
+import dev.aapy.commands.social.*;
+import dev.aapy.manager.handler.Handler;
+
+/**
+ * @author 7qv_ and Alexito2060 on 19/2/2022.
+ * @project SnakeHub
+ *
+**/
+
+public final class CommandManager extends Handler {
+
+ private Command command;
+
+ public CommandManager(SnakeHub plugin) { super(plugin); }
+
+ @Override
+ public void enable() {
+ this.command = new Command("", false);
+ command.register(new HubCore());
+ command.register(new WebSite());
+ command.register(new Twitter());
+ command.register(new TeamSpeak());
+ command.register(new Store());
+ command.register(new Discord());
+ this.command.registerAll();
+ }
+
+ @Override
+ public void disable() {
+ this.command.unregisterAll();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/manager/managers/ListenerManager.java b/src/main/java/dev/aapy/manager/managers/ListenerManager.java
new file mode 100644
index 0000000..c6f1fb8
--- /dev/null
+++ b/src/main/java/dev/aapy/manager/managers/ListenerManager.java
@@ -0,0 +1,49 @@
+package dev.aapy.manager.managers;
+
+import com.google.common.collect.Lists;
+import dev.aapy.SnakeHub;
+import dev.aapy.file.Config;
+import dev.aapy.listeners.*;
+import dev.aapy.listeners.hotbar.*;
+import dev.aapy.listeners.hotbar.particles.Particles;
+import dev.aapy.manager.handler.Handler;
+import lombok.Getter;
+import org.bukkit.plugin.PluginManager;
+
+import java.util.List;
+
+/**
+ * @author 7qv_ and Alexito2060 on 19/2/2022.
+ * @project SnakeHub
+ */
+
+@Getter
+public final class ListenerManager extends Handler {
+
+ private final List listener = Lists.newArrayList();
+
+ public ListenerManager(SnakeHub plugin) { super(plugin); }
+
+ @Override
+ public void enable() {
+ PluginManager manager = getPlugin().getServer().getPluginManager();
+ manager.registerEvents(new PlayerListener(),getPlugin());
+ if (Config.getConfig().getBoolean("BOOLEANS.LUNAR-CLIENT.NAMETAG")) {
+ manager.registerEvents(new LunarListener(), getPlugin());
+ }
+ manager.registerEvents(new DeveloperListener(), getPlugin());
+ manager.registerEvents(new EnderButtListener(), getPlugin());
+ manager.registerEvents(new ChatFormatListener(), getPlugin());
+ manager.registerEvents(new JumpListener(), getPlugin());
+ manager.registerEvents(new LaunchPadListener(), getPlugin());
+ manager.registerEvents(new Particles(), getPlugin());
+ manager.registerEvents(new PlayerInvisibilityListener(), getPlugin());
+ manager.registerEvents(new PvPListener(), getPlugin());
+ manager.registerEvents(new OutfitsListener(), getPlugin());
+ manager.registerEvents(new CosmeticListener(), getPlugin());
+ manager.registerEvents(new SelectorListener(), getPlugin());
+ manager.registerEvents(new CosmeticListener(), getPlugin());
+ manager.registerEvents(new ChatFormatListener(), getPlugin());
+ manager.registerEvents(new WorldListener(), getPlugin());
+ }
+}
diff --git a/src/main/java/dev/aapy/manager/managers/PermissionManager.java b/src/main/java/dev/aapy/manager/managers/PermissionManager.java
new file mode 100644
index 0000000..dbd4955
--- /dev/null
+++ b/src/main/java/dev/aapy/manager/managers/PermissionManager.java
@@ -0,0 +1,41 @@
+package dev.aapy.manager.managers;
+
+import dev.aapy.SnakeHub;
+import dev.aapy.ranks.Permission;
+import dev.aapy.ranks.type.AquaCore;
+import dev.aapy.ranks.type.Default;
+import dev.aapy.ranks.type.LuckPerms;
+import lombok.Getter;
+import org.bukkit.Bukkit;
+import org.bukkit.plugin.RegisteredServiceProvider;
+
+import net.milkbowl.vault.chat.Chat;
+
+@Getter
+public final class PermissionManager {
+
+ private final SnakeHub plugin;
+ private String name;
+ private Permission permission;
+ private net.luckperms.api.LuckPerms luckperms;
+ private Chat chat;
+
+ public PermissionManager(SnakeHub plugin) { this.plugin = plugin; }
+
+ public void loadHook() {
+ if (Bukkit.getPluginManager().getPlugin("AquaCore") != null) this.setPermission(new AquaCore(), "AquaCore");
+ if (Bukkit.getPluginManager().getPlugin("Vault") != null && this.loadVault() && this.getChat().getName().contains("LuckPerms")) this.setPermission(new LuckPerms(), "LuckPerms");
+ this.setPermission(new Default(), "None");
+ }
+
+ private boolean loadVault() {
+ RegisteredServiceProvider service = this.plugin.getServer().getServicesManager().getRegistration(Chat.class);
+ if (service != null) this.chat = service.getProvider();
+ return this.chat != null;
+ }
+
+ private void setPermission(Permission permission, String name) {
+ this.permission = permission;
+ this.name = name;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/manager/managers/ScoreBoardManager.java b/src/main/java/dev/aapy/manager/managers/ScoreBoardManager.java
new file mode 100644
index 0000000..eeb7479
--- /dev/null
+++ b/src/main/java/dev/aapy/manager/managers/ScoreBoardManager.java
@@ -0,0 +1,41 @@
+package dev.aapy.manager.managers;
+
+import dev.aapy.SnakeHub;
+import dev.aapy.file.Config;
+import dev.aapy.manager.handler.Handler;
+import dev.aapy.scoreboard.ScoreBoardProvider;
+import dev.aapy.scoreboard.assamble.Assemble;
+import dev.aapy.scoreboard.assamble.AssembleStyle;
+import dev.aapy.util.ScoreFooterTask;
+import dev.aapy.util.ScoreTitleTask;
+import lombok.Getter;
+
+/**
+ * @author 7qv_ on 20/2/2022.
+ * @project SnakeHub
+ */
+
+@Getter
+public final class ScoreBoardManager extends Handler {
+
+ private ScoreFooterTask scoreTask;
+ private ScoreTitleTask scoreTitleTask;
+
+ public ScoreBoardManager(SnakeHub plugin) {
+ super(plugin);
+ }
+
+ @Override
+ public void enable() {
+ Assemble assemble = new Assemble(this.getPlugin(), new ScoreBoardProvider());
+ assemble.setTicks(2);
+ assemble.setAssembleStyle(AssembleStyle.VIPER);
+
+ if (Config.getConfig().getBoolean("BOOLEANS.SCOREBOARD.ANIMATED.FOOTER")) {
+ (this.scoreTask = new ScoreFooterTask()).runTaskTimerAsynchronously(this.getPlugin(), 0L, 20L);
+ }
+ if (Config.getConfig().getBoolean("BOOLEANS.SCOREBOARD.ANIMATED.TITLE")) {
+ (this.scoreTitleTask = new ScoreTitleTask()).runTaskTimerAsynchronously(this.getPlugin(), 0L, 20L);
+ }
+ }
+}
diff --git a/src/main/java/dev/aapy/ranks/Permission.java b/src/main/java/dev/aapy/ranks/Permission.java
new file mode 100644
index 0000000..3fa0045
--- /dev/null
+++ b/src/main/java/dev/aapy/ranks/Permission.java
@@ -0,0 +1,14 @@
+package dev.aapy.ranks;
+
+import org.bukkit.OfflinePlayer;
+
+public interface Permission {
+
+ String getName(OfflinePlayer offlinePlayer);
+
+ String getPrefix(OfflinePlayer offlinePlayer);
+
+ String getSuffix(OfflinePlayer offlinePlayer);
+
+ String getColor(OfflinePlayer offlinePlayer);
+}
diff --git a/src/main/java/dev/aapy/ranks/type/AquaCore.java b/src/main/java/dev/aapy/ranks/type/AquaCore.java
new file mode 100644
index 0000000..0c841fa
--- /dev/null
+++ b/src/main/java/dev/aapy/ranks/type/AquaCore.java
@@ -0,0 +1,34 @@
+package dev.aapy.ranks.type;
+
+import dev.aapy.ranks.Permission;
+import org.bukkit.OfflinePlayer;
+
+import me.activated.core.api.player.PlayerData;
+import me.activated.core.plugin.AquaCoreAPI;
+
+public class AquaCore implements Permission {
+
+ @Override
+ public String getName(OfflinePlayer player) {
+ PlayerData data = AquaCoreAPI.INSTANCE.getPlayerData(player.getUniqueId());
+ return (data == null) ? "None" : data.getHighestRank().getName();
+ }
+
+ @Override
+ public String getPrefix(OfflinePlayer player) {
+ PlayerData data = AquaCoreAPI.INSTANCE.getPlayerData(player.getUniqueId());
+ return (data == null) ? "None" : data.getHighestRank().getPrefix();
+ }
+
+ @Override
+ public String getSuffix(OfflinePlayer player) {
+ PlayerData data = AquaCoreAPI.INSTANCE.getPlayerData(player.getUniqueId());
+ return (data == null) ? "None" : data.getHighestRank().getSuffix();
+ }
+
+ @Override
+ public String getColor(OfflinePlayer player) {
+ PlayerData data = AquaCoreAPI.INSTANCE.getPlayerData(player.getUniqueId());
+ return (data == null) ? "None" : data.getHighestRank().getColor() + data.getHighestRank().getName();
+ }
+}
diff --git a/src/main/java/dev/aapy/ranks/type/Default.java b/src/main/java/dev/aapy/ranks/type/Default.java
new file mode 100644
index 0000000..107f184
--- /dev/null
+++ b/src/main/java/dev/aapy/ranks/type/Default.java
@@ -0,0 +1,28 @@
+package dev.aapy.ranks.type;
+
+import dev.aapy.ranks.Permission;
+import org.bukkit.OfflinePlayer;
+
+
+public class Default implements Permission {
+
+ @Override
+ public String getName(OfflinePlayer player) {
+ return "None";
+ }
+
+ @Override
+ public String getPrefix(OfflinePlayer player) {
+ return "None";
+ }
+
+ @Override
+ public String getSuffix(OfflinePlayer player) {
+ return "None";
+ }
+
+ @Override
+ public String getColor(OfflinePlayer player) {
+ return "None";
+ }
+}
diff --git a/src/main/java/dev/aapy/ranks/type/LuckPerms.java b/src/main/java/dev/aapy/ranks/type/LuckPerms.java
new file mode 100644
index 0000000..0870f4e
--- /dev/null
+++ b/src/main/java/dev/aapy/ranks/type/LuckPerms.java
@@ -0,0 +1,30 @@
+package dev.aapy.ranks.type;
+
+import dev.aapy.SnakeHub;
+import dev.aapy.ranks.Permission;
+import dev.aapy.util.CC;
+import org.bukkit.OfflinePlayer;
+
+
+public class LuckPerms implements Permission {
+
+ @Override
+ public String getName(OfflinePlayer player) {
+ return CC.translate(SnakeHub.getInst().getManager().getPlugin().getPermission().getChat().getPrimaryGroup(String.valueOf(SnakeHub.getInst().getManager().getPlugin().getPermission().getPlugin().getServer().getWorlds().get(0).getName()), player));
+ }
+
+ @Override
+ public String getPrefix(OfflinePlayer player) {
+ return CC.translate(SnakeHub.getInst().getManager().getPlugin().getPermission().getChat().getPlayerPrefix(String.valueOf(SnakeHub.getInst().getManager().getPlugin().getPermission().getPlugin().getServer().getWorlds().get(0).getName()), player));
+ }
+
+ @Override
+ public String getSuffix(OfflinePlayer player) {
+ return CC.translate(SnakeHub.getInst().getManager().getPlugin().getPermission().getChat().getPlayerSuffix(String.valueOf(SnakeHub.getInst().getManager().getPlugin().getPermission().getPlugin().getServer().getWorlds().get(0).getName()), player));
+ }
+
+ @Override
+ public String getColor(OfflinePlayer player) {
+ return CC.translate(SnakeHub.getInst().getManager().getPlugin().getPermission().getChat().getPrimaryGroup(String.valueOf(SnakeHub.getInst().getManager().getPlugin().getPermission().getPlugin().getServer().getWorlds().get(0).getName()), player));
+ }
+}
diff --git a/src/main/java/dev/aapy/scoreboard/ScoreBoardProvider.java b/src/main/java/dev/aapy/scoreboard/ScoreBoardProvider.java
new file mode 100644
index 0000000..b730993
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/ScoreBoardProvider.java
@@ -0,0 +1,48 @@
+package dev.aapy.scoreboard;
+
+import dev.aapy.SnakeHub;
+import dev.aapy.file.Config;
+import dev.aapy.file.Scoreboard;
+import dev.aapy.manager.managers.ScoreBoardManager;
+import dev.aapy.scoreboard.assamble.AssembleAdapter;
+import dev.aapy.util.CC;
+import dev.aapy.util.SnakeUtil;
+import me.clip.placeholderapi.PlaceholderAPI;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author 7qv_ on 7/2/2022.
+ * @project SnakeHub
+ */
+
+public class ScoreBoardProvider implements AssembleAdapter {
+
+ private final ScoreBoardManager scoreboard = SnakeHub.getInst().getManager().getScoreboard();
+
+ @Override
+ public String getTitle(Player player) {
+ return Config.getConfig().getBoolean("BOOLEANS.SCOREBOARD.ANIMATED.TITLE") ? this.scoreboard.getScoreTitleTask().sendTitle() : CC.translate(Scoreboard.getConfig().getString("SCOREBOARD.TITLE"));
+ }
+
+ @Override
+ public List getLines(Player player) {
+ final List list = new ArrayList<>();
+ for (String lines : Scoreboard.getConfig().getStringList("SCOREBOARD.LINES")) {
+ lines = lines.replace("{arrow}", StringEscapeUtils.unescapeJava("\\u2a20"));
+ lines = lines.replace("{placeholder:date}", SnakeUtil.getDate());
+ lines = lines.replace("{placeholder:time}", SnakeUtil.getHour());
+ lines = lines.replace("{players_online}", Bukkit.getOnlinePlayers().size() + "/" + Bukkit.getServer().getMaxPlayers());
+ lines = lines.replace("{rank}", SnakeHub.getInst().getPermission().getPermission().getPrefix(player));
+ lines = lines.replace("{ign}", player.getName());
+ lines = lines.replace("{footers}", Config.getConfig().getBoolean("BOOLEANS.SCOREBOARD.ANIMATED.FOOTER") ? this.scoreboard.getScoreTask().sendFooter() : CC.translate(Scoreboard.getConfig().getString("SCOREBOARD.FOOTER")));
+
+ list.add(PlaceholderAPI.setPlaceholders(player, lines));
+ }
+ return list;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/scoreboard/assamble/Assemble.java b/src/main/java/dev/aapy/scoreboard/assamble/Assemble.java
new file mode 100644
index 0000000..764545b
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/assamble/Assemble.java
@@ -0,0 +1,115 @@
+package dev.aapy.scoreboard.assamble;
+
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import dev.aapy.scoreboard.events.AssembleBoardCreateEvent;
+import lombok.Getter;
+import lombok.Setter;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.bukkit.plugin.java.JavaPlugin;
+
+@Getter @Setter
+public class Assemble {
+
+ private final JavaPlugin plugin;
+
+ private AssembleAdapter adapter;
+ private AssembleThread thread;
+ private AssembleListener listeners;
+ private AssembleStyle assembleStyle = AssembleStyle.MODERN;
+
+ private Map boards;
+
+ private long ticks = 2;
+ private boolean hook = false, debugMode = true, callEvents = true;
+
+ private final ChatColor[] chatColorCache = ChatColor.values();
+
+ /**
+ * Assemble.
+ *
+ * @param plugin instance.
+ * @param adapter that is being provided.
+ */
+ public Assemble(JavaPlugin plugin, AssembleAdapter adapter) {
+ if (plugin == null) {
+ throw new RuntimeException("Assemble can not be instantiated without a plugin instance!");
+ }
+
+ this.plugin = plugin;
+ this.adapter = adapter;
+ this.boards = new ConcurrentHashMap<>();
+
+ this.setup();
+ }
+
+ /**
+ * Setup Assemble.
+ */
+ public void setup() {
+ // Register Events.
+ this.listeners = new AssembleListener(this);
+ this.plugin.getServer().getPluginManager().registerEvents(listeners, this.plugin);
+
+ // Ensure that the thread has stopped running.
+ if (this.thread != null) {
+ this.thread.stop();
+ this.thread = null;
+ }
+
+ // Register new boards for existing online players.
+ for (Player player : this.getPlugin().getServer().getOnlinePlayers()) {
+
+ // Call Events if enabled.
+ if (this.isCallEvents()) {
+ AssembleBoardCreateEvent createEvent = new AssembleBoardCreateEvent(player);
+
+ Bukkit.getPluginManager().callEvent(createEvent);
+ if (createEvent.isCancelled()) {
+ continue;
+ }
+ }
+
+ getBoards().putIfAbsent(player.getUniqueId(), new AssembleBoard(player, this));
+ }
+
+ // Start Thread.
+ this.thread = new AssembleThread(this);
+ }
+
+ /**
+ * Cleanup Assemble.
+ */
+ public void cleanup() {
+ // Stop thread.
+ if (this.thread != null) {
+ this.thread.stop();
+ this.thread = null;
+ }
+
+ // Unregister listeners.
+ if (listeners != null) {
+ HandlerList.unregisterAll(listeners);
+ listeners = null;
+ }
+
+ // Destroy player scoreboards.
+ for (UUID uuid : getBoards().keySet()) {
+ Player player = Bukkit.getPlayer(uuid);
+
+ if (player == null || !player.isOnline()) {
+ continue;
+ }
+
+ getBoards().remove(uuid);
+ player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard());
+ }
+ }
+
+}
diff --git a/src/main/java/dev/aapy/scoreboard/assamble/AssembleAdapter.java b/src/main/java/dev/aapy/scoreboard/assamble/AssembleAdapter.java
new file mode 100644
index 0000000..8ec5aee
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/assamble/AssembleAdapter.java
@@ -0,0 +1,24 @@
+package dev.aapy.scoreboard.assamble;
+
+import java.util.List;
+import org.bukkit.entity.Player;
+
+public interface AssembleAdapter {
+
+ /**
+ * Get's the scoreboard title.
+ *
+ * @param player who's title is being displayed.
+ * @return title.
+ */
+ String getTitle(Player player);
+
+ /**
+ * Get's the scoreboard lines.
+ *
+ * @param player who's lines are being displayed.
+ * @return lines.
+ */
+ List getLines(Player player);
+
+}
diff --git a/src/main/java/dev/aapy/scoreboard/assamble/AssembleBoard.java b/src/main/java/dev/aapy/scoreboard/assamble/AssembleBoard.java
new file mode 100644
index 0000000..3bfcb2a
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/assamble/AssembleBoard.java
@@ -0,0 +1,130 @@
+package dev.aapy.scoreboard.assamble;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import dev.aapy.scoreboard.events.AssembleBoardCreatedEvent;
+import lombok.Getter;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.scoreboard.DisplaySlot;
+import org.bukkit.scoreboard.Objective;
+import org.bukkit.scoreboard.Scoreboard;
+
+@Getter
+public class AssembleBoard {
+
+ private final Assemble assemble;
+
+ private final List entries = new ArrayList<>();
+ private final List identifiers = new ArrayList<>();
+
+ private final UUID uuid;
+
+ /**
+ * Assemble Board.
+ *
+ * @param player that the board belongs to.
+ * @param assemble instance.
+ */
+ public AssembleBoard(Player player, Assemble assemble) {
+ this.uuid = player.getUniqueId();
+ this.assemble = assemble;
+ this.setup(player);
+ }
+
+ /**
+ * Get's a player's bukkit scoreboard.
+ *
+ * @return either existing scoreboard or new scoreboard.
+ */
+ public Scoreboard getScoreboard() {
+ Player player = Bukkit.getPlayer(getUuid());
+ if (getAssemble().isHook() || player.getScoreboard() != Bukkit.getScoreboardManager().getMainScoreboard()) {
+ return player.getScoreboard();
+ } else {
+ return Bukkit.getScoreboardManager().getNewScoreboard();
+ }
+ }
+
+ /**
+ * Get's the player's scoreboard objective.
+ *
+ * @return either existing objecting or new objective.
+ */
+ public Objective getObjective() {
+ Scoreboard scoreboard = getScoreboard();
+ if (scoreboard.getObjective("Assemble") == null) {
+ Objective objective = scoreboard.registerNewObjective("Assemble", "dummy");
+ objective.setDisplaySlot(DisplaySlot.SIDEBAR);
+ objective.setDisplayName(getAssemble().getAdapter().getTitle(Bukkit.getPlayer(getUuid())));
+ return objective;
+ } else {
+ return scoreboard.getObjective("Assemble");
+ }
+ }
+
+ /**
+ * Setup the board.
+ *
+ * @param player who's board to setup.
+ */
+ private void setup(Player player) {
+ Scoreboard scoreboard = getScoreboard();
+ player.setScoreboard(scoreboard);
+ getObjective();
+
+ // Call Events if enabled.
+ if (assemble.isCallEvents()) {
+ AssembleBoardCreatedEvent createdEvent = new AssembleBoardCreatedEvent(this);
+ Bukkit.getPluginManager().callEvent(createdEvent);
+ }
+ }
+
+ /**
+ * Get the board entry at a specific position.
+ *
+ * @param pos to find entry.
+ * @return entry if it isn't out of range.
+ */
+ public AssembleBoardEntry getEntryAtPosition(int pos) {
+ return pos >= this.entries.size() ? null : this.entries.get(pos);
+ }
+
+ /**
+ * Get the unique identifier for position in scoreboard.
+ *
+ * @param position for identifier.
+ * @return unique identifier.
+ */
+ public String getUniqueIdentifier(int position) {
+ String identifier = getRandomChatColor(position) + ChatColor.WHITE;
+
+ while (this.identifiers.contains(identifier)) {
+ identifier = identifier + getRandomChatColor(position) + ChatColor.WHITE;
+ }
+
+ // This is rare, but just in case, make the method recursive
+ if (identifier.length() > 16) {
+ return this.getUniqueIdentifier(position);
+ }
+
+ // Add our identifier to the list so there are no duplicates
+ this.identifiers.add(identifier);
+
+ return identifier;
+ }
+
+ /**
+ * Gets a ChatColor based off the position in the collection.
+ *
+ * @param position of entry.
+ * @return ChatColor adjacent to position.
+ */
+ private String getRandomChatColor(int position) {
+ return assemble.getChatColorCache()[position].toString();
+ }
+
+}
diff --git a/src/main/java/dev/aapy/scoreboard/assamble/AssembleBoardEntry.java b/src/main/java/dev/aapy/scoreboard/assamble/AssembleBoardEntry.java
new file mode 100644
index 0000000..42b40d7
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/assamble/AssembleBoardEntry.java
@@ -0,0 +1,91 @@
+package dev.aapy.scoreboard.assamble;
+
+import org.bukkit.scoreboard.Scoreboard;
+import org.bukkit.scoreboard.Team;
+
+import lombok.Setter;
+
+public class AssembleBoardEntry {
+
+ private final AssembleBoard board;
+
+ private Team team;
+ @Setter
+ private String text, identifier;
+
+ /**
+ * Assemble Board Entry
+ *
+ * @param board that entry belongs to.
+ * @param text of entry.
+ * @param position of entry.
+ */
+ public AssembleBoardEntry(AssembleBoard board, String text, int position) {
+ this.board = board;
+ this.text = text;
+ this.identifier = this.board.getUniqueIdentifier(position);
+
+ this.setup();
+ }
+
+ /**
+ * Setup Board Entry.
+ */
+ public void setup() {
+ final Scoreboard scoreboard = this.board.getScoreboard();
+
+ if (scoreboard == null) {
+ return;
+ }
+
+ String teamName = this.identifier;
+
+ // This shouldn't happen, but just in case.
+ if (teamName.length() > 16) {
+ teamName = teamName.substring(0, 16);
+ }
+
+ Team team = scoreboard.getTeam(teamName);
+
+ // Register the team if it does not exist.
+ if (team == null) {
+ team = scoreboard.registerNewTeam(teamName);
+ }
+
+ // Add the entry to the team.
+ if (!team.getEntries().contains(this.identifier)) {
+ team.addEntry(this.identifier);
+ }
+
+ // Add the entry if it does not exist.
+ if (!this.board.getEntries().contains(this)) {
+ this.board.getEntries().add(this);
+ }
+
+ this.team = team;
+ }
+
+ /**
+ * Send Board Entry Update.
+ *
+ * @param position of entry.
+ */
+ public void send(int position) {
+ // Set Prefix & Suffix.
+ String[] split = AssembleUtils.splitTeamText(text);
+ this.team.setPrefix(split[0]);
+ this.team.setSuffix(split[1]);
+
+ // Set the score
+ this.board.getObjective().getScore(this.identifier).setScore(position);
+ }
+
+ /**
+ * Remove Board Entry from Board.
+ */
+ public void remove() {
+ this.board.getIdentifiers().remove(this.identifier);
+ this.board.getScoreboard().resetScores(this.identifier);
+ }
+
+}
diff --git a/src/main/java/dev/aapy/scoreboard/assamble/AssembleException.java b/src/main/java/dev/aapy/scoreboard/assamble/AssembleException.java
new file mode 100644
index 0000000..4c0e87e
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/assamble/AssembleException.java
@@ -0,0 +1,14 @@
+package dev.aapy.scoreboard.assamble;
+
+public class AssembleException extends RuntimeException {
+
+ /**
+ * Assemble Exception.
+ *
+ * @param message attributed to exception.
+ */
+ public AssembleException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/dev/aapy/scoreboard/assamble/AssembleListener.java b/src/main/java/dev/aapy/scoreboard/assamble/AssembleListener.java
new file mode 100644
index 0000000..9a5d042
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/assamble/AssembleListener.java
@@ -0,0 +1,57 @@
+package dev.aapy.scoreboard.assamble;
+
+import dev.aapy.scoreboard.events.AssembleBoardCreateEvent;
+import dev.aapy.scoreboard.events.AssembleBoardDestroyEvent;
+import lombok.Getter;
+import org.bukkit.Bukkit;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+
+@Getter
+public class AssembleListener implements Listener {
+
+ private final Assemble assemble;
+
+ /**
+ * Assemble Listener.
+ *
+ * @param assemble instance.
+ */
+ public AssembleListener(Assemble assemble) {
+ this.assemble = assemble;
+ }
+
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent event) {
+ // Call Events if enabled.
+ if (assemble.isCallEvents()) {
+ AssembleBoardCreateEvent createEvent = new AssembleBoardCreateEvent(event.getPlayer());
+
+ Bukkit.getPluginManager().callEvent(createEvent);
+ if (createEvent.isCancelled()) {
+ return;
+ }
+ }
+
+ getAssemble().getBoards().put(event.getPlayer().getUniqueId(), new AssembleBoard(event.getPlayer(), getAssemble()));
+ }
+
+ @EventHandler
+ public void onPlayerQuit(PlayerQuitEvent event) {
+ // Call Events if enabled.
+ if (assemble.isCallEvents()) {
+ AssembleBoardDestroyEvent destroyEvent = new AssembleBoardDestroyEvent(event.getPlayer());
+
+ Bukkit.getPluginManager().callEvent(destroyEvent);
+ if (destroyEvent.isCancelled()) {
+ return;
+ }
+ }
+
+ getAssemble().getBoards().remove(event.getPlayer().getUniqueId());
+ event.getPlayer().setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard());
+ }
+
+}
diff --git a/src/main/java/dev/aapy/scoreboard/assamble/AssembleStyle.java b/src/main/java/dev/aapy/scoreboard/assamble/AssembleStyle.java
new file mode 100644
index 0000000..73a6987
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/assamble/AssembleStyle.java
@@ -0,0 +1,38 @@
+package dev.aapy.scoreboard.assamble;
+
+import lombok.Getter;
+
+@Getter
+public enum AssembleStyle {
+
+ KOHI(true, 15), VIPER(true, -1), MODERN(false, 1), CUSTOM(false, 0);
+
+ private boolean descending;
+ private int startNumber;
+
+ /**
+ * Assemble Style.
+ *
+ * @param descending whether the positions are going down or up.
+ * @param startNumber from where to loop from.
+ */
+ AssembleStyle(boolean descending, int startNumber) {
+ this.descending = descending;
+ this.startNumber = startNumber;
+ }
+
+ public AssembleStyle reverse() {
+ return descending(!this.descending);
+ }
+
+ public AssembleStyle descending(boolean descending) {
+ this.descending = descending;
+ return this;
+ }
+
+ public AssembleStyle startNumber(int startNumber) {
+ this.startNumber = startNumber;
+ return this;
+ }
+
+}
diff --git a/src/main/java/dev/aapy/scoreboard/assamble/AssembleThread.java b/src/main/java/dev/aapy/scoreboard/assamble/AssembleThread.java
new file mode 100644
index 0000000..93222fe
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/assamble/AssembleThread.java
@@ -0,0 +1,127 @@
+package dev.aapy.scoreboard.assamble;
+
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.scoreboard.Objective;
+import org.bukkit.scoreboard.Scoreboard;
+
+import java.util.Collections;
+import java.util.List;
+
+public class AssembleThread extends Thread {
+
+ private final Assemble assemble;
+
+ /**
+ * Assemble Thread.
+ *
+ * @param assemble instance.
+ */
+ AssembleThread(Assemble assemble) {
+ this.assemble = assemble;
+ this.start();
+ }
+
+ @Override
+ public void run() {
+ while(true) {
+ try {
+ tick();
+ sleep(assemble.getTicks() * 50);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Tick logic for thread.
+ */
+ private void tick() {
+ for (Player player : this.assemble.getPlugin().getServer().getOnlinePlayers()) {
+ try {
+ AssembleBoard board = this.assemble.getBoards().get(player.getUniqueId());
+
+ // This shouldn't happen, but just in case.
+ if (board == null) {
+ continue;
+ }
+
+ Scoreboard scoreboard = board.getScoreboard();
+ Objective objective = board.getObjective();
+
+ if (scoreboard == null || objective == null) {
+ continue;
+ }
+
+ // Just make a variable so we don't have to
+ // process the same thing twice.
+ String title = ChatColor.translateAlternateColorCodes('&', this.assemble.getAdapter().getTitle(player));
+
+ // Update the title if needed.
+ if (!objective.getDisplayName().equals(title)) {
+ objective.setDisplayName(title);
+ }
+
+ List newLines = this.assemble.getAdapter().getLines(player);
+
+ // Allow adapter to return null/empty list to display nothing.
+ if (newLines == null || newLines.isEmpty()) {
+ board.getEntries().forEach(AssembleBoardEntry::remove);
+ board.getEntries().clear();
+ } else {
+ if (newLines.size() > 15) {
+ newLines = newLines.subList(0, 15);
+ }
+
+ // Reverse the lines because scoreboard scores are in descending order.
+ if (!this.assemble.getAssembleStyle().isDescending()) {
+ Collections.reverse(newLines);
+ }
+
+ // Remove excessive amount of board entries.
+ if (board.getEntries().size() > newLines.size()) {
+ for (int i = newLines.size(); i < board.getEntries().size(); i++) {
+ AssembleBoardEntry entry = board.getEntryAtPosition(i);
+
+ if (entry != null) {
+ entry.remove();
+ }
+ }
+ }
+
+ // Update existing entries / add new entries.
+ int cache = this.assemble.getAssembleStyle().getStartNumber();
+ for (int i = 0; i < newLines.size(); i++) {
+ AssembleBoardEntry entry = board.getEntryAtPosition(i);
+
+ // Translate any colors.
+ String line = ChatColor.translateAlternateColorCodes('&', newLines.get(i));
+
+ // If the entry is null, just create a new one.
+ // Creating a new AssembleBoardEntry instance will add
+ // itself to the provided board's entries list.
+ if (entry == null) {
+ entry = new AssembleBoardEntry(board, line, i);
+ }
+
+ // Update text, setup the team, and update the display values.
+ entry.setText(line);
+ entry.setup();
+ entry.send(
+ this.assemble.getAssembleStyle().isDescending() ? cache-- : cache++
+ );
+ }
+ }
+
+ if (player.getScoreboard() != scoreboard && !assemble.isHook()) {
+ player.setScoreboard(scoreboard);
+ }
+ } catch(Exception e) {
+ e.printStackTrace();
+ throw new AssembleException("There was an error updating " + player.getName() + "'s scoreboard.");
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/dev/aapy/scoreboard/assamble/AssembleUtils.java b/src/main/java/dev/aapy/scoreboard/assamble/AssembleUtils.java
new file mode 100644
index 0000000..c7849f1
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/assamble/AssembleUtils.java
@@ -0,0 +1,35 @@
+package dev.aapy.scoreboard.assamble;
+
+import org.bukkit.ChatColor;
+
+public class AssembleUtils {
+
+ public static String[] splitTeamText(String input) {
+ final int inputLength = input.length();
+ if (inputLength > 16) {
+ // Make the prefix the first 16 characters of our text
+ String prefix = input.substring(0, 16);
+
+ // Get the last index of the color char in the prefix
+ final int lastColorIndex = prefix.lastIndexOf(ChatColor.COLOR_CHAR);
+
+ String suffix;
+
+ if (lastColorIndex >= 14) {
+ prefix = prefix.substring(0, lastColorIndex);
+ suffix = ChatColor.getLastColors(input.substring(0, 17)) + input.substring(lastColorIndex + 2);
+ } else {
+ suffix = ChatColor.getLastColors(prefix) + input.substring(16);
+ }
+
+ if (suffix.length() > 16) {
+ suffix = suffix.substring(0, 16);
+ }
+
+ return new String[] {prefix, suffix};
+ } else {
+ return new String[] {input, ""};
+ }
+ }
+
+}
diff --git a/src/main/java/dev/aapy/scoreboard/events/AssembleBoardCreateEvent.java b/src/main/java/dev/aapy/scoreboard/events/AssembleBoardCreateEvent.java
new file mode 100644
index 0000000..561bdd1
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/events/AssembleBoardCreateEvent.java
@@ -0,0 +1,31 @@
+package dev.aapy.scoreboard.events;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+@Getter @Setter
+public class AssembleBoardCreateEvent extends Event implements Cancellable {
+
+ @Getter public static HandlerList handlerList = new HandlerList();
+
+ private Player player;
+ private boolean cancelled = false;
+
+ /**
+ * Assemble Board Create Event.
+ *
+ * @param player that the board is being created for.
+ */
+ public AssembleBoardCreateEvent(Player player) {
+ this.player = player;
+ }
+
+ @Override
+ public HandlerList getHandlers() {
+ return handlerList;
+ }
+}
diff --git a/src/main/java/dev/aapy/scoreboard/events/AssembleBoardCreatedEvent.java b/src/main/java/dev/aapy/scoreboard/events/AssembleBoardCreatedEvent.java
new file mode 100644
index 0000000..81fd7bd
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/events/AssembleBoardCreatedEvent.java
@@ -0,0 +1,30 @@
+package dev.aapy.scoreboard.events;
+
+import dev.aapy.scoreboard.assamble.AssembleBoard;
+import lombok.Getter;
+import lombok.Setter;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+@Getter @Setter
+public class AssembleBoardCreatedEvent extends Event {
+
+ @Getter public static HandlerList handlerList = new HandlerList();
+
+ private boolean cancelled = false;
+ private final AssembleBoard board;
+
+ /**
+ * Assemble Board Created Event.
+ *
+ * @param board of player.
+ */
+ public AssembleBoardCreatedEvent(AssembleBoard board) {
+ this.board = board;
+ }
+
+ @Override
+ public HandlerList getHandlers() {
+ return handlerList;
+ }
+}
diff --git a/src/main/java/dev/aapy/scoreboard/events/AssembleBoardDestroyEvent.java b/src/main/java/dev/aapy/scoreboard/events/AssembleBoardDestroyEvent.java
new file mode 100644
index 0000000..fa3a601
--- /dev/null
+++ b/src/main/java/dev/aapy/scoreboard/events/AssembleBoardDestroyEvent.java
@@ -0,0 +1,31 @@
+package dev.aapy.scoreboard.events;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+@Getter @Setter
+public class AssembleBoardDestroyEvent extends Event implements Cancellable {
+
+ @Getter public static HandlerList handlerList = new HandlerList();
+
+ private Player player;
+ private boolean cancelled = false;
+
+ /**
+ * Assemble Board Destroy Event.
+ *
+ * @param player who's board got destroyed.
+ */
+ public AssembleBoardDestroyEvent(Player player) {
+ this.player = player;
+ }
+
+ @Override
+ public HandlerList getHandlers() {
+ return handlerList;
+ }
+}
diff --git a/src/main/java/dev/aapy/tablist/PlayerTablist.java b/src/main/java/dev/aapy/tablist/PlayerTablist.java
new file mode 100644
index 0000000..37de8d1
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/PlayerTablist.java
@@ -0,0 +1,191 @@
+package dev.aapy.tablist;
+
+import dev.aapy.tablist.impl.v1_7TabImpl;
+import dev.aapy.tablist.playerversion.PlayerVersion;
+import dev.aapy.tablist.playerversion.PlayerVersionHandler;
+import dev.aapy.tablist.skin.Skin;
+import dev.aapy.tablist.utils.LegacyClient;
+import lombok.Getter;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.scoreboard.Scoreboard;
+import org.bukkit.scoreboard.Team;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Getter
+public class PlayerTablist {
+
+ private final Player player;
+ private Scoreboard scoreboard;
+ private int lastHeaderFooter;
+
+ private final Set currentEntrySet = new HashSet<>();
+
+ @SuppressWarnings("deprecation")
+ public PlayerTablist(Player player) {
+ this.player = player;
+
+ scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
+
+ //Scoreboard
+ if (!this.player.getScoreboard().equals(Bukkit.getScoreboardManager().getMainScoreboard())) {
+ scoreboard = player.getScoreboard();
+ }
+
+ player.setScoreboard(scoreboard);
+
+ this.setup();
+ Team team1 = player.getScoreboard().getTeam("\\u000181");
+ if (team1 == null) {
+ team1 = player.getScoreboard().registerNewTeam("\\u000181");
+ }
+ team1.addEntry(player.getName());
+ for (Player loopPlayer : Bukkit.getServer().getOnlinePlayers()) {
+ Team team = loopPlayer.getScoreboard().getTeam("\\u000181");
+ if (team == null) {
+ team = loopPlayer.getScoreboard().registerNewTeam("\\u000181");
+ }
+ team.addEntry(player.getName());
+ team.addEntry(loopPlayer.getName());
+ team1.addEntry(loopPlayer.getName());
+ team1.addEntry(player.getName());
+ }
+ }
+
+ public static String[] splitStrings(String text, int rawSlot) {
+ if (text.length() > 16) {
+ String prefix = text.substring(0, 16);
+ String suffix;
+
+ if (prefix.charAt(15) == ChatColor.COLOR_CHAR || prefix.charAt(15) == '&') {
+ prefix = prefix.substring(0, 15);
+ suffix = text.substring(15);
+ } else if (prefix.charAt(14) == ChatColor.COLOR_CHAR || prefix.charAt(14) == '&') {
+ prefix = prefix.substring(0, 14);
+ suffix = text.substring(14);
+ } else {
+ suffix = ChatColor.getLastColors(ChatColor.translateAlternateColorCodes('&', prefix)) + text.substring(16);
+ }
+
+ if (suffix.length() > 16) {
+ suffix = suffix.substring(0, 16);
+ }
+
+ return new String[]{
+ prefix,
+ suffix
+ };
+ } else {
+ return new String[]{
+ text
+ };
+ }
+ }
+
+ private void setup() {
+ final int possibleSlots = (PlayerVersionHandler.getPlayerVersion(player) == PlayerVersion.v1_7 ? 60 : 80);
+ for (int i = 1; i <= possibleSlots; i++) {
+ final TabColumn tabColumn = TabColumn.getFromSlot(player, i);
+ if (tabColumn == null) {
+ continue;
+ }
+ TabEntry tabEntry = Tab.getInstance().getImplementation().createFakePlayer(
+ this,
+ "0" + (i > 9 ? i : "0" + i) + "|Tab",
+ tabColumn,
+ tabColumn.getNumb(player, i),
+ i
+ );
+ if (Bukkit.getPluginManager().getPlugin("Featherboard") == null
+ && (PlayerVersionHandler.version.getPlayerVersion(player) == PlayerVersion.v1_7
+ || Tab.getInstance().getImplementation() instanceof v1_7TabImpl)) {
+ Team team = player.getScoreboard().getTeam(LegacyClient.NAMES.get(i - 1));
+ if (team != null) {
+ team.unregister();
+ }
+ team = player.getScoreboard().registerNewTeam(LegacyClient.NAMES.get(i - 1));
+ team.setPrefix("");
+ team.setSuffix("");
+
+ team.addEntry(LegacyClient.ENTRY.get(i - 1));
+
+ }
+ currentEntrySet.add(tabEntry);
+ }
+
+ if (Bukkit.getPluginManager().getPlugin("Featherboard") != null) {
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ for (int i = 1; i <= possibleSlots; i++) {
+ if (PlayerVersionHandler.version.getPlayerVersion(player) == PlayerVersion.v1_7 || Tab.getInstance().getImplementation() instanceof v1_7TabImpl) {
+ Team team = player.getScoreboard().getTeam(LegacyClient.NAMES.get(i - 1));
+ if (team != null) {
+ team.unregister();
+ }
+ team = player.getScoreboard().registerNewTeam(LegacyClient.NAMES.get(i - 1));
+ team.setPrefix("");
+ team.setSuffix("");
+
+ team.addEntry(LegacyClient.ENTRY.get(i - 1));
+
+ }
+ }
+ }
+ }.runTaskLater(Tab.getInstance().getPlugin(), 40);
+ }
+ }
+
+ public void update() {
+ if (PlayerVersionHandler.getPlayerVersion(player) != PlayerVersion.v1_7) {
+ List header = Tab.getInstance().getProvider().getHeader(player);
+ List footer = Tab.getInstance().getProvider().getFooter(player);
+
+ int headerFooter = header.hashCode() + footer.hashCode();
+
+ if (headerFooter != lastHeaderFooter) {
+ lastHeaderFooter = headerFooter;
+ Tab.getInstance().getImplementation().updateHeaderAndFooter(player, header, footer);
+ }
+ }
+
+
+ Set lastSet = new HashSet<>(currentEntrySet);
+ for (TabLayout layout : Tab.getInstance().getProvider().getProvider(player)) {
+ TabEntry tabEntry = getEntry(layout.getColumn(), layout.getSlot());
+ if (tabEntry != null) {
+ lastSet.remove(tabEntry);
+ Tab.getInstance().getImplementation().updateFakeName(this, tabEntry, layout.getText());
+ Tab.getInstance().getImplementation().updateFakeLatency(this, tabEntry, layout.getPing());
+ if (PlayerVersionHandler.getPlayerVersion(player) != PlayerVersion.v1_7) {
+ if (layout.getSkin() != null || !tabEntry.getSkin().equals(layout.getSkin())) {
+
+ Tab.getInstance().getImplementation().updateFakeSkin(this, tabEntry, layout.getSkin());
+ }
+ }
+ }
+ }
+ for (TabEntry tabEntry : lastSet) {
+ Tab.getInstance().getImplementation().updateFakeName(this, tabEntry, "");
+ Tab.getInstance().getImplementation().updateFakeLatency(this, tabEntry, -1);
+ if (PlayerVersionHandler.getPlayerVersion(player) != PlayerVersion.v1_7) {
+ Tab.getInstance().getImplementation().updateFakeSkin(this, tabEntry, Skin.DEFAULT);
+ }
+ }
+ lastSet.clear();
+ }
+
+ public TabEntry getEntry(TabColumn column, Integer slot) {
+ for (TabEntry entry : currentEntrySet) {
+ if (entry.getColumn().name().equalsIgnoreCase(column.name()) && entry.getSlot() == slot) {
+ return entry;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/dev/aapy/tablist/Tab.java b/src/main/java/dev/aapy/tablist/Tab.java
new file mode 100644
index 0000000..28a6e4d
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/Tab.java
@@ -0,0 +1,92 @@
+package dev.aapy.tablist;
+
+import dev.aapy.tablist.impl.v1_7TabImpl;
+import dev.aapy.tablist.impl.v1_8TabImpl;
+import dev.aapy.tablist.playerversion.PlayerVersionHandler;
+import lombok.Getter;
+import org.bukkit.Bukkit;
+import org.bukkit.event.HandlerList;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Getter
+public class Tab {
+
+ @Getter
+ private static Tab instance;
+
+ private final JavaPlugin plugin;
+ private final TabProvider provider;
+ private final Map tablists;
+ private TabThread thread;
+ private TabNMS implementation;
+ private TabListener listeners;
+
+
+ public Tab(JavaPlugin plugin, TabProvider provider) {
+ instance = this;
+
+ this.plugin = plugin;
+ this.provider = provider;
+ this.tablists = new ConcurrentHashMap<>();
+
+ new PlayerVersionHandler();
+
+ this.registerImplementation();
+
+ this.setup();
+ }
+
+ private void registerImplementation() {
+ String serverVersion = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
+
+ if (serverVersion.equalsIgnoreCase("v1_7_R4")) {
+ this.implementation = new v1_7TabImpl();
+ System.out.println("Registered Implementation with 1.7 Tab");
+ return;
+ }
+ if (serverVersion.equalsIgnoreCase("v1_8_R3")) {
+ this.implementation = new v1_8TabImpl();
+ System.out.println("Registered Implementation with 1.8 Tab");
+ return;
+ }
+
+ if (Bukkit.getPluginManager().getPlugin("ProtocolLib") != null) {
+ plugin.getLogger().info("Registered Implementation with ProtocolLib");
+ return;
+ }
+
+ }
+
+ @SuppressWarnings("deprecation")
+ private void setup() {
+ listeners = new TabListener();
+ //Register Events
+ this.plugin.getServer().getPluginManager().registerEvents(listeners, this.plugin);
+
+ //Ensure that the thread has stopped running
+ if (this.thread != null) {
+ this.thread.stop();
+ this.thread = null;
+ }
+
+ //Start Thread
+ this.thread = new TabThread(this);
+ }
+
+ @SuppressWarnings("deprecation")
+ public void disable() {
+ if (this.thread != null) {
+ this.thread.stop();
+ this.thread = null;
+ }
+
+ if (listeners != null) {
+ HandlerList.unregisterAll(listeners);
+ listeners = null;
+ }
+ }
+}
diff --git a/src/main/java/dev/aapy/tablist/TabColumn.java b/src/main/java/dev/aapy/tablist/TabColumn.java
new file mode 100644
index 0000000..d8614f3
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/TabColumn.java
@@ -0,0 +1,105 @@
+package dev.aapy.tablist;
+
+
+import dev.aapy.tablist.playerversion.PlayerVersion;
+import dev.aapy.tablist.playerversion.PlayerVersionHandler;
+import lombok.Getter;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@Getter
+public enum TabColumn {
+
+ LEFT(0, "Left", -2, 1, 3),
+ MIDDLE(1, "Middle", -1, 21, 3),
+ RIGHT(2, "Right", 0, 41, 3),
+ /**
+ * Far Right Column
+ * Note: This Column is only visible on 1.8+ player versions.
+ */
+ FAR_RIGHT(3, "Far-Right", 60, 61, 1);
+
+ private final int startNumber;
+ private final int incrementBy;
+ private final int rawStart;
+ private final List numbers = new ArrayList<>();
+ private final String identifier;
+ private final int ordinal;
+
+ TabColumn(int ordinal, String identifier, int rawStart, int startNumber, int incrementBy) {
+ this.ordinal = ordinal;
+ this.identifier = identifier;
+ this.rawStart = rawStart;
+ this.startNumber = startNumber;
+ this.incrementBy = incrementBy;
+ generate();
+ }
+
+ public static TabColumn getColumn(String identifier) {
+ for (TabColumn tabColumn : TabColumn.values()) {
+ if (tabColumn.getIdentifier().equalsIgnoreCase(identifier)) {
+ return tabColumn;
+ }
+ }
+ return null;
+ }
+
+ private static boolean isBetween(int input, int min, int max) {
+ return input >= min && input <= max;
+ }
+
+ public static TabColumn getFromSlot(Player player, Integer slot) {
+ /* Player Version 1.7 */
+ if (PlayerVersionHandler.getPlayerVersion(player) == PlayerVersion.v1_7) {
+ return Arrays.stream(TabColumn.values())
+ .filter(tabColumn -> tabColumn.getNumbers().contains(slot))
+ .findFirst().get();
+ /* Player Version 1.8+ */
+ } else {
+ /* Left Column */
+ if (isBetween(slot, 1, 20)) return LEFT;
+ /* Middle Column */
+ if (isBetween(slot, 21, 40)) return MIDDLE;
+ /* Right Column */
+ if (isBetween(slot, 41, 60)) return RIGHT;
+ /* Far Right Column */
+ if (isBetween(slot, 61, 80)) return FAR_RIGHT;
+ return null;
+ }
+ }
+
+ public static TabColumn getFromOrdinal(int ordinal) {
+ for (TabColumn column : TabColumn.values()) {
+ if (column.getOrdinal() == ordinal) {
+ return column;
+ }
+ }
+ return null;
+ }
+
+ private void generate() {
+ for (int i = 1; i <= 20; i++) {
+ Integer numb = rawStart + (i * incrementBy);
+ this.numbers.add(numb);
+ }
+ }
+
+ public Integer getNumb(Player player, int raw) {
+ /* Check if the Player is not a 1.7 User */
+ if (PlayerVersionHandler.getPlayerVersion(player) != PlayerVersion.v1_7) {
+ return raw - startNumber + 1;
+ }
+ int number = 0;
+ for (int integer : numbers) {
+ number++;
+ if (integer == raw) {
+ return number;
+ }
+ }
+ return number;
+ }
+}
+
diff --git a/src/main/java/dev/aapy/tablist/TabEntry.java b/src/main/java/dev/aapy/tablist/TabEntry.java
new file mode 100644
index 0000000..d5774bf
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/TabEntry.java
@@ -0,0 +1,25 @@
+package dev.aapy.tablist;
+
+
+import dev.aapy.tablist.skin.Skin;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import org.bukkit.OfflinePlayer;
+
+@Getter
+@Setter
+@AllArgsConstructor
+public class TabEntry {
+
+ private String id;
+ private OfflinePlayer offlinePlayer;
+ private String text;
+ private PlayerTablist tab;
+ private Skin skin;
+ private TabColumn column;
+ private int slot;
+ private int rawSlot;
+ private int latency;
+
+}
diff --git a/src/main/java/dev/aapy/tablist/TabLayout.java b/src/main/java/dev/aapy/tablist/TabLayout.java
new file mode 100644
index 0000000..78de357
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/TabLayout.java
@@ -0,0 +1,43 @@
+package dev.aapy.tablist;
+
+import dev.aapy.tablist.skin.Skin;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class TabLayout {
+
+ private TabColumn column = TabColumn.LEFT;
+ private int ping = 0;
+ private int slot = 1;
+ private String text = "";
+ private Skin skin = Skin.DEFAULT;
+
+
+ public TabLayout text(String text) {
+ this.text = text;
+ return this;
+ }
+
+ public TabLayout skin(Skin skin) {
+ this.skin = skin;
+ return this;
+ }
+
+ public TabLayout slot(Integer slot) {
+ this.slot = slot;
+ return this;
+ }
+
+ public TabLayout ping(Integer ping) {
+ this.ping = ping;
+ return this;
+ }
+
+ public TabLayout column(TabColumn tabColumn) {
+ this.column = tabColumn;
+ return this;
+ }
+
+}
diff --git a/src/main/java/dev/aapy/tablist/TabListener.java b/src/main/java/dev/aapy/tablist/TabListener.java
new file mode 100644
index 0000000..18840e0
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/TabListener.java
@@ -0,0 +1,47 @@
+package dev.aapy.tablist;
+
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerKickEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.event.server.PluginDisableEvent;
+import org.bukkit.scoreboard.Team;
+
+public class TabListener implements Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onJoin(PlayerJoinEvent event) {
+ final Player player = event.getPlayer();
+
+ Tab.getInstance().getTablists().put(player.getUniqueId(), new PlayerTablist(event.getPlayer()));
+ }
+
+
+ private void handleDisconnect(Player player) {
+ Team team = player.getScoreboard().getTeam("\\u000181");
+ if (team != null) {
+ team.unregister();
+ }
+
+ Tab.getInstance().getTablists().remove(player.getUniqueId());
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void onPlayerQuit(PlayerQuitEvent event) {
+ handleDisconnect(event.getPlayer());
+ }
+
+ @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
+ public void onPlayerKick(PlayerKickEvent event) {
+ handleDisconnect(event.getPlayer());
+ }
+
+
+ @EventHandler
+ public void onPluginDisable(PluginDisableEvent event) {
+ Tab.getInstance().disable();
+ }
+}
diff --git a/src/main/java/dev/aapy/tablist/TabNMS.java b/src/main/java/dev/aapy/tablist/TabNMS.java
new file mode 100644
index 0000000..3cc86e2
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/TabNMS.java
@@ -0,0 +1,33 @@
+package dev.aapy.tablist;
+
+import dev.aapy.tablist.skin.Skin;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+
+public interface TabNMS {
+
+ TabEntry createFakePlayer(
+ PlayerTablist playerTablist, String string, TabColumn column, Integer slot, Integer rawSlot
+ );
+
+ void updateFakeName(
+ PlayerTablist playerTablist, TabEntry tabEntry, String text
+ );
+
+ void updateFakeLatency(
+ PlayerTablist playerTablist, TabEntry tabEntry, Integer latency
+ );
+
+ void updateFakeSkin(
+ PlayerTablist playerTablist, TabEntry tabEntry, Skin skin
+ );
+
+ void updateHeaderAndFooter(
+ Player player, List header, List footer
+ );
+
+ Skin getSkin(
+ Player player);
+
+}
diff --git a/src/main/java/dev/aapy/tablist/TabProvider.java b/src/main/java/dev/aapy/tablist/TabProvider.java
new file mode 100644
index 0000000..bf525de
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/TabProvider.java
@@ -0,0 +1,17 @@
+package dev.aapy.tablist;
+
+import org.bukkit.entity.Player;
+
+import java.util.List;
+import java.util.Set;
+
+
+public interface TabProvider {
+
+ Set getProvider(Player player);
+
+ List getFooter(Player player);
+
+ List getHeader(Player player);
+
+}
diff --git a/src/main/java/dev/aapy/tablist/TabThread.java b/src/main/java/dev/aapy/tablist/TabThread.java
new file mode 100644
index 0000000..00c2918
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/TabThread.java
@@ -0,0 +1,35 @@
+package dev.aapy.tablist;
+
+public class TabThread extends Thread {
+
+ private final Tab htab;
+
+ public TabThread(Tab htab) {
+ this.htab = htab;
+ this.start();
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ //Tick
+ try {
+ tick();
+ } catch (NullPointerException e) {
+ e.printStackTrace();
+ }
+ //Thread Sleep
+ try {
+ sleep(250L);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void tick() {
+ for (PlayerTablist tablist : htab.getTablists().values()) {
+ tablist.update();
+ }
+ }
+}
diff --git a/src/main/java/dev/aapy/tablist/impl/v1_7TabImpl.java b/src/main/java/dev/aapy/tablist/impl/v1_7TabImpl.java
new file mode 100644
index 0000000..06d1371
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/impl/v1_7TabImpl.java
@@ -0,0 +1,300 @@
+package dev.aapy.tablist.impl;
+
+import dev.aapy.tablist.utils.CC;
+import dev.aapy.tablist.utils.Reflection;
+import dev.aapy.tablist.PlayerTablist;
+import dev.aapy.tablist.TabColumn;
+import dev.aapy.tablist.TabEntry;
+import dev.aapy.tablist.TabNMS;
+import dev.aapy.tablist.playerversion.PlayerVersion;
+import dev.aapy.tablist.playerversion.PlayerVersionHandler;
+import dev.aapy.tablist.skin.Skin;
+import dev.aapy.tablist.utils.LegacyClient;
+import net.minecraft.server.v1_7_R4.*;
+import net.minecraft.util.com.mojang.authlib.GameProfile;
+import net.minecraft.util.com.mojang.authlib.properties.Property;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.craftbukkit.v1_7_R4.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.scoreboard.Team;
+import org.spigotmc.ProtocolInjector;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+
+public class v1_7TabImpl implements TabNMS {
+
+ private static final MinecraftServer server = MinecraftServer.getServer();
+ private static final WorldServer world = server.getWorldServer(0);
+ private static final PlayerInteractManager manager = new PlayerInteractManager(world);
+
+ public v1_7TabImpl() {
+ }
+
+ @Override
+ public TabEntry createFakePlayer(PlayerTablist playerTablist, String string, TabColumn column, Integer slot, Integer rawSlot) {
+ final OfflinePlayer offlinePlayer = new OfflinePlayer() {
+ private final UUID uuid = UUID.randomUUID();
+
+ @Override
+ public boolean isOnline() {
+ return true;
+ }
+
+ @Override
+ public String getName() {
+ return string;
+ }
+
+ @Override
+ public UUID getUniqueId() {
+ return uuid;
+ }
+
+ @Override
+ public boolean isBanned() {
+ return false;
+ }
+
+ @Override
+ public void setBanned(boolean b) {
+
+ }
+
+ @Override
+ public boolean isWhitelisted() {
+ return false;
+ }
+
+ @Override
+ public void setWhitelisted(boolean b) {
+
+ }
+
+ @Override
+ public Player getPlayer() {
+ return null;
+ }
+
+ @Override
+ public long getFirstPlayed() {
+ return 0;
+ }
+
+ @Override
+ public long getLastPlayed() {
+ return 0;
+ }
+
+
+ @Override
+ public boolean hasPlayedBefore() {
+ return false;
+ }
+
+ @Override
+ public Location getBedSpawnLocation() {
+ return null;
+ }
+
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean isOp() {
+ return false;
+ }
+
+ @Override
+ public void setOp(boolean b) {
+
+ }
+ };
+ final Player player = playerTablist.getPlayer();
+ final PlayerVersion playerVersion = PlayerVersionHandler.getPlayerVersion(player);
+
+ GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), LegacyClient.ENTRY.get(rawSlot - 1) + "");
+ EntityPlayer entity = new EntityPlayer(server, world, profile, manager);
+
+ if (playerVersion != PlayerVersion.v1_7) {
+ profile.getProperties().removeAll("textures");
+ profile.getProperties().put("textures", new Property("textures", Skin.DEFAULT.getValue(), Skin.DEFAULT.getSignature()));
+ }
+ entity.ping = 1;
+
+ sendPacket(playerTablist.getPlayer(), PacketPlayOutPlayerInfoWrapper.newAddPacket(profile));
+
+ return new TabEntry(string, offlinePlayer, "", playerTablist, Skin.DEFAULT, column, slot, rawSlot, 0);
+ }
+
+ @SuppressWarnings("unused")
+ @Override
+ public void updateFakeName(PlayerTablist playerTablist, TabEntry tabEntry, String text) {
+ if (tabEntry.getText().equals(text)) {
+ return;
+ }
+
+ final Player player = playerTablist.getPlayer();
+ final PlayerVersion playerVersion = PlayerVersionHandler.getPlayerVersion(player);
+ String[] newStrings = PlayerTablist.splitStrings(text, tabEntry.getRawSlot());
+
+ Team team = player.getScoreboard().getTeam(LegacyClient.NAMES.get(tabEntry.getRawSlot() - 1));
+ team.setPrefix(ChatColor.translateAlternateColorCodes('&', newStrings[0]));
+ if (newStrings.length > 1) {
+ team.setSuffix(ChatColor.translateAlternateColorCodes('&', newStrings[1]));
+ } else {
+ team.setSuffix("");
+ }
+
+ tabEntry.setText(text);
+ }
+
+ @Override
+ public void updateFakeLatency(PlayerTablist playerTablist, TabEntry tabEntry, Integer latency) {
+ if (tabEntry.getLatency() == latency) {
+ return;
+ }
+
+ GameProfile profile = new GameProfile(tabEntry.getOfflinePlayer().getUniqueId(), LegacyClient.ENTRY.get(tabEntry.getRawSlot() - 1) + "");
+ EntityPlayer entity = new EntityPlayer(server, world, profile, manager);
+ entity.ping = latency;
+
+ sendPacket(playerTablist.getPlayer(), PacketPlayOutPlayerInfoWrapper.updateLatency(profile));
+ tabEntry.setLatency(latency);
+ }
+
+ @Override
+ public void updateFakeSkin(PlayerTablist playerTablist, TabEntry tabEntry, Skin skin) {
+ if (tabEntry.getSkin() == skin) {
+ return;
+ }
+ GameProfile profile = new GameProfile(tabEntry.getOfflinePlayer().getUniqueId(), LegacyClient.ENTRY.get(tabEntry.getRawSlot() - 1) + "");
+ profile.getProperties().removeAll("textures");
+ profile.getProperties().put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+
+ sendPacket(playerTablist.getPlayer(), PacketPlayOutPlayerInfoWrapper.newRemovePacket(profile));
+ sendPacket(playerTablist.getPlayer(), PacketPlayOutPlayerInfoWrapper.newAddPacket(profile));
+
+
+ tabEntry.setSkin(skin);
+ }
+
+ @Override
+ public void updateHeaderAndFooter(Player player, List header, List footer) {
+ IChatBaseComponent headerComponent = ChatSerializer.a("{text:\"" + StringEscapeUtils.escapeJava(this.getListFromString(CC.translate(header))) + "\"}");
+ IChatBaseComponent footerComponent = ChatSerializer.a("{text:\"" + StringEscapeUtils.escapeJava(this.getListFromString(CC.translate(footer))) + "\"}");
+ ProtocolInjector.PacketTabHeader packetTabHeader = new ProtocolInjector.PacketTabHeader(headerComponent, footerComponent);
+ sendPacket(player, packetTabHeader);
+ }
+
+ public String getListFromString(List list) {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < list.size(); ++i) {
+ stringBuilder.append(list.get(i));
+ if (i != list.size() - 1) {
+ stringBuilder.append('\n');
+ }
+ }
+ return stringBuilder.toString();
+ }
+
+ @Override
+ public Skin getSkin(Player player) {
+ if (Skin.CACHE.containsKey(player.getUniqueId())) return Skin.CACHE.get(player.getUniqueId());
+
+ try {
+ CraftPlayer craftPlayer = (CraftPlayer) player;
+ EntityPlayer entityPlayer = craftPlayer.getHandle();
+
+ Property property = entityPlayer.getProfile().getProperties().get("textures").stream().findFirst().orElse(null);
+
+ if (property != null) {
+ return Skin.CACHE.put(player.getUniqueId(), new Skin(property.getValue(), property.getSignature()));
+ }
+ } catch (Exception ignored) {
+ // ignored
+ }
+
+ return Skin.STEVE;
+ }
+
+ public static class PacketPlayOutPlayerInfoWrapper {
+
+ private static MethodHandle PLAYER_SETTER;
+ private static MethodHandle USERNAME_SETTER;
+ private static MethodHandle ACTION_SETTER;
+
+ static {
+ try {
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ PLAYER_SETTER = lookup.unreflectSetter(Reflection.setAccessibleAndGet(PacketPlayOutPlayerInfo.class, "player"));
+ USERNAME_SETTER = lookup.unreflectSetter(Reflection.setAccessibleAndGet(PacketPlayOutPlayerInfo.class, "username"));
+ ACTION_SETTER = lookup.unreflectSetter(Reflection.setAccessibleAndGet(PacketPlayOutPlayerInfo.class, "action"));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+ public static PacketPlayOutPlayerInfo newAddPacket(GameProfile gameProfile) {
+ PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
+
+ try {
+ PLAYER_SETTER.invokeExact(packet, gameProfile);
+ USERNAME_SETTER.invokeExact(packet, gameProfile.getName());
+ ACTION_SETTER.invokeExact(packet, 0);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ return packet;
+ }
+
+ public static PacketPlayOutPlayerInfo newRemovePacket(GameProfile gameProfile) {
+ PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
+
+ try {
+ PLAYER_SETTER.invokeExact(packet, gameProfile);
+ USERNAME_SETTER.invokeExact(packet, gameProfile.getName());
+ ACTION_SETTER.invokeExact(packet, 4);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ return packet;
+ }
+
+ public static PacketPlayOutPlayerInfo updateLatency(GameProfile gameProfile) {
+ PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
+
+ try {
+ PLAYER_SETTER.invokeExact(packet, gameProfile);
+ USERNAME_SETTER.invokeExact(packet, gameProfile.getName());
+ ACTION_SETTER.invokeExact(packet, 2);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ return packet;
+ }
+
+ }
+
+ private void sendPacket(Player player, Packet packet) {
+ getEntity(player).playerConnection.sendPacket(packet);
+ }
+
+ private EntityPlayer getEntity(Player player) {
+ return ((CraftPlayer) player).getHandle();
+ }
+
+}
diff --git a/src/main/java/dev/aapy/tablist/impl/v1_8TabImpl.java b/src/main/java/dev/aapy/tablist/impl/v1_8TabImpl.java
new file mode 100644
index 0000000..d1f8d49
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/impl/v1_8TabImpl.java
@@ -0,0 +1,347 @@
+package dev.aapy.tablist.impl;
+
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import dev.aapy.tablist.utils.CC;
+import dev.aapy.tablist.utils.Reflection;
+import dev.aapy.tablist.PlayerTablist;
+import dev.aapy.tablist.TabColumn;
+import dev.aapy.tablist.TabEntry;
+import dev.aapy.tablist.TabNMS;
+import dev.aapy.tablist.playerversion.PlayerVersion;
+import dev.aapy.tablist.playerversion.PlayerVersionHandler;
+import dev.aapy.tablist.skin.Skin;
+import dev.aapy.tablist.utils.LegacyClient;
+import net.minecraft.server.v1_8_R3.*;
+import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo.EnumPlayerInfoAction;
+import net.minecraft.server.v1_8_R3.WorldSettings.EnumGamemode;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.scoreboard.Team;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+
+public class v1_8TabImpl implements TabNMS {
+
+ public v1_8TabImpl() {
+ }
+
+ @Override
+ public TabEntry createFakePlayer(PlayerTablist playerTablist, String string, TabColumn column, Integer slot, Integer rawSlot) {
+ final OfflinePlayer offlinePlayer = new OfflinePlayer() {
+ private final UUID uuid = UUID.randomUUID();
+
+ @Override
+ public boolean isOnline() {
+ return true;
+ }
+
+ @Override
+ public String getName() {
+ return string;
+ }
+
+ @Override
+ public UUID getUniqueId() {
+ return uuid;
+ }
+
+ @Override
+ public boolean isBanned() {
+ return false;
+ }
+
+ @Override
+ public void setBanned(boolean b) {
+
+ }
+
+ @Override
+ public boolean isWhitelisted() {
+ return false;
+ }
+
+ @Override
+ public void setWhitelisted(boolean b) {
+
+ }
+
+ @Override
+ public Player getPlayer() {
+ return null;
+ }
+
+ @Override
+ public long getFirstPlayed() {
+ return 0;
+ }
+
+ @Override
+ public long getLastPlayed() {
+ return 0;
+ }
+
+
+ @Override
+ public boolean hasPlayedBefore() {
+ return false;
+ }
+
+ @Override
+ public Location getBedSpawnLocation() {
+ return null;
+ }
+
+ @Override
+ public Map serialize() {
+ return null;
+ }
+
+ @Override
+ public boolean isOp() {
+ return false;
+ }
+
+ @Override
+ public void setOp(boolean b) {
+
+ }
+ };
+ final Player player = playerTablist.getPlayer();
+ final PlayerVersion playerVersion = PlayerVersionHandler.getPlayerVersion(player);
+
+ GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), (playerVersion != PlayerVersion.v1_7 ? string : LegacyClient.ENTRY.get(rawSlot - 1) + ""));
+
+ if (playerVersion != PlayerVersion.v1_7) {
+ profile.getProperties().removeAll("textures");
+ profile.getProperties().put("textures", new Property("textures", Skin.DEFAULT.getValue(), Skin.DEFAULT.getSignature()));
+ }
+
+ sendPacket(playerTablist.getPlayer(), PacketPlayOutPlayerInfoWrapper.newAddPacket(profile, 1, player));
+
+ return new TabEntry(string, offlinePlayer, "", playerTablist, Skin.DEFAULT, column, slot, rawSlot, 0);
+ }
+
+ @SuppressWarnings("unused")
+ @Override
+ public void updateFakeName(PlayerTablist playerTablist, TabEntry tabEntry, String text) {
+ if (tabEntry.getText().equals(text)) {
+ return;
+ }
+
+ final Player player = playerTablist.getPlayer();
+ final PlayerVersion playerVersion = PlayerVersionHandler.getPlayerVersion(player);
+ String[] newStrings = PlayerTablist.splitStrings(text, tabEntry.getRawSlot());
+ if (playerVersion == PlayerVersion.v1_7) {
+
+ Team team = player.getScoreboard().getTeam(LegacyClient.NAMES.get(tabEntry.getRawSlot() - 1));
+ team.setPrefix(ChatColor.translateAlternateColorCodes('&', newStrings[0]));
+ if (newStrings.length > 1) {
+ team.setSuffix(ChatColor.translateAlternateColorCodes('&', newStrings[1]));
+ } else {
+ team.setSuffix("");
+ }
+ } else {
+
+ GameProfile gameProfile = new GameProfile(tabEntry.getOfflinePlayer().getUniqueId(), tabEntry.getId());
+
+ sendPacket(player, PacketPlayOutPlayerInfoWrapper.updateDisplayName(gameProfile, CC.translate(newStrings.length > 1 ? newStrings[0] + newStrings[1] : newStrings[0]), tabEntry.getLatency()));
+
+ }
+ tabEntry.setText(text);
+ }
+
+ @Override
+ public void updateFakeLatency(PlayerTablist playerTablist, TabEntry tabEntry, Integer latency) {
+ if (tabEntry.getLatency() == latency) {
+ return;
+ }
+
+ GameProfile profile = new GameProfile(tabEntry.getOfflinePlayer().getUniqueId(), LegacyClient.ENTRY.get(tabEntry.getRawSlot() - 1) + "");
+
+ sendPacket(playerTablist.getPlayer(), PacketPlayOutPlayerInfoWrapper.updateLatency(profile, CC.translate(tabEntry.getText()), latency));
+
+ tabEntry.setLatency(latency);
+ }
+
+ @Override
+ public void updateFakeSkin(PlayerTablist playerTablist, TabEntry tabEntry, Skin skin) {
+ if (tabEntry.getSkin() == skin) {
+ return;
+ }
+ GameProfile profile = new GameProfile(tabEntry.getOfflinePlayer().getUniqueId(), LegacyClient.ENTRY.get(tabEntry.getRawSlot() - 1) + "");
+ profile.getProperties().removeAll("textures");
+ profile.getProperties().put("textures", new Property("textures", skin.getValue(), skin.getSignature()));
+
+ sendPacket(playerTablist.getPlayer(), PacketPlayOutPlayerInfoWrapper.newRemovePacket(profile, tabEntry.getLatency()));
+ sendPacket(playerTablist.getPlayer(), PacketPlayOutPlayerInfoWrapper.newAddPacket(profile, tabEntry.getLatency(), playerTablist.getPlayer()));
+
+ tabEntry.setSkin(skin);
+ }
+
+ @Override
+ public void updateHeaderAndFooter(Player player, List header, List footer) {
+ IChatBaseComponent headerComponent = IChatBaseComponent.ChatSerializer.a("{text:\"" + StringEscapeUtils.escapeJava(this.getListFromString(CC.translate(header))) + "\"}");
+ IChatBaseComponent footerComponent = IChatBaseComponent.ChatSerializer.a("{text:\"" + StringEscapeUtils.escapeJava(this.getListFromString(CC.translate(footer))) + "\"}");
+ PacketPlayOutPlayerListHeaderFooter packet = new PacketPlayOutPlayerListHeaderFooter();
+
+ try {
+ Field headerField = packet.getClass().getDeclaredField("a");
+ headerField.setAccessible(true);
+ headerField.set(packet, headerComponent);
+ headerField.setAccessible(!headerField.isAccessible());
+
+ Field footerField = packet.getClass().getDeclaredField("b");
+ footerField.setAccessible(true);
+ footerField.set(packet, footerComponent);
+ footerField.setAccessible(!footerField.isAccessible());
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ }
+ sendPacket(player, packet);
+ }
+
+ public String getListFromString(List list) {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < list.size(); ++i) {
+ stringBuilder.append(list.get(i));
+ if (i != list.size() - 1) {
+ stringBuilder.append('\n');
+ }
+ }
+ return stringBuilder.toString();
+ }
+
+ @Override
+ public Skin getSkin(Player player) {
+ if (Skin.CACHE.containsKey(player.getUniqueId())) return Skin.CACHE.get(player.getUniqueId());
+
+ try {
+ CraftPlayer craftPlayer = (CraftPlayer) player;
+ EntityPlayer entityPlayer = craftPlayer.getHandle();
+
+ Property property = entityPlayer.getProfile().getProperties().get("textures").stream().findFirst().orElse(null);
+
+ if (property != null) {
+ return Skin.CACHE.put(player.getUniqueId(), new Skin(property.getValue(), property.getSignature()));
+ }
+ } catch (Exception ignored) {
+ // ignored
+ }
+
+ return Skin.STEVE;
+ }
+
+ private void sendPacket(Player player, Packet packet) {
+ getEntity(player).playerConnection.sendPacket(packet);
+ }
+
+ private EntityPlayer getEntity(Player player) {
+ return ((CraftPlayer) player).getHandle();
+ }
+
+
+ public static class PacketPlayOutPlayerInfoWrapper {
+
+ private static MethodHandle PLAYER_INFO_SETTER;
+ private static MethodHandle ACTION_SETTER;
+
+ static {
+ try {
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ PLAYER_INFO_SETTER = lookup.unreflectSetter(Reflection.setAccessibleAndGet(PacketPlayOutPlayerInfo.class, "b"));
+ ACTION_SETTER = lookup.unreflectSetter(Reflection.setAccessibleAndGet(PacketPlayOutPlayerInfo.class, "a"));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+ public static PacketPlayOutPlayerInfo newAddPacket(com.mojang.authlib.GameProfile gameProfile, Integer ping, Player playerTab) {
+ PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
+ PlayerVersion playerVersion = PlayerVersionHandler.getPlayerVersion(playerTab);
+
+ try {
+ PacketPlayOutPlayerInfo.PlayerInfoData infoData = new PacketPlayOutPlayerInfo.PlayerInfoData(gameProfile, ping,
+ EnumGamemode.NOT_SET, new ChatComponentText(
+
+
+ (playerVersion != PlayerVersion.v1_7 ? "" : gameProfile.getName())));
+
+ PLAYER_INFO_SETTER.invokeExact(packet, Collections.singletonList(infoData));
+ ACTION_SETTER.invokeExact(packet, EnumPlayerInfoAction.ADD_PLAYER);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ return packet;
+ }
+
+ public static PacketPlayOutPlayerInfo newRemovePacket(GameProfile gameProfile, Integer ping) {
+ PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
+
+ try {
+ PacketPlayOutPlayerInfo.PlayerInfoData infoData = new PacketPlayOutPlayerInfo.PlayerInfoData(gameProfile, ping,
+ EnumGamemode.NOT_SET, new ChatComponentText(gameProfile.getName()));
+
+ PLAYER_INFO_SETTER.invokeExact(packet, Collections.singletonList(infoData));
+ ACTION_SETTER.invokeExact(packet, EnumPlayerInfoAction.REMOVE_PLAYER);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ return packet;
+ }
+
+ public static PacketPlayOutPlayerInfo updateDisplayName(GameProfile profile, String displayName, Integer ping) {
+ PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
+
+ try {
+ PacketPlayOutPlayerInfo.PlayerInfoData infoData = new PacketPlayOutPlayerInfo.PlayerInfoData(profile, ping,
+ EnumGamemode.NOT_SET, new ChatComponentText(displayName));
+
+ PLAYER_INFO_SETTER.invokeExact(packet, Collections.singletonList(infoData));
+ ACTION_SETTER.invokeExact(packet, EnumPlayerInfoAction.UPDATE_DISPLAY_NAME);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ return packet;
+ }
+
+
+ public static PacketPlayOutPlayerInfo updateLatency(GameProfile profile, String displayName, Integer ping) {
+ PacketPlayOutPlayerInfo packet = new PacketPlayOutPlayerInfo();
+
+ try {
+ PacketPlayOutPlayerInfo.PlayerInfoData infoData = new PacketPlayOutPlayerInfo.PlayerInfoData(
+
+ profile,
+ ping,
+ EnumGamemode.NOT_SET,
+ new ChatComponentText(displayName));
+
+ PLAYER_INFO_SETTER.invokeExact(packet, Collections.singletonList(infoData));
+ ACTION_SETTER.invokeExact(packet, EnumPlayerInfoAction.UPDATE_LATENCY);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ return packet;
+ }
+
+ }
+
+
+}
diff --git a/src/main/java/dev/aapy/tablist/playerversion/IPlayerVersion.java b/src/main/java/dev/aapy/tablist/playerversion/IPlayerVersion.java
new file mode 100644
index 0000000..d676b36
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/playerversion/IPlayerVersion.java
@@ -0,0 +1,8 @@
+package dev.aapy.tablist.playerversion;
+
+import org.bukkit.entity.Player;
+
+public interface IPlayerVersion {
+
+ PlayerVersion getPlayerVersion(Player player);
+}
diff --git a/src/main/java/dev/aapy/tablist/playerversion/PlayerVersion.java b/src/main/java/dev/aapy/tablist/playerversion/PlayerVersion.java
new file mode 100644
index 0000000..baf4afe
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/playerversion/PlayerVersion.java
@@ -0,0 +1,32 @@
+package dev.aapy.tablist.playerversion;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+
+@Getter
+public enum PlayerVersion {
+
+ v1_7(4, 5),
+ v1_8(47),
+ v1_9(107, 108, 109, 110),
+ v1_10(210),
+ v1_11(315, 316),
+ v1_12(335, 338, 340),
+ v1_13(393, 401, 404);
+
+ private final Integer[] rawVersion;
+
+ PlayerVersion(Integer... rawVersionNumbers) {
+ this.rawVersion = rawVersionNumbers;
+ }
+
+ public static PlayerVersion getVersionFromRaw(Integer input) {
+ for (PlayerVersion playerVersion : PlayerVersion.values()) {
+ if (Arrays.asList(playerVersion.rawVersion).contains(input)) {
+ return playerVersion;
+ }
+ }
+ return v1_8;
+ }
+}
diff --git a/src/main/java/dev/aapy/tablist/playerversion/PlayerVersionHandler.java b/src/main/java/dev/aapy/tablist/playerversion/PlayerVersionHandler.java
new file mode 100644
index 0000000..2e9a265
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/playerversion/PlayerVersionHandler.java
@@ -0,0 +1,42 @@
+package dev.aapy.tablist.playerversion;
+
+import dev.aapy.tablist.playerversion.impl.PlayerVersion1_7Impl;
+import dev.aapy.tablist.playerversion.impl.PlayerVersionProtocolLibImpl;
+import dev.aapy.tablist.playerversion.impl.PlayerVersionViaVersionImpl;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.PluginManager;
+
+public class PlayerVersionHandler {
+
+ public static IPlayerVersion version;
+
+ public PlayerVersionHandler() {
+ /* Plugin Manager */
+ PluginManager pluginManager = Bukkit.getServer().getPluginManager();
+
+ /* 1.7 Protocol */
+ String serverVersion = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
+
+ if (serverVersion.equalsIgnoreCase("v1_7_R4")) {
+ version = new PlayerVersion1_7Impl();
+ return;
+ }
+
+ /* ViaVersion */
+ if (pluginManager.getPlugin("ViaVersion") != null) {
+ version = new PlayerVersionViaVersionImpl();
+ return;
+ }
+
+ /* ProtocolLib */
+ if (pluginManager.getPlugin("ProtocolLib") != null) {
+ version = new PlayerVersionProtocolLibImpl();
+ return;
+ }
+ }
+
+ public static PlayerVersion getPlayerVersion(Player player) {
+ return version.getPlayerVersion(player);
+ }
+}
diff --git a/src/main/java/dev/aapy/tablist/playerversion/impl/PlayerVersion1_7Impl.java b/src/main/java/dev/aapy/tablist/playerversion/impl/PlayerVersion1_7Impl.java
new file mode 100644
index 0000000..c0a9b28
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/playerversion/impl/PlayerVersion1_7Impl.java
@@ -0,0 +1,16 @@
+package dev.aapy.tablist.playerversion.impl;
+
+import dev.aapy.tablist.playerversion.IPlayerVersion;
+import dev.aapy.tablist.playerversion.PlayerVersion;
+import org.bukkit.craftbukkit.v1_7_R4.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+
+public class PlayerVersion1_7Impl implements IPlayerVersion {
+
+ @Override
+ public PlayerVersion getPlayerVersion(Player player) {
+ return PlayerVersion.getVersionFromRaw(
+ ((CraftPlayer) player).getHandle().playerConnection.networkManager.getVersion()
+ );
+ }
+}
diff --git a/src/main/java/dev/aapy/tablist/playerversion/impl/PlayerVersionProtocolLibImpl.java b/src/main/java/dev/aapy/tablist/playerversion/impl/PlayerVersionProtocolLibImpl.java
new file mode 100644
index 0000000..ec0613a
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/playerversion/impl/PlayerVersionProtocolLibImpl.java
@@ -0,0 +1,15 @@
+package dev.aapy.tablist.playerversion.impl;
+
+
+
+import com.comphenix.protocol.ProtocolLibrary;
+import dev.aapy.tablist.playerversion.IPlayerVersion;
+import dev.aapy.tablist.playerversion.PlayerVersion;
+import org.bukkit.entity.Player;
+
+public class PlayerVersionProtocolLibImpl implements IPlayerVersion {
+ @Override
+ public PlayerVersion getPlayerVersion(Player player) {
+ return PlayerVersion.getVersionFromRaw(ProtocolLibrary.getProtocolManager().getProtocolVersion(player));
+ }
+}
diff --git a/src/main/java/dev/aapy/tablist/playerversion/impl/PlayerVersionViaVersionImpl.java b/src/main/java/dev/aapy/tablist/playerversion/impl/PlayerVersionViaVersionImpl.java
new file mode 100644
index 0000000..653b356
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/playerversion/impl/PlayerVersionViaVersionImpl.java
@@ -0,0 +1,15 @@
+package dev.aapy.tablist.playerversion.impl;
+
+
+
+import dev.aapy.tablist.playerversion.IPlayerVersion;
+import dev.aapy.tablist.playerversion.PlayerVersion;
+import org.bukkit.entity.Player;
+import us.myles.ViaVersion.api.Via;
+
+public class PlayerVersionViaVersionImpl implements IPlayerVersion {
+ @Override
+ public PlayerVersion getPlayerVersion(Player player) {
+ return PlayerVersion.getVersionFromRaw(Via.getAPI().getPlayerVersion(player));
+ }
+}
diff --git a/src/main/java/dev/aapy/tablist/provider/TablistProvider.java b/src/main/java/dev/aapy/tablist/provider/TablistProvider.java
new file mode 100644
index 0000000..e4980ee
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/provider/TablistProvider.java
@@ -0,0 +1,311 @@
+package dev.aapy.tablist.provider;
+
+import dev.aapy.file.Tablist;
+import me.activated.core.plugin.AquaCoreAPI;
+import me.clip.placeholderapi.PlaceholderAPI;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.entity.Player;
+import dev.aapy.tablist.TabColumn;
+import dev.aapy.tablist.TabLayout;
+import dev.aapy.tablist.TabProvider;
+import dev.aapy.tablist.skin.Skin;
+import dev.aapy.tablist.utils.CC;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+public class TablistProvider implements TabProvider {
+ YamlConfiguration config;
+
+ public TablistProvider() {
+ this.config = Tablist.getConfig();
+ }
+
+ @Override
+ public List getFooter(Player player) {
+ return CC.translate(Tablist.getConfig().getStringList("TAB.FOOTER"));
+ }
+
+
+ @Override
+ public List getHeader(Player player) {
+ return CC.translate(Tablist.getConfig().getStringList("TAB.HEADER"));
+ }
+
+ @SuppressWarnings({"deprecation", "unchecked", "rawtypes"})
+ public String factions(Player player, String path) {
+ path = path.replace("{players_online}", String.valueOf(Bukkit.getOnlinePlayers().size()));
+ if (path.contains("|")) {
+ path = path.replace("|", "\u2503");
+ }
+ if (path.contains("{rank}")) {
+ path = path.replace("{rank}", AquaCoreAPI.INSTANCE.getPlayerRank(player.getUniqueId()).getColor().toString() + AquaCoreAPI.INSTANCE.getPlayerRank(player.getUniqueId()).getPrefix().toString());
+ }
+ if (path.contains("{players_max_online}")) {
+ path = path.replace("{players_max_online}", String.valueOf(Bukkit.getMaxPlayers()));
+ }
+ if (path.contains("{ign}")) {
+ path = path.replace("{ign}",player.getName());
+ }
+ return path;
+ }
+
+
+ private TabLayout getInfo(int slot, TabColumn place, Player p) {
+ TabLayout object = new TabLayout();
+
+ String text = "";
+ switch (place) {
+ case LEFT: {
+ if (this.config.getString("TAB.LEFT." + slot + ".TEXT") == null ||
+ this.config.getString("TAB.LEFT." + slot + ".TEXT") == " " ||
+ this.config.getString("TAB.LEFT." + slot + ".TEXT") == "") {
+ text = " ";
+ break;
+ }
+ text = this.config.getString("TAB.LEFT." + slot + ".TEXT");
+ break;
+ }
+ case RIGHT: {
+ if (this.config.getString("TAB.RIGHT." + slot + ".TEXT") == null ||
+ this.config.getString("TAB.RIGHT." + slot + ".TEXT") == " " ||
+ this.config.getString("TAB.RIGHT." + slot + ".TEXT") == "") {
+ text = " ";
+ break;
+ }
+ text = this.config.getString("TAB.RIGHT." + slot + ".TEXT");
+ break;
+ }
+ case MIDDLE: {
+ if (this.config.getString("TAB.CENTER." + slot + ".TEXT") == null ||
+ this.config.getString("TAB.CENTER." + slot + ".TEXT") == " " ||
+ this.config.getString("TAB.CENTER." + slot + ".TEXT") == "") {
+ text = " ";
+ break;
+ }
+ text = this.config.getString("TAB.CENTER." + slot + ".TEXT");
+ break;
+ }
+ case FAR_RIGHT: {
+ if (this.config.getString("TAB.FARRIGHT." + slot + ".TEXT") == null ||
+ this.config.getString("TAB.FARRIGHT." + slot + ".TEXT") == " " ||
+ this.config.getString("TAB.FARRIGHT." + slot + ".TEXT") == "") {
+ text = " ";
+ break;
+ }
+ text = this.config.getString("TAB.FARRIGHT." + slot + ".TEXT");
+ break;
+ }
+ }
+ text = factions(p, text);
+ object.column(place);
+ if (Bukkit.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI")) {
+
+ object.text(PlaceholderAPI.setPlaceholders(p, text));
+ } else {
+ object.text(text);
+
+ }
+ object.slot(slot);
+
+ String skin = "";
+ switch (place) {
+ case LEFT: {
+ if (this.config.getString("TAB.LEFT." + slot + ".SKIN") == null || this.config.getString("TAB.LEFT." + slot + ".SKIN") == " " || this.config.getString("TAB.LEFT." + slot + ".SKIN") == "") {
+ skin = " ";
+ break;
+ }
+ skin = this.config.getString("TAB.LEFT." + slot + ".SKIN");
+ break;
+ }
+ case RIGHT: {
+ if (this.config.getString("TAB.RIGHT" + slot + ".SKIN") == null || this.config.getString("TAB.RIGHT." + slot + ".SKIN") == " " || this.config.getString("TAB.RIGHT." + slot + ".SKIN") == "") {
+ skin = " ";
+ break;
+ }
+ skin = this.config.getString("TAB.RIGHT." + slot + ".SKIN");
+ break;
+ }
+ case MIDDLE: {
+ if (this.config.getString("TAB.CENTER." + slot + ".SKIN") == null || this.config.getString("TAB.CENTER." + slot + ".SKIN") == " " || this.config.getString("TAB.CENTER." + slot + ".SKIN") == "") {
+ skin = " ";
+ break;
+ }
+ skin = this.config.getString("TAB.CENTER." + slot + ".SKIN");
+ break;
+ }
+ case FAR_RIGHT: {
+ if (this.config.getString("TAB.FARRIGHT." + slot + ".SKIN") == null || this.config.getString("TAB.FARRIGHT." + slot + ".SKIN") == " " || this.config.getString("TAB.FARRIGHT." + slot + ".SKIN") == "") {
+ skin = " ";
+ break;
+ }
+ skin = this.config.getString("TAB.FARRIGHT." + slot + ".SKIN");
+ break;
+ }
+ }
+
+ object.skin(skins(p, skin));
+ return object;
+ }
+
+
+ public Skin skins(Player player, String skinTab) {
+ Skin skinDefault = Skin.DEFAULT;
+
+
+ if (skinTab.contains("{player}")) {
+ skinDefault = Skin.getSkin(player);
+ }
+ if (skinTab.contains("{discord}")) {
+ skinDefault = Skin.DISCORD_SKIN;
+ }
+ if (skinTab.contains("{youtube}")) {
+ skinDefault = Skin.YOUTUBE_SKIN;
+ }
+ if (skinTab.contains("{twitter}")) {
+ skinDefault = Skin.TWITTER_SKIN;
+
+ }
+ if (skinTab.contains("{facebook}")) {
+ skinDefault = Skin.FACEBOOK_SKIN;
+
+ }
+ if (skinTab.contains("{store}")) {
+ skinDefault = Skin.STORE_SKIN;
+ }
+
+ if (skinTab.contains("{green}")) {
+ skinDefault = Skin.getDot(ChatColor.GREEN);
+ }
+ if (skinTab.contains("{blue}")) {
+ skinDefault = Skin.getDot(ChatColor.BLUE);
+ }
+ if (skinTab.contains("{dark_blue}")) {
+ skinDefault = Skin.getDot(ChatColor.DARK_BLUE);
+ }
+ if (skinTab.contains("{dark_aqua}")) {
+ skinDefault = Skin.getDot(ChatColor.DARK_AQUA);
+ }
+ if (skinTab.contains("{dark_purple}")) {
+ skinDefault = Skin.getDot(ChatColor.DARK_PURPLE);
+ }
+ if (skinTab.contains("{light_purple}")) {
+ skinDefault = Skin.getDot(ChatColor.LIGHT_PURPLE);
+ }
+ if (skinTab.contains("{gray}")) {
+ skinDefault = Skin.getDot(ChatColor.GRAY);
+ }
+ if (skinTab.contains("{red}")) {
+ skinDefault = Skin.getDot(ChatColor.RED);
+ }
+ if (skinTab.contains("{yellow}")) {
+ skinDefault = Skin.getDot(ChatColor.YELLOW);
+ }
+ if (skinTab.contains("{dark_green}")) {
+ skinDefault = Skin.getDot(ChatColor.DARK_GREEN);
+ }
+ if (skinTab.contains("{dark_red}")) {
+ skinDefault = Skin.getDot(ChatColor.DARK_RED);
+ }
+ if (skinTab.contains("{gold}")) {
+ skinDefault = Skin.getDot(ChatColor.GOLD);
+ }
+ if (skinTab.contains("{aqua}")) {
+ skinDefault = Skin.getDot(ChatColor.AQUA);
+ }
+ if (skinTab.contains("{white}")) {
+ skinDefault = Skin.getDot(ChatColor.WHITE);
+ }
+ if (skinTab.contains("{dark_gray}")) {
+ skinDefault = Skin.getDot(ChatColor.DARK_GRAY);
+ }
+ if (skinTab.contains("{black}")) {
+ skinDefault = Skin.getDot(ChatColor.BLACK);
+ }
+ if (skinTab.contains("{warning}")) {
+ skinDefault = Skin.WARNING_SKIN;
+ }
+ if (skinTab.contains("{website}")) {
+ skinDefault = Skin.WEBSITE_SKIN;
+ }
+ if (skinTab.contains("{watch}")) {
+ skinDefault = Skin.QUEUE_SKIN;
+ }
+ if (skinTab.contains("{information}")) {
+ skinDefault = Skin.INFORMATION_SKIN;
+ }
+ if (skinTab.contains("{wood_shield}")) {
+ skinDefault = Skin.WOOD_SHIELD_SKIN;
+ }
+ if (skinTab.contains("{diamond_shield}")) {
+ skinDefault = Skin.DIAMOND_SHIELD_SKIN;
+ }
+ if (skinTab.contains("{bow}")) {
+ skinDefault = Skin.BOW_SKIN;
+ }
+ if (skinTab.contains("{potion}")) {
+ skinDefault = Skin.POTION_SKIN;
+ }
+ if (skinTab.contains("{telegram}")) {
+ skinDefault = Skin.TELEGRAM_SKIN;
+ }
+ if (skinTab.contains("{enderchest}")) {
+ skinDefault = Skin.ENDERCHEST_SKIN;
+ }
+ if (skinTab.contains("{coin}")) {
+ skinDefault = Skin.COIN_SKIN;
+ }
+ if (skinTab.contains("{heart}")) {
+ skinDefault = Skin.HEART_SKIN;
+ }
+ if (skinTab.contains("{earth}")) {
+ skinDefault = Skin.EARTH_SKIN;
+ }
+ if (skinTab.contains("{crown}")) {
+ skinDefault = Skin.CROWN_SKIN;
+ }
+ if (skinTab.contains("{castle}")) {
+ skinDefault = Skin.CASTLE_SKIN;
+ }
+ if (skinTab.contains("{ping}")) {
+ skinDefault = Skin.PING_SKIN;
+ }
+ if (skinTab.contains("{stats}")) {
+ skinDefault = Skin.STATS_SKIN;
+ }
+ if (skinTab.contains("{compass}")) {
+ skinDefault = Skin.COMPASS_SKIN;
+ }
+
+ return skinDefault;
+
+ }
+
+
+ @Override
+ public Set getProvider(Player player) {
+ Set toReturn = new HashSet<>();
+
+
+ for (int i = 1; i < 21; ++i) {
+ toReturn.add(this.getInfo(i, TabColumn.LEFT, player));
+ }
+ for (int i = 1; i < 21; ++i) {
+ toReturn.add(this.getInfo(i, TabColumn.MIDDLE, player));
+ }
+ for (int i = 1; i < 21; ++i) {
+ toReturn.add(this.getInfo(i, TabColumn.RIGHT, player));
+ }
+ for (int i = 1; i < 21; ++i) {
+ toReturn.add(this.getInfo(i, TabColumn.FAR_RIGHT, player));
+ }
+
+ return toReturn;
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/tablist/skin/Skin.java b/src/main/java/dev/aapy/tablist/skin/Skin.java
new file mode 100644
index 0000000..3b1c6c9
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/skin/Skin.java
@@ -0,0 +1,332 @@
+package dev.aapy.tablist.skin;
+
+import com.google.common.collect.Lists;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import dev.aapy.tablist.Tab;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Getter
+@AllArgsConstructor
+public class Skin {
+
+ private final String value;
+ private final String signature;
+
+ public static final Map CACHE = new ConcurrentHashMap<>();
+
+
+ @Override
+ public boolean equals(Object object) {
+ if (object == null) return false;
+ if (!object.getClass().equals(getClass())) return false;
+
+ Skin skin = (Skin) object;
+
+ return skin.getValue().equals(value) && skin.getSignature().equals(signature);
+ }
+
+
+ public static final Skin STEVE = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxODI4Nzc3MDYxNSwKICAicHJvZmlsZUlkIiA6ICI4NjY3YmE3MWI4NWE0MDA0YWY1NDQ1N2E5NzM0ZWVkNyIsCiAgInByb2ZpbGVOYW1lIiA6ICJTdGV2ZSIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS82MGE1YmQwMTZiM2M5YTFiOTI3MmU0OTI5ZTMwODI3YTY3YmU0ZWJiMjE5MDE3YWRiYmM0YTRkMjJlYmQ1YjEiCiAgICB9LAogICAgIkNBUEUiIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzk1M2NhYzhiNzc5ZmU0MTM4M2U2NzVlZTJiODYwNzFhNzE2NThmMjE4MGY1NmZiY2U4YWEzMTVlYTcwZTJlZDYiCiAgICB9CiAgfQp9",
+ "dnRZKI5Y443vH8PJASARp6D1RKayS5aAxEg6xkPX0wiIVo94YWiCu86/2NrYeh/Ltm76wHN9lTi/gBfhGY/De70SINNZEgTYAso9G3NsoBmAzQawsMdK5e4IRHvx5jun5sPqGS63Kb4Kuue8VNzsWz1eVOJus6GlN36GFwvO32qrXhhJaEho21MIYa9ySQQua38I3/Du5wfKiC5JerVjr7LP1GXEQvz3OrCP0u0dNs56JlqMjmTIcLmStx4EKJaHks5rfUKZON79TpjyJQkmw2rWOL2357ROpp3dBtH12Tie3MHchwYd7JEtkKx7JVq7kgVjF4yCBJ2ugBH8+Nc/GQij03sK4dASj3S+/o7zdBvWRIOnqNa7KEpP2s3l846NRwSC5YlKBK4hlccmGnlpmBzHlPl4b1vA3jZNG1HBNQ6VHX/LIJRUfvWnEXZVU0b+usTTdTdx5HB1ZYfN4Uekk/ilE5R/UNQ7A1q9EJ/WnbfA/SeZHda4k0he9PJDp52mcHMB0Q+fb1dEgFnxkF1OVHtJsHKi2zplpDtTPejy98d5qvBwVa9Ss2ygc1eoBG6QCcrf7ESTWgNrNPJLdEkahQCDVad6B8UpMq8LLREf2csMQt89XoAgS6n9OZTSLbzUxttvIq+Dkzo9Ae9iz3JlmEIGcBKoAE+9UUTl52L+E8o="
+ );
+
+ public static final Skin DEFAULT = new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0MTEyNjg3OTI3NjUsInByb2ZpbGVJZCI6IjNmYmVjN2RkMGE1ZjQwYmY5ZDExODg1YTU0NTA3MTEyIiwicHJvZmlsZU5hbWUiOiJsYXN0X3VzZXJuYW1lIiwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg0N2I1Mjc5OTg0NjUxNTRhZDZjMjM4YTFlM2MyZGQzZTMyOTY1MzUyZTNhNjRmMzZlMTZhOTQwNWFiOCJ9fX0=",
+ "u8sG8tlbmiekrfAdQjy4nXIcCfNdnUZzXSx9BE1X5K27NiUvE1dDNIeBBSPdZzQG1kHGijuokuHPdNi/KXHZkQM7OJ4aCu5JiUoOY28uz3wZhW4D+KG3dH4ei5ww2KwvjcqVL7LFKfr/ONU5Hvi7MIIty1eKpoGDYpWj3WjnbN4ye5Zo88I2ZEkP1wBw2eDDN4P3YEDYTumQndcbXFPuRRTntoGdZq3N5EBKfDZxlw4L3pgkcSLU5rWkd5UH4ZUOHAP/VaJ04mpFLsFXzzdU4xNZ5fthCwxwVBNLtHRWO26k/qcVBzvEXtKGFJmxfLGCzXScET/OjUBak/JEkkRG2m+kpmBMgFRNtjyZgQ1w08U6HHnLTiAiio3JswPlW5v56pGWRHQT5XWSkfnrXDalxtSmPnB5LmacpIImKgL8V9wLnWvBzI7SHjlyQbbgd+kUOkLlu7+717ySDEJwsFJekfuR6N/rpcYgNZYrxDwe4w57uDPlwNL6cJPfNUHV7WEbIU1pMgxsxaXe8WSvV87qLsR7H06xocl2C0JFfe2jZR4Zh3k9xzEnfCeFKBgGb4lrOWBu1eDWYgtKV67M2Y+B3W5pjuAjwAxn0waODtEn/3jKPbc/sxbPvljUCw65X+ok0UUN1eOwXV5l2EGzn05t3Yhwq19/GxARg63ISGE8CKw="
+ );
+
+ private static final List DOT_SKINS = Lists.newArrayList();
+
+ public static final Skin DISCORD_SKIN;
+ public static final Skin FACEBOOK_SKIN;
+ public static final Skin TWITTER_SKIN;
+ public static final Skin YOUTUBE_SKIN;
+
+ public static final Skin PLANET_SKIN;
+ public static final Skin WARNING_SKIN;
+
+
+ public static final Skin STORE_SKIN;
+
+ public static final Skin ONLINE_SKIN;
+ public static final Skin OFFLINE_SKIN;
+ public static final Skin QUEUE_SKIN;
+ public static final Skin WEBSITE_SKIN;
+
+
+ public static final Skin INFORMATION_SKIN;
+ public static final Skin WOOD_SHIELD_SKIN;
+ public static final Skin DIAMOND_SHIELD_SKIN;
+ public static final Skin BOW_SKIN;
+ public static final Skin POTION_SKIN;
+ public static final Skin TELEGRAM_SKIN;
+ public static final Skin ENDERCHEST_SKIN;
+ public static final Skin COIN_SKIN;
+ public static final Skin HEART_SKIN;
+
+ public static final Skin EARTH_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYyODE3ODczOTQzNywKICAicHJvZmlsZUlkIiA6ICI5MzI0N2IzMzllMTQ0MDBkYjk5Y2ViM2Y0NzA4ZTBhNiIsCiAgInByb2ZpbGVOYW1lIiA6ICJBemFyb3dfIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2EzMWI3ZDdlNjM0ZjBhZjA1MTFmYzg0NzYxMGE4NjVlYzFjODQwMjM0MTAwMDg5M2FiNjM5NzlmYzhlODVlMzUiLAogICAgICAibWV0YWRhdGEiIDogewogICAgICAgICJtb2RlbCIgOiAic2xpbSIKICAgICAgfQogICAgfQogIH0KfQ==",
+ "lKjhX6fDX0JxC++G/xo9k4q7psvLx7HAadzdQ9iasfYBw3jCzqVgXaHkhlNyN+iluFHevPqJ0nLobatuATyjexKASOE5wRQmL9WgdJnYEaQnb8+abE2sei2eS6tHGVkzYYbFmv4GmzcpA/CIk2HeSguVhZ4+zxQcnJYVFQqi2qyUo5ZMwLQ9ZiNaVy29LHYcIQp5yGBGFcoZIj0StLhrPOtN8GkBSLaTah2wUMtyAFGa5GJivd0lYh+7MPMZX6MIoZgtmCQC1ZLtiJmyByQv8mAfTAdcNKVpXoK0/F+RjkHIQkQ7hRfIV+g41l7H4SmfW53UMpxv7NXE4gv6Fu3OzSGE6Wmg2BkWbOTj4oIqsnfRPEFozesNwqfgQidP0ngqnRHIG5eX8iI6cXwFNFX7RFTXtIpJ8JhWOLyFAAFcdW46skCIKECm7eH0pEgJl7Q/22hnAz8rnoSh+irxbLQtTeyekUoPSpAPFPtp96Ud401Q7F30gYgpcrZztQ+hxbEnapLFv9l+4fda4USub4+9MlYaWpLWv+a+6EexLYOu163GCdEbkLdQsj2qPk87pRicw3v5pBq7ZnLN3nBGFU5WBsrfOggYfxnrlUDhyK3A7nZcTwc4qAZjS3ptWrk+HydQBNn09Zf8E+kdHArqy8ov0CMcwNFt3r0SOwvnvuxC7V8="
+ );
+ public static final Skin CROWN_SKIN =
+ new Skin("ewogICJ0aW1lc3RhbXAiIDogMTYyODE3ODc1NDAyMSwKICAicHJvZmlsZUlkIiA6ICIyM2YxYTU5ZjQ2OWI0M2RkYmRiNTM3YmZlYzEwNDcxZiIsCiAgInByb2ZpbGVOYW1lIiA6ICIyODA3IiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzRmOWM3M2EzMTNlNjkxZjY3YzdjZmFkMjRlYTlmY2U4OGFkOGZkNGNkYzE4YjZiODViNTc0M2I0Yzg1ZTVhNmQiLAogICAgICAibWV0YWRhdGEiIDogewogICAgICAgICJtb2RlbCIgOiAic2xpbSIKICAgICAgfQogICAgfQogIH0KfQ==",
+ "XPrRIarTKPwHpF+HhkrAlVzH3hnzCDJlMZXJFKf7jo9YkYJyTc5D1UQSQlZw6k2k5ZdbEXUp1xonPiYMr9auf88uURz2UvdrDtXkKZ2DD5u9t5f0ktWEA06HijfG7iHERum89xA1RLr0zmMwNcrgCHtteebfZJM3B5JkRYRDjgF3i3D6JYuC79JsQVDAro6aPHzVbxTog3FW7UaQ5FC2cSr88rrE692/dHyJfqcj2Kqy3lIFBaWhUa3YY0B4dCUowVsvdDhMH/Y7kt5yLkc+hCDafZ0+/OptQ+/YppcZDrMC+L7JQBDIy5KrICKKMdHPM2CmNUMK8qUscLKqeIANxZ12WR4526leSD+2cxQKQ7vXxbSy4ujWxV3seUJIwk0ln/RbMvfC2CwmsVW9vUQbqM4Ci/+oyL4qqBtEqPqtfC6OKaxJXkB+zqmRlZpmSsPgXKTpJuBY6ixFigRNpTL4DiT7byZTZZUdDvWXhOAr5NAoSBr3thQ9t8j5saF02clBeA2dmatsty56F/bmgqKg4mpi8I/ICkZ38FGMInq7AUXtQMFgDWpCVlJ3O38KDaZcO9NCjsfzCp8NcfcZ2vSkXxgdVDLHdSm7dgBKyIuofmgztgWzLRq+/LdMMjZcsi89ZUdA2826HxxC1LgZvDRt6o8sQHhegryCKJnKinYMXUA=");
+ public static final Skin PING_SKIN =
+ new Skin("ewogICJ0aW1lc3RhbXAiIDogMTYyODE3ODczMjg1MiwKICAicHJvZmlsZUlkIiA6ICI0ZDEzZWUyZjViOWI0N2I2OGU2NzhhMjAxN2VmZTc1MyIsCiAgInByb2ZpbGVOYW1lIiA6ICJCcmF5ZGVyZWsiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWRjMzEwYzQ3Y2FjOGM3MGRhYmQ3MTVhZDc1MzRlNmUxOTc4ZDBmMWQ5YWY0OGNhZWQzYzBjZjM5ZmQ5NmRhYSIKICAgIH0KICB9Cn0=",
+ "AKVgDDVqCv13V5+/2HNs7LlHMfB5kReaweJU2DiUQo4B4vctCqk1cJomkE1N1F2FAWlIvhkc58/zXqxNLhTXFMdzrhfle6BfKyocNeXz7BYwXIHD3RkD5187VHQb6y3rbBw9G4qdTLmEZPc/0/f2HJH46qV03YWxGXgFSjpQR48u00ZnLJWXumcGXYTzLUBFN2rJfPAB4j+chNs/MWOk/Bs0fo+OmNW2TRHt0KT2+Bdyg6a9xLPFKxtzzDZaWsW1ayuM0L95MOUCvS9O56oVVZQ+TUjVhqindugXqy9dQr9RAXbIFW/rthPgvdlujpSyc7oa4MqMuG84CHHvidOoKmKf14kv6kSjnjdfWAMQ1YM+vTvaBWvIuUrNYraW4zqLeVi2apNV+oFCI+xOn6P+GQzQkiDLI5oCvc5FcrM6L159ctPC5jRtwTH45G66MiJja/WK1u38Q8FseuSfDmutkGdJs7sim0AOlkpd9df7hZxNFnnlW4O3DI4nuwAMGkwfEh4T/U4nXitza2Rgk9EHH0hcFG5W2cCVUt4wImHbMRtOKlMWZ2+ZZWctu1AmttDCkFoEUyeEQSMkIPiWFTPBhgtDDRbYop3macH9l3Y9Nhq6/I5uphfbxve6ArQBPpW+mENiUtVuJaQDJTydUZ3xgR4bwrqneHd6iTNj6hTTdFE=");
+
+ public static final Skin STATS_SKIN =
+ new Skin("ewogICJ0aW1lc3RhbXAiIDogMTYyODE3ODY3Njc3NSwKICAicHJvZmlsZUlkIiA6ICI1N2IzZGZiNWY4YTY0OWUyOGI1NDRlNGZmYzYzMjU2ZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJYaWthcm8iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzJkYmFkNzIzOGE5YjM2NWM2OWYxOTk5MWJhZmRmNzEwNjU0ZjMyM2Y0MWE0NGU5ZjEwMjZjYzIwNTkyNzExNSIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9",
+ "GFnXdHoFH3vUgvizZ5N7wxoOsSNvvPgsuUlWr/eIpGs6EQZotqPpUjZBlZmbwYQrNj076BGeWx4nrxhFxR4A54NZeXB08J661zE8ddXliwg4aTgsxEvPgOqXkAb7rKTR2oe5FE0lC1IUI7ZXN+6C3/nxJ7fmMULJp4sOeHfzuYZa5xYFfpd3wy6knKs6SJf6BobaN8/ooqTAUP+yDvdbeA5uuk2Ljc0Pi4P7mWPABLFLfttvzhcjFy+3i8y1TbjKVnP8ILC2h3liXZUGIBHH3OGmWjNEVgg6znPVkqfKNarEv/CF9H9Sd3S9SCL2v2fKmd1TP3Qd8tT5CbxeMFDlOxCUgfkj0b5mgvkAwVYjpXk8RR2y8643sQN04p9ctNK1bTZdAqMyIkJbSAh5JUNgX7AZxLq7WJoM+85vXiZRpKHCXNY1psu2Z1NU0YahB2e0wQDka+CprmgvdRYJcupb2fwpZN4TmyQWf+/WrGPBAgQbOqTYqe63RVrwDhHd6vSn0mIvjbmP/6vi179Ww3ZgkfPXErwqYAy8ARcjuLoB30QbbLfMC0KC3LmW9EjBgQUotGNrysi4r7BC3gOjGdNJRB1QBAcyvg9PaDtiFuyVCFbAhfS1mDy1I/1S1sKqf6KoYmzPAU1YHIFHajOQ+DIWkFe3+SGQqZ4qQoceJTbpcyU=");
+ public static final Skin CASTLE_SKIN =
+ new Skin("ewogICJ0aW1lc3RhbXAiIDogMTYyODE3ODc2NDgxNywKICAicHJvZmlsZUlkIiA6ICI4YWFlYTdlYjViOWM0ZWEwODUxNWU3MDhhZGIxODBkNyIsCiAgInByb2ZpbGVOYW1lIiA6ICJNYVBhODA3MTEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2MyMDI1YTdiYTJhYjZhODYxOTk5N2VhMjMzMTBmNTk4NGExZjRjNThkZjllOTYxNjVlZjFmNDliYmQ3ZTllMCIKICAgIH0KICB9Cn0=",
+ "VXJnpMLuXnV6eKHODxb86GS/iTPzuV4CIpDK1arbuiaOdySIUYtm9j9vzvKMHJRyrgarNt8TkGXVJo5for7kfzc990CZXou9erTv1YhOWvm6FRjW8nusV4gmLKla0sI6GU1y85LizCP6An51QUNS73c4OsfFY5Ng9OhYjYKJ+3DiVHs/hg4UOux/BedjbUdJIPpFBJIMRisURi4eCcH+1zahC8GBK0s5O3KUsGd/jdszDVYeJ6B9jqd9RT+Ww3b/s3eoy+G8NArp6XdFKFV/Hp3TXvaCw5IENnniGgRMLZ/w9MGDnO0/81dTO8BUqVymNLEj8fKPOfmahEtvQcIXt+fNQLIaSgFuTLpc+NEfX6XtqVNAz2huKpg46ym+k/qjxev/7i4CGPGCf9rMgc4dUYfJm/h5Nwybt8ciE3RmyuGqYCTY7nEQFKEoTBlW9UUijqZO1F17Dhe7hmxjpd6i0OITjCdiWEE/S5v7e0Mq3BmsQjs07TA9aOp/dLRUIOAYivfOIXKRRN1OFc1noO00sVro+kt3RSLWKToD8IYOgovsOcHgcizrnhsYGWfbJo08z74X5I2IKYowDjpV3SEI5GSiX1HT13fxpSybXGSZ12Vmd11wVgJ/OCjEg5jUSuLzWDpK6kLM+QZgff/8hbMOMoNfDeqcBcvXTr8HBgZQClk=");
+
+ public static final Skin COMPASS_SKIN =
+ new Skin("ewogICJ0aW1lc3RhbXAiIDogMTYyODE3ODk2MDc0OCwKICAicHJvZmlsZUlkIiA6ICJhMjk1ODZmYmU1ZDk0Nzk2OWZjOGQ4ZGE0NzlhNDNlZSIsCiAgInByb2ZpbGVOYW1lIiA6ICJWaWVydGVsdG9hc3RpaWUiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjA1OTcwNGQ2NzQ3ZTkzOWFlN2YxYWNkZWRlODU3Yjk3OGM2NGMxNzJjOWRiZWY1MjVjNWNjNmQyMzE0NjY2NSIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9",
+ "OCVftL19cjD2kLoJgExHWLm8k7xgl8WEKQ57pqN3iOuR38HJ6HDKB34RKnezKBI+tyfoXCnxZugfKON2oPOsFER65jVT2rUqVjnqRb4cQjYWpzTmasz1reZnqWnlseFAquCbdIkV/c3Zo4x2I4lwOdveCE/IAFz/dxxc1zW90cfE16F4/qmKu7xd9FxuoGJeJkHLV/4NakI0o8Va3FlGo4K3foUsdJNDP75NRnzl/wOLS0tdf1uyZFYc2wJLBgULL9RLnMjFcukRG1FNDL/IOfMMddoep/DCEnBcoO2CIW2StTZjzVqrdkC53pNGqV/v7Qrmg0uL7qVSm0h0TnIFAdvvaRV/dQ6H9uB2ftUSZajO1dxhK0z8+EuJQDPzRWQgwVgN5iHx9cGRV5urbZvt+InbDOVHo/JKkUiDo/AefRGc8PglCIe8obk2+Z0SGL2xw0wny16LCKXcbMaF8As/BlckNHiexxcAZFSQmipVmTH0bXEoPYkf57ILRIFx3nf7z2D8fzv/2qCOuVPMN38O8e4kra1aCZhJx9dN6li7Ar1Tn5/zJ+lF9XNWFZnFyUdrTveeaWAwfNkiZ8W7OwRbvVoz2REW9xtrFietjzx8CIGPj4FJcYbaNkTmhT3yBxfBS6S2KgCRIas8R1tUOXG4LxEk3E0FKUSoPJg6wbdTnMM=");
+
+
+ static {
+ WOOD_SHIELD_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxNzQyNjkyODg0OCwKICAicHJvZmlsZUlkIiA6ICJiYzRlZGZiNWYzNmM0OGE3YWM5ZjFhMzlkYzIzZjRmOCIsCiAgInByb2ZpbGVOYW1lIiA6ICI4YWNhNjgwYjIyNDYxMzQwIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzhkMTc0ZjU5YmNhYTYxNDlhZTVlYzRmNDE0MWM0ZTU3M2U5M2E0MzI3YzI2NDI3OWJlM2U4N2VhNzUyMWY0NjQiLAogICAgICAibWV0YWRhdGEiIDogewogICAgICAgICJtb2RlbCIgOiAic2xpbSIKICAgICAgfQogICAgfQogIH0KfQ==",
+ "XcPZhO0+VxdN+Vf/SRJ9/TXkS7WxNe+sL2eTLODZ+Q8z94ej7bgoSnwszjX0RLDLSiA16ueOHeSZLnJp189Yh9ja7nbuAkhQcU7Gq5IbdSiVioWp8P81H3byjXrGfr8k8d+SUB3HMQfr2ARPQG39AzOdaNymSPFlAMqvG0txMRyZQJISXHcehcPMx2Woz75Ne5QTo352jqF3GOEIgce1yTRhWs6n5l5+t8zqlmwEk0pvMoRNuKRdDd8/7iccYalqcKsr0yE7ytvTbgpmnuZhcRqqDg2BQMdT1okhk/5pvbSAvqhP5NDVAqrmOgF5YHB5I/H5EVd4xIocYzKZLBOwOTYKOHpeSL+c/cCEkiPq/omcLvFDLFX5Cl5P2CbNvYS/ELuKMa9qvIDSVo+bbQkOLaU7az2bRbaYDX4SkIboiBFjJCxlyr2aa3eFf1yCWt5JlQsx02ZT2xHBbdZfkYiGEJ4HWA6u27vxdKNRyySmMPnQ8hK9KT+b535NUiGaI7VO0Ni4vOgst4PXZYSAow6eEtfNQDw2nJqgjJgRvIGfQZhIGh2VDOcqewOVyfshCywRSuRI9l3XL1N6iJsYqj2CrpQVOatawV8YHdhRJ7f5RfE1FRET2g+PbXtTEI3Tu5p+//eKWYUpiRR0eU6LRz84/Tfk72/qxbGJFDQrnGr9c0w="
+ );
+
+
+ DIAMOND_SHIELD_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTU5ODk5MDYxOTg4MSwKICAicHJvZmlsZUlkIiA6ICI5MThhMDI5NTU5ZGQ0Y2U2YjE2ZjdhNWQ1M2VmYjQxMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJCZWV2ZWxvcGVyIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzI1MjU1OWYyYmNlYWQ5ODNmNGI2NTYxYzJiNWYyYjU4OGYwZDYxMTZkNDQ2NjZjZWZmMTIwMjA3OWQyN2NhNzQiCiAgICB9CiAgfQp9",
+ "Tig86czlFqclLJAPUny5gwL8SHENX+St6KTD68YKiAzQJo1Z/5NToq/8XV/2xSnJjdiuB02d6wnACxYg48Sfo5+hcEpLA4YqmNkDriNQuB1Im3I4WCTS6ItkHyqBzQDQEDcA45o0/eWpalht9X7KRYamOGuw0ajltB/bZrWOX7hjOg1qaXpURsO4AlybUjtX+bwm8cb09JEQ5tzZM/B/tMjkg6BVSvgxG76F7dFH4zYV9HLZilk/Mt7B1pPJxN2Wfvod4ucin1pcohepxqRRSXH4g3d4r0sPrgb2O/iT93dh0gE83G7YIUxIp/vwRpDLid40gYGphYvzvhmld8y3vMsKqRgHeb/nmLhDuEnaetWbNGT+yYKcXtKEyYbzCwb+Ecq4+BdRGI0ZdB7084iZVfQONmoTkp8hXu/VRtomyaQRWOwTdCYGgz1vA7iM+NHp/Hg+BrN1WQs6+6uy7Rjwo3Db92NSYW5bkiHNp2II22qdnrZ/oekdCc4EkYasMbLhIzZ4iz17KTXjgV00BgeJ8XvkcuX49tB3Hr7sgmsy1K7zp0zByEb64Q3qbGVB1epmbqZYeJNsdq95ZJ1VGqqPVdVCpTM3XAnjBtc1mgdXInQI8fWhrtRXRDpyzZ4hA8XTCeofXBT9/MjybvFAqyOiRBdIskoO9CsiuZUwsDxaezg="
+ );
+
+ BOW_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxNzQyNzE5ODc4NCwKICAicHJvZmlsZUlkIiA6ICI5ZDEzZjcyMTcxM2E0N2U0OTAwZTMyZGVkNjBjNDY3MyIsCiAgInByb2ZpbGVOYW1lIiA6ICJUYWxvZGFvIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzJhOWZhMzZhZjhkNmI2MDg1MDlkMjY4ZTJkYzE2MDY0ZDcyOGY4MjQwYWRjNTRjOWQ3ZDUxYTE5MTc3MDMyYTYiCiAgICB9CiAgfQp9",
+ "CQB3pJMuzjE7G8yaxNl+ks8weqHhD0JxGUMqYHCf6AUQM7rAEwxCKvm2sbelnKjCof4BXCHL2GKzG5AEAmz1kj+ZD9egDb4H1l3TCXGiA6vL3Ey2LpS+g0x2S0MkFVTONGAnhP/zt0gjC3PG9QH/W/7k64HyxnyBOPRVn9KLgVVnVkAMYWiPwp7XzuEAaWBEC1t9/0YB0RjxpOnV8n7lL121StH5czSU2fGWcSv4Cb/jbEhtCZW+pyDzttGPYUa8/RHqD+cM60Y23sYU5jZwyQDx7onPWrlTHpz3iwClAR7UWOtdlUWDGwsR6CtxsEvmPfmN2r2WKnR+GuYcj0riGic0nTXuEz5MB3gkFfmPARQfcOPkG+wV0+2KyTxtU4HZJMBPvbX9zEigKhZnzwvWsWpTHdbxpNc69H+TURowuNvDRj21h/exTlOykPglzCF/Bh5lTa3Kg6tuII8n3z7ibSY6e8kKzV+hmlxvq0hhMw0/CHsp0iBrh4IFYCvU+LTA+8erKGQlrUs+N843MC09toAQr08gJL2xHEYGWq0tKFPVKsC4r56CZD4fMqcSUTbEgiEC7kunl4c5W6z8BuhfkSu1q5IE2CQn2eXUt404IE80jBmqSl7OQhdpNNQbiGYCssR45fL7xTin92CXEMkCiuL3qAJdDWZN+uaeZdaSUD0="
+ );
+
+
+ POTION_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxNzQyNzU4MDcyOCwKICAicHJvZmlsZUlkIiA6ICJjZGM5MzQ0NDAzODM0ZDdkYmRmOWUyMmVjZmM5MzBiZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJSYXdMb2JzdGVycyIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS8xN2UzZGI2NDAxNGE0Nzg4NjcwZTQ5Y2E3YmUzZGE0MWZmM2ZiYmFmMWM1Mzk1ODRjNjM1MzU5YTVjYjYwYWFiIiwKICAgICAgIm1ldGFkYXRhIiA6IHsKICAgICAgICAibW9kZWwiIDogInNsaW0iCiAgICAgIH0KICAgIH0KICB9Cn0=",
+ "ilOd9dJuBwtaDrHagf6hJrSAMeUabnmQ98OVN9WQkhtBAPdfPPrNwN7FTGuAs0Z4Vx45I8zot/MpG0T0krX3eUhv0KJpGJf93iBqiPfEp0vFRMO9VV7n8oLrqkqUT0MkT/Lv8lt6DKNMuR7dDHpdHsu2sfbtLDC4TYyeq9WM9R6KlD5LHV8hA8sFxpuFaMlnvITihqNnVgL/zxQ84L6DLckHIC6QKfzQv6sfrnbyrGlyd/vc2cQLA8cHKkgSu3uWbvOWihxn+WTuEHIbAbbBdiZToiKG5WMxuMfSYUSs3j2vxsJsTnIHk/wfsd23soAZ1bRN7NbJLg84gRGvd1w50D426F8l0ryo0jvaMzizql7votNB/u/eE6qMotHP0JkHE/+5AhKO+2raX9I3Fci0gnob7EsmxPICzNFqppa475NBuHwIGccEiWJw0vGInPGr3bNFrq32xT6U1mIcHuvuv65lJuQ9bmAEdBdCd0/q/JdnOJBl7bhCrkW5XD0ysUZmlc7LC4Fs5z1JFj58vMATdzSAqu152EREQBO5JXe7jdX4dUlpHvqpZgFLWyKxUDl/oyO0ix1XR0MHJAVDjr6elWozgvbgtMWlPqw1wA7TNU/fjhUZRr1+vztKJMCQGW4dfPIftVuYJ21PK1AwM2ZUtQw+3frMxwghsY2dh4BEt9Q="
+ );
+
+
+ TELEGRAM_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxNzQyODQ3NzcxMCwKICAicHJvZmlsZUlkIiA6ICIyNzc1MmQ2ZTUyYmM0MzVjYmNhOWQ5NzY1MjQ2YWNhNSIsCiAgInByb2ZpbGVOYW1lIiA6ICJkZW1pbWVkIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzNlYjNhNTM5OTM3ZjhlOGUxMTcwMzRhNzE3M2JkZGVkNWEwMzIzYzk3OTRhYWVkZjE5MTg3MzFmNGY4NzI5YmIiCiAgICB9CiAgfQp9",
+ "f7Ic3pnJr9Pb+EC1dwnZaTZtZGnb/DdMzzpH5lQFhZKMkHU40crm0cYUQUPnXQ5d3ozfHpYfndkPgMF8lByDMIkewT9t3yUdJEfRFp+bpdMronC1F6psxRAa0EkqlY4rCxonq3uVGYYm3XweutkxDtj7bZp8E9oH2POJRGIhvc03vCLKQHIn5W3CYIuh6exmEM0rvmD+OybkMV8RNYJLr4vfCpSXj0hcD564qboKH7ikBOFfAQJoXqeE5eaUJJWqSg+tkoX+ICB3INfV+xdSr1U6JSKhIuRAwIsTY4s47t7O1FXjZtIAtwB4eb3f9ltGhTF5A9DTqLrVTRCXbCESGZ0JM4Ps79CAarjMW0+cbYaeVTm+P4IzTQnGJOkBlKcwwt0HTJ+zKQHs48Ld86zfq2UP4MYCdotQs1KbPhgishqNP5jjVrA0KCCibA0UlhZZI06EnCGhK3kI4ZbVaszUY0R+jGuvD2XuF1iD6BcWZ/ja+6hhP4r66JWPfLm3VVSiEi12uXhTuayu0+4tTZ12q0AvlxWPfRq+kv05izhfzPHx2rgLZXkW3z0+v/Fn4y4WEVF3NLDit5huUkmimN/ACfWp9XJZ0xTZ8IQGcfp+yXF2pt4O3UxKAG16jBEXgi0X9muSGL2Bpv2LYQWi+3XDkVooi6IVHzO+LAgbC8KLA18="
+ );
+
+
+ ENDERCHEST_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxNzQyODYwNjAwOSwKICAicHJvZmlsZUlkIiA6ICIwYWFjMWRlZjUwZmI0N2RjODNmOGU2Njk3MTg1ODRkZSIsCiAgInByb2ZpbGVOYW1lIiA6ICJQZW50YWdyaWQiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGQ5ZThjZDJiNjk1MWQ1ZTgwNmJlYTgxM2JkNDZhY2IxOGY4N2Q1ZWM2ZjUxMzkzYmUyZjMzODM1MDY5OWQ2MiIKICAgIH0KICB9Cn0=",
+ "CpOBAguihQpQZwQzx+KsClGpsJRSo3hGKlxXupivUHgyV0VZ6pn9XgKAUnRHB9txEr5uVBZPVfQQKc9XVj+fI7u7bwvLyQy6LalEfjZSrnmuCljmEGdbZMITSMLVHYsr8MQWq3eFn12i06hEaVSM5qdWksdmwhGMzAmmZPVWgtzoPum7WrbjSBiBOJP4BwKhKx+ViDZsy8pVF7z80Zh/IfFFsa3yLBkfIGlW8aCpScQFoL5r9pzjIHdkkCvd6w32irWzinNKS5PwCEOtEEwDBiSRkvYEWsd+rZCt+Jg+Xf3P2i3xfjaMroEyCOYvZdkV3czQdVrC4HHFZYCAJi0IjfMs8xtZAJ9NPCV4qA43tUchPWzD6JJe/ZFJ7OK5lPE7aVxb51z15RxNPadpmEiR4XB+86obCEvvXoudY/yRA8AZm+326q7nCt+dTFxhtHtYOV9NGBrlDFkf7LpCCX9KOP2IBmBXPJfxa1Fg5iu5F3lC1+4X0yK2m0yc84FvfLHvBqSCHEPpXt8GdP3F3zQiqt8ipU66Pcuri0f3f6EQK2xYdbq6MvyduuX8d1EEiM1QulMOZuQ+PJTW3R5eKbAHc4koT4ZP8MAVFpQV97xt63G5KVTsXYpuK1IYvaqExn4iBNEuUyfyZR7sKW/SNzBWPB8di6DJZ0QhHSiIgbFlAQM="
+ );
+
+
+ COIN_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYwNDc2NTA1OTAyMywKICAicHJvZmlsZUlkIiA6ICIyM2YxYTU5ZjQ2OWI0M2RkYmRiNTM3YmZlYzEwNDcxZiIsCiAgInByb2ZpbGVOYW1lIiA6ICIyODA3IiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2IwYTdiOTRjNGU1ODFiNjk5MTU5ZDQ4ODQ2ZWMwOTEzOTI1MDYyMzdjODlhOTdjOTMyNDhhMGQ4YWJjOTE2ZDUiCiAgICB9CiAgfQp9",
+ "lo2u3k3VE6OFENGpr2HYMgRBUWthI8P2//oxEKTMWSgMvGTpRz7j9hrOKyDejUCGFtX0/+WbxciLNbVOLRuJYoYhoEGUUgrtz1ol/LveXV0i0qOVMHLm+lHgJZR6CUzoV0PcLWmKwEjgq9MxCW0BBAx/Llls6+Jgqio+4zc1dn/RBAitf6WDL2DuXg/KSswTOeDIEY6JVQhQc2KfrHL0o66dX7lSePTSurn8vlXvMQaB0n3GWTwt2lEiFky4LNo90JNVBgWBd9RE9x/kqlFck0k0KJdStIz/shEejPGy0gts7jN55F3VrYz31E5Ica5MOSabsbdHvM/4KrJ9KVZ+gGmHNvBAo0bBbye0xqZtOnyOsb/2vXbEr8XpPh0/DEWukyCMLqWQbl/bLRlct7QhISnKoOzdTukYxc6QbFPsg/ARU1qn4hRpoT6vrlOPTOR2/cUKUIxNOaU4Tj3G9XRQftVS3P9iMS1fiPQHP1Cb9kbXCXmbREGEShKv9eFVVU5g8hSW50ftmlQ8nP1LTh09xLRu97547hW6WecRjS2r+9F9m2Tp7uOmdwM5aWHO7DphAASgYHmyKcaboGmt5o7xJkznwCkKWKX5FJAzVA+aw6wk/jma25fn1djuWHNYtzupK3qVlB/YnEGmjE8XzGf0q88WJuZBf6NNhdgqRk/oe6M="
+ );
+
+
+ HEART_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxNzQyOTI1NzE2MywKICAicHJvZmlsZUlkIiA6ICJkYmNlZjMyZjI5ZDc0Y2UzOTUzOWMwYjBhMTE1YjZiZCIsCiAgInByb2ZpbGVOYW1lIiA6ICJyYW1waXJlIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzZlODc0MGVkZGJkNTU4NGVmMmI2MDE4MmIzMTQzODNjYzk0YTk1OTQzY2UwZDc0ZDFjNTk1ZjRkM2RmMmI2NDgiLAogICAgICAibWV0YWRhdGEiIDogewogICAgICAgICJtb2RlbCIgOiAic2xpbSIKICAgICAgfQogICAgfQogIH0KfQ==",
+ "OVJONWOypE5IaaKcTUZ7TWnMaLkTIiyU9h2x5X3DXPThOQw93og9dR4+6aTvy9H1DOA1nFC/ySZlVZCui428kCpTFlndLY3s/tJxfFrZkWGV2jfi4ZZQ+Cb5RUj7vJ4vLYNeXCunqC8bi/Ptuyv9Tyz9kHd5xS8gdkpDdWbOyqm+gwjHWVDuqg2QG1LU48w57fNVLoJ4c6FdzSfpSa//MkjEjjloVjIPtSeoUtrDQBO2xU4utYejIMSGlI9FLxjzS2gI6Pq45xB4RbqXsmo96CxvrFbj4+Y8Nm3Ili6kG95N+HeWOPIXvNnX76ZJZyV0IqcSuqhY+FcOg6sZORG+8JmE5rQv+daXG8hhM/t8so996cmPnJ8BMKorKTQXtmH7Uy4ZqEXF0cvQ9Bta0KYqtMnEzyBoUGagIBu42ctRrs4f90SiitGlU4YRVBkDlHNfawvEA5qUywlIW1nLeFriEk6VMRRH1EXOEetGE3wL7RxTq28Q/1UmUJw3gzejgyFjnLRHKVcpkixx7XTqoF7jps+tNyRgLbUZHJem0L7W71KYa7MWd3QJ7T8LdX1xGgv2kZly+4H8tyv4y+L+p2XS4L2E+s7PzT8MkiD5YYr08nuEhqSbnBiA7G/CkcF/B37QRVaRLH+uLJrCIzvdQqhJO1yejzvLm+eTPaMS9I54X7M="
+ );
+
+
+ INFORMATION_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxNzQyNjczNDUzMywKICAicHJvZmlsZUlkIiA6ICJmZDQ3Y2I4YjgzNjQ0YmY3YWIyYmUxODZkYjI1ZmMwZCIsCiAgInByb2ZpbGVOYW1lIiA6ICJDVUNGTDEyIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2M4ZjZiN2E4ODAxYjcwNTIxYWQ5YWRhZTg4MzIxYTk5NzE2MjZhYTMzMDUyMThjMzllNjlmYmYwY2NiZWEwOWEiCiAgICB9CiAgfQp9",
+ "H7UZydA3X0iF+ps2zlrIh/hdlt8mANce12pyJLk+cl+Gtygak68LFLQMRrmS1zXUwengZBMyaH6A4ZJq57E6x2OpjasVGpoRadH2CfxgLftjRu7iK1/skhCgzUZnmfPNpGmIiMYlx35aG5T8I/MgTtxKauJCNGx+UzXzD1hSn+V0CHYgy2TYeHm+1LgHnZCHbOJqW7sTMZZ5wjGfjolAiV3ypJjaFqMxfixUzT686FWBFr/AX440c3OZMgwPYhrB94rJum0SaIqqemOrzA6zPJf3aLxCicKk5rbEYE4k1nRhEqOnG4f06BjFSFVbsVpisoIeVkeHpQcO3xwx8XeCEfLe4B07DnWg7gonoWkqWVzsqOgvcoo9BCqXoaxt94MgprE/xdPALdB4KaydYpvH9ueMExzIXSMrJ3BtcZGjlgOfMiBb9jTocbMtYTFFaMdUJW5XpvD7ijgJRoScO/WCnHSyNRzlxnYeoNLL2R/5ZVVXkh+84Ou01cTMQUdM2CpNGxdnKDOXaDF0q28n+6sgDMtwG2HuQITAqq8nNXQOs3FaBxK2n/rFsPVKBJMBkStjOQ+S/60Gtw32Ubvjix91p/KAo72a7jrsLRQeEUxPWhVwpPH10rZTl939RaVBFxJms+P/NFGGTDEKiHS+0fUZwvFzDFZPjGwQE1MpbO1eyyU="
+ );
+
+
+ WEBSITE_SKIN = new Skin("ewogICJ0aW1lc3RhbXAiIDogMTYxNzQyNjU5MzI3MywKICAicHJvZmlsZUlkIiA6ICI0ZTMwZjUwZTdiYWU0M2YzYWZkMmE3NDUyY2ViZTI5YyIsCiAgInByb2ZpbGVOYW1lIiA6ICJfdG9tYXRvel8iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTBhMTU3NWVkNWNlMmNiM2U1YmZmNGIzNTExY2JmNDJjODdkN2E4YzZkY2U2ZDU5ZjE2YTM5NzQxMWUwMTM5NSIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9",
+ "cY3BuEjltZ3hFhCNpzGBZg4qUx44Yov3AB58HAeDt83ez9Q0g9AhH8tSF7mk+iMBE4VgSPRPOJpbhe83jMDxEYuEH5sizvP4JNrkhztEYIRCFLF2FcOepEnJg69WgW1EYB1s9Hu+CR5f8sLsMOyVdCP7/qFc5nhPtiGivPEXvzHKpX0SV8PJXGRezphj1AghVfNRO/dtRvrPl6wwSbYzqzgztuJ39RCWzwx9dOWEpT0sGxA84RtaXTKPRH77zkQJ3gyo/h0sU2sFzfdG8l1XYuBJX1rcXyS6HVbfn7v0C0KmW2Cd7hYodAnc26QMiBz1LQobOmXXA8pQbQVOjZB888KewjP+WLxwg4rLnD3xrTzuha2LwZXUCEutWgWEDJnNjO0+BoQj0gj8fVehlF20LLmyzrtNNin+NJT8P2buVDnVhqbjLpQUL8nAzLllVStnebk36lpAh3qQvB/aR5SAdlgpd9GjoCmhjKx+RYBn9DL4vLkmHCNLgMi2WaHlp6JgPkj6v38QV7bRbVXHI/aHcdxZ70KSRxpwzMOK2BDdFtgQqeNnp496Y5su9XR4LsgE9WJG5S2Zp5ED7nR9b9me/XIC+06ORrUAwwvuu09HIQiYqESnjhBRrAIsi7VyDBVKN/97q6MMPEOrJnG8hPP/vZInyVvYZPd/Sg9tbGhT5x0=");
+
+ QUEUE_SKIN = new Skin("ewogICJ0aW1lc3RhbXAiIDogMTYxNzQyODc1ODI4MywKICAicHJvZmlsZUlkIiA6ICI5MWZlMTk2ODdjOTA0NjU2YWExZmMwNTk4NmRkM2ZlNyIsCiAgInByb2ZpbGVOYW1lIiA6ICJoaGphYnJpcyIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS8yN2EyZmU2NWM2YzI2NDJkZTI0ZWIyMjgxZmMyNjhhODk0Y2U1NTZkZjNmOGZkNDdlNzMxMmNhNjQ5ODNlZDIiCiAgICB9CiAgfQp9",
+ "iM33myFYDjRR2qBM8OHDV/ae2iK4ZeTr+euXAq/QBsLfQQVccrGC6qUNju/1gkKUHV98vk5e4IGvjvuCR9aITK079Kq+tUrmLoZeztbi76iATDnObVtc+Obxc1PiEpnsOvA5MRZ5zUkPgouhf30556PxYHo31Yce9/bftpAF/ix5qlA1W9U6oboSxBKvJmq8EJ9zwzfHTXPnjtOTAdHUhPz+OttmBl+u3V6PXLPrHgbnx6NKqrVqlbg6UZpylKx1+VHVbQT2MsFyIE5L4Wu5p2zaMR7K8cq7xsC/Rdes+HQcSmW62wYhH+dpJxZX5iakXxeCdZes06Ym2mIPCiD9+jB6cWn5TNWofH+nE87d9RY4yj/KL2+mgU/6hOPEMLn0zBA5aq8gimEbij2J8GOZVmPBeWGghsSYywtXl3LsucQrfkcn68rI+hRNEbidNEPkez6VwiF8goyIN17eLKSae+QcLpH3uqrhxXySmyafk0JcPvBOK5Id0jrUPiJ6KO3Rbb77HcdqyO03hNsHOWF2Q9FQOibjgQL710ztOp2NgEgFc/aUk252tT5MC/7vPTucBk2UEA9lgF5moaHN3nwvKwW7d4C2DRCz3ZQWtuFQooV3Bx9g2lZwTzFTeGEM0uuRMHRKboth+FDxsqitQfcbLAqeZa4Adg9E/R831umMXDc=");
+
+ ONLINE_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxNzQyODM5ODg5MywKICAicHJvZmlsZUlkIiA6ICI3NzI3ZDM1NjY5Zjk0MTUxODAyM2Q2MmM2ODE3NTkxOCIsCiAgInByb2ZpbGVOYW1lIiA6ICJsaWJyYXJ5ZnJlYWsiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2EzMTdhNDVjNzEwNzNiMTQ3OWVlODA2NTE3OWYxYWVkNzJkYTA1MWI0NzNjMjBhYTMyYTFhMmUxYWJiZmY1ZCIKICAgIH0KICB9Cn0=",
+ "Z1JxCDSrN/VcYainqtkI2vY8Je34lZ/CV5MzNTMQ+gp4kMQoGACehF+0e/hzzdU2HiVk3Cn5utUdAerNTXblnVO9pQOEUVnq9MQkLghGF2vRMif6Q3k46lJZw74hYQaSPX2xe9cDGEjx+oL8ce13VM5cov0CkUBnjN9Qzgp7wJXH8nI/dKurxaiM7la4g/mOxeAPbW88jAYOfYHuyQONkoEcxdjW4/SM8r4dPaRYjTX0upJ3j3WqjAnKQyytRyLwl3Vqj82MYY17SeHbAuLLYDFY/x+DW5Mo+4GuuCRVYofxhXLn3uOkbsoRlknyxld/Zn9kpKQQ/WMKam+sjyJ4/cZDTNCMDrDTpGrelivsMeDaZ0lZqW/YiAKsLGh1gG8UNNOBw1zn/ARwSYlQdtMbT4c6hcWFpc0Q4yRwjwkEnvA3Jiws7htpDr4A+qSdjttS8ED/8uK2d3o2c2OR5bcFOfxTY7UT64I7GIR8Qqe95xBm1YWhaj08t04NR6sPQ3W9sGPfC8z4E+jG68c/YjZMv2z3ibSuR9KansuKhkYDcdGhlvxoxe4a4icQR/94njkYej0qbhqnjuaVmFTUgw8bZnMRkPOPQauma13JNbRO7CCLuzQxvA0YzIG0jEF6JqxqTod7jYCF/F2xkt9g9OaUtTDCH13coMrxOsCvB/DzqlM="
+ );
+ OFFLINE_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxMDU4MTcwNzgzNCwKICAicHJvZmlsZUlkIiA6ICJiOTY5NzViNTBiM2Y0N2RhOTUwYTM5MTgxNjU3MDZjZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJHZXBoIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2EyZDcwNjVjNDhiOThhYjI4NjRmMjVhOWEyNzVmMmM4Mjc0MmI0ZWFiN2Q2YTcxZGFiOWZiZDVjZTcwODk5MTciCiAgICB9CiAgfQp9",
+ "GcCkA5ZeqmUXdu7FV2T2ZgtIZW0X/1kX+bXXqqmRdJV1vogukr97YAhMiSKyW6gwVizRs2WZxvtyLhSw6Cfih1btRhRQ2tWzna3lHxYAockdQ1XsWyYkCQ3keBYcLL0ji+f7CJUtdruO4AqXSu1JdmaMT+Y1Inx55g0AukgV1Tr7WgCOBobDfMvpbg8dqIsmpOITQtegahKfeAlLNBhrzN5S4au6b8CdQHxfiR2lDv282yGG6gYqc9X62KkrWfl+adfmpEdJuddHqZWhnQXBu9iPvHDXdCAqgvPrjwsk0OpQrbVOeZcXxbjDxqDI5OZ4HuWKu716fDVYJVHaO+fBeqXI2URw+T/b8wIYFPii+yB6HPrL48SOYyQjAZeKGl0LYDDC1UTQmzxTORe+1siEoiauPjjb5lDBzDqR682Cmtu8gdG2/dErQE3bVQRfBPuyVfAPdRcFIiCx4ESnVDo3AyN+DYfls7+JLzJ38cI2TPMWtO+PKpWbfsszJlxdcv3OQ8myku+5UIVRTQdION8+i2C9Ho1una0Rs0eE4vFVVFWO0wKRQgd0DEnuEPVWP/Rk9KRjvd3/WNOm/GW3Q1MrrKB8K0zd8O0YvBd3yHLVZPYquSoBU+aJhO5jr0JO09MMSTze8sO3QHAxldTEOTBjZt8QRO05StiWFfqjFovKaLg="
+ );
+
+ STORE_SKIN = new Skin("ewogICJ0aW1lc3RhbXAiIDogMTYxNzQyNjQyNDM1NSwKICAicHJvZmlsZUlkIiA6ICIyNzc1MmQ2ZTUyYmM0MzVjYmNhOWQ5NzY1MjQ2YWNhNSIsCiAgInByb2ZpbGVOYW1lIiA6ICJkZW1pbWVkIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2Y2OTExOTBkZjA1YzNhZGE0OGRlY2QzY2Y5N2I4YWNlNzJhMWZmZmUzMjg3N2Q2YTRjY2EzOGYxNTNkM2ExYzciLAogICAgICAibWV0YWRhdGEiIDogewogICAgICAgICJtb2RlbCIgOiAic2xpbSIKICAgICAgfQogICAgfQogIH0KfQ==",
+ "p2CsjB/P32BlYnCusp75ylxa0EMbP0c6fQiq1XkSzkqBmFmb0m/ZHz0hCCo0fIX5TmkICF6UqmEIZ+pmSIAvP8/G/9Oe1CSf4hH7acInsN96ZGb0x8rf95iMJUtTWBO9R3EtT+kNG3A3NcOdvlknCEc8938MqKXfGMndu1Xk5WCfvP1U3jk/FVXa88eE8bW1Z7b33ePYQOePruLhwUE2bV4wDh0O64/l3hVVsLhL8yv9RyDTZWrRd/1aOFh6jxZBouTxI16uDu8/ZsgiPg+W0nuLa6kAft2BRprpsZvn0IHF3xnczfDL/aVX9TtM1W9RbzLE/tV0W2DuaKiK+Z626OHhgsUdvY3fFCGzTeazO3G3sUM2KOlIm62965w8IWhCE7qBpksMuNSSRva4r6Mmn5alrtrrX9sfNGwSto6ttOgXvvrsY2XKL+OmeYIYAQ4DGZNq8kJkQeGUS1WQz81aVgRiWjp1z0Hg6LYHBUYKb8jiKl2a0vCQce/VetHsa2lVCX4tgjzU91Oi3KG9R/xY/xeqDNPHaMgU7fIdTZFOXj8JjHqHV9JxjvhBeZv0gHGS+MXiRYWHWG3lNvL3B0oWVOlq2eqqU6KjRotWJs8fHRLPnvIND29TtvkHXUwh37Dpx4Uf4AEH822OkL8zTpp7zhwhAjSQMCNZKbLgEpmlYrc=");
+
+
+ WARNING_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxMjExODA0NTUwMSwKICAicHJvZmlsZUlkIiA6ICJlNzkzYjJjYTdhMmY0MTI2YTA5ODA5MmQ3Yzk5NDE3YiIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaGVfSG9zdGVyX01hbiIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS84NzljMTkwYzJmZTc2OWQ3OGVmOWJlMmJlMmVkNzM1NGM0NDQzY2Y2MWEwYzhmOTJlNjdlMWU3ZjNhOGU4N2RlIgogICAgfQogIH0KfQ==",
+
+ "i4g4EzIuN7Wg9f/XRP2OH1pRo6w99SUw5k/R3esUjhHDaHrr6VXqc22aC1KIhEAMvAbKgqNMxOswEp+5gZmCAJ+gCuQQ+F4s+1W+POAF25k6p0EO/T676rUweBobdalMM8an+eOBOSVsIBKjenI1Xdz/UysWNXSccoybRoEACQULT4Gx5hy/qGFGP3+gyXLzoVfOQx69ZETkfASY2JNOPet7Z3wftF0RbK1pSbh9xn0xmr/qiAJsVbp0rITuo2D3bGPfWmfrjkUU5JNOXHzAex7KixAJa/DwHWATBmeFDzhre2KJP10avPMcUC7W1obG5h9tZtXOJtpuEKBpYt0X4XTcfTsnaKnEAbar/YEgvLczErc8kEW8Zjq0DWteb7niUbuFPtXvgl4awaJKOCIh9GevkRZ7fVbGUG5I0WvvyQd08XR0Lm/WmqcuBde8lu3Rr41lB6Q/ART2gov48UZ2+LFTmfJT6QOkJMr/YfiSmBMIGqWZKXMpLAxtKCcL2MfBLUR25GCQC+8cgqkp+Q4C7wqyr3QxeB56fOOggFyqcriRZo8C47rIvKRzDzILXyWMSIFRZfn4F4NEpmGkRRsRtBku8HwnIYtFItXldvo81/fV6YXe4G2aFRhU0iE8av6boxQ4XmDTA4CulBScGpoihMrcSnzflDDtftIOdvFQFT0=");
+
+ PLANET_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxMjA1OTg1ODEzNywKICAicHJvZmlsZUlkIiA6ICJkODY1NjliNzg1ODU0OGU3OTJlYmJjNDM2MGYxNjkwNyIsCiAgInByb2ZpbGVOYW1lIiA6ICJPY2FuYW0iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzg2N2MwZmFkZjRjNWQwOTkwNzE3NjFiZWQ2OWZiNDIxMzAwMTZiZTc2ODU2YzEyM2NmMzg2OTUxNjU0OTQ3NCIKICAgIH0KICB9Cn0=",
+
+ "iFdepbBq8WHQKmYlREoYQiByuGWWWgXv1NOxjBzPxSwSZzbujWRvwasgWbGCYs05G3m8AVKxjsecuZlfKdlgjJspvBV6QaFyYWAQwMiDhBN/9DRbuY3O+lvxzcjGH4jowrS6v6DDQOCk+b7HdNUq/0bXpKF6taV3tAe9ocojf540OdVCzwxB3b0se/nn4O4x6zZIvBN8mnzJNEB5uUlnAwRZrzxuFk50wZHBI1u5tLWr2UZ7Ed6W1wgeIAvygJdDdWaVp5IdvQGEcdtSMXXF1XoC1pWYf1pOSHt5TBH7OH/zI5KJ6xX1cy5EmyorJJZjqjJkntF4Ade7RieYT4g2FBwIco4LWTx3ACnHBB9bwu1iPDYDOK3JqWRmozTovt2vxq3pvAeNblYUlZi+GvhXCvWU0U49DwNi9Gw361Vy3JJXI5LrrNZD5eMYsMfE1l52zRf8w7e0i2PH3aJIAMVdj5CcOwb16drHeEitUT2v39BHLcNDw/MwMkYpm5B1rvspt3Y/4j67MX3ORmvhdmEVR/ztIPj4h8V4BQS0CIKNX6lOJ9HtgL33cP+PcdaVN6Mhqiqd4juxB2alToxJNtR/9ZTf8Kz7zcbGnjkIsJItBuUvzmYXzBAECglf9wzE9m81LmSpZRRMK9fxI78RPfktAZrT7onADK8WkM3STrEXvsw=");
+
+ // Social skins + 1.8
+ DISCORD_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTU5ODkzNTkzNzY5NywKICAicHJvZmlsZUlkIiA6ICJlYTk3YThkMTFmNzE0Y2UwYTc2ZDdjNTI1M2NjN2Y3MiIsCiAgInByb2ZpbGVOYW1lIiA6ICJfTXJfS2VrcyIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9kYzU5ZTVjN2IwNzM4YjU3OWYzYjQ0NGMxM2E0N2JlZDQ5NmIzMDgzOGIyZWUyYjEyN2NjNTljZDc5OGFlZTc3IgogICAgfQogIH0KfQ==",
+ "d00dnONViJCmrK0WdKODJ7tFb8vGKL+/GEq8NAqIa0jLNuCjz6pz+Rk/eoflg6vNnYRueD5c3f3M2ohM7dbggY0LZC9x2ef7/PYF57gRkA114DXJN/lZcq8vXQcZNFPqRiLlrMfzB2JwTyuCg5Ssoww3i5Fz4J0h9Y+ok8e9LfQzY5ficfyuo30cVB88ybQ5VS2Q5kxLgodrYgX+IUAJr+ns4Y48tKzPEVn4JGlJOLpY0tk8OMNTqFRlHw3cPMLQENeKb9OJQsstjsGHT4mvk7I8y/WdD0oUCj5xVUER/vgFBVwZuRJSBzFbUa5Hq8Z3JlriueQ/iCwR9t92yJGPQwB0kG0OH2wgolDgm2of7+1+67yZDk1X56/W82pxW5MEKjCnkfkGuGLvbydp8tf+6P4gX6mtWJudzibEpA+L5dfdHRJF5/l8FE4gqmbCKBhYdRT2keR/acB6bBF2g0vY1VCvaJe4vb3gFB4+FViDwnDhssLpHwgWxR//LEWrP4fmCJgLee2EYfySmMeVTW1gknHptIMJQtV92xxmft+vRi/WV3hqIkRNkBMI4+1MO96+buesKHUHg5yWH7TixcrFvbH8q3SAhQGqwV8Ksv44jSC8Bch9YP268DjruN6+TC/Lj+fGcFe9tErlbYM0hVCMUEeRDhQ3PzpThUegQmJ7Qk4="
+ );
+
+ FACEBOOK_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTU5ODkzNjE4ODI3MCwKICAicHJvZmlsZUlkIiA6ICI2MTI4MTA4MjU5M2Q0OGQ2OWIzMmI3YjlkMzIxMGUxMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJuaWNyb25pYzcyMTk2IiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzM1M2IwZTIyMGYyNzk4YjY4YzRmYzg4ZWY2NDU4MDkxZDcyMDU2ZTFkNGNkOGU4MmRkNjRiNWQ2NTcwZjM1MTQiCiAgICB9CiAgfQp9",
+ "aT/m2pZfq9tR1QwcIIgQTm8ytO4BRLXj5eZxZaFEr1k8IK2+utDCtfErrWtA5fNnWrkyj4AspPKT0Cw0WmgsYyqghhKBi9VS5CUCi/o2i8H6K76vFiYO5+5sKJ560RoPC/d2yJ/QS1qa6tbqD+8cIT4Hrh2Ni3ouuEtz1/MPg68p/EqkdNQEzNKE7xnuH9BFX06JLiKql35t/Mk/iMC3WdqCp1SuEmFE5sXEwfR+YpB3fuhmwi6xZj66TaVSZ0WFVkI1j09ROnVAcdhUa/yj4Q/kKBCeV7/4LsBeQhkr2noJh2UFDYPTSpQSgeNBlzgvSMr78CPLIVdpeyQ6MuoiG8HED5vytwJSymvgIf8v94tsDB8s8HfKwWIer7FoZ8kfY9BGhoXw22wCnmkRtzEVB+8wSpIKxwrjYMrSGiTIh71wrLkPi3nBVzy0lAEnQPmm7qePjET8R/l4LWT3kWojqiqS+YwMIXecSWTlhbquI1d8F9mFmDXYh+xSXsD+DqGpVlKuCn9RKXBrtaDIQtXu/5AxryQFgSSJOinxweOwlUAgFmiB6bO20KUfLM3YXdaxK7NNxCPVAoGb3gmvlsSpoGCW7KRobVwVNLQaCSzcXwE7WeRb1+c/xb918+b98eaGj7iIHicrxOMfuXOWEaDHDrrAXVydhEhcS6+3eccVZ84="
+ );
+
+ TWITTER_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTU5ODkzNjM2MDYzNywKICAicHJvZmlsZUlkIiA6ICI1NjY3NWIyMjMyZjA0ZWUwODkxNzllOWM5MjA2Y2ZlOCIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaGVJbmRyYSIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9hNjFiZDYyNjEyMzY0MDFlYWQyY2YzZTI4NjBlOTg5NDcwNDM3MTVjMTBjNmZiZWVlMDMzZTdlNzE2NzhmMzAwIgogICAgfQogIH0KfQ==",
+ "WWGuBEL0OlGmc7dhEiERLmv3MimSzTcg3cEqNgTVAQzGuidFN90YeE7EjUqAQXlgWEswXuXCJlMxYbM8szLkQ7tJiN7fQYKeqWeSU/GZUXTEuwkDudTF1en6lKx43i+iJEd46UMowBPO8inSjYJfLmMJn9+IStcol87o0TYce3iFjAHQtDootygAqR3w6LsYbABbfabFiHLP7r0FpqzO21xCyIJ6fcmRh8jEawJ56i0WuyaK+DuSa5COIYYQgNtfQJ1K4Bo18yuxFgi3uDvksK+p+ZfFJTdcKoWFO6SmLZpYLDaRL+dg5HZhYjfF29J8SBWXgDjJhjDXJ6fUpy5+2JEvKfZJHyGmqx4NrKF4Nku1Dof1L4e/m6P9Rzc79AjA0UpAX5OrVK7MaUm8LySM0b38F8TSHtLlK+BTiwbrxHKJZja280cOJsnOw0FI34g//0neLUv5mZlX6RT6ZuEebX6F3bhdCP0orqsEV8SgFjumGQmcWd4KeH8bk21ZOPoUeVoeh3HAHF+CbFydp8M1q5jAhupf4/bVFdmyc7lMMrL+DD/RqAo3xTbSbyxjWp21Hd0yIUcT83bAAIa+AyolGHmsI5rtr8P9zcEcsfMi8NEH0GhEqEKoYoSAzSNQ+6BF4GOcMbO4+MLtUZO6EPCA0pXwXRD5765ZvYIdVgi4HVg="
+ );
+
+ YOUTUBE_SKIN = new Skin(
+ "ewogICJ0aW1lc3RhbXAiIDogMTU5ODk5NjQzNzA0MSwKICAicHJvZmlsZUlkIiA6ICJhNzFjNTQ5MmQwNTE0ZDg3OGFiOTEwZmRmZmRmYzgyZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJBcHBsZTU0NDciLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmExYzQ4YmYwYTIyMzBhNDYxMDMwMDY1ZWI5NDFhZDU2MGQwOGZhZDUwYWU1NjM0OTczZTVhYWVjNDcwZTZiYiIKICAgIH0KICB9Cn0=",
+ "ljAxdmighg13rgsWrkIuLmtPF/cNi3nVccEQSJD2FSwGvF7avKDuh9xV1ybM4XdHQVusdFSsdEhofDktszyMauUOvF/GZPxGGG+6WDG1HSPD3JmbUckYdd0608unBP8atA7TThUyP3tncnHhn9MtUbVwdq6WCtSCWw0LejLyyOHz4mSzMjcfbZUkOKhRf6zZ3ZjvLx92UDMiOFJcZ+HBXMIrpFgO2RrJvxJpVQYCFZptdCcPyuwh5Di3LVmy01ZAp4hfxCVOIjpcNMd0UcgjYdmDvGSFkXZty2DaVFma3OeowNZS2ISjG4E3GbBmPBSnctiT60ugrSmFQk2/9oHYeO4cs9cuW4baYOY2yHrNwsTWYjIoqf84wzzlpYxwWNejXYa6ckc3iM9ycgaGeCes3pzG7U01M7qQl85xigg5c0CZFgrjMCdCMwG8cp4uTtNY3TZg+jK7PtYE1QCrq6uIwBeBAN0/Me3lNgKEVKDXrsvtmUvTp5eerlm1lpQGIdF+L6HLV9ZBDWRV+gPEjgeZPdQaq4QmV3/88xs0SGScwdJkT3dRy6fdVnseYLZhSWeqP9cy28vm32JcTcOZMEbc6JBrwmj0POoE8PlllaSotCqW/RGopSiDAzH/tGhKTDX8XDYwK4eQ8jj+8frK1Q8S13wKCpdpGRGpQtZQfG1ntxg="
+ );
+
+ //TODO: Circle dots for minecraft player + 1.8
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTc0NTY5MDEsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS85ZjcxNTBkM2U1ZGY3ZjIxNzEyODlmM2M1ODYzYzkyYzJjODkwOGMzMmFkZGM4NmVhN2Y2MWVkODQ3YjY5ZCJ9fX0=",
+ "v4HSztoVOn0TMBHyDymPBItvOpWs8z6twVamfdrE4yhr8HZoBYWzl+qxfWu+8+DNyBSCpN6nr/UQpFErdys9Kk6urIURx8mEeWDXcYOhXrFs7oNpXiD7UvYm4nd+vNr0xbpfQmSXBGIZ+eOei4ThbKdkSIB79mlq0ugbwxCsK2I8kUlUU6+KnsunPr80adcPu9RryAW00Bmta+eP65nIKwUWNKeLb5iHaPq+N/IZ5aKHmLFiSXiWniDB5UAYybkBZFuvosSr4TBpn1pTbEF3PtKpnPM/8mpt+97W1JcCAv0mdFZUr0hT9eMAe3U0r37J4w/RmLd0sCD7zOBX0pIPPIMrXOQ4DfuDbKSJPXyXiLQQrWCHYnOO8+8kiQcoQ427trsb2y+jMwYel2GEU6gS5zOdkkVm8Je6tNxgA8vRGqA8ABW8SVQz7y5spk2CGiTQQbV3EeJwKcZHXAAplkoSB0p8fRE1fEY0+REoETg5TbguZnONm1+PdW/LdLifL2tGClSz6Nb4D513zZuJaFc/dQ7yagJR0cFkuWVuI59ZnoKqiEW+tMsrhn7QwCwGN6eASHd9seNvnTXsGOyZ0iOWFCay7JWOGSMr8iGiYCd92kn4r+UbCJ+OtokHzxFIoEHr2hRnN6thye27/tpP9Is7cmmmrDAKvecGtYfsrCVmTIw="
+ )
+ );
+
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTc1MzgyNDIsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS8zM2I2NWQ3OGMwYjI5N2RhMzgxYWJlN2JhZmM1ZmE2YzFhZWVhZTY5NDcxZDlhN2JhYWQxZDQ5Y2FmZjVkYjkifX19",
+ "mKqD4+2/uXiIjNmtQDcaGoxghxN3d+YFX5VgVHO1whwWSdEzRtNj3tw5CJOyBZVzQh6GfYqqi38ylfCiBq6t3JAYfaf4BxsDSKyq4yRfNb2JnYQoXGrhIhwMqEEyieXoJUshnBXpneASDf0a+BE5hN29l2vqQGs9VPKggqbt2zpZHyUi6tQMlwOiL+jDKh1bcSr4Wl1Ad8JC/BhUXytOR5u0FWm4vOEsqq8Td7S4Jm+XzgwxogtrpeVhRMFwYL7snjehYF3qh1W9p8PNmJGtZ9AApUctc/qEVnWeCOnDAaKgqozj4ruc4Xk2KMXxj0GmDS6b65C3m71MG+cW/0sS/Rx8vmif9SJum+E8C0X8inNr1nui+3ulmwqC3x0MeVsp81cr+LJIA2dcryKVWV3W6hkYuc3OBUjxrN6NOP495fEsPTFx33eop+pajS8g8Re4drNYHUSy7suzDOq+Yv1XM3hOASN/msCU79/tj1G7HIQ2+RHz2eFZlUWC3IEX+5BM5cf7uK1hhkkbejUkmQSblFGeuTnUdV7Yr6kmn0kXQbHAOIrRvw8d91x1lHoX7yjh+HbG4+RymOcm09MJAfdaut7Q8fINHM7rsiHOT6P0Tj7u1UXUUT9w9YXkVgEPCpjSjsjfkGblq/bzDzg8d/es3aZd00WmqFGjlNMx/EKVf/A="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTc2MzUyNTgsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS8xMDU3ZTUxYWE2MmFmMjQ4NjdjNjc1Mzc4NmYyMzRkOWJlYjI1NDEyMjM5MTc4YTcxODZkODE4NjkxNmU2YyJ9fX0=",
+ "P6gT4sSTDPKon9h+Qp/JEK1minlQQRi0ReIsYdYFzHiVpOejPxq4MU+0Ebmvs23mgX2tgqUQV8oeHK9xNCoTB4cKrLMq0U7JJ4C6ShCrQXL3Mr6MilVIDUbP4Fvj9uLU9vFCEiyHVnYwKlnIsnDxnOOBFzki5TyaFTVt2LeNrlso6eh9ARpa5PCAevtEDDrZ51ftvoI268RrbQTfgE7coiDYAcEzgSY9Lm5I9vQxIN6VWhh/tUxHHdn8u1eDIbga/I/EuQZ6H+V0E3THmR55ob4mKZ4e3TYWWRRlOIZPOdFcPIluVdkVZG03cQfw8RYsON/dazBnbME55NTF8U6ovyDWcwYhCEJtRtA4yGMOocX06InRDOkmFk8FcomtJF0WFSSZRbNfxEmG1XXZx1VtKX4eYR97Y/ihOBilN+Aq5yQ2AB+JvEPb1NFiQHdu3mQ/E4tJxKgsorFd75xbPBV7A/mPsrUV2GHvLFJzlBQGDYJCWqqIEdRV/V417j0XlpM+D7UBiIekcsDo2ajOg0v5mQqGF5d1+H16K58PgAOkPLmKwy3lTAnpPWhSWfcrSbkon93eezlD6eMZie8YG2ucaPR9TXYXRwLxK9DrCx5ZfzQV4lgeDSsL2i8kNnYmTLZ1DnsVw8IwWifUFGwwapHFWO1thdy5yifjaa/AOWYTJQE="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTc3MDY0NTAsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9mODZiZmEyODRjOGM1ODk3NTFiMzQ1NDA1NTc0NGM4YmM0MGVmNjVlYTZiY2RlYzc3NDg2YzllNDE3N2FmOSJ9fX0=",
+ "LGisiuVbSaI9K2dXN9CsV8SxuXieWvCHTg1mdjUh744AYQBbINiEgEbXiFz3cQXzzJttUAW8MPZyBnl4qxJr5QRXd4mB8bOd6nA9eimRPiCIpS8QG6V5YZWdyEvKuV+xpdWNkB8I4kpgkRFBmYsKNWeg3xhmgeA0QP1kpadGKU4oOMb5vzUzsIVbyycjhtGcRNuGKjZaNoHVssuTUpi83xIqdCPI353rsltncBY4Idheig0cUzBXqvLX0K3pVxVgg+jQxRPRlGdLhiMXXs6IkRj1glvcZO4MEMg4IfA/W6Vq4UiVG6RpubS53jDJDt4G4ZrtSVX07rQOowHlnY8xIgtpSAbW2iy+uHu3mvv4lWATZE7irU3QrRg7PUSZYSIihqY+CWp8eJwhs+JxTTBMqCzfv5HvZg73WVj2003JTIIxtqTyrlBxIa+4DnPBhoCJ+N0v7wmLdZQC+PsVaRAC8nrlhgDewfglW9HHhqU8m5LVa5gDyMlkIOo6w8cW3mOCTqndGNf4GmDVCbli5Yu5SptaZXvibCp8HcNmkJdP6yf4h/hKPEvOc1QzQOm4L5+9jJxGtpZA2+sTDXqucI2TPy5XNxd9+GaZP9J/xMiwihqeGYmNXbjCJdFSE5NX71HH0NbIVQu5G2VIFccuKkz0iDP1vl60ZiHZdVhn3DcL1gY="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTY3MTU0NzcsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS82YWM4ZDlmNjQ1ZDU1MDE4MzRkZGZjNGY4YjVkMzIxNmQ5NGYyMTEyOWE2OWQ4YmE0YzJiZjE4YzE0MzEyOWQifX19",
+ "D7ub7tuNpCdQckdl9tMJMoSF9XfEAhL0UA4hqMNUcm++uHJviVXbI9ePlg98+N5aisqzVj19/Ld1DaJENFH8eKtQ+lhvzS6Rh+x/JF/QGfDGbWSbx9J9H86LvJpY28hQ/XJ1cFSmtqK5xlnXBNilFj+sAtqCJ+KRdPzwnhgvMNqFMmy5op4qjHaQH4QN997DDF8RWt/9dMzoBDS32sr9RAwzyQzuRsa2mHyMbrrPzST78tcyBWk/dddE5zY9qdt7sDtkar3hDOEMgrid+ChxmAlh/LulaXhpW2S0XEsUEY3uBc58iNrnIWaQedaYYaFFdXPe95BPMaMXtgHblRsOhWlvTAXv9P/CB3v0PKlbfH+kFZyf/OgHfkZan575dAdeEl5mVdT6h7rqriau3MIj/MPUX76xMY+0cbNUGG8Dmw5s6Fw2CnkBuRJWaf9NlSynxm0S/K8BqF/UdGCHc3BVYJ54Bhc65KyN2EONaON2OT2p41Ssvt0Z1UEdb9w+0G+pMYJ9qp/firkdsyQC0VQepymxTDvsmhrA+MC/fb4QL47XucJIFGzhi/qbxj+AjKSt6jhbqYUNE74Y4S8U6fsjIko5dEiQ1eVhq+TOsGAiF0M5M84Jpcyh3B/agvJLic4zIwR0AEE91Ok5ZM8hOimhQf206XvYItw3FqNGjdOsiPw="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTc5MTAxMDMsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS83NmNiYjYzYWFjMzM2OWE2NzI1ZDQyZmEyMjM4OGFhZmUzYzFiM2YyYTE1MTlkMTA3MjE4NDMxOTgzNWNjYyJ9fX0=",
+ "QUWtd7snPe+R9CWdOgAVlagJE79wO4NUGouqctu+/38p2L2b8PRyFydPURaN7gimsBd3+XM6fd2SqS5goc/wj/YXn7FKrIAWP7Wlq1+638006wKaqtyeIXPIOEGBt5fZ/ooYvKDlVjEkyZ1MHwhUVtkmBDUGkvG05WKOJ0LscyCuUw93qfE9LJjowMLubIw1Aq3gSo0dmcN+KcSebHxP7ppThE14BZBrUr2h5zbu1LLYSDKgjFiO3BFkVKFTXtz8P3/kLprQUycT+ojGf8aye2WjO9GlEkiEEj/MLb31B8ImbOZcFWpmqEGfxctKyK2UNZdVrof+Y2qKpZMMVcn6H1SWCM+H/vt7y0wxs9j6kk+xkFTgQJUJY4Y+lBuT+id5Zm0iP3Ua/dCauhlQNezWvCnvx/ICKtGaibzpsouScj/2XMapnQQBNnurTK6v5viDvlt3vF5sdg/pRYDtqyKF6j0prBjQJBayAmANMIefAVYKwGyHONg+JJi72JEm9srIamp1a3ijfP+gYj/1wKtu38w4t3Yfbr7PRO5ArhZbUKvxw+nIDRPwK41SqARU/j9aWVtsud4ASigNno8KNndH9Q/RIfXXukKBNi69PRvPgG+FKhrpN+U+13Zcdzx0mtkMK+ZGb1Qp05Ko7gDfCFawWQE8wKiFC6mIWzWVSeCMqdQ="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTc5NDUxMzEsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9jOGM0ZDQ0OGIxZTEzYTI1ZGUzODg0ZGIxN2Q5YjBlZDM4ZGY1ZDEyM2RlNTc3M2YzODIyZWJiNTNhNzYxZTMzIn19fQ==",
+ "gdr3b0Zy/uOlU4VdDuAmnPGhKlg9qImK4zj0qoisJZfiVYrPNPeQCocxVvnkAYqsuTsoe7UUo5/oW/G6Z6AKw+2aapkNbUSwxhdCb2vLmnIt8WGhxTxKcd2OEdCnAmCNgtcF8kF062yK8Enoni2eJI2oV+7MektoFWV5pWBkSmhNMBuw5AraYv9S0+zJTYjX0eANTuNXV+VKnfzMCcKuyOBwqXhNMzL9vmvXTMBJAr9bYx/xH3POO5xhGRrW4NyuWSE9SXhV4NngSR+59kImfZmSA6d9kuK26feZrfRrAME/UV2rjbnT4WWumYzvrroZKJBcq++yBEsVluEagkWzs8UXOtOiNYttp4ETg19aYObXdQSLGFRzTeVCVw4cHVSX6Svbiie/Kyr+s/5fQX7/LCs7uVlclPMrabQiam/DzDRre3hbEHXTfiUCLFQLjyqOQ1+gsPqWN2E/HMj0I9gbKL6qrgRVstvTf97UXqXxXudbOC3EthdgAM4n/lR8s6RqmqwzfdkWAyvYGW2c49tImnEtaltwhzeprURNy/dEbLkU3KYfXx2nVHO7+d67WJscwHiffyxDpLwTWkclIrC7bl2SKyfib1cElDqzXNzKYeqZ595PkiHeBBRjL9CWLTlXcLMWuJtdqvquCXt6oJ7EtalcVhKE6DHXdtBDDYDaWpA="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTc5NjU3ODgsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS8yYzkzZWJjNzc3YTg3OWVkZWViMTFiOTY2MWNmYTZkNzdkZjk0ZTY1NWM0ZTI4N2Y5NmY0ZmY3OTI1Mjc2In19fQ==",
+ "jL/5arN/cnJbD/DZG9HTo1ckkwZk+XXYUe6QUqbZ0QAm/wecw/mDZqvGwqwnngsgyg0UelxPHvRK3J3z3SdVq7Kavq2UdGkFLr1fe+34bxTnzricHXs4baYDQPOunmbdHgDs+7wwjYJbuQ4nNRE0vQsCmMAe2epchFEDRsiWYuBS0bWCDtQzCBJasGridmH8MIpBmicKQ8OWor9q9T/Pvxh1KEJdpFJuvEGS6xA1J3GxuRT6Iq1elATJNhW3P0MeHU5f/C8N42clLy9K2W8DGm0VuDQbYZmBCaxYcIo3kbkAVVZ6LGHfO8q0kxKIq9q+qXcmn5TQK3BmyjqTGY3PFYRVR9thgA+LWk1s1Ln1jA6ousckJmQJa1eW73mRt91fvRVAMUGm5qrwScL6q2pe3BjBfB3OnilSR3x2cdwM3WkmfN8VuELykJvxHIhDXGCxI5Xg4ghPyZvqW1NNTJmCUokp/fEt+64ZkXoqXzzV88pGZXuVC3ySgg4hdhL4he0tUOVQHttls+lQ2id6R3XaHdh4Hlk/EjSDM5O9auenvKdKAis+vVUV2oqJ+XGb5juD/MOG/INieNfuhQArWeTxyeufsOj8llWEcyYVRVcmJJfjrAagSLuY9OfoNVlSBM2wP92tzQUXQrvHM+mqw9gDlhudOnJAyP6iP8bVsqPN1bU="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTgyODg3MzcsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9lODQzY2ZjM2ExMmNiNjQ0MWY5NjA5MDIwNjM2NzI2NTdlMDhjNmQ4MzQ0YjUyOGE4NDU5YmQ1MTYyYjJkNDgifX19",
+ "nPEbxncNxOm4I6BEsRQ+nsSy5qXKsvKkKLTYHUkze9fQS5JYyiTgAuN/ouljx8fBSbEBdFWxFZq68WxF5h3QDIX7O9x2OFtx9L7vURndZ9pACBRJehy2Kt50eLlEeNMfg1z12J0ODQ36fKbujUYK4ad2ZkM+IOd+QGRV2EDRqFpKC4NMIiXnQ40RYo5GJBAIuW96kioCvaN7+jbpyKW7ub9RAj7dVlXeBbP7cCYvPHb74Ww/lw/EhcsbrwH92eqrApr/oq0Aa9MoW4FKLsEejXvYFjzn6d44uPddwjkcWnd0B2Z8Z8PU/ajS+ZYQY/RqQKRo72bjjPKmn92A19ULtPTFTSOsxxVmLTSSFbYqujt4hUd7BEcDlFcowfhdXtUQWYp1c0DV63UU+dkp8bmnaSCHoG+goyJJN43eqZwSiln2UzEGb+it/wSE3kgsy8q2X4pNgx67ZVUW1ZdRomsBIO0WoanuYoeCNXKRzwMj2mygocdlSer5ZmsnvqG8e+zt8j4iytYDRZ9AWu4euHPPYPbWozAUUbqzsAkogcqa29Bz0mEbr56Per+4806tmPrg+kheI/pBvqCv+HBMRM5ZEEO9FWkTKl2hvr6t6uTNuXFnlVkwspEJaocE+8JJ0E4WDW2mR997uvYYbohY/HPMUG6cK05SwghM9OhQmD8L1Ao="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTYxNzkxNDYsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS80ZjE1NWRiMmIwZjE1YmIxMThjMmNjZjYyMWI5Y2JlNDBiZjQzODk4ZmZkODRhZjczMmMxNWYzZGNlNWM4In19fQ==",
+ "tXZ/NzLISCygr4aGFLVwW6g8lZdoPruN472pVGHepHU+e+spVjOoQQ/vXrIl2nO5EZe4yVsXYDGZK7UD8v3pNfjyXdwAdaRplgQy4B71dvpxoookgN6ytbkr3EV0WucsNCpJPVEAWN8P1DGYVU0lVWyqdphfmbqGaTQOtJonS95TIbfJvmropA86Uc3s6mCOGceb6+wu216IGOtQ1tnBI7wJJF6p3nYm2hXKPDz/ulZNUb6A17T532hfLNRk7tWaPsjzYnKdTFvpVzuVyulfUPz0cxfjQPAreU072/GxKxk2eTlK6qBCT4hOBa+jlnBUUuG8JIL1/HetF5e+svs4LcMzVh1ZSnPsu6ucEpN8VESDK6ErUSuxIm/f2FnaR8eHaqdJBd/1xaA2jAILNP/Y//4G72BdnMnFsv+rVptE+V+yWzg0Pvlv3I0FqGNc+fZWmP4pqjIUd2T7LjtztV7MyBDECg2ASXRhmaaldjKcZAjgaOyPjYkQ8ydFgPMrQB/xR4yiHnivguJWG9ReuwALI480ZKw5VM4evp6JhvYGBkgnrvC+AKGX+gAZhfAnIT+KdUXAJh3LYfy984e1OQQqNCOg+lHR1aPU1RbtSEN878gqYNbMVbZ7Q5fAEo7kz9V9uqmHSrqQ8w4ltUO9W4zbMYJDVVdVAWbzF915ohYpgp8="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTgzMjE5NTAsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9jMGQzODkzMjYyMWI5NTIzZTlkODdjODcxMzEyNTk3ZTU0Y2QyMjRjODQ0NmY2NTE0ODY1ODE0Y2RlMzhhMTIifX19",
+ "huZ5VsNJVXyj1jijC2KE3rE/XbF47jfj/dApSKRqMbTmHQhi3AEFUAetgN0TsBJWaynz/bgADVTY84WsDeeZyW6u1FZHQtOyvq6zxVCw2L1tFrjO7Ts0AYXpNvaZawz+r9OuM01Y62z9oK4VwA7e9oFHDSuo4mExcTgd35cqyxJmqNA2k5xMh88BBiKumJNTenzTEqfQaaWesSmRJWnxZ09zZKhZb2E0m4ekymZPKZWPuxxfOenaFWlpyltLnx/2pC7VRkG1v+zoBe/VmfsEtu5qWPPS8UPtg1Fpx+Q3GtxIApGj0Ni/DiKkaOmOY/5HH9uYD4BtJ3NjXEFCWbkQOXEgLrgwdstRVL53opC3+07QZTbnXVNA2Ua76Gu6T8j+KMxpA0+q0nS+FQZCL2TEt2Pm9nsAZx43kvQ/iA3hnM1hZ64jSQ4nj38mUJ7bnmqM2bcZpQMtIDzwMwswMLh9/jpYFZBK9p5tG2TW91RjSne6R0sOyzZyfOBX/T8oNohBCSVokD4+8SGyBGzknUb1VE0YOZ5HOj3N7agGxhWyPB6DrYCUT8hljtezFO+iPBSBLVo2yuX1PMrrQYB9ir+rTc7mjOYWmL6ENrkSN52fBDCd4yLhPZyU0AP4ov+Nl175c32e5f8Ihhz7IRnVhNDzOE12WS55ynn1IofblMSgfPU="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTgzNDc3NjIsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS83YWQzYTk4NmU4N2E3ZDZjMzk5MTNjNmM5MmE1MmNkNTI0MmUyNmU2ZDc4NzRhYzVkYmFiMDdkODNiYzE4NCJ9fX0=",
+ "QwTBMrsbG4EGg5GnaYGyWy5S6G7UWJTTafe/22OMDEsmIy2mcaPzTRHdxQjeWPa8Zk5wGlp7ehZMbC262DRdDG5Wg7SKuAkxNdow/u8BhrUJg4Z9nQhfOauoN2tk/F1j+isV+xVi58EsEhhsr9h/1s9vxJKI2GBJJUmTjZ8xzYmcsihpoM4LaHKRu8sXWQ1MHa5QBgqzOy8UPRabFFNg/5GT8xo0UqM/5FlsYMdiIPsEdOi5bMPsU6ZTco/hWpqTMAlhDMw3hLUxvknnQ6Pf1Mi6GOqTSucaKggAyrj++p9LMtihwBOvRHhWUfIPTKdZ05JllS8Q6aZioOqVbsd+GLHYZp/PKtwKNC62rPzpqZMIBw3HgZ5ciQhSmDMr/l2dDUKEn/LIAJew9P+GXVEpPTAJSLy2IkcEKzrtU5ZSTmbZwzzldviK0+tPVCE3AzMcnYqoVbj4uOpo9Uo/uaunLWm8/PWcjRw3qy8c3czxC1xVynEDA5J6wjo8oqjSnEOuHuJ6cFLCYUf4QMlRmVIaA4lllAOOr+68QEHzek+DRc6rNgkUoqCcHF53YCfH7JItpSxxTZ6snFS2LI20KFUp93DibVEkxifkyQLbqB1OAcyDXkji8HJ7IKUMAUKoNFpLL5eANJsv/96P81N16rGA3THLe5iz17L5xVX/hpruKAo="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTgzNjk3OTUsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS84OGNiOTNlOTgwZjYyOTMxMzYwNGNkMzMzODEzOTRjNTA5ZjljMTIxOGRjMjYyM2Q2NTBlZmI4ZjNkMjAifX19",
+ "FqA2ErdpdSPLYrb+O0O1i5dxEr9ZD7ZhaeiSZmU8QSf6+yA8eGo+KZo0N7EHC6YFXnxkgySFqJYk7itcHQ5bLRKpKCaSKAXP4XX5a94/7x6lNa8ev82L+Er3A/mH/0cllxmngqLY5vK8Hej09NoMMNNAhtp+f07TkqLPCi3J6G4mFK4zHAId1gEIEyj7JxlTDeOeU0MRUE4bbngyt2h5VsGpitFaYWJZTSnl8XsXr+6/diXk1nM9smKmmwIv8C02Ufdw3N4/fB93qWfuDUmpd4RLck6XJpp8qJ95twQTmdlpEkUtTt258mHnCV/pjMY9T0J7R1MDbYajkfhDQ1xIdKpVZEsYroEVv4jNOedbRHccF5XZLG7QcYGUk22A53XT0/zuyIBfQbYk/XShABdIHoNW+PNscrtahAmqqGmxkxQqZdI7DdB6V4f5J2YpLkt6k/nXvV1uA+Gm2uPylPvvJusVJJD0Z+BroyM4SsXFfaN9oAqGmNFMdIWR+17vl9TZmfN+K3KodMeiSTcVNUFKVAtMFXSaz80UzmKAB1D+EsZQrJ/Qzo4+OP52TwMmlLOBUY3TvgZkJrK+2MC5kGnwJlW3atjR8JlsKTdNJx/xoCg8HRbaqdxQAfz7zYBRnYfFeuf9Uvb0G7RW33CO0ifqP0gi9HUoQH3LxAiJ0zNqh+o="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTgzODM4OTUsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9lN2E3ZmY2M2RjZDU4NWM0YzZmNjM4OWI0ODZlMzBkNjg0MjE2NGZjNDRlOTQ2N2I4OWM0ZTFjZTZjMzg2OWY5In19fQ==",
+ "HMmoTUZECnTE/LoW4y4+yH7YENNOHqFdhYPFmULfFsEYjU/cY0eUu2LmlFcfjox0RTHqGebR0OmGnfVgim/p6n1RQtOXW0dt3GZKgrU10LPGRvEwQ6SMAB9/o5qKL+tnNDAtzbgrUJQh6kQGI7EU89h1KWeUpXmksPhnAPTvuXhFYEj467Ocg5Jz+CT1n8x4Gu0lXI8v8jHW+G/KP2JSQkLeLkqVRb8dGs9laFRvVwXQ3zLgTFgksgwGnuSlWTxoKVS//oLjwlZtiSowg1g+mQJJZxoH8esfAFGsxNKV+7JrdN13PfCkbdZYDpm5eom4SdrSflP3DXCBuGvBSFoStDYYegZEY5t7GhRizubZOU8ze3hfnbU8HqXZH4wqvmHzH7PhM6edQUrgJ+j9HV5jfpV9fQ9vhtlAFg9x1s9V8+yxpQ827FIqwyR4LY5cVZHyQCl1vkeCSuImrIUmYZ3ZsbQXzODDlzLEox++YDiEnUeuRCdJi4MInO9oKbZnZltEO4fsyWj7dRgQZQKWCR+iXaWiGsNmiiJiishn2+dEjFGg0L0pG6KE4XmkCJtDX2VvvgK3q4e9a0mZucZn68SjV3CcBghXkZ31pKzxxaQrKQoxs1KZFfG2UL7QDGmUURZxwWYzOo6KhI9eyAx41mujy8xlzarQzUErN4cwoFoPSmA="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTg0MDE0NzAsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS8zYzY2ZDFmMDhkZmRmZTY2ZjljZDExYjA1MmY0YzM1YTdkMjk0MWZmMjNhOTRjY2UyM2Y3ZjgyMTg1NzcyZDgifX19",
+ "Rs2GuNrHjFBLk09ymZ/3UpTNSbbjmnZ3WvzA8n0X0gwzNHAx+8u/pNWO2uMEW1TZE5fhmrRAb8krfEpr/D5RdeXl+Se7NRch4mxpWqz4jiipMigFgGnf/s0JY+/dn5amGnoHKzqsktHFx3qwwOjGaz2jj1vhysuzQLGptnurn9wnRgVIueWfR2Cctc0v1pJ9jBVx/gkG3N+2Wznml+50pphxhcYBtfUKtwnMRxHIOz0me1KuRhqmBtmMzoQUArJXiz7cAX8cRlTqUg2ilY4UYLxNsH3cyaJi//tOzpk7EEwo2W1vYT/ZqiHTUvDBeRSu4Or9YZ7TwF/klbSnZJqaC2X0du00QcaoGAvFPY+A9HXZ3QII7k4g0M+aI3huiDUQX24O3p9h4J4dKJpktq1FH0G271uf5m3DMQlAQHTJWP07r3rL/23hAALMtIjE4SvUANd+WBxAeAlgSQamWk2YKQv/TxnNlr6tZMKOz/L1xsXJdn4eATWO786wH5IlxHKwgIQnmEYPSZX3AYsGtIsYuQhttbjmqYiecNdywXy6/WpZwhUHWW2aKuvkczJ8kX5Mcq+viVQRWRJNsCwqwzeXMLEX5tpNGOlQAyRJ/lyGUYJKmEXyqWXIxJstbJG09OR/G9V53ZhNa1hEaaVGv1FwZ9WdH1xHhGyJySz9JtrmKQ0="
+ )
+ );
+ DOT_SKINS.add(
+ new Skin(
+ "eyJ0aW1lc3RhbXAiOjE0NTI0MTg0MjUyNTQsInByb2ZpbGVJZCI6ImU4MjYwM2RmNDE3ZDRhOTViZDFmMTcyMDY0OGJlMGI0IiwicHJvZmlsZU5hbWUiOiJQYWJsZXRlMTIzNCIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9jMWViNWQ1MzExZjI1YjQ5MmEyMTIyYWM0YTNkYWUzZjNiMmRmNTc1NmFjYWM4ZjVjYjk2NWEyYjhjMGY4In19fQ==",
+ "LHeNKZWS3u7hmMmxqjEiCLAlhHRR4ZzQDZkCwJNid0odX38Qm98teyCwg4VmYKUrovIpqX3xReYiZ2LIY2SQDz6nARj6qarHQHDMgZ6Itqfd8jue5ZlzbwRwv9Fmirxdq67yA/VAMmy7Hel60X39PF/qVlVmA1k9nFz2NDmMlASA61nI2oEjfvdwRgODAG0rSkocIqxpZ8y/hUAsUsP2NPISIRl+yY+QLpzkx56+iTvLvYsYbhFMMJyjshjgL6j/TH9XRyjfqxfthTiKrH7zYSbxIb1nQC+Osrzg2EN9M2BPfyvF/MiFsQGu8It9CXSSR6ZFqTnDmhteFySiOrC8WF6F6rZL+vMYLSgke4vixLFLLdgdb1NBBMy8wGfEJFfLGs0n7UcnHERLg8ZTzz3yov6vKVd5dqv8uClQGHbv4iHVpvvepZ8BUuPH4PQgxqhs1akQ/q9B0RVXucigEcQMWfBAftGEDUI9PL17jjjsNbLYnX7yjSV3AWi3PPFVs7JWXrG+9KQPYHO1OuoA0ld3gA50+nSRXqcpDrvxRqo88MlqAv54Wc/I/lYOfpzx9BCgQsMz7n6wq22BsGLhNdbB+Usw/GB8s50KDZ91Zigc2REljgyoabzNBMHa/ACaPiBuFZ8ApBd84no+ipnpVJXnNcFxSH44AShuIcZaCdBlwbw="
+ )
+ );
+
+ }
+
+
+ public static Skin getDot(ChatColor color) {
+ return (DOT_SKINS.get(color.ordinal()));
+ }
+
+ public static Skin getSkin(UUID uniqueId) {
+ if (CACHE.containsKey(uniqueId)) return CACHE.get(uniqueId);
+
+ try {
+ URL url = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + uniqueId.toString().replace("-", "") + "?unsigned=false");
+ JsonObject json = new JsonParser().parse(new InputStreamReader(url.openStream())).getAsJsonObject().get("properties").getAsJsonArray().get(0).getAsJsonObject();
+
+ return CACHE.put(uniqueId, new Skin(json.get("value").getAsString(), json.get("signature").getAsString()));
+ } catch (IOException ignored) {
+ // ignored
+ }
+
+ return STEVE;
+ }
+
+ public static Skin getSkin(Player player) {
+ return Tab.getInstance().getImplementation().getSkin(player);
+ }
+
+}
diff --git a/src/main/java/dev/aapy/tablist/utils/CC.java b/src/main/java/dev/aapy/tablist/utils/CC.java
new file mode 100644
index 0000000..8e42376
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/utils/CC.java
@@ -0,0 +1,67 @@
+package dev.aapy.tablist.utils;
+
+import org.bukkit.ChatColor;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class CC {
+
+ public static Enchantment FAKE_GLOW;
+
+ public static String translate(String message) {
+ return ChatColor.translateAlternateColorCodes('&', message);
+ }
+
+ public static List translate(List s) {
+ return s.stream().map(CC::translate).collect(Collectors.toList());
+ }
+
+ public static ItemStack nameItem(ItemStack item, String name, short durability, int amount, List lores) {
+ ItemMeta meta = item.getItemMeta();
+ meta.setDisplayName(CC.translate(name));
+ meta.setLore(CC.translate(lores));
+ item.setItemMeta(meta);
+ item.setAmount(amount);
+ item.setDurability(durability);
+ return item;
+ }
+
+ public static ItemStack nameItem(Material item, String name, short durability, int amount, List lores) {
+ return nameItem(new ItemStack(item), name, durability, amount, lores);
+
+ }
+
+ public static ItemStack enumItem(ItemStack item, short durability) {
+ item.setDurability(durability);
+ return item;
+ }
+
+ public static ItemStack enumItem(Material item, short durability) {
+ return enumItem(new ItemStack(item), durability);
+
+ }
+
+ public static void registerFakeEnchantmentGlow() {
+ try {
+ Field f = Enchantment.class.getDeclaredField("acceptingNew");
+ f.setAccessible(true);
+ f.set(null, true);
+
+ Enchantment.registerEnchantment(FAKE_GLOW);
+ } catch (IllegalArgumentException e1) {
+ FAKE_GLOW = Enchantment.getById(70);
+ } catch (Exception e2) {
+ e2.printStackTrace();
+ }
+ }
+
+ static {
+ FAKE_GLOW = new FakeGlow(70);
+ }
+}
diff --git a/src/main/java/dev/aapy/tablist/utils/FakeGlow.java b/src/main/java/dev/aapy/tablist/utils/FakeGlow.java
new file mode 100644
index 0000000..16bf1ee
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/utils/FakeGlow.java
@@ -0,0 +1,43 @@
+package dev.aapy.tablist.utils;
+
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.enchantments.EnchantmentTarget;
+import org.bukkit.enchantments.EnchantmentWrapper;
+import org.bukkit.inventory.ItemStack;
+
+public class FakeGlow extends EnchantmentWrapper {
+
+ public FakeGlow(int id) {
+ super(id);
+ }
+
+ @Override
+ public boolean canEnchantItem(ItemStack item) {
+ return true;
+ }
+
+ @Override
+ public boolean conflictsWith(Enchantment item) {
+ return false;
+ }
+
+ @Override
+ public EnchantmentTarget getItemTarget() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return "FakeGlow";
+ }
+
+ @Override
+ public int getStartLevel() {
+ return 1;
+ }
+
+ @Override
+ public int getMaxLevel() {
+ return 10;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/tablist/utils/LegacyClient.java b/src/main/java/dev/aapy/tablist/utils/LegacyClient.java
new file mode 100644
index 0000000..d09f112
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/utils/LegacyClient.java
@@ -0,0 +1,34 @@
+package dev.aapy.tablist.utils;
+
+import org.bukkit.ChatColor;
+
+import java.util.ArrayList;
+
+public class LegacyClient {
+
+ public static ArrayList ENTRY = getTabEntrys();
+ public static ArrayList NAMES = getTeamNames();
+
+ private static ArrayList getTabEntrys() {
+ ArrayList list = new ArrayList<>();
+ for (int i = 1; i <= 15; i++) {
+ String entry = ChatColor.values()[i].toString();
+ list.add(ChatColor.RED + entry);
+ list.add(ChatColor.GREEN + entry);
+ list.add(ChatColor.DARK_RED + entry);
+ list.add(ChatColor.DARK_GREEN + entry);
+ list.add(ChatColor.BLUE + entry);
+ list.add(ChatColor.DARK_BLUE + entry);
+ }
+ return list;
+ }
+
+ private static ArrayList getTeamNames() {
+ ArrayList list = new ArrayList<>();
+ for (int i = 0; i < 80; i++) {
+ String s = (i < 10 ? "\\u00010" : "\\u0001") + i;
+ list.add(s);
+ }
+ return list;
+ }
+}
diff --git a/src/main/java/dev/aapy/tablist/utils/Reflection.java b/src/main/java/dev/aapy/tablist/utils/Reflection.java
new file mode 100644
index 0000000..b3d7041
--- /dev/null
+++ b/src/main/java/dev/aapy/tablist/utils/Reflection.java
@@ -0,0 +1,14 @@
+package dev.aapy.tablist.utils;
+
+
+import java.lang.reflect.Field;
+
+public class Reflection {
+
+ public static Field setAccessibleAndGet(Class> clazz, String fieldName) throws NoSuchFieldException {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+
+ return field;
+ }
+}
diff --git a/src/main/java/dev/aapy/util/ArmorCreator.java b/src/main/java/dev/aapy/util/ArmorCreator.java
new file mode 100644
index 0000000..d9f7296
--- /dev/null
+++ b/src/main/java/dev/aapy/util/ArmorCreator.java
@@ -0,0 +1,204 @@
+package dev.aapy.util;
+
+import com.google.common.collect.Lists;
+import lombok.AllArgsConstructor;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Color;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.meta.LeatherArmorMeta;
+import org.bukkit.inventory.meta.PotionMeta;
+import org.bukkit.inventory.meta.SkullMeta;
+import org.bukkit.material.MaterialData;
+import org.bukkit.potion.PotionEffect;
+
+import java.util.List;
+
+/**
+ * @author 7qv_ on 9/2/2022.
+ * @project SnakeHub
+ */
+@AllArgsConstructor
+public class ArmorCreator {
+
+ private ItemStack itemStack;
+
+ public ArmorCreator(Material material) {
+ this(material, 1);
+ }
+
+ public ArmorCreator(Material material, int amount) {
+ this(material, amount, (short) 0);
+ }
+
+ public ArmorCreator(Material material, int amount, short damage) {
+ this(new ItemStack(material, amount, damage));
+ }
+
+ public ArmorCreator setColor(Color color) {
+ LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) itemStack.getItemMeta();
+ leatherArmorMeta.setColor(color);
+ itemStack.setItemMeta(leatherArmorMeta);
+ return this;
+ }
+
+ public ArmorCreator setType(Material material) {
+ itemStack.setType(material);
+ return this;
+ }
+
+ public ArmorCreator setAmount(int amount) {
+ itemStack.setAmount(amount);
+ return this;
+ }
+
+ public ArmorCreator setDurability(int durability) {
+ itemStack.setDurability((short) durability);
+ return this;
+ }
+
+ public ArmorCreator setData(int data) {
+ itemStack.setData(new MaterialData(data));
+ return this;
+ }
+
+ public ArmorCreator addEnchantment(Enchantment enchantment) {
+ addEnchantment(enchantment, 1);
+ return this;
+ }
+
+ public ArmorCreator addEnchantment(Enchantment enchantment, int level) {
+ itemStack.addUnsafeEnchantment(enchantment, level);
+ return this;
+ }
+
+ public ArmorCreator removeEnchantment(Enchantment enchantment) {
+ itemStack.removeEnchantment(enchantment);
+ return this;
+ }
+
+ public ArmorCreator clearEnchantments() {
+ for (Enchantment enchantment : itemStack.getEnchantments().keySet())
+ itemStack.removeEnchantment(enchantment);
+
+ return this;
+ }
+
+ public ArmorCreator setDisplayName(String name) {
+ ItemMeta itemMeta = itemStack.getItemMeta();
+ itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', name));
+ itemStack.setItemMeta(itemMeta);
+ return this;
+ }
+
+ public ArmorCreator addLore(String lore) {
+ ItemMeta itemMeta = itemStack.getItemMeta();
+
+ List lores = itemMeta.getLore();
+ if (lores == null)
+ lores = Lists.newArrayList();
+
+ lores.add(CC.translate(lore));
+
+ itemMeta.setLore(lores);
+
+ itemStack.setItemMeta(itemMeta);
+ return this;
+ }
+
+ public ArmorCreator setLore(String... lores) {
+ clearLore();
+
+ for (String lore : lores)
+ addLore(lore);
+
+ return this;
+ }
+
+ public ArmorCreator setLore(List lore) {
+ clearLore();
+
+ ItemMeta itemMeta = itemStack.getItemMeta();
+ itemMeta.setLore(CC.translate(lore));
+ itemStack.setItemMeta(itemMeta);
+
+ return this;
+ }
+
+ public ArmorCreator clearLore() {
+ ItemMeta itemMeta = itemStack.getItemMeta();
+ itemMeta.setLore(Lists.newArrayList());
+ itemStack.setItemMeta(itemMeta);
+ return this;
+ }
+
+ public ArmorCreator setPotionEffect(PotionEffect effect) {
+ PotionMeta potionMeta = (PotionMeta) itemStack.getItemMeta();
+ potionMeta.setMainEffect(effect.getType());
+ potionMeta.addCustomEffect(effect, false);
+ itemStack.setItemMeta(potionMeta);
+ return this;
+ }
+
+ public ItemStack build() {
+ ItemMeta itemMeta = itemStack.getItemMeta();
+ final ItemStack clone = this.itemStack.clone();
+ clone.setItemMeta(itemMeta.clone());
+ return clone;
+ }
+
+ public ArmorCreator setPotionEffects(PotionEffect... effects) {
+ PotionMeta potionMeta = (PotionMeta) itemStack.getItemMeta();
+ potionMeta.setMainEffect(effects[0].getType());
+
+ for (PotionEffect effect : effects)
+ potionMeta.addCustomEffect(effect, false);
+
+ itemStack.setItemMeta(potionMeta);
+ return this;
+ }
+
+ public static Inventory createInventory(String title, int rows) {
+ Inventory inv = Bukkit.getServer().createInventory(null, rows * 9, CC.translate(title));
+ return inv;
+ }
+
+ public static ItemStack createItemStack(String name, List lore, Material material, int amount, int data) {
+ ItemStack item = new ItemStack(material, amount, (short) data);
+ ItemMeta itemmeta = item.getItemMeta();
+ itemmeta.setDisplayName(CC.translate(name));
+ itemmeta.setLore(CC.translateFromArray(lore));
+ item.setItemMeta(itemmeta);
+ return item;
+ }
+
+ public static ItemStack createItemStackWithoutLore(String name, Material material, int amount, int data) {
+ ItemStack item = new ItemStack(material, amount, (short) data);
+ ItemMeta itemmeta = item.getItemMeta();
+ itemmeta.setDisplayName(CC.translate(name));
+ item.setItemMeta(itemmeta);
+ return item;
+ }
+
+ public ArmorCreator setSkullOwner(String owner) {
+ SkullMeta skullMeta = (SkullMeta) itemStack.getItemMeta();
+ skullMeta.setOwner(owner);
+
+ itemStack.setItemMeta(skullMeta);
+ return this;
+ }
+
+ public ArmorCreator setName(final String displayName) {
+ ItemMeta itemMeta = itemStack.getItemMeta();
+ itemMeta.setDisplayName(displayName);
+ return this;
+ }
+
+ public ItemStack create() {
+ return itemStack;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/util/CC.java b/src/main/java/dev/aapy/util/CC.java
new file mode 100644
index 0000000..123e422
--- /dev/null
+++ b/src/main/java/dev/aapy/util/CC.java
@@ -0,0 +1,119 @@
+package dev.aapy.util;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author 7qv_ on 7/2/2022.
+ * @project SnakeHub
+ */
+public class CC {
+
+ public static final String BLUE = ChatColor.BLUE.toString();
+ public static final String AQUA = ChatColor.RED.toString();
+ public static final String YELLOW = ChatColor.GRAY.toString();
+ public static final String RED = ChatColor.RED.toString();
+ public static final String GRAY = ChatColor.GRAY.toString();
+ public static final String GOLD = ChatColor.RED.toString();
+ public static final String GREEN = ChatColor.GREEN.toString();
+ public static final String WHITE = ChatColor.WHITE.toString();
+ public static final String BLACK = ChatColor.BLACK.toString();
+ public static final String BOLD = ChatColor.BOLD.toString();
+ public static final String ITALIC = ChatColor.ITALIC.toString();
+ public static final String UNDER_LINE = ChatColor.UNDERLINE.toString();
+ public static final String STRIKE_THROUGH = ChatColor.STRIKETHROUGH.toString();
+ public static final String RESET = ChatColor.RESET.toString();
+ public static final String MAGIC = ChatColor.MAGIC.toString();
+ public static final String DARK_BLUE = ChatColor.DARK_BLUE.toString();
+ public static final String DARK_AQUA = ChatColor.DARK_AQUA.toString();
+ public static final String DARK_GRAY = ChatColor.DARK_GRAY.toString();
+ public static final String DARK_GREEN = ChatColor.DARK_GREEN.toString();
+ public static final String DARK_PURPLE = ChatColor.DARK_PURPLE.toString();
+ public static final String DARK_RED = ChatColor.DARK_RED.toString();
+ public static final String PINK = ChatColor.LIGHT_PURPLE.toString();
+
+
+ public static List translateFromArray(List text) {
+ List messages = new ArrayList();
+ for (String string : text) {
+ messages.add(translateFromString(string));
+ }
+ return messages;
+ }
+
+ public static String translateFromString(String text) {
+ return StringEscapeUtils.unescapeJava(ChatColor.translateAlternateColorCodes('&', text));
+ }
+
+ /**
+ * The constant MENU_BAR.
+ */
+ public static final String MENU_BAR = ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH.toString() + "------------------------";
+ /**
+ * The constant CHAT_BAR.
+ */
+ public static final String CHAT_BAR = ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH.toString() + "------------------------------------------------";
+ /**
+ * The constant SB_BAR.
+ */
+ public static final String SB_BAR = ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH.toString() + "----------------------";
+
+ /**
+ * Translate string.
+ *
+ * @param in the in
+ * @return the string
+ */
+ public static String translate(String in) {
+ return ChatColor.translateAlternateColorCodes('&', in);
+ }
+
+ public static void log(String in) {
+ Bukkit.getConsoleSender().sendMessage(translate(in));
+ }
+
+ /**
+ * Translate list.
+ *
+ * @param lines the lines
+ * @return the list
+ */
+ public static List translate(List lines) {
+ List toReturn = new ArrayList<>();
+
+ for (String line : lines) {
+ toReturn.add(ChatColor.translateAlternateColorCodes('&', line));
+ }
+
+ return toReturn;
+ }
+
+ /**
+ * Translate list.
+ *
+ * @param lines the lines
+ * @return the list
+ */
+ public static List translate(String[] lines) {
+ List toReturn = new ArrayList<>();
+
+ for (String line : lines) {
+ if (line != null) {
+ toReturn.add(ChatColor.translateAlternateColorCodes('&', line));
+ }
+ }
+
+ return toReturn;
+ }
+ public static boolean isInteger(String value) {
+ try {
+ Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/util/ItemCreator.java b/src/main/java/dev/aapy/util/ItemCreator.java
new file mode 100644
index 0000000..d1b8c83
--- /dev/null
+++ b/src/main/java/dev/aapy/util/ItemCreator.java
@@ -0,0 +1,94 @@
+package dev.aapy.util;
+
+import org.bukkit.Color;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.meta.LeatherArmorMeta;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * @author 7qv_ on 18/2/2022.
+ * @project SnakeHub
+ */
+public class ItemCreator {
+ private Material material;
+ private Short durability;
+ private String title;
+ private int amount = 1;
+ private List lores;
+ @SuppressWarnings("unused")
+ private byte materialData;
+ private HashMap enchantments = new HashMap<>();
+ private ItemStack itemStack;
+
+ public ItemCreator() {
+ this.itemStack = new ItemStack(Material.AIR);
+ }
+
+ public ItemCreator(Material material) {
+ this.itemStack = new ItemStack(material);
+ }
+
+ public ItemCreator(ItemStack itemStack) {
+ this.itemStack = itemStack;
+ }
+
+ public ItemCreator material(Material material){
+ this.material = material;
+ return this;
+ }
+
+ public ItemCreator durability(short durability){
+ this.durability = durability;
+ return this;
+ }
+
+ public ItemCreator title(String title){
+ this.title = title;
+ return this;
+ }
+
+ public ItemCreator amount(int amount){
+ this.amount = amount;
+ return this;
+ }
+
+ public ItemCreator lores(List lores){
+ this.lores = lores;
+ return this;
+ }
+ public ItemStack build(){
+ ItemStack itemStack = this.itemStack;
+ if (this.material != null) {
+ itemStack.setType(this.material);
+ }
+ //TODO Enchantments
+ for (Enchantment enchantment : enchantments.keySet()) {
+ itemStack.addUnsafeEnchantment(enchantment, enchantments.get(enchantment));
+ }
+ ItemMeta meta = itemStack.getItemMeta();
+ if (this.amount > 0)
+ itemStack.setAmount(this.amount);
+ if (this.durability != null)
+ itemStack.setDurability(this.durability);
+ if (this.title != null)
+ meta.setDisplayName(CC.translate("&r" + this.title));
+ if (this.lores != null && this.lores.size() > 0)
+ meta.setLore(CC.translate(this.lores));
+ itemStack.setItemMeta(meta);
+ return itemStack;
+ }
+ public ItemCreator color(Color color) {
+ ItemMeta meta = this.itemStack.getItemMeta();
+ if (!(meta instanceof LeatherArmorMeta)) {
+ throw new UnsupportedOperationException("Cannot set color of a non-leather armor item.");
+ }
+ ((LeatherArmorMeta)meta).setColor(color);
+ this.itemStack.setItemMeta(meta);
+ return this;
+ }
+}
diff --git a/src/main/java/dev/aapy/util/ScoreFooterTask.java b/src/main/java/dev/aapy/util/ScoreFooterTask.java
new file mode 100644
index 0000000..b3a19a5
--- /dev/null
+++ b/src/main/java/dev/aapy/util/ScoreFooterTask.java
@@ -0,0 +1,52 @@
+package dev.aapy.util;
+
+import dev.aapy.file.Scoreboard;
+import org.bukkit.Bukkit;
+import org.bukkit.scheduler.BukkitRunnable;
+
+/**
+ * @author 7qv_ on 11/2/2022.
+ * @project SnakeHub
+ */
+public class ScoreFooterTask extends BukkitRunnable {
+
+ public static String footer = "";
+
+ private int left;
+
+ public ScoreFooterTask() {
+ this.left = 3;
+ }
+
+ @Deprecated
+ public void run() {
+ --this.left;
+ if (this.left < 0) {
+ this.left = 3;
+ this.sendFooter();
+ }
+ if (Bukkit.getOnlinePlayers().size() < 0) {
+ this.cancel();
+ }
+
+ }
+
+ public String sendFooter() {
+ String message = footer;
+ if (this.left <= 3) {
+ if (this.left < 4) {
+ message = Scoreboard.getConfig().getString("SCOREBOARD.ANIMATED.FOOTER.LINES.1");
+ }
+ if (this.left < 3) {
+ message = Scoreboard.getConfig().getString("SCOREBOARD.ANIMATED.FOOTER.LINES.2");
+ }
+ if (this.left < 2) {
+ message = Scoreboard.getConfig().getString("SCOREBOARD.ANIMATED.FOOTER.LINES.3");
+ }
+ if (this.left < 1) {
+ message = Scoreboard.getConfig().getString("SCOREBOARD.ANIMATED.FOOTER.LINES.4");
+ }
+ }
+ return message;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/aapy/util/ScoreTitleTask.java b/src/main/java/dev/aapy/util/ScoreTitleTask.java
new file mode 100644
index 0000000..e217c67
--- /dev/null
+++ b/src/main/java/dev/aapy/util/ScoreTitleTask.java
@@ -0,0 +1,61 @@
+package dev.aapy.util;
+
+import dev.aapy.file.Scoreboard;
+import org.bukkit.Bukkit;
+import org.bukkit.scheduler.BukkitRunnable;
+
+/**
+ * @author 7qv_ on 16/2/2022.
+ * @project SnakeHub
+ */
+public class ScoreTitleTask extends BukkitRunnable {
+
+ public static String title = "";
+
+ private int left;
+
+ public ScoreTitleTask() {
+ this.left = 8;
+ }
+
+ @Deprecated
+ public void run() {
+ --this.left;
+ if (this.left < 0) {
+ this.left = 8;
+ this.sendTitle();
+ }
+ if (Bukkit.getOnlinePlayers().size() < 0) {
+ this.cancel();
+ }
+
+ }
+
+ public String sendTitle() {
+ String message = title;
+ if (this.left <= 8) {
+ if (this.left < 7) {
+ message = Scoreboard.getConfig().getString("SCOREBOARD.ANIMATED.TITLE.LINES.1");
+ }
+ if (this.left < 6) {
+ message = Scoreboard.getConfig().getString("SCOREBOARD.ANIMATED.TITLE.LINES.2");
+ }
+ if (this.left < 5) {
+ message = Scoreboard.getConfig().getString("SCOREBOARD.ANIMATED.TITLE.LINES.3");
+ }
+ if (this.left < 4) {
+ message = Scoreboard.getConfig().getString("SCOREBOARD.ANIMATED.TITLE.LINES.4");
+ }
+ if (this.left < 3) {
+ message = Scoreboard.getConfig().getString("SCOREBOARD.ANIMATED.TITLE.LINES.5");
+ }
+ if (this.left < 2) {
+ message = Scoreboard.getConfig().getString("SCOREBOARD.ANIMATED.TITLE.LINES.6");
+ }
+ if (this.left < 1) {
+ message = Scoreboard.getConfig().getString("SCOREBOARD.ANIMATED.TITLE.LINES.7");
+ }
+ }
+ return message;
+ }
+}
diff --git a/src/main/java/dev/aapy/util/SnakeUtil.java b/src/main/java/dev/aapy/util/SnakeUtil.java
new file mode 100644
index 0000000..6465c84
--- /dev/null
+++ b/src/main/java/dev/aapy/util/SnakeUtil.java
@@ -0,0 +1,18 @@
+package dev.aapy.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author 7qv_ on 14/3/2022.
+ * @project SnakeHub
+ */
+public class SnakeUtil {
+ public static String getDate() {
+ return (new SimpleDateFormat("dd/MM/yyyy")).format(new Date());
+ }
+
+ public static String getHour() {
+ return (new SimpleDateFormat("HH:mm")).format(new Date());
+ }
+}
diff --git a/src/main/java/dev/aapy/util/bungee/BungeeChannel.java b/src/main/java/dev/aapy/util/bungee/BungeeChannel.java
new file mode 100644
index 0000000..24b5ede
--- /dev/null
+++ b/src/main/java/dev/aapy/util/bungee/BungeeChannel.java
@@ -0,0 +1,21 @@
+package dev.aapy.util.bungee;
+
+import com.google.common.io.ByteArrayDataOutput;
+import com.google.common.io.ByteStreams;
+import dev.aapy.SnakeHub;
+import org.bukkit.entity.Player;
+
+/**
+ * @author 7qv_ on 16/2/2022.
+ * @project SnakeHub
+ */
+public class BungeeChannel {
+
+ public static void sendToServer(final Player player, final String server) {
+ final ByteArrayDataOutput out = ByteStreams.newDataOutput();
+ out.writeUTF("Connect");
+ out.writeUTF(server);
+ player.sendPluginMessage(SnakeHub.getInst(), "BungeeCord", out.toByteArray());
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
new file mode 100644
index 0000000..386473d
--- /dev/null
+++ b/src/main/resources/config.yml
@@ -0,0 +1,147 @@
+# ____ _ _ _ _ #
+# / ___| _ __ __ _| | _____| | | |_ _| |__ #
+# \___ \| "_ \ / _` | |/ / _ \ |_| | | | | "_ \ #
+# ___) | | | | (_| | < __/ _ | |_| | |_) |#
+# |____/|_| |_|\__,_|_|\_\___|_| |_|\__,_|_.__/ #
+#################################################
+
+# BOOLEANS CONFIG
+
+BOOLEANS:
+ JOIN-MESSAGE: false
+ QUIT-MESSAGE: false
+ TABLIST: false
+ LUNAR-CLIENT:
+ NAMETAG: false
+ SCOREBOARD:
+ ANIMATED:
+ FOOTER: true
+ TITLE: false
+
+CHAT-FORMAT:
+ - "{prefix}{player}&7: &f{message}"
+
+LAUNCH-PAD:
+ MATERIAL: GOLD_PLATE
+ SOUND: EXPLODE
+
+SOCIAL:
+ DISCORD: discord.gg/InfernalMC
+ STORE: store.infernalmc.cc
+ TEAMSPEAK: ts.infernalmc.cc
+ TWITTER: twitter.com/InfernalMC_
+ WEBSITE: www.infernalmc.cc
+
+SELECTOR:
+ ENABLED: true
+ MATERIAL: WATCH
+ ENCHANTED: false
+ SOUND_ENABLED: false
+ SOUND: CHEST_OPEN
+ GLASS_PANEL:
+ ENABLED: false
+ ID: 14
+ DISPLAYNAME: "&4\u2726 &4Server Selector &4\u2726"
+ TITLE: "&8Select A Server"
+ SLOT: 4
+ LORE: "&7Right-click to open the hub menu!"
+ SERVERS:
+ "1":
+ DISPLAYNAME: "&e&lDEV &4Kits"
+ MATERIAL: GOLDEN_APPLE
+ ENCHANTED: false
+ SLOT: 11
+ MESSAGE: "&aSent you to the server Kitmap!"
+ BUNGEE:
+ ENABLED: false
+ SERVER: KITMAP
+ EZQUEUE:
+ ENABLED: true
+ QUEUE: PRACTICE
+ LORE:
+ - "&7Battle other users in a shot-"
+ - "&7paced environment. Build your"
+ - "&7base and practice classes."
+ - ""
+ - "&6Players: &f%bungee_kitmap%"
+ - "&6Status: &f%aqua_server_status_Kits%"
+ - ""
+ - "&7&oClick to join the queue."
+ "2":
+ DISPLAYNAME: "&4HCF"
+ MATERIAL: DIAMOND_PICKAXE
+ ENCHANTED: false
+ SLOT: 15
+ MESSAGE: "&aSent you to the server HCF!"
+ BUNGEE:
+ ENABLED: false
+ SERVER: HCF
+ EZQUEUE:
+ ENABLED: true
+ QUEUE: Leagues
+ LORE:
+ - "&7Create your team and grind"
+ - "&7to become the most powerful"
+ - "&7faction on the server."
+ - ""
+ - "&6Map Kit: &fUndefined"
+ - "&6Faction Size: &fUndefined"
+ - ""
+ - "&6Players: &f%bungee_Leagues%"
+ - "&6Status: &f%aqua_server_status_Leagues%"
+ - ""
+ - "&7&oClick to join the queue."
+ "3":
+ DISPLAYNAME: "&4???"
+ MATERIAL: REDSTONE_BLOCK
+ ENCHANTED: false
+ SLOT: 13
+ MESSAGE: "&C???"
+ BUNGEE:
+ ENABLED: false
+ SERVER: PRACTICE
+ EZQUEUE:
+ ENABLED: true
+ QUEUE: PRACTICE
+ LORE:
+ - "&C???"
+PVP:
+ ENABLED: false
+ MATERIAL: DIAMOND_SWORD
+ ENCHANTED: true
+ SOUND: CHEST_OPEN
+ DISPLAYNAME: "&4\u2726 &4PvP Mode &4\u2726"
+ SLOT: 6
+ LORE: "&7Right-click to join to PvP Mode!"
+
+COSMETIC:
+ ENABLED: false
+ MATERIAL: EMERALD
+ ENCHANTED: false
+ GLASS_PANEL:
+ ENABLED: true
+ ID: 3
+ DISPLAYNAME: "&4\u2726 &4Cosmetics &4\u2726"
+ SLOT: 6
+ LORE: "&7Right-click to open the cosmetics menu!"
+
+ENDERBUTT:
+ ENABLED: true
+ MATERIAL: ENDER_PEARL
+ ENCHANTED: false
+ SOUND: PORTAL
+ DISPLAYNAME: "&4\u2726 &4EnderButt &4\u2726"
+ SLOT: 2
+ LORE: "&7Right-Click For Fly"
+
+INVISIBILITY:
+ ENABLED: true
+ ITEM:
+ SHOW-PLAYER:
+ NAME: "&4\u2726 &aShow Players &4\u2726"
+ MATERIAL: BLAZE_ROD
+ SLOT: 6
+ HIDE-PLAYER:
+ NAME: "&4\u2726 &7Hide Players &4\u2726"
+ MATERIAL: CLAY_BALL
+ SLOT: 6
\ No newline at end of file
diff --git a/src/main/resources/lang.yml b/src/main/resources/lang.yml
new file mode 100644
index 0000000..579f704
--- /dev/null
+++ b/src/main/resources/lang.yml
@@ -0,0 +1,46 @@
+# GENERAL LANG CONFIG
+
+JOIN:
+ MESSAGE:
+ - "&7&m-----*----------------------------------*-----"
+ - "&fBienvenido &c&l{ign} &fHubCore creada por &c&l7qv_"
+ - ""
+ - " &7\u25CF &fTu rango actual es: {rank}"
+ - " &7\u25CF &c&lStore: &f{store}"
+ - " &7\u25CF &c&lTeamspeak: &f{team-speak}"
+ - " &7\u25CF &c&lTwitter: &f{twitter}"
+ - " &7\u25CF &c&lDiscord: &f{discord}"
+ - " &7\u25CF &c&lWebsite: &f{web-site}"
+ - "&7&m-----*---------------------------------*-----"
+
+TITLE: #ONLY FOR LUNAR CLIENT API COMPATIBILITY WITH PLACEHOLDERAPI
+ ENABLED: true
+ JOIN:
+ TITLE:
+ MESSAGE: "&c&lInfernalMC Network"
+ SUBTITLE:
+ MESSAGE: "&fThanks For Playing"
+
+QUIT:
+ MESSAGE:
+ - "&7&m-----*----------------------------------*-----"
+ - ""
+ - "{rank} &c&l{ign} &fse desconecto"
+ - ""
+ - "&7&m-----*---------------------------------*-----"
+
+
+HIDE-PLAYER: "&cPlayer visibility has been &cdisable&c."
+SHOW-PLAYER: "&cPlayer visibility has been &aenable&c."
+
+SOCIAL:
+ DISCORD:
+ - "&cDiscord&7: &f{discord}"
+ STORE:
+ - "&cStore&7: &f{store}"
+ TEAMSPEAK:
+ - "&cTeamSpeak&7: &f{team-speak}"
+ TWITTER:
+ - "&cTwitter&7: &f{twitter}"
+ WEBSITE:
+ - "&cWebSite&7: &f{website}"
\ No newline at end of file
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..7b00511
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,4 @@
+name: SnakeHub
+version: 1.2.0-HOTFIX
+main: dev.aapy.SnakeHub
+authors: [Aapy]
\ No newline at end of file
diff --git a/src/main/resources/scoreboard.yml b/src/main/resources/scoreboard.yml
new file mode 100644
index 0000000..18882e1
--- /dev/null
+++ b/src/main/resources/scoreboard.yml
@@ -0,0 +1,29 @@
+SCOREBOARD:
+ TITLE: "&c&lInfernalMC &f\u2503 &7Hub"
+ FOOTER: "&7ts.infernalmc.cc"
+ LINES:
+ - "&7&m--------------------"
+ - "&8{placeholder:date} &7&o{placeholder:time}"
+ - " "
+ - "&cOnline&7: {players_online}"
+ - ""
+ - "&cRank&7: {rank}"
+ - " "
+ - "{footers}"
+ - "&7&m--------------------"
+ ANIMATED:
+ FOOTER:
+ LINES:
+ 1: "&7discord.gg/InfernalMC"
+ 2: "&7twitter.com/InfernalMC_"
+ 3: "&7ts.infernalmc.cc"
+ 4: "&7store.infernalmc.cc"
+ TITLE:
+ LINES:
+ 1: "&cI"
+ 2: "&cIn"
+ 3: "&cInf"
+ 4: "&cInfe"
+ 5: "&cInfer"
+ 6: "&cInferna"
+ 7: "&cInfernalMC"
\ No newline at end of file
diff --git a/src/main/resources/tab.yml b/src/main/resources/tab.yml
new file mode 100644
index 0000000..199bbd4
--- /dev/null
+++ b/src/main/resources/tab.yml
@@ -0,0 +1,254 @@
+TAB:
+ ENABLED: true
+ HEADER:
+ - "&c&lInfernalMC &lNetwork"
+
+ FOOTER:
+ - "&fYou are playing &cHub-01 &fon &cinfernalmc.cc"
+
+ LEFT:
+ 1:
+ TEXT: ""
+ SKIN: ""
+ 2:
+ TEXT: ""
+ SKIN: ""
+ 3:
+ TEXT: ""
+ SKIN: ""
+ 4:
+ TEXT: "&c&lStore"
+ SKIN: "{store}"
+ 5:
+ TEXT: "&fstore.infernalmc.cc"
+ SKIN: ""
+ 6:
+ TEXT: ""
+ SKIN: ""
+ 7:
+ TEXT: ""
+ SKIN: ""
+ 8:
+ TEXT: ""
+ SKIN: ""
+ 9:
+ TEXT: "&cKitmap&f: %pinger_players_localhost:25561%"
+ SKIN: "{enderchest}"
+ 10:
+ TEXT: "&fStatus: %pinger_isonline_localhost:25561%"
+ SKIN: ""
+ 11:
+ TEXT: "&eUnder Maintenance"
+ SKIN: ""
+ 12:
+ TEXT: ""
+ SKIN: ""
+ 13:
+ TEXT: ""
+ SKIN: ""
+ 14:
+ TEXT: ""
+ SKIN: ""
+ 15:
+ TEXT: ""
+ SKIN: ""
+ 16:
+ TEXT: ""
+ SKIN: ""
+ 17:
+ TEXT: ""
+ SKIN: ""
+ 18:
+ TEXT: ""
+ SKIN: ""
+ 19:
+ TEXT: ""
+ SKIN: ""
+ 20:
+ TEXT: ""
+ SKIN: ""
+ CENTER:
+ 1:
+ TEXT: "&c&lInfernalMC"
+ SKIN: "{planet}"
+ 2:
+ TEXT: "&cOnline&f: {players_online}/{players_max_online}"
+ SKIN: ""
+ 3:
+ TEXT: ""
+ SKIN: ""
+ 4:
+ TEXT: ""
+ SKIN: ""
+ 5:
+ TEXT: ""
+ SKIN: ""
+ 6:
+ TEXT: ""
+ SKIN: ""
+ 7:
+ TEXT: "&c&lServer &lInfo"
+ SKIN: ""
+ 8:
+ TEXT: ""
+ SKIN: ""
+ 9:
+ TEXT: "&cHCF&f: %pinger_players_localhost:25567%"
+ SKIN: "{castle}"
+ 10:
+ TEXT: "&fStatus: %pinger_isonline_localhost:25567%"
+ SKIN: ""
+ 11:
+ TEXT: "&fKit: Prot I, Sharp I"
+ SKIN: ""
+ 12:
+ TEXT: ""
+ SKIN: ""
+ 13:
+ TEXT: ""
+ SKIN: ""
+ 14:
+ TEXT: ""
+ SKIN: ""
+ 15:
+ TEXT: ""
+ SKIN: ""
+ 16:
+ TEXT: ""
+ SKIN: ""
+ 17:
+ TEXT: ""
+ SKIN: ""
+ 18:
+ TEXT: ""
+ SKIN: ""
+ 19:
+ TEXT: ""
+ SKIN: ""
+ 20:
+ TEXT: ""
+ SKIN: ""
+ RIGHT:
+ 1:
+ TEXT: ""
+ SKIN: ""
+ 2:
+ TEXT: ""
+ SKIN: ""
+ 3:
+ TEXT: ""
+ SKIN: ""
+ 4:
+ TEXT: "&c&lDiscord"
+ SKIN: "{discord}"
+ 5:
+ TEXT: "discord.gg/InfernalMC"
+ SKIN: ""
+ 6:
+ TEXT: ""
+ SKIN: ""
+ 7:
+ TEXT: ""
+ SKIN: ""
+ 8:
+ TEXT: ""
+ SKIN: ""
+ 9:
+ TEXT: "&cPractice&f: %pinger_players_localhost:25527%"
+ SKIN: "{heart}"
+ 10:
+ TEXT: "&fStatus: %pinger_isonline_localhost:25562%"
+ SKIN: ""
+ 11:
+ TEXT: "&eUnder Maintenance"
+ SKIN: ""
+ 12:
+ TEXT: ""
+ SKIN: ""
+ 13:
+ TEXT: ""
+ SKIN: ""
+ 14:
+ TEXT: ""
+ SKIN: ""
+ 15:
+ TEXT: ""
+ SKIN: ""
+ 16:
+ TEXT: ""
+ SKIN: ""
+ 17:
+ TEXT: ""
+ SKIN: ""
+ 18:
+ TEXT: ""
+ SKIN: ""
+ 19:
+ TEXT: ""
+ SKIN: ""
+ 20:
+ TEXT: ""
+ SKIN: ""
+
+ # Only 1.8 #
+ farright:
+ 1:
+ TEXT: ""
+ SKIN: ""
+ 2:
+ TEXT: ""
+ SKIN: ""
+ 3:
+ TEXT: ""
+ SKIN: ""
+ 4:
+ TEXT: ""
+ SKIN: ""
+ 5:
+ TEXT: ""
+ SKIN: ""
+ 6:
+ TEXT: ""
+ SKIN: ""
+ 7:
+ TEXT: ""
+ SKIN: ""
+ 8:
+ TEXT: ""
+ SKIN: ""
+ 9:
+ TEXT: ""
+ SKIN: ""
+ 10:
+ TEXT: ""
+ SKIN: ""
+ 11:
+ TEXT: ""
+ SKIN: ""
+ 12:
+ TEXT: ""
+ SKIN: ""
+ 13:
+ TEXT: ""
+ SKIN: ""
+ 14:
+ TEXT: ""
+ SKIN: ""
+ 15:
+ TEXT: ""
+ SKIN: ""
+ 16:
+ TEXT: ""
+ SKIN: ""
+ 17:
+ TEXT: ""
+ SKIN: ""
+ 18:
+ TEXT: ""
+ SKIN: ""
+ 19:
+ TEXT: ""
+ SKIN: ""
+ 20:
+ TEXT: ""
+ SKIN: ""
\ No newline at end of file