l2 = new ArrayList<>();
+ if (sitout != null) {
+ l1.remove(sitout);
+
+ Player player = this.plugin.getServer().getPlayer(sitout);
+ player.sendMessage(Messages.TOURNAMENT_SITOUT.getMessage());
+ }
+
+ Collections.shuffle(l1);
+ for (int i = 0; i < (l1.size() / 2); i++) {
+ l2.add(l1.get(i));
+ l1.remove(l1.get(i));
+ }
+ if (l2.size() != l1.size()) {
+ end(null);
+ return;
+ }
+ for (int i = 0; i < l1.size(); i++) {
+ if (l1.get(i) != l2.get(i)) {
+ Match match = new Match(this.plugin, kit, ListUtil.newList(l1.get(i)), ListUtil.newList(l2.get(i)), false, true);
+ matchList.add(match);
+ match.start();
+
+ Player p1 = this.plugin.getServer().getPlayer(l1.get(i));
+ PracticeProfile p1p = this.plugin.getManagerHandler().getProfileManager().getProfile(p1);
+
+ p1p.setMatch(match);
+ p1p.setPlayerState(PlayerState.MATCH);
+ kit.getUnrankedMatch().add(p1.getUniqueId());
+
+ Player p2 = this.plugin.getServer().getPlayer(l2.get(i));
+ PracticeProfile p2p = this.plugin.getManagerHandler().getProfileManager().getProfile(p2);
+
+ p2p.setMatch(match);
+ p2p.setPlayerState(PlayerState.MATCH);
+ kit.getUnrankedMatch().add(p2.getUniqueId());
+ }
+ }
+ }
+
+ public void end(String winner) {
+ this.plugin.getServer().broadcastMessage(winner != null ? Messages.TOURNAMENT_WINNER.getMessage().replace("%player%", winner).replace("%kit%", kit.getName()) : Messages.TOURNAMENT_CANCELLED.getMessage().replace("%kit%", kit.getName()));
+
+ participants.forEach(u -> {
+ Player player = PracticePlugin.getInstance().getServer().getPlayer(u);
+
+ PracticeProfile practiceProfile = PracticePlugin.getInstance().getManagerHandler().getProfileManager().getProfile(player);
+ practiceProfile.setPlayerState(PlayerState.LOBBY);
+ practiceProfile.setTournament(null);
+
+ this.plugin.getManagerHandler().getPlayerManager().giveItems(player, true);
+ this.plugin.getManagerHandler().getPlayerManager().teleportSpawn(player);
+ });
+
+ this.plugin.getManagerHandler().getTournamentManager().setTournament(null);
+ }
+
+ public void broadcast(String message) {
+ participants.forEach(u -> this.plugin.getServer().getPlayer(u).sendMessage(message));
+ }
+}
diff --git a/src/main/java/me/abhi/practice/tournament/TournamentState.java b/src/main/java/me/abhi/practice/tournament/TournamentState.java
new file mode 100644
index 0000000..da14d8a
--- /dev/null
+++ b/src/main/java/me/abhi/practice/tournament/TournamentState.java
@@ -0,0 +1,6 @@
+package me.abhi.practice.tournament;
+
+public enum TournamentState {
+
+ STARTING, STARTED, WAITING
+}
diff --git a/src/main/java/me/abhi/practice/util/DurationUtil.java b/src/main/java/me/abhi/practice/util/DurationUtil.java
new file mode 100644
index 0000000..527ed0f
--- /dev/null
+++ b/src/main/java/me/abhi/practice/util/DurationUtil.java
@@ -0,0 +1,46 @@
+package me.abhi.practice.util;
+
+import java.text.DecimalFormat;
+import java.util.concurrent.TimeUnit;
+
+@SuppressWarnings("Duplicates")
+public class DurationUtil {
+
+ private static DecimalFormat decimalFormat = new DecimalFormat("00");
+
+ public static String getDuration(long startTime) {
+ int difference = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - startTime);
+
+ int h = difference / 3600;
+ int s = difference % 60;
+ int m = difference / 60 % 60;
+
+ return (startTime > 0) ? (h > 0 ? decimalFormat.format(h) + ":" : "") + decimalFormat.format(m) + ":" + decimalFormat.format(s) : "00:00";
+ }
+
+ public static String getDuration(long startTime, long endTime) {
+ int difference = (int) TimeUnit.MILLISECONDS.toSeconds(endTime - startTime);
+
+ int h = difference / 3600;
+ int s = difference % 60;
+ int m = difference / 60 % 60;
+
+ return (startTime > 0) ? (h > 0 ? decimalFormat.format(h) + ":" : "") + decimalFormat.format(m) + ":" + decimalFormat.format(s) : "00:00";
+ }
+
+ public static String getDurationDown(long start, int i) {
+ long time = i - (TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - start));
+
+ long seconds = time % 60;
+ long minutes = time / 60 % 60;
+ long hours = (time / 60) / 60;
+ DecimalFormat decimalFormat = new DecimalFormat("00");
+
+ String toReturn = decimalFormat.format(minutes) + ":" + decimalFormat.format(seconds);
+
+ if (hours > 0) {
+ toReturn = decimalFormat.format(hours) + ":" + toReturn;
+ }
+ return toReturn;
+ }
+}
diff --git a/src/main/java/me/abhi/practice/util/EloUtil.java b/src/main/java/me/abhi/practice/util/EloUtil.java
new file mode 100644
index 0000000..8aa18fb
--- /dev/null
+++ b/src/main/java/me/abhi/practice/util/EloUtil.java
@@ -0,0 +1,35 @@
+package me.abhi.practice.util;
+
+public class EloUtil {
+
+ private static double[] getEstimations(double rankingA, double rankingB) {
+ double[] ret = new double[2];
+ double estA = 1.0 / (1.0 + Math.pow(10.0, (rankingB - rankingA) / 400.0));
+ double estB = 1.0 / (1.0 + Math.pow(10.0, (rankingA - rankingB) / 400.0));
+ ret[0] = estA;
+ ret[1] = estB;
+ return ret;
+ }
+
+ private static int getConstant(int ranking) {
+ if (ranking < 1400) {
+ return 32;
+ }
+ if (ranking >= 1400 && ranking < 1800) {
+ return 24;
+ }
+ if (ranking >= 1800 && ranking < 2400) {
+ return 16;
+ }
+ return 0;
+ }
+
+ public static int[] getNewRankings(int rankingA, int rankingB, boolean victoryA) {
+ int[] elo = new int[2];
+ double[] estimates = getEstimations(rankingA, rankingB);
+ int newRankA = (int) (rankingA + getConstant(rankingA) * ((victoryA ? 1 : 0) - estimates[0]));
+ elo[0] = Math.round((float) newRankA);
+ elo[1] = Math.round((float) (rankingB - (newRankA - rankingA)));
+ return elo;
+ }
+}
diff --git a/src/main/java/me/abhi/practice/util/InventoryUtil.java b/src/main/java/me/abhi/practice/util/InventoryUtil.java
new file mode 100644
index 0000000..52df41f
--- /dev/null
+++ b/src/main/java/me/abhi/practice/util/InventoryUtil.java
@@ -0,0 +1,168 @@
+package me.abhi.practice.util;
+
+import org.bukkit.Bukkit;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.PlayerInventory;
+import org.bukkit.util.io.BukkitObjectInputStream;
+import org.bukkit.util.io.BukkitObjectOutputStream;
+import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class InventoryUtil {
+ /**
+ * Converts the player inventory to a String array of Base64 strings. First string is the content and second string is the armor.
+ *
+ * @param playerInventory to turn into an array of strings.
+ * @return Array of strings: [ main content, armor content ]
+ * @throws IllegalStateException
+ */
+ public static String[] playerInventoryToBase64(PlayerInventory playerInventory) throws IllegalStateException {
+ //get the main content part, this doesn't return the armor
+ String content = toBase64(playerInventory);
+ String armor = itemStackArrayToBase64(playerInventory.getArmorContents());
+
+ return new String[]{content, armor};
+ }
+
+ /**
+ * A method to serialize an {@link ItemStack} array to Base64 String.
+ *
+ *
+ *
+ * Based off of {@link #toBase64(Inventory)}.
+ *
+ * @param items to turn into a Base64 String.
+ * @return Base64 string of the items.
+ * @throws IllegalStateException
+ */
+ public static String itemStackArrayToBase64(ItemStack[] items) throws IllegalStateException {
+ try {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream);
+
+ // Write the size of the inventory
+ dataOutput.writeInt(items.length);
+
+ // Save every element in the list
+ for (int i = 0; i < items.length; i++) {
+ dataOutput.writeObject(items[i]);
+ }
+
+ // Serialize that array
+ dataOutput.close();
+ return Base64Coder.encodeLines(outputStream.toByteArray());
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to save item stacks.", e);
+ }
+ }
+
+ /**
+ * A method to serialize an inventory to Base64 string.
+ *
+ *
+ *
+ * Special thanks to Comphenix in the Bukkit forums or also known
+ * as aadnk on GitHub.
+ *
+ * Original Source
+ *
+ * @param inventory to serialize
+ * @return Base64 string of the provided inventory
+ * @throws IllegalStateException
+ */
+ public static String toBase64(Inventory inventory) throws IllegalStateException {
+ try {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream);
+
+ // Write the size of the inventory
+ dataOutput.writeInt(inventory.getSize());
+
+ // Save every element in the list
+ for (int i = 0; i < inventory.getSize(); i++) {
+ dataOutput.writeObject(inventory.getItem(i));
+ }
+
+ // Serialize that array
+ dataOutput.close();
+ return Base64Coder.encodeLines(outputStream.toByteArray());
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to save item stacks.", e);
+ }
+ }
+
+ /**
+ * A method to get an {@link Inventory} from an encoded, Base64, string.
+ *
+ *
+ *
+ * Special thanks to Comphenix in the Bukkit forums or also known
+ * as aadnk on GitHub.
+ *
+ * Original Source
+ *
+ * @param data Base64 string of data containing an inventory.
+ * @return Inventory created from the Base64 string.
+ * @throws IOException
+ */
+ public static Inventory fromBase64(String data) {
+ try {
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(data));
+ BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
+ Inventory inventory = Bukkit.getServer().createInventory(null, dataInput.readInt());
+
+ // Read the serialized inventory
+ for (int i = 0; i < inventory.getSize(); i++) {
+ inventory.setItem(i, (ItemStack) dataInput.readObject());
+ }
+
+ dataInput.close();
+ return inventory;
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ /**
+ * Gets an array of ItemStacks from Base64 string.
+ *
+ *
+ *
+ * Base off of {@link #fromBase64(String)}.
+ *
+ * @param data Base64 string to convert to ItemStack array.
+ * @return ItemStack array created from the Base64 string.
+ * @throws IOException
+ */
+ public static ItemStack[] itemStackArrayFromBase64(String data) {
+ try {
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(data));
+ BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
+ ItemStack[] items = new ItemStack[dataInput.readInt()];
+
+ // Read the serialized inventory
+ for (int i = 0; i < items.length; i++) {
+ items[i] = (ItemStack) dataInput.readObject();
+ }
+
+ dataInput.close();
+ return items;
+ } catch (Exception ex) {
+ }
+ return null;
+ }
+
+ public static Inventory cloneInventory(Inventory inventory) {
+ Inventory clone = Bukkit.createInventory(null, inventory.getSize(), inventory.getName());
+ clone.setContents(inventory.getContents());
+ return clone;
+ }
+
+ public static ItemStack[] cloneArmor(ItemStack[] armor) {
+ return armor.clone();
+ }
+}
diff --git a/src/main/java/me/abhi/practice/util/ListUtil.java b/src/main/java/me/abhi/practice/util/ListUtil.java
new file mode 100644
index 0000000..cd59236
--- /dev/null
+++ b/src/main/java/me/abhi/practice/util/ListUtil.java
@@ -0,0 +1,15 @@
+package me.abhi.practice.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+public class ListUtil {
+
+ public static List newList(UUID... uuids) {
+ List toReturn = new ArrayList<>();
+ Arrays.stream(uuids).forEach(u -> toReturn.add(u));
+ return toReturn;
+ }
+}
diff --git a/src/main/java/me/abhi/practice/util/LocationUtil.java b/src/main/java/me/abhi/practice/util/LocationUtil.java
new file mode 100644
index 0000000..0741bf7
--- /dev/null
+++ b/src/main/java/me/abhi/practice/util/LocationUtil.java
@@ -0,0 +1,60 @@
+package me.abhi.practice.util;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+
+public class LocationUtil {
+
+ public static String getStringFromLocation(Location loc) {
+ if (loc == null) {
+ return "";
+ }
+ return loc.getWorld().getName() + ":" + loc.getX() + ":" + loc.getY() + ":" + loc.getZ() + ":" + loc.getYaw() + ":" + loc.getPitch();
+ }
+
+ public static Location getLocationFromString(String s) {
+ if (s == null || s.trim() == "") {
+ return null;
+ }
+ String[] parts = s.split(":");
+ if (parts.length == 6) {
+ World w = Bukkit.getServer().getWorld(parts[0]);
+ double x = Double.parseDouble(parts[1]);
+ double y = Double.parseDouble(parts[2]);
+ double z = Double.parseDouble(parts[3]);
+ float yaw = Float.parseFloat(parts[4]);
+ float pitch = Float.parseFloat(parts[5]);
+ return new Location(w, x, y, z, yaw, pitch);
+ }
+ return null;
+ }
+
+ public static String getLiteStringFromLocation(Location loc) {
+ if (loc == null) {
+ return "";
+ }
+ return loc.getWorld().getName() + ":" + loc.getBlockX() + ":" + loc.getBlockY() + ":" + loc.getBlockZ();
+ }
+
+ public static Location getLiteLocationFromString(String s) {
+ if (s == null || s.trim() == "") {
+ return null;
+ }
+ String[] parts = s.split(":");
+ if (parts.length == 4) {
+ World w = Bukkit.getServer().getWorld(parts[0]);
+ double x = Double.parseDouble(parts[1]);
+ double y = Double.parseDouble(parts[2]);
+ double z = Double.parseDouble(parts[3]);
+ return new Location(w, x, y, z);
+ }
+ return null;
+ }
+
+ public static Location getSpawn(Location s1, Location s2) {
+ Location spawn = s1.clone();
+ spawn.setYaw(s1.toVector().angle(s2.toVector()));
+ return spawn;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/abhi/practice/util/enums/Items.java b/src/main/java/me/abhi/practice/util/enums/Items.java
new file mode 100644
index 0000000..45443c0
--- /dev/null
+++ b/src/main/java/me/abhi/practice/util/enums/Items.java
@@ -0,0 +1,34 @@
+package me.abhi.practice.util.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import org.bukkit.inventory.ItemStack;
+
+@Getter
+@AllArgsConstructor
+public enum Items {
+
+ UNRANKED(null, 0),
+ RANKED(null, 0),
+ PARTY(null, 0),
+ EDITKIT(null, 0),
+ LEAVE_QUEUE(null, 0),
+ CUSTOM_KIT(null, 0),
+ DEFAULT_KIT(null, 0),
+ PARTY_EVENTS(null, 0),
+ HCF_SELECTOR(null, 0),
+ LEADER_PARTY_INFO(null, 0),
+ PLAYER_PARTY_INFO(null, 0),
+ DISBAND_PARTY(null, 0),
+ LEAVE_PARTY(null, 0),
+ LEAVE_EVENT(null, 0),
+ LEAVE_TOURNAMENT(null, 0),
+ STOP_SPECTATING(null, 0);
+
+ @Setter
+ private ItemStack item;
+
+ @Setter
+ private int slot;
+}
diff --git a/src/main/java/me/abhi/practice/util/enums/Menus.java b/src/main/java/me/abhi/practice/util/enums/Menus.java
new file mode 100644
index 0000000..7482e4f
--- /dev/null
+++ b/src/main/java/me/abhi/practice/util/enums/Menus.java
@@ -0,0 +1,33 @@
+package me.abhi.practice.util.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import org.bukkit.inventory.Inventory;
+
+import java.util.List;
+
+@Getter
+@AllArgsConstructor
+public enum Menus {
+
+ UNRANKED(null, null, null),
+ RANKED(null, null, null),
+ EDITKIT(null, null, null),
+ PARTYFFA(null, null, null),
+ PARTYSPLIT(null, null, null),
+ DUEL(null, null, null),
+ TOURNAMENT(null, null, null),
+ LEADERBOARDS(null, null, null),
+ SETTINGS(null, null, null);
+
+ @Setter
+ private Inventory inventory;
+
+ @Setter
+ private String itemPrefix;
+
+ @Setter
+ private List itemLore;
+
+}
diff --git a/src/main/java/me/abhi/practice/util/enums/Messages.java b/src/main/java/me/abhi/practice/util/enums/Messages.java
new file mode 100644
index 0000000..341709b
--- /dev/null
+++ b/src/main/java/me/abhi/practice/util/enums/Messages.java
@@ -0,0 +1,204 @@
+package me.abhi.practice.util.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import me.abhi.practice.PracticePlugin;
+import me.abhi.practice.util.misc.CC;
+
+@Getter
+@AllArgsConstructor
+public enum Messages {
+
+ SPAWN_SET("&aYou have successfully set the spawn."),
+ EDITOR_SET("&aYou have successfully set the editor."),
+ KIT_ALREADY_EXISTS("&cThat kit already exists."),
+ KIT_DOESNT_EXIST("&cThat kit doesn't exist."),
+ KIT_CREATED("&eYou have created the kit &a%kit%&e."),
+ KIT_DELETED("&eYou have deleted the kit &a%kit%&e."),
+ LOADED_KIT("&eYou have loaded the kit &a%kit%&e."),
+ KIT_NOT_SET("&cYou don't have an inventory set for that kit."),
+ HAND_CANT_BE_AIR("&cYour hand may not be air."),
+ KIT_DISPLAY_SET("&eYou have updated the display of kit &a%kit%&e."),
+ KIT_INVENTORY_SET("&eYou have set the inventory for the kit &a%kit%&e."),
+ KIT_EDITCHEST_UPDATED("&eYou have updated the edit chest of kit &a%kit% &eto &a%value%&e."),
+ KIT_TYPE_DOESNT_EXIST("&cThat kit type doesn't exist."),
+ KIT_TYPE_UPDATED("&eYou have updated the type of kit &a%kit%&e to &a%type%&e."),
+ KIT_TICKS_UPDATED("&eYou have updated the type of kit &a%kit%&e to &a%ticks%&e."),
+ KIT_EDITINV_UPDATED("&eYou have set the edit inventory for the kit &a%kit%&e."),
+ KIT_RANKED_UPDATED("&eYou have updated ranked of kit &a%kit% &eto &a%value%&e."),
+ KIT_UNRANKED_UPDATED("&eYou have updated unranked of kit &a%kit% &eto &a%value%&e."),
+ KIT_EDITABLE_UPDATED("&eYou have updated editable of kit &a%kit% &eto &a%value%&e."),
+ KIT_ISNT_RANKED("&cThat kit isn't ranked."),
+ JOINED_UNRANKED_QUEUE("&aYou are now queued for Unranked %kit%."),
+ JOINED_RANKED_QUEUE("&aYou are now queued for Ranked %kit%."),
+ UNRANKED_MATCH_FOUND("&e&lMatch found! &eOpponent: &b%player%"),
+ RANKED_MATCH_FOUND("&e&lMatch found! &eOpponent: &b%player% (%elo% Elo)"),
+ MATCH_STARTING("&e%time%..."),
+ MATCH_STARTED("&aMatch started."),
+ LEFT_QUEUE("&cYou have left the queue for %queueType% %kit%."),
+ ARENA_ALREADY_EXISTS("&cThat arena already exists."),
+ ARENA_CREATED("&eYou have created the arena &a%arena%&e."),
+ ARENA_DOESNT_EXIST("&cThat arena doesn't exist."),
+ ARENA_DELETED("&eYou have deleted the arena &a%arena%&e."),
+ ARENA_FIRST_SET("&eYou set the first location for arena &a%arena%&e."),
+ ARENA_SECOND_SET("&eYou set the second location for arena &a%arena%&e."),
+ ARENA_TYPE_UPDATED("&eYou have updated the type of arena &a%arena%&e to &a%type%&e."),
+ INVALID_STATE("&cYou cannot do this in your current state."),
+ TELEPORTING_TO_SPAWN("&eTeleporting you to spawn..."),
+ PLAYER_DEATH_KILLED("&c%player% &7was killed by &a%killer%&7."),
+ PLAYER_DEATH_DIED("&c%player% &7died."),
+ PLAYER_DEATH_DISCONNECTED("&c%player% &7disconnected."),
+ PLAYER_DEATH_LEFT("&c%player% &7left."),
+ MATCH_END("&6Post-match inventories &7(Click to view):\n\n&6Winner: &a%winnerNames%\n&6Loser: &c%loserNames%"),
+ ELO_CHANGES("&eElo changes: &a%winner% +%eloDifference% (%newWinnerElo%) &c%loser% -%eloDifference% (%newLoserElo%)"),
+ INVENTORY_HOVER("Click here to view %player%'s inventory."),
+ MAY_PEARL_AGAIN("&aYou may pearl again!"),
+ MUST_WAIT_TO_PEARL("&cYou must wait %time%s to do that again!"),
+ INVENTORY_NOT_FOUND("&cThere was no inventory found for that player."),
+ SAVED_CUSTOM_KIT("&eSaved custom kit &a%kit% #%number%&e."),
+ DELETED_CUSTOM_KIT("&eDeleted custom kit &a%kit% #%number%&e."),
+ EQUIPPED_CUSTOM_KIT("&eEquipped custom kit &r%name%&e."),
+ EQUIPPED_DEFAULT_KIT("&eEquipped default kit for %kit%."),
+ LOADED_CUSTOM_KIT("&eLoaded custom kit for %kit% &a#%number%."),
+ SET_CUSTOM_NAME("&eType your kit name in chat (color codes are applicable)"),
+ CUSTOM_NAME_SET("&eCustom name for %kit% &a#%number% to &r%name%&e."),
+ PARTY_HELP("&8&m--------------------------------------\n&d&lParty Help\n&8&m--------------------------------------\n&d/party create - Create a party\n/party invite - Invite a player to your party\n/party join - Join a player's party\n/party leave - Leave your party\n/party kick - Kick a player from your party\n/party open - Open your party\n/party promote - Transfer leadership of party\n/party disband - Disband party\n/party info - View party details\n \nUse '&6@&d' &dto type in party chat\n&8&m--------------------------------------"),
+ MUST_BE_IN_LOBBY("&cYou must be in the lobby to do this."),
+ CREATED_PARTY("&eYou have created a party!"),
+ NOT_IN_PARTY("&cYou are not in a party."),
+ MUST_BE_PARTY_LEADER("&cYou must be the party leader to do this."),
+ PARTY_DISBANDED("&cYour party has been disbanded."),
+ COULD_NOT_FIND_PLAYER("&cCould not find player with the name %player%."),
+ EXISTING_PARTY_INVITE("&cYou already have an existing party invite out to that player."),
+ PARTY_INVITE_SENT("&a%player% &ehas been invited to the party."),
+ PARTY_INVITE("&a%player% &ehas invited you to their party (&a%amount%&e) &a[Accept]"),
+ PARTY_INVITE_HOVER("Click here to join %player%'s party."),
+ PLAYER_NOT_IN_PARTY("&c%player% is not in a party."),
+ PLAYERS_PARTY_NOT_IN_LOBBY("&c%player%'s party is not in the lobby."),
+ PARTY_INVITE_NOT_FOUND("&cYou do not have an invite from that party."),
+ PLAYER_JOINED_PARTY("&a%player% &ehas joined the party."),
+ LEADER_CANT_LEAVE("&cYou are the party leader. To leave the party, you must promote someone else or disband the party."),
+ PLAYER_LEFT_PARTY("&a%player% &ehas left the party."),
+ LEFT_PARTY("&cYou have left the party."),
+ PLAYER_NOT_IN_LOBBY("&c%player% is not in the lobby."),
+ PLAYER_NOT_IN_YOUR_PARTY("&c%player% is not in your party."),
+ PARTY_FULL("&cThat party is full."),
+ PARTY_OPENED("&eThe party has been &aopened&e."),
+ PARTY_CLOSED("&eThe party has been &cclosed&e."),
+ PLAYER_PROMOTED("&a%player% &ehas been promoted to party leader."),
+ CANT_PROMOTE_YOURSELF("&aYou can't promote yourself!"),
+ PARTY_INFO("&8&m--------------------------------------\n&6Leader: &e%leader%\n&6Members (&e%amount%&6): &e%members%\n&6Status: &e%status%\n&8&m--------------------------------------"),
+ PROVIDE_A_MESSAGE("&cPlease provide a message."),
+ PARTY_FFA_STARTING("&eParty ffa starting..."),
+ FEATURE_DISABLED("&cThis feature is currently disabled."),
+ MUST_NEED_TWO_MEMBERS("&cYou need at least 2 players in your party to do this."),
+ TIME_SET_DAY("&aTime set to day."),
+ TIME_SET_SUNSET("&aTime set to sunset."),
+ TIME_SET_NIGHT("&aTime set to night."),
+ DUEL_REQUEST_EXISTS("&cYou already have an existing duel request to that player."),
+ CANT_DUEL_YOURSELF("&cYou can't duel yourself!"),
+ PARTY_DOESNT_EXIST("&cThat party no longer exists."),
+ PARTY_NOT_IN_LOBBY("&cThat party is not in the lobby."),
+ SENT_PARTY_DUEL("&eSent a duel request to &a%player%'s Party &ewith the kit &a%kit%&e."),
+ PARTY_DUEL_REQUEST("&a%player%'s Party &e(&a%amount%&e) has sent you a duel request with the kit &a%kit% [Accept]"),
+ PARTY_DUEL_HOVER("Click here to accept %player%'s party duel request."),
+ SENT_DUEL("&eSent a duel request to &a%player% &ewith the kit &a%kit%&e."),
+ DUEL_REQUEST("&a%player% &ehas sent you a duel request with the kit &a%kit% [Accept]"),
+ DUEL_HOVER("Click here to accept %player%'s duel request."),
+ PLAYER_DISABLED_DUELS("&c%player% has duel requests disabled."),
+ MUST_CREATE_PARTY_TO_DUEL("&cYou must create a party to duel %player%'s party."),
+ INVALID_PAGE_NUMBER("&cInvalid page number."),
+ LEADERBOARDS_PAGE_DOESNT_EXIST("&cThat page doesn't exist."),
+ LEADERBOARDS_HEADER("&a%kit% &eleaderboards page &a%page%"),
+ LEADERBOARDS_PLAYER("&a#%place%&e. &a%player% &e(&a%elo%&e)"),
+ DUEL_REQUEST_NOT_FOUND("&cThat duel request was not found."),
+ CANT_DROP_FIRST_ITEM("&cYou can't drop the item in your first slot."),
+ DIAMOND_KIT_SET("&eYou have set the kit for HCF &aDiamond&e."),
+ ARCHER_KIT_SET("&eYou have set the kit for HCF &aArcher&e."),
+ BARD_KIT_SET("&eYou have set the kit for HCF &aBard&e."),
+ ROGUE_KIT_SET("&eYou have set the kit for HCF &aRogue&e."),
+ MUST_WAIT_TO_BARD_BUFF("&cYou can only buff every 6 seconds. You must wait %time%s."),
+ NEED_MORE_ENERGY("&cYou need %energy% energy to do this."),
+ ACTIVATED_BARD_BUFF("&6[&eBard&6] &eYou have activated the buff &a%buff%&e."),
+ MUST_WAIT_TO_ARCHER_BUFF("&cYou can only buff every 60 seconds. You must wait %time%s."),
+ ACTIVATED_ARCHER_BUFF("&6[&eArcher&6] &eYou have activated the buff &a%buff%&e."),
+ MUST_WAIT_TO_ROGUE_BUFF("&cYou can only buff every 60 seconds. You must wait %time%s."),
+ ACTIVATED_ROGUE_BUFF("&6[&eRogue&6] &eYou have activated the buff &a%buff%&e."),
+ ARCHER_TAGGED("&6[&eRogue&6] &eYou have been archer tagged for &615 &eseconds!"),
+ PLAYER_ARCHER_TAGGED("&6[&eArcher&6] &eYou have archer tagged &6%player% &efor &615 &eseconds!"),
+ NO_LONGER_ARCHER_MARKED("&6[&eArcher&6] &eYou are no longer archer tagged!"),
+ MUST_WAIT_TO_BACKSTAB("&cYou must wait to %time%s to backstab again."),
+ MAY_BACKSTAB_AGAIN("&6[&eRogue&6] &eYou may use backstab again!"),
+ BACKSTABBED("&6[&eRogue&6] &eYou were backstabbed by &6%player%&e."),
+ BACKSTABBED_PLAYER("&6[&eRogue&6] &eYou backstabbed &6%player%&e."),
+ EVENT_PLAYER_ELIMINATED("&c%player% &7has been eliminated."),
+ EVENT_HELP("&8&m--------------------------------------\n&d&lEvent Help\n&8&m--------------------------------------\n&d/event start - Start an event\n/event join - Join an event\n/event leave - Leave an event\n/event spectate - Spectate an event\n&8&m--------------------------------------"),
+ NO_EVENT_STARTED("&cThere is no event by that name started."),
+ EVENT_ALREADY_STARTED("&cThat event has already started."),
+ EVENT_DELAY("You must wait for the event cooldown to end before starting another one."),
+ EVENT_DOESNT_EXIST("&cThat event doesn't exist."),
+ EVENT_STARTING("&a%player% &eis hosting a &a%event% &eevent! &a[Join]"),
+ EVENT_HOVER("Click to join the %event% event."),
+ PLAYER_JOINED_EVENT("&a%player% &ehas joined the event!"),
+ NOT_IN_EVENT("&cYou are not in an event."),
+ PLAYER_LEFT_EVENT("&a%player% &ehas left the event!"),
+ LEFT_EVENT("&cYou have left the event."),
+ EVENT_WINNER("&6[&eEvent&6] &a%player% &ehas won the &a%event% &eevent!"),
+ EVENT_LOBBY_SET("&eThe lobby for event &a%event% &ehas been set."),
+ EVENT_FIRST_SET("&eThe first spawn for event &a%event% &ehas been set."),
+ EVENT_SECOND_SET("&eThe second spawn for event &a%event% &ehas been set."),
+ SUMO_EVENT_MATCHUP("&6[&eSumo&6] &eNow fighting: &a%player1% &evs. &a%player2%"),
+ SUMO_EVENT_MATCH_STARTING("&e%time%..."),
+ SUMO_EVENT_MATCH_STARTED("&aMatch started!"),
+ SUMO_ROUND_STARTING("&6[&eSumo&6] &eNext round starting in &a%time%..."),
+ SCOREBOARD_ENABLED("&6[&eScoreboard&6] &aEnabled"),
+ SCOREBOARD_DISABLED("&6[&eScoreboard&6] &cDisabled"),
+ SILENT_ENABLED("&6[&eSilent&6] &aEnabled"),
+ SILENT_DISABLED("&6[&eSilent&6] &cDisabled"),
+ BUILDER_ENABLED("&6[&eBuilder&6] &aEnabled"),
+ BUILDER_DISABLED("&6[&eBuilder&6] &cDisabled"),
+ DUEL_REQUEST_ENABLED("&6[&eDuel Requests&6] &aEnabled"),
+ DUEL_REQUEST_DISABLED("&6[&eDuel Requests&6] &cDisabled"),
+ EVENT_CANCELLED("&6[&eEvent&6] &eThe &a%event% &ehas been cancelled."),
+ EVENT_FULL("&cThat event is full."),
+ TOURNAMENT_HELP("&8&m--------------------------------------\n&d&lTournament Help\n&8&m--------------------------------------\n&d/tournament join - Join a tournament\n/tournament leave - Leave a tournament\n/tournament status - View all tournament matches\n&8&m--------------------------------------"),
+ TOURNAMENT_ALREADY_STARTED("&cThere is already a tournament started."),
+ TOURNAMENT_STARTING("&eThere is a &a%kit% &etournament starting! &a[Join]"),
+ TOURNAMENT_HOVER("Click to join the %kit% tournament."),
+ NO_TOURNAMENT_STARTED("&cThere is no tournament started."),
+ PLAYER_JOINED_TOURNAMENT("&a%player% &ehas joined the tournament &a(%players%/%max%)"),
+ PLAYER_LEFT_TOURNAMENT("&a%player% &ehas left the tournament &a(%players%/%max%)"),
+ PLAYER_ELIMINATED_TOURNAMENT("&a%player% &ehas been eliminated!"),
+ TOURNAMENT_FULL("&cThe tournament is full."),
+ NOT_IN_TOURNAMENT("&cYou are not in a tournament."),
+ LEFT_TOURNAMENT("&cYou have left the tournament."),
+ TOURNAMENT_WINNER("&6[&eTournament&6] &a%player% &ehas won the &a%kit% &etournament!"),
+ TOURNAMENT_CANCELLED("&6[&eTournament&6] &eThe &a%kit% &etournament has been cancelled."),
+ TOURNAMENT_SITOUT("&cWe could not find you a match. You will automatically be advanced to the next round."),
+ TOURNAMENT_NEXT_ROUND("&6[&eTournament&6] &eRound &a%round% &ewill start in &a30 &eseconds."),
+ PLAYER_NOT_IN_MATCH("&c%player% is not in a match."),
+ PLAYER_NOW_SPECTATING("&7* &a%player% &eis now spectating."),
+ PLAYER_NO_LONGER_SPECTATING("&7* &a%player% &eis no longer spectating."),
+ NO_LONGER_SPECTATING("&cYou are no longer spectating."),
+ TOURNAMENT_STATUS_HEADER("&8&m-----------------------------------"),
+ TOURNAMENT_STATUS_MATCH("&d%player1% vs. %player2%"),
+ TOURNAMENT_STATUS_FOOTER("&8&m-----------------------------------"),
+ TOURNAMENT_NO_FIGHTS("&cThere are no fights happening."),
+ NOT_HCF_ARENA("&cThat is not an HCF arena."),
+ PLAYER_HEALTH("&a%player%'s &ehealth is &c%health% \u2764"),
+ NEVER_PLAYED_BEFORE("&c%player% has never played before."),
+ INVALID_AMOUNT("&cInvalid amount."),
+ INVALID_ELO("&cThe elo amount you have entered is either too little or too big."),
+ SET_ELO("&eYou have set &a%player%'s &eelo for kit &a%kit% &eto &a%elo%&e.");
+
+ private String defaultMessage;
+
+ public String getMessage() {
+ return (PracticePlugin.getInstance().getManagerHandler().getConfigurationManager().getMessagesFile().get(getPath()) != null ? CC.translate(PracticePlugin.getInstance().getManagerHandler().getConfigurationManager().getMessagesFile().getString(getPath())) : CC.translate(defaultMessage)).replace("%splitter%", "โ");
+ }
+
+ public String getPath() {
+ return this.toString().replace("_", "-");
+ }
+
+}
diff --git a/src/main/java/me/abhi/practice/util/misc/BlankObject.java b/src/main/java/me/abhi/practice/util/misc/BlankObject.java
new file mode 100644
index 0000000..0594cd5
--- /dev/null
+++ b/src/main/java/me/abhi/practice/util/misc/BlankObject.java
@@ -0,0 +1,16 @@
+package me.abhi.practice.util.misc;
+
+public class BlankObject {
+
+ /*
+
+
+
+
+ Empty class. When /togglescoreboard is disabled or /settings, this is the class that is registered instead
+
+
+
+
+ */
+}
diff --git a/src/main/java/me/abhi/practice/util/misc/CC.java b/src/main/java/me/abhi/practice/util/misc/CC.java
new file mode 100644
index 0000000..f5cf549
--- /dev/null
+++ b/src/main/java/me/abhi/practice/util/misc/CC.java
@@ -0,0 +1,87 @@
+package me.abhi.practice.util.misc;
+
+import org.bukkit.ChatColor;
+
+public class CC {
+
+ public static final String RED = "" + ChatColor.RED;
+ public static final String DARK_RED = "" + ChatColor.DARK_RED;
+ public static final String AQUA = "" + ChatColor.AQUA;
+ public static final String DARK_AQUA = "" + ChatColor.DARK_AQUA;
+ public static final String BLUE = "" + ChatColor.BLUE;
+ public static final String DARK_BLUE = "" + ChatColor.DARK_BLUE;
+ public static final String GREEN = "" + ChatColor.GREEN;
+ public static final String DARK_GREEN = "" + ChatColor.DARK_GREEN;
+ public static final String PINK = "" + ChatColor.LIGHT_PURPLE;
+ public static final String PURPLE = "" + ChatColor.DARK_PURPLE;
+ public static final String YELLOW = "" + ChatColor.YELLOW;
+ public static final String GOLD = "" + ChatColor.GOLD;
+ public static final String GRAY = "" + ChatColor.GRAY;
+ public static final String DARK_GRAY = "" + ChatColor.DARK_GRAY;
+ public static final String WHITE = "" + ChatColor.WHITE;
+ public static final String BLACK = "" + ChatColor.BLACK;
+ public static final String ITALIC = "" + ChatColor.ITALIC;
+ public static final String BOLD = "" + ChatColor.BOLD;
+ public static final String STRIKE = "" + ChatColor.STRIKETHROUGH;
+ public static final String UNDERLINE = "" + ChatColor.UNDERLINE;
+ public static final String RANDOM = "" + ChatColor.MAGIC;
+ public static final String RESET = "" + ChatColor.RESET;
+ public String from(String string) {
+ switch(string.toLowerCase()) {
+ case "c":
+ return RED;
+ case "4":
+ return DARK_RED;
+ case "b":
+ return AQUA;
+ case "3":
+ return DARK_AQUA;
+ case "1":
+ return DARK_BLUE;
+ case "9":
+ return BLUE;
+ case "a":
+ return GREEN;
+ case "2":
+ return DARK_GREEN;
+ case "d":
+ return PINK;
+ case "5":
+ return PURPLE;
+ case "e":
+ return YELLOW;
+ case "6":
+ return GOLD;
+ case "7":
+ return GRAY;
+ case "8":
+ return DARK_GRAY;
+ case "f":
+ return WHITE;
+ case "0":
+ return BLACK;
+ case "o":
+ return ITALIC;
+ case "l":
+ return BOLD;
+ case "m":
+ return STRIKE;
+ case "n":
+ return UNDERLINE;
+ case "k":
+ return RANDOM;
+ }
+ return WHITE;
+ }
+
+ public static String translate(String message) {
+ // random nullpointer mhm
+ return message.replace('&', 'ยง');
+
+ }
+
+ public static String strip(String message) {
+ return ChatColor.stripColor(message);
+ }
+
+}
diff --git a/src/main/java/me/abhi/practice/util/misc/EntityHider.java b/src/main/java/me/abhi/practice/util/misc/EntityHider.java
new file mode 100644
index 0000000..2870bc2
--- /dev/null
+++ b/src/main/java/me/abhi/practice/util/misc/EntityHider.java
@@ -0,0 +1,371 @@
+package me.abhi.practice.util.misc;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.ProtocolLibrary;
+import com.comphenix.protocol.ProtocolManager;
+import com.comphenix.protocol.events.PacketAdapter;
+import com.comphenix.protocol.events.PacketContainer;
+import com.comphenix.protocol.events.PacketEvent;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDeathEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.event.world.ChunkUnloadEvent;
+import org.bukkit.plugin.Plugin;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+
+import static com.comphenix.protocol.PacketType.Play.Server.*;
+
+public class EntityHider implements Listener {
+
+ protected Table observerEntityMap = HashBasedTable.create();
+
+ // Packets that update remote player entities
+ private static PacketType[] ENTITY_PACKETS = {
+ ENTITY_EQUIPMENT, BED, ANIMATION, NAMED_ENTITY_SPAWN,
+ COLLECT, SPAWN_ENTITY, SPAWN_ENTITY_LIVING, SPAWN_ENTITY_PAINTING, SPAWN_ENTITY_EXPERIENCE_ORB,
+ ENTITY_LOOK, ENTITY_TELEPORT, ENTITY_HEAD_ROTATION,
+ ENTITY_STATUS, ATTACH_ENTITY, ENTITY_METADATA, ENTITY_EFFECT, REMOVE_ENTITY_EFFECT,
+ BLOCK_BREAK_ANIMATION
+
+ // We don't handle DESTROY_ENTITY though
+ // Removed for knockback: ENTITY_VELOCITY, REL_ENTITY_MOVE,
+ };
+
+ /**
+ * The current entity visibility policy.
+ *
+ * @author Kristian
+ */
+ public enum Policy {
+ /**
+ * All entities are invisible by default. Only entities specifically made visible may be seen.
+ */
+ WHITELIST,
+
+ /**
+ * All entities are visible by default. An entity can only be hidden explicitly.
+ */
+ BLACKLIST,
+ }
+
+ private ProtocolManager manager;
+
+ // Listeners
+ private Listener bukkitListener;
+ private PacketAdapter protocolListener;
+
+ // Current policy
+ protected Policy policy;
+
+ /**
+ * Construct a new entity hider.
+ *
+ * @param plugin - the plugin that controls this entity hider.
+ * @param policy - the default visibility policy.
+ */
+ public EntityHider(Plugin plugin, Policy policy) {
+ Preconditions.checkNotNull(plugin, "plugin cannot be NULL.");
+
+ // Save policy
+ this.policy = policy;
+ this.manager = ProtocolLibrary.getProtocolManager();
+
+ // Register event and packet listener
+ plugin.getServer().getPluginManager().registerEvents(
+ bukkitListener = constructBukkit(), plugin);
+ manager.addPacketListener(
+ protocolListener = constructProtocol(plugin));
+ }
+
+ /**
+ * Set the visibility status of a given entity for a particular observer.
+ *
+ * @param observer - the observer player.
+ * @param entityID - ID of the entity that will be hidden or made visible.
+ * @param visible - TRUE if the entity should be made visible, FALSE if not.
+ * @return TRUE if the entity was visible before this method call, FALSE otherwise.
+ */
+ protected boolean setVisibility(Player observer, int entityID, boolean visible) {
+ switch (policy) {
+ case BLACKLIST:
+ // Non-membership means they are visible
+ return !setMembership(observer, entityID, !visible);
+ case WHITELIST:
+ return setMembership(observer, entityID, visible);
+ default:
+ throw new IllegalArgumentException("Unknown policy: " + policy);
+ }
+ }
+
+ /**
+ * Add or remove the given entity and observer entry from the table.
+ *
+ * @param observer - the player observer.
+ * @param entityID - ID of the entity.
+ * @param member - TRUE if they should be present in the table, FALSE otherwise.
+ * @return TRUE if they already were present, FALSE otherwise.
+ */
+ // Helper method
+ protected boolean setMembership(Player observer, int entityID, boolean member) {
+ if (member) {
+ return observerEntityMap.put(observer.getEntityId(), entityID, true) != null;
+ } else {
+ return observerEntityMap.remove(observer.getEntityId(), entityID) != null;
+ }
+ }
+
+ /**
+ * Determine if the given entity and observer is present in the table.
+ *
+ * @param observer - the player observer.
+ * @param entityID - ID of the entity.
+ * @return TRUE if they are present, FALSE otherwise.
+ */
+ protected boolean getMembership(Player observer, int entityID) {
+ return observerEntityMap.contains(observer.getEntityId(), entityID);
+ }
+
+ /**
+ * Determine if a given entity is visible for a particular observer.
+ *
+ * @param observer - the observer player.
+ * @param entityID - ID of the entity that we are testing for visibility.
+ * @return TRUE if the entity is visible, FALSE otherwise.
+ */
+ protected boolean isVisible(Player observer, int entityID) {
+ // If we are using a whitelist, presence means visibility - if not, the opposite is the case
+ boolean presence = getMembership(observer, entityID);
+
+ return policy == Policy.WHITELIST ? presence : !presence;
+ }
+
+ /**
+ * Remove the given entity from the underlying map.
+ *
+ * @param entity - the entity to remove.
+ * @param destroyed - TRUE if the entity was killed, FALSE if it is merely unloading.
+ */
+ protected void removeEntity(Entity entity, boolean destroyed) {
+ int entityID = entity.getEntityId();
+
+ Iterator