stacks = new ArrayList<>();
+
+ for(int i = 0; i <= 15; i++) {
+ stacks.add(new ItemStack(Material.WOOL, 1, (byte)i));
+ }
+
+ inv.setContents(stacks.toArray(new ItemStack[0]));
+
+ player.openInventory(inv);
+
+ }
+
+ public ItemMeta getChangeColMeta() {
+ return changeColMeta;
+ }
+
+ public ItemMeta getRestartMeta() {
+ return restartMeta;
+ }
+
+ public ItemMeta getRefillMeta() {
+ return refillMeta;
+ }
+
+ public ItemMeta getLeaveMeta() {
+ return leaveMeta;
+ }
+
+ public ItemMeta getSpectatorLeave() {
+ return spectatorLeave;
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/PlayerSpeed.java b/src/main/java/com/github/thethingyee/bridgingpractice/PlayerSpeed.java
new file mode 100644
index 0000000..f776cdc
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/PlayerSpeed.java
@@ -0,0 +1,42 @@
+package com.github.thethingyee.bridgingpractice;
+
+import com.github.thethingyee.bridgingpractice.utils.HMaps;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+
+public class PlayerSpeed {
+
+ private final BridgingPractice bridgingPractice;
+
+ public PlayerSpeed(BridgingPractice bridgingPractice) {
+ this.bridgingPractice = bridgingPractice;
+ }
+
+ public void startPlayerSpeed(Player player) {
+ HMaps hMaps = bridgingPractice.gethMaps();
+ BukkitRunnable runnable = new BukkitRunnable() {
+ Location oldLoc = player.getLocation();
+ @Override
+ public void run() {
+ Location newLoc = player.getLocation();
+ double equation = newLoc.distance(oldLoc) * 2;
+ hMaps.getPlayerSpeed().put(player, equation);
+ oldLoc = newLoc;
+ }
+ };
+ if(player == null) Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "NULL WTFFFF");
+ if(hMaps.getPlayerRunnable().containsKey(player)) return;
+ hMaps.getPlayerRunnable().put(player, runnable);
+ hMaps.getPlayerRunnable().get(player).runTaskTimer(bridgingPractice, 0, 10);
+ }
+
+ public void stopPlayerSpeed(Player player) {
+ HMaps hMaps = bridgingPractice.gethMaps();
+ if(!hMaps.getPlayerRunnable().containsKey(player)) return;
+ hMaps.getPlayerRunnable().get(player).cancel();
+ hMaps.getPlayerRunnable().remove(player);
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/ScoreboardManager.java b/src/main/java/com/github/thethingyee/bridgingpractice/ScoreboardManager.java
new file mode 100644
index 0000000..e3f35ff
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/ScoreboardManager.java
@@ -0,0 +1,83 @@
+package com.github.thethingyee.bridgingpractice;
+
+import com.github.thethingyee.bridgingpractice.libraries.FastBoard;
+import com.github.thethingyee.bridgingpractice.utils.HMaps;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+
+public class ScoreboardManager {
+
+ private final BridgingPractice bridgingPractice;
+
+ public ScoreboardManager(BridgingPractice bridgingPractice) {
+ this.bridgingPractice = bridgingPractice;
+ }
+
+ public void init() {
+ HMaps hMaps = bridgingPractice.gethMaps();
+ BukkitRunnable runnable = new BukkitRunnable() {
+ @Override
+ public void run() {
+ for(Player player : hMaps.getPlayerScoreboard().keySet()) {
+ if(hMaps.getSpectatingPlayer().containsKey(player)) {
+ continue;
+ }
+ FastBoard fastBoard = hMaps.getPlayerScoreboard().get(player);
+ fastBoard.updateTitle(ChatColor.YELLOW + "" + ChatColor.BOLD + "Bridging");
+
+ fastBoard.updateLines(
+ "",
+ "Name: " + ChatColor.GREEN + player.getName(),
+ "",
+ "Blocks Placed: " + ChatColor.GREEN + hMaps.getBlocksPlaced().get(player),
+ "Speed: " + ChatColor.GREEN + String.format("%.2f", hMaps.getPlayerSpeed().get(player)) + " m/s",
+ "",
+ "Online Players: " + ChatColor.GREEN + Bukkit.getOnlinePlayers().size(),
+ "",
+ ChatColor.RED + bridgingPractice.getConfig().getString("scoreboard.server-ip")
+ );
+ }
+ }
+ };
+ runnable.runTaskTimer(bridgingPractice, 0, 5);
+
+ BukkitRunnable runnable2 = new BukkitRunnable() {
+ @Override
+ public void run() {
+ for(Player p : hMaps.getSpectatingPlayer().keySet()) {
+ if(hMaps.getSpectatingPlayer().get(p) != null) {
+ Player target = hMaps.getSpectatingPlayer().get(p);
+ FastBoard fastBoard = hMaps.getPlayerScoreboard().get(p);
+ fastBoard.updateTitle(ChatColor.YELLOW + "" + ChatColor.BOLD + "Bridging");
+
+ fastBoard.updateLines(
+ "",
+ "Name: " + ChatColor.GREEN + target.getName(),
+ "",
+ "Blocks Placed: " + ChatColor.GREEN + hMaps.getBlocksPlaced().get(target),
+ "Speed: " + ChatColor.GREEN + String.format("%.2f", hMaps.getPlayerSpeed().get(target)) + " m/s",
+ "",
+ "Online Players: " + ChatColor.GREEN + Bukkit.getOnlinePlayers().size(),
+ "",
+ ChatColor.RED + bridgingPractice.getConfig().getString("scoreboard.server-ip")
+ );
+ }
+ }
+ }
+ };
+ runnable2.runTaskTimer(bridgingPractice, 0, 5);
+ }
+
+ public void showPlayingScoreboard(Player player) {
+ HMaps hMaps = bridgingPractice.gethMaps();
+ hMaps.getPlayerScoreboard().put(player, new FastBoard(player));
+ }
+
+ public void showSpectateScoreboard(Player request, Player target) {
+ HMaps hMaps = bridgingPractice.gethMaps();
+ hMaps.getPlayerScoreboard().put(request, new FastBoard(request));
+ hMaps.getSpectatingPlayer().put(request, target);
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/libraries/FastBoard.java b/src/main/java/com/github/thethingyee/bridgingpractice/libraries/FastBoard.java
new file mode 100644
index 0000000..2879d77
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/libraries/FastBoard.java
@@ -0,0 +1,454 @@
+package com.github.thethingyee.bridgingpractice.libraries;
+
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * Lightweight packet-based scoreboard API for Bukkit plugins.
+ * It can be used safely in an async thread as everything is at packet level.
+ *
+ * The project is on GitHub.
+ *
+ * @author MrMicky
+ * @version 1.2.0-SNAPSHOT
+ */
+public class FastBoard {
+
+ private static final Map, List> PACKETS = new HashMap<>(8);
+ private static final VersionType VERSION_TYPE;
+ // Packets and components
+ private static final Class> CHAT_COMPONENT_CLASS;
+ private static final MethodHandle MESSAGE_FROM_STRING;
+ private static final MethodHandle PLAYER_CONNECTION;
+ private static final MethodHandle SEND_PACKET;
+ private static final MethodHandle PLAYER_GET_HANDLE;
+ // Scoreboard packets
+ private static final MethodHandle PACKET_SB_OBJ;
+ private static final MethodHandle PACKET_SB_DISPLAY_OBJ;
+ private static final MethodHandle PACKET_SB_SCORE;
+ private static final MethodHandle PACKET_SB_TEAM;
+ // Scoreboard enums
+ private static final Class> ENUM_SB_HEALTH_DISPLAY;
+ private static final Class> ENUM_SB_ACTION;
+ private static final Object ENUM_SB_HEALTH_DISPLAY_INTEGER;
+ private static final Object ENUM_SB_ACTION_CHANGE;
+ private static final Object ENUM_SB_ACTION_REMOVE;
+
+ static {
+ try {
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ MethodType voidType = MethodType.methodType(void.class);
+
+ if (FastReflection.nmsOptionalClass("ScoreboardServer$Action").isPresent()) {
+ VERSION_TYPE = VersionType.V1_13;
+ } else if (FastReflection.nmsOptionalClass("IScoreboardCriteria$EnumScoreboardHealthDisplay").isPresent()) {
+ VERSION_TYPE = VersionType.V1_8;
+ } else {
+ VERSION_TYPE = VersionType.V1_7;
+ }
+
+ Class> craftPlayerClass = FastReflection.obcClass("entity.CraftPlayer");
+ Class> craftChatMessageClass = FastReflection.obcClass("util.CraftChatMessage");
+ Class> entityPlayerClass = FastReflection.nmsClass("EntityPlayer");
+ Class> playerConnectionClass = FastReflection.nmsClass("PlayerConnection");
+ Class> packetClass = FastReflection.nmsClass("Packet");
+ Class> packetSbObjClass = FastReflection.nmsClass("PacketPlayOutScoreboardObjective");
+ Class> packetSbDisplayObjClass = FastReflection.nmsClass("PacketPlayOutScoreboardDisplayObjective");
+ Class> packetSbScoreClass = FastReflection.nmsClass("PacketPlayOutScoreboardScore");
+ Class> packetSbTeamClass = FastReflection.nmsClass("PacketPlayOutScoreboardTeam");
+
+ MESSAGE_FROM_STRING = lookup.unreflect(craftChatMessageClass.getMethod("fromString", String.class));
+ CHAT_COMPONENT_CLASS = FastReflection.nmsClass("IChatBaseComponent");
+ PLAYER_GET_HANDLE = lookup.findVirtual(craftPlayerClass, "getHandle", MethodType.methodType(entityPlayerClass));
+ PLAYER_CONNECTION = lookup.findGetter(entityPlayerClass, "playerConnection", playerConnectionClass);
+ SEND_PACKET = lookup.findVirtual(playerConnectionClass, "sendPacket", MethodType.methodType(void.class, packetClass));
+ PACKET_SB_OBJ = lookup.findConstructor(packetSbObjClass, voidType);
+ PACKET_SB_DISPLAY_OBJ = lookup.findConstructor(packetSbDisplayObjClass, voidType);
+ PACKET_SB_SCORE = lookup.findConstructor(packetSbScoreClass, voidType);
+ PACKET_SB_TEAM = lookup.findConstructor(packetSbTeamClass, voidType);
+
+ for (Class> clazz : Arrays.asList(packetSbObjClass, packetSbDisplayObjClass, packetSbScoreClass, packetSbTeamClass)) {
+ List fields = Arrays.asList(clazz.getDeclaredFields());
+ fields.forEach(field -> field.setAccessible(true));
+ PACKETS.put(clazz, fields);
+ }
+
+ if (VersionType.V1_8.isHigherOrEqual()) {
+ String enumSbActionClass = VersionType.V1_13.isHigherOrEqual()
+ ? "ScoreboardServer$Action"
+ : "PacketPlayOutScoreboardScore$EnumScoreboardAction";
+ ENUM_SB_HEALTH_DISPLAY = FastReflection.nmsClass("IScoreboardCriteria$EnumScoreboardHealthDisplay");
+ ENUM_SB_ACTION = FastReflection.nmsClass(enumSbActionClass);
+ ENUM_SB_HEALTH_DISPLAY_INTEGER = FastReflection.enumValueOf(ENUM_SB_HEALTH_DISPLAY, "INTEGER");
+ ENUM_SB_ACTION_CHANGE = FastReflection.enumValueOf(ENUM_SB_ACTION, "CHANGE");
+ ENUM_SB_ACTION_REMOVE = FastReflection.enumValueOf(ENUM_SB_ACTION, "REMOVE");
+ } else {
+ ENUM_SB_HEALTH_DISPLAY = null;
+ ENUM_SB_ACTION = null;
+ ENUM_SB_HEALTH_DISPLAY_INTEGER = null;
+ ENUM_SB_ACTION_CHANGE = null;
+ ENUM_SB_ACTION_REMOVE = null;
+ }
+ } catch (ReflectiveOperationException e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ private final Player player;
+ private final String id;
+
+ private final List lines = new ArrayList<>();
+ private String title = ChatColor.RESET.toString();
+
+ private boolean deleted = false;
+
+ /**
+ * Creates a new FastBoard.
+ *
+ * @param player the owner of the scoreboard
+ */
+ public FastBoard(Player player) {
+ this.player = Objects.requireNonNull(player, "player");
+ this.id = "fb-" + Integer.toHexString(ThreadLocalRandom.current().nextInt());
+
+ try {
+ sendObjectivePacket(ObjectiveMode.CREATE);
+ sendDisplayObjectivePacket();
+ } catch (Throwable t) {
+ throw new RuntimeException("Unable to create scoreboard", t);
+ }
+ }
+
+ /**
+ * Update the scoreboard title.
+ *
+ * @param title the new scoreboard title
+ * @throws IllegalArgumentException if the title is longer than 32 chars on 1.12 or lower
+ * @throws IllegalStateException if {@link #delete()} was call before
+ */
+ public void updateTitle(String title) {
+ if (this.title.equals(Objects.requireNonNull(title, "title"))) {
+ return;
+ }
+
+ if (!VersionType.V1_13.isHigherOrEqual() && title.length() > 32) {
+ throw new IllegalArgumentException("Title is longer than 32 chars");
+ }
+
+ this.title = title;
+
+ try {
+ sendObjectivePacket(ObjectiveMode.UPDATE);
+ } catch (Throwable t) {
+ throw new RuntimeException("Unable to update scoreboard title", t);
+ }
+ }
+
+ /**
+ * Update all the scoreboard lines.
+ *
+ * @param lines the new lines
+ * @throws IllegalArgumentException if one line is longer than 30 chars on 1.12 or lower
+ * @throws IllegalStateException if {@link #delete()} was call before
+ */
+ public void updateLines(String... lines) {
+ updateLines(Arrays.asList(lines));
+ }
+
+ /**
+ * Update the lines of the scoreboard
+ *
+ * @param lines the new scoreboard lines
+ * @throws IllegalArgumentException if one line is longer than 30 chars on 1.12 or lower
+ * @throws IllegalStateException if {@link #delete()} was call before
+ */
+ public synchronized void updateLines(Collection lines) {
+ Objects.requireNonNull(lines, "lines");
+ checkLineNumber(lines.size());
+
+ if (!VersionType.V1_13.isHigherOrEqual()) {
+ int lineCount = 0;
+ for (String s : lines) {
+ if (s != null && s.length() > 30) {
+ throw new IllegalArgumentException("Line " + lineCount + " is longer than 30 chars");
+ }
+ lineCount++;
+ }
+ }
+
+ List oldLines = new ArrayList<>(this.lines);
+ this.lines.clear();
+ this.lines.addAll(lines);
+
+ int linesSize = this.lines.size();
+
+ try {
+ if (oldLines.size() != linesSize) {
+ List oldLinesCopy = new ArrayList<>(oldLines);
+
+ if (oldLines.size() > linesSize) {
+ for (int i = oldLinesCopy.size(); i > linesSize; i--) {
+ sendTeamPacket(i - 1, TeamMode.REMOVE);
+ sendScorePacket(i - 1, ScoreboardAction.REMOVE);
+
+ oldLines.remove(0);
+ }
+ } else {
+ for (int i = oldLinesCopy.size(); i < linesSize; i++) {
+ sendScorePacket(i, ScoreboardAction.CHANGE);
+ sendTeamPacket(i, TeamMode.CREATE);
+
+ oldLines.add(oldLines.size() - i, getLineByScore(i));
+ }
+ }
+ }
+
+ for (int i = 0; i < linesSize; i++) {
+ if (!Objects.equals(getLineByScore(oldLines, i), getLineByScore(i))) {
+ sendTeamPacket(i, TeamMode.UPDATE);
+ }
+ }
+ } catch (Throwable t) {
+ throw new RuntimeException("Unable to update scoreboard lines", t);
+ }
+ }
+
+ /**
+ * Get the player who has the scoreboard.
+ *
+ * @return current player for this FastBoard
+ */
+ public Player getPlayer() {
+ return this.player;
+ }
+
+ /**
+ * Delete this FastBoard, and will remove the scoreboard for the associated player if he is online.
+ * After this, all uses of {@link #updateLines} and {@link #updateTitle} will throws an {@link IllegalStateException}
+ *
+ * @throws IllegalStateException if this was already call before
+ */
+ public void delete() {
+ try {
+ for (int i = 0; i < this.lines.size(); i++) {
+ sendTeamPacket(i, TeamMode.REMOVE);
+ }
+
+ sendObjectivePacket(ObjectiveMode.REMOVE);
+ } catch (Throwable t) {
+ throw new RuntimeException("Unable to delete scoreboard", t);
+ }
+
+ this.deleted = true;
+ }
+
+ /**
+ * Return if the player has a prefix/suffix characters limit.
+ * By default, it returns true only in 1.12 or lower.
+ * This method can be overridden to fix compatibility with some versions support plugin.
+ *
+ * @return max length
+ */
+ protected boolean hasLinesMaxLength() {
+ return !VersionType.V1_13.isHigherOrEqual();
+ }
+
+ private void checkLineNumber(int line) {
+ if (line < 0) {
+ throw new IllegalArgumentException("Line number must be positive");
+ }
+
+ if (line >= ChatColor.values().length - 1) {
+ throw new IllegalArgumentException("Line number is too high: " + this.lines.size());
+ }
+ }
+
+ private String getColorCode(int score) {
+ return ChatColor.values()[score].toString();
+ }
+
+ private String getLineByScore(int score) {
+ return getLineByScore(this.lines, score);
+ }
+
+ private String getLineByScore(List lines, int score) {
+ return lines.get(lines.size() - score - 1);
+ }
+
+ private void sendObjectivePacket(ObjectiveMode mode) throws Throwable {
+ Object packet = PACKET_SB_OBJ.invoke();
+
+ setField(packet, String.class, this.id);
+ setField(packet, int.class, mode.ordinal());
+
+ if (mode != ObjectiveMode.REMOVE) {
+ setComponentField(packet, this.title, 1);
+
+ if (VersionType.V1_8.isHigherOrEqual()) {
+ setField(packet, ENUM_SB_HEALTH_DISPLAY, ENUM_SB_HEALTH_DISPLAY_INTEGER);
+ }
+ } else if (VERSION_TYPE == VersionType.V1_7) {
+ setField(packet, String.class, "", 1);
+ }
+
+ sendPacket(packet);
+ }
+
+ private void sendDisplayObjectivePacket() throws Throwable {
+ Object packet = PACKET_SB_DISPLAY_OBJ.invoke();
+
+ setField(packet, int.class, 1); // Position (1: sidebar)
+ setField(packet, String.class, this.id); // Score Name
+
+ sendPacket(packet);
+ }
+
+ private void sendScorePacket(int score, ScoreboardAction action) throws Throwable {
+ Object packet = PACKET_SB_SCORE.invoke();
+
+ setField(packet, String.class, getColorCode(score), 0); // Player Name
+
+ if (VersionType.V1_8.isHigherOrEqual()) {
+ setField(packet, ENUM_SB_ACTION, action == ScoreboardAction.REMOVE ? ENUM_SB_ACTION_REMOVE : ENUM_SB_ACTION_CHANGE);
+ } else {
+ setField(packet, int.class, action.ordinal(), 1); // Action
+ }
+
+ if (action == ScoreboardAction.CHANGE) {
+ setField(packet, String.class, this.id, 1); // Objective Name
+ setField(packet, int.class, score); // Score
+ }
+
+ sendPacket(packet);
+ }
+
+ private void sendTeamPacket(int score, TeamMode mode) throws Throwable {
+ if (mode == TeamMode.ADD_PLAYERS || mode == TeamMode.REMOVE_PLAYERS) {
+ throw new UnsupportedOperationException();
+ }
+
+ int maxLength = hasLinesMaxLength() ? 16 : 1024;
+ Object packet = PACKET_SB_TEAM.invoke();
+
+ setField(packet, String.class, this.id + ':' + score); // Team name
+ setField(packet, int.class, mode.ordinal(), VERSION_TYPE == VersionType.V1_8 ? 1 : 0); // Update mode
+
+ if (mode == TeamMode.CREATE || mode == TeamMode.UPDATE) {
+ String line = getLineByScore(score);
+ String prefix;
+ String suffix = null;
+
+ if (line == null || line.isEmpty()) {
+ prefix = getColorCode(score) + ChatColor.RESET;
+ } else if (line.length() <= maxLength) {
+ prefix = line;
+ } else {
+ // Prevent splitting color codes
+ int index = line.charAt(maxLength - 1) == ChatColor.COLOR_CHAR ? (maxLength - 1) : maxLength;
+ prefix = line.substring(0, index);
+ String suffixTmp = line.substring(index);
+ ChatColor chatColor = null;
+
+ if (suffixTmp.length() >= 2 && suffixTmp.charAt(0) == ChatColor.COLOR_CHAR) {
+ chatColor = ChatColor.getByChar(suffixTmp.charAt(1));
+ }
+
+ String color = ChatColor.getLastColors(prefix);
+ boolean addColor = chatColor == null || chatColor.isFormat();
+
+ suffix = (addColor ? (color.isEmpty() ? ChatColor.RESET.toString() : color) : "") + suffixTmp;
+ }
+
+ if (prefix.length() > maxLength || (suffix != null && suffix.length() > maxLength)) {
+ // Something went wrong, just cut to prevent client crash/kick
+ prefix = prefix.substring(0, maxLength);
+ suffix = (suffix != null) ? suffix.substring(0, maxLength) : null;
+ }
+
+ setComponentField(packet, prefix, 2); // Prefix
+ setComponentField(packet, suffix == null ? "" : suffix, 3); // Suffix
+ setField(packet, String.class, "always", 4); // Visibility for 1.8+
+ setField(packet, String.class, "always", 5); // Collisions for 1.9+
+
+ if (mode == TeamMode.CREATE) {
+ setField(packet, Collection.class, Collections.singletonList(getColorCode(score))); // Players in the team
+ }
+ }
+
+ sendPacket(packet);
+ }
+
+ private void sendPacket(Object packet) throws Throwable {
+ if (this.deleted) {
+ throw new IllegalStateException("This FastBoard is deleted");
+ }
+
+ if (this.player.isOnline()) {
+ Object entityPlayer = PLAYER_GET_HANDLE.invoke(this.player);
+ Object playerConnection = PLAYER_CONNECTION.invoke(entityPlayer);
+ SEND_PACKET.invoke(playerConnection, packet);
+ }
+ }
+
+ private void setField(Object object, Class> fieldType, Object value) throws ReflectiveOperationException {
+ setField(object, fieldType, value, 0);
+ }
+
+ private void setField(Object packet, Class> fieldType, Object value, int count) throws ReflectiveOperationException {
+ int i = 0;
+ for (Field field : PACKETS.get(packet.getClass())) {
+ if (field.getType() == fieldType && count == i++) {
+ field.set(packet, value);
+ }
+ }
+ }
+
+ private void setComponentField(Object packet, String value, int count) throws Throwable {
+ if (VERSION_TYPE != VersionType.V1_13) {
+ setField(packet, String.class, value, count);
+ return;
+ }
+
+ int i = 0;
+ for (Field field : PACKETS.get(packet.getClass())) {
+ if ((field.getType() == String.class || field.getType() == CHAT_COMPONENT_CLASS) && count == i++) {
+ field.set(packet, Array.get(MESSAGE_FROM_STRING.invoke(value), 0));
+ }
+ }
+ }
+
+ enum ObjectiveMode {
+ CREATE, REMOVE, UPDATE
+ }
+
+ enum TeamMode {
+ CREATE, REMOVE, UPDATE, ADD_PLAYERS, REMOVE_PLAYERS
+ }
+
+ enum ScoreboardAction {
+ CHANGE, REMOVE
+ }
+
+ enum VersionType {
+ V1_7, V1_8, V1_13;
+
+ public boolean isHigherOrEqual() {
+ return VERSION_TYPE.ordinal() >= ordinal();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/libraries/FastReflection.java b/src/main/java/com/github/thethingyee/bridgingpractice/libraries/FastReflection.java
new file mode 100644
index 0000000..9111774
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/libraries/FastReflection.java
@@ -0,0 +1,54 @@
+package com.github.thethingyee.bridgingpractice.libraries;
+
+import org.bukkit.Bukkit;
+
+import java.util.Optional;
+
+/**
+ * Small reflection utility class to use CraftBukkit and NMS.
+ *
+ * @author MrMicky
+ */
+public final class FastReflection {
+
+ public static final String OBC_PACKAGE = "org.bukkit.craftbukkit";
+ public static final String NMS_PACKAGE = "net.minecraft.server";
+
+ public static final String VERSION = Bukkit.getServer().getClass().getPackage().getName().substring(OBC_PACKAGE.length() + 1);
+
+ private FastReflection() {
+ throw new UnsupportedOperationException();
+ }
+
+ public static String nmsClassName(String className) {
+ return NMS_PACKAGE + '.' + VERSION + '.' + className;
+ }
+
+ public static Class> nmsClass(String className) throws ClassNotFoundException {
+ return Class.forName(nmsClassName(className));
+ }
+
+ public static Optional> nmsOptionalClass(String className) {
+ return optionalClass(nmsClassName(className));
+ }
+
+ public static String obcClassName(String className) {
+ return OBC_PACKAGE + '.' + VERSION + '.' + className;
+ }
+
+ public static Class> obcClass(String className) throws ClassNotFoundException {
+ return Class.forName(obcClassName(className));
+ }
+
+ public static Optional> optionalClass(String className) {
+ try {
+ return Optional.of(Class.forName(className));
+ } catch (ClassNotFoundException e) {
+ return Optional.empty();
+ }
+ }
+
+ public static Object enumValueOf(Class> enumClass, String enumName) {
+ return Enum.valueOf(enumClass.asSubclass(Enum.class), enumName);
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/listeners/BlockBreak.java b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/BlockBreak.java
new file mode 100644
index 0000000..f49c602
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/BlockBreak.java
@@ -0,0 +1,36 @@
+package com.github.thethingyee.bridgingpractice.listeners;
+
+import com.github.thethingyee.bridgingpractice.BridgingPractice;
+import com.github.thethingyee.bridgingpractice.utils.HMaps;
+import org.bukkit.ChatColor;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockBreakEvent;
+
+public class BlockBreak implements Listener {
+
+ private final BridgingPractice bridgingPractice;
+
+ public BlockBreak(BridgingPractice bridgingPractice) {
+ this.bridgingPractice = bridgingPractice;
+ }
+
+ @EventHandler
+ public void onBreak(BlockBreakEvent e) {
+
+ HMaps hMaps = bridgingPractice.gethMaps();
+
+ if(hMaps.getSpectatingPlayer().containsKey(e.getPlayer())) {
+ if(hMaps.getSpectatingPlayer().get(e.getPlayer()).getWorld().getName().equalsIgnoreCase(e.getPlayer().getWorld().getName())) {
+ e.setCancelled(true);
+ e.getPlayer().sendMessage(bridgingPractice.prefix + ChatColor.RED + "You can't place blocks here!");
+ }
+ }
+
+ if (e.getPlayer().getWorld().getName().equalsIgnoreCase(e.getPlayer().getUniqueId().toString().replaceAll("-", ""))) {
+ e.setCancelled(true);
+ e.getPlayer().sendMessage(bridgingPractice.prefix + ChatColor.RED + "You are not allowed to break blocks.\n" + ChatColor.AQUA +
+ "Coming soon - Break blocks outside the island.");
+ }
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/listeners/BlockPlace.java b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/BlockPlace.java
new file mode 100644
index 0000000..5ce3cc8
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/BlockPlace.java
@@ -0,0 +1,56 @@
+package com.github.thethingyee.bridgingpractice.listeners;
+
+import com.github.thethingyee.bridgingpractice.BridgingPractice;
+import com.github.thethingyee.bridgingpractice.utils.HMaps;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockPlaceEvent;
+
+import java.util.ArrayList;
+
+public class BlockPlace implements Listener {
+
+ private final BridgingPractice bridgingPractice;
+
+ public BlockPlace(BridgingPractice bridgingPractice) {
+ this.bridgingPractice = bridgingPractice;
+
+ }
+
+ @EventHandler
+ public void onPlace(BlockPlaceEvent e) {
+ HMaps hMaps = bridgingPractice.gethMaps();
+ if(e.getPlayer().getWorld().getName().equalsIgnoreCase(bridgingPractice.getConfig().getString("defaults.world"))) return;
+
+ if(hMaps.getSpectatingPlayer().containsKey(e.getPlayer())) {
+ if(hMaps.getSpectatingPlayer().get(e.getPlayer()).getWorld().getName().equalsIgnoreCase(e.getPlayer().getWorld().getName())) {
+ e.setCancelled(true);
+ e.getPlayer().sendMessage(bridgingPractice.prefix + ChatColor.RED + "You can't place blocks here!");
+ }
+ }
+
+ if(e.getPlayer().getWorld().getName().equalsIgnoreCase(e.getPlayer().getUniqueId().toString().replaceAll("-", ""))) {
+ if (e.getBlockPlaced().getType().equals(Material.WOOL)) {
+ if (hMaps.getBlockPlaced().containsKey(e.getPlayer())) {
+ hMaps.getBlockPlaced().get(e.getPlayer()).add(new Location(e.getPlayer().getWorld(), e.getBlockPlaced().getLocation().getBlockX(), e.getBlockPlaced().getLocation().getBlockY(), e.getBlockPlaced().getLocation().getBlockZ()));
+ int placedBlocks = hMaps.getBlocksPlaced().get(e.getPlayer());
+ hMaps.getBlocksPlaced().put(e.getPlayer(), (placedBlocks + 1));
+ } else {
+ hMaps.getBlockPlaced().put(e.getPlayer(), new ArrayList<>());
+ hMaps.getBlocksPlaced().put(e.getPlayer(), 1);
+ hMaps.getBlockPlaced().get(e.getPlayer()).add(new Location(e.getPlayer().getWorld(), e.getBlockPlaced().getLocation().getBlockX(), e.getBlockPlaced().getLocation().getBlockY(), e.getBlockPlaced().getLocation().getBlockZ()));
+ bridgingPractice.getPlayerSpeed().startPlayerSpeed(e.getPlayer());
+ }
+ } else {
+ e.setCancelled(true);
+ e.getPlayer().sendMessage(bridgingPractice.prefix + ChatColor.RED + "You can only place WOOL here.");
+ }
+ } else {
+ e.setCancelled(true);
+ e.getPlayer().sendMessage(bridgingPractice.prefix + ChatColor.RED + "You can't place blocks here!");
+ }
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/listeners/ChangeWorld.java b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/ChangeWorld.java
new file mode 100644
index 0000000..a6f12bf
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/ChangeWorld.java
@@ -0,0 +1,29 @@
+package com.github.thethingyee.bridgingpractice.listeners;
+
+import com.github.thethingyee.bridgingpractice.BridgingPractice;
+import com.github.thethingyee.bridgingpractice.PlayerSpeed;
+import com.github.thethingyee.bridgingpractice.utils.HMaps;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerChangedWorldEvent;
+
+public class ChangeWorld implements Listener {
+
+ private final BridgingPractice bridgingPractice;
+
+ public ChangeWorld(BridgingPractice bridgingPractice) {
+ this.bridgingPractice = bridgingPractice;
+ }
+
+ @EventHandler
+ public void onChangeWorld(PlayerChangedWorldEvent e) {
+ HMaps hMaps = bridgingPractice.gethMaps();
+ PlayerSpeed playerSpeed = bridgingPractice.getPlayerSpeed();
+ if(e.getFrom().getName().equalsIgnoreCase(e.getPlayer().getUniqueId().toString().replaceAll("-", ""))) {
+ playerSpeed.stopPlayerSpeed(e.getPlayer());
+ hMaps.getPlayerSchematic().remove(e.getPlayer());
+ hMaps.getPlayerScoreboard().get(e.getPlayer()).delete();
+ hMaps.getPlayerScoreboard().remove(e.getPlayer());
+ }
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/listeners/EntityDamage.java b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/EntityDamage.java
new file mode 100644
index 0000000..0c400f7
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/EntityDamage.java
@@ -0,0 +1,57 @@
+package com.github.thethingyee.bridgingpractice.listeners;
+
+import com.github.thethingyee.bridgingpractice.BridgingPractice;
+import com.github.thethingyee.bridgingpractice.utils.HMaps;
+import com.github.thethingyee.bridgingpractice.utils.Offsets;
+import com.github.thethingyee.bridgingpractice.utils.WoolColor;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageEvent;
+
+public class EntityDamage implements Listener {
+
+ private final BridgingPractice bridgingPractice;
+
+ public EntityDamage(BridgingPractice bridgingPractice) {
+ this.bridgingPractice = bridgingPractice;
+ }
+
+ @EventHandler
+ public void onDamage(EntityDamageEvent e) {
+ HMaps hMaps = bridgingPractice.gethMaps();
+ if(e.getEntity() instanceof Player) {
+ Player player = (Player) e.getEntity();
+ if (player.getWorld().getName().equalsIgnoreCase(player.getUniqueId().toString().replaceAll("-", ""))) {
+ if(e.getCause().equals(EntityDamageEvent.DamageCause.VOID)) {
+ player.teleport(new Location(Bukkit.getWorld(player.getUniqueId().toString().replaceAll("-", "")), 0.0, 128.0, 0.0)
+ .add(Offsets.getOffsets(hMaps.getPlayerSchematic().get(player))[0], Offsets.getOffsets(hMaps.getPlayerSchematic().get(player))[1]+1, Offsets.getOffsets(hMaps.getPlayerSchematic().get(player))[2]));
+ if(hMaps.getBlockPlaced().containsKey(player)) {
+ for (Location loc : hMaps.getBlockPlaced().get(player)) {
+ player.getWorld().getBlockAt(loc).setType(Material.AIR);
+ }
+ }
+ player.getInventory().clear();
+ bridgingPractice.getGuiManager().giveInventoryItems(player, hMaps.getSelectedWoolColor().get(player), WoolColor.woolToDye(hMaps.getSelectedWoolColor().get(player)));
+
+ hMaps.getBlockPlaced().remove(player);
+ hMaps.getBlocksPlaced().put(player, 0);
+ player.sendMessage(bridgingPractice.prefix + ChatColor.RED + "Oops! You fell down! Restarting..");
+ }
+ e.setCancelled(true);
+ }
+ if(!player.getWorld().equals(Bukkit.getWorld(bridgingPractice.getConfig().getString("defaults.world")))) {
+ if(e.getCause().equals(EntityDamageEvent.DamageCause.VOID)) {
+ player.teleport(new Location(player.getWorld(), 0.0, 128.0, 0.0)
+ .add(Offsets.getOffsets(hMaps.getPlayerSchematic().get(hMaps.getSpectatingPlayer().get(player)))[0], Offsets.getOffsets(hMaps.getPlayerSchematic().get(hMaps.getSpectatingPlayer().get(hMaps.getSpectatingPlayer().get(player))))[1]+1, Offsets.getOffsets(hMaps.getPlayerSchematic().get(hMaps.getSpectatingPlayer().get(player)))[2]));
+ player.sendMessage(bridgingPractice.prefix + ChatColor.RED + "You fell down! Putting back to spawn.");
+ }
+ e.setCancelled(true);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/listeners/InvClick.java b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/InvClick.java
new file mode 100644
index 0000000..0115dd3
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/InvClick.java
@@ -0,0 +1,36 @@
+package com.github.thethingyee.bridgingpractice.listeners;
+
+import com.github.thethingyee.bridgingpractice.BridgingPractice;
+import com.github.thethingyee.bridgingpractice.utils.HMaps;
+import com.github.thethingyee.bridgingpractice.utils.WoolColor;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+
+public class InvClick implements Listener {
+
+ private final BridgingPractice bridgingPractice;
+
+ public InvClick(BridgingPractice bridgingPractice) {
+ this.bridgingPractice = bridgingPractice;
+ }
+
+ @EventHandler
+ public void onClick(InventoryClickEvent e) {
+ HMaps hMaps = bridgingPractice.gethMaps();
+ if(e.getClickedInventory() == null) return;
+ if(e.getCurrentItem().getItemMeta() != null) {
+ if (e.getClickedInventory().getName().equalsIgnoreCase(ChatColor.GOLD + "" + ChatColor.BOLD + "Select Color")) {
+ e.setCancelled(true);
+ if (e.getWhoClicked() instanceof Player) {
+ Player player = (Player) e.getWhoClicked();
+ bridgingPractice.getGuiManager().giveInventoryItems(player, e.getCurrentItem().getDurability(), WoolColor.woolToDye(e.getCurrentItem().getDurability()));
+ hMaps.getSelectedWoolColor().put(player, e.getCurrentItem().getDurability());
+ player.closeInventory();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/listeners/PlayerInteract.java b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/PlayerInteract.java
new file mode 100644
index 0000000..8ec7696
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/PlayerInteract.java
@@ -0,0 +1,100 @@
+package com.github.thethingyee.bridgingpractice.listeners;
+
+import com.github.thethingyee.bridgingpractice.BridgingPractice;
+import com.github.thethingyee.bridgingpractice.GUIManager;
+import com.github.thethingyee.bridgingpractice.utils.HMaps;
+import com.github.thethingyee.bridgingpractice.utils.Offsets;
+import com.github.thethingyee.bridgingpractice.utils.WoolColor;
+import org.apache.commons.io.FileUtils;
+import org.bukkit.*;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerInteractEvent;
+
+import java.io.File;
+import java.io.IOException;
+
+public class PlayerInteract implements Listener {
+
+ private final BridgingPractice bridgingPractice;
+
+ public PlayerInteract(BridgingPractice bridgingPractice) {
+ this.bridgingPractice = bridgingPractice;
+ }
+
+ @EventHandler
+ public void onInteract(PlayerInteractEvent e) {
+ HMaps hMaps = bridgingPractice.gethMaps();
+ GUIManager guiManager = bridgingPractice.getGuiManager();
+ if (e.getPlayer().getWorld().getName().equalsIgnoreCase(e.getPlayer().getUniqueId().toString().replaceAll("-", ""))) {
+ if(e.getPlayer().getItemInHand().getItemMeta() == null) return;
+ if (e.getPlayer().getItemInHand().getItemMeta().equals(guiManager.getChangeColMeta())) {
+ guiManager.changeColorGUI(e.getPlayer());
+ e.getPlayer().sendMessage(bridgingPractice.prefix + ChatColor.GREEN + "You have opened the Change Color GUI.");
+ } else if (e.getPlayer().getItemInHand().getItemMeta().equals(guiManager.getRestartMeta())) {
+ if (e.getPlayer().getWorld().getName().equalsIgnoreCase(e.getPlayer().getUniqueId().toString().replaceAll("-", ""))) {
+
+ e.getPlayer().teleport(new Location(Bukkit.getWorld(e.getPlayer().getUniqueId().toString().replaceAll("-", "")), 0.0, 128.0, 0.0).add(Offsets.getOffsets(hMaps.getPlayerSchematic().get(e.getPlayer()))[0], Offsets.getOffsets(hMaps.getPlayerSchematic().get(e.getPlayer()))[1]+1, Offsets.getOffsets(hMaps.getPlayerSchematic().get(e.getPlayer()))[2]));
+ if (hMaps.getBlockPlaced().containsKey(e.getPlayer())) {
+ for (Location loc : hMaps.getBlockPlaced().get(e.getPlayer())) {
+ e.getPlayer().getWorld().getBlockAt(loc).setType(Material.AIR);
+ }
+ }
+ hMaps.getBlocksPlaced().put(e.getPlayer(), 0);
+ e.getPlayer().sendMessage(bridgingPractice.prefix + ChatColor.GREEN + "Successfully restarted world.");
+
+ }
+ } else if (e.getPlayer().getItemInHand().getItemMeta().equals(guiManager.getLeaveMeta())) {
+ if (hMaps.getAssignedWorld().containsKey(e.getPlayer())) {
+ e.getPlayer().teleport(Bukkit.getWorld(bridgingPractice.getConfig().getString("defaults.world")).getSpawnLocation());
+ String worldName = e.getPlayer().getUniqueId().toString().replaceAll("-", "");
+ World world = Bukkit.getWorld(worldName);
+ if (world != null) {
+ if(!world.getPlayers().isEmpty()) {
+ for(Player player : world.getPlayers()) {
+ if(hMaps.getSpectatingPlayer().get(player) == e.getPlayer()) {
+ hMaps.getPlayerScoreboard().get(player).delete();
+ hMaps.getPlayerScoreboard().remove(player);
+ hMaps.getSpectatingPlayer().remove(player);
+ player.setAllowFlight(false);
+ player.setFlying(false);
+ player.getInventory().clear();
+ }
+ player.teleport(Bukkit.getWorld(bridgingPractice.getConfig().getString("defaults.world")).getSpawnLocation());
+ e.getPlayer().showPlayer(player);
+ }
+ }
+ Bukkit.unloadWorld(world, false);
+ try {
+ FileUtils.deleteDirectory(new File(Bukkit.getWorldContainer() + File.separator + "/" + worldName));
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ Bukkit.getConsoleSender().sendMessage(bridgingPractice.prefix + "Deleted world '" + worldName + "'");
+ hMaps.getAssignedWorld().remove(e.getPlayer());
+ hMaps.getPlayerSchematic().remove(e.getPlayer());
+ bridgingPractice.getWorldArray().remove(worldName);
+ }
+ }
+ e.getPlayer().getInventory().clear();
+ } else if(e.getPlayer().getItemInHand().getItemMeta().equals(guiManager.getRefillMeta())) {
+ e.getPlayer().getInventory().clear();
+ guiManager.giveInventoryItems(e.getPlayer(), hMaps.getSelectedWoolColor().get(e.getPlayer()), WoolColor.woolToDye(hMaps.getSelectedWoolColor().get(e.getPlayer())));
+ }
+ }
+ if(hMaps.getSpectatingPlayer().containsKey(e.getPlayer())) {
+ if(hMaps.getSpectatingPlayer().get(e.getPlayer()).getWorld() == e.getPlayer().getWorld()) {
+ if(e.getPlayer().getItemInHand().getItemMeta() == null) return;
+ if(e.getPlayer().getItemInHand().getItemMeta().equals(guiManager.getSpectatorLeave())) {
+ hMaps.getPlayerScoreboard().get(e.getPlayer()).delete();
+ hMaps.getPlayerScoreboard().remove(e.getPlayer());
+ hMaps.getSpectatingPlayer().remove(e.getPlayer());
+ e.getPlayer().teleport(Bukkit.getWorld(bridgingPractice.getConfig().getString("defaults.world")).getSpawnLocation());
+ e.getPlayer().sendMessage(bridgingPractice.prefix + ChatColor.GREEN + "Teleported!");
+ e.getPlayer().getInventory().clear();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/listeners/PlayerLeave.java b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/PlayerLeave.java
new file mode 100644
index 0000000..320e37c
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/PlayerLeave.java
@@ -0,0 +1,63 @@
+package com.github.thethingyee.bridgingpractice.listeners;
+
+import com.github.thethingyee.bridgingpractice.BridgingPractice;
+import com.github.thethingyee.bridgingpractice.utils.HMaps;
+import org.apache.commons.io.FileUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerQuitEvent;
+
+import java.io.File;
+import java.io.IOException;
+
+public class PlayerLeave implements Listener {
+
+ private final BridgingPractice bridgingPractice;
+
+ public PlayerLeave(BridgingPractice bridgingPractice) {
+ this.bridgingPractice = bridgingPractice;
+ }
+
+ @EventHandler
+ public void onLeave(PlayerQuitEvent e) {
+ HMaps hMaps = bridgingPractice.gethMaps();
+ Player p = e.getPlayer();
+ if(hMaps.getAssignedWorld().containsKey(p)) {
+ p.teleport(Bukkit.getWorld(bridgingPractice.getConfig().getString("defaults.world")).getSpawnLocation());
+ String worldName = p.getUniqueId().toString().replaceAll("-", "");
+ World world = Bukkit.getWorld(worldName);
+ if(world != null) {
+ if(!world.getPlayers().isEmpty()) {
+ for(Player player : world.getPlayers()) {
+ if(hMaps.getSpectatingPlayer().get(player) == e.getPlayer()) {
+ hMaps.getPlayerScoreboard().get(player).delete();
+ hMaps.getPlayerScoreboard().remove(player);
+ hMaps.getSpectatingPlayer().remove(player);
+ player.setAllowFlight(false);
+ player.setFlying(false);
+ player.getInventory().clear();
+ }
+ player.teleport(Bukkit.getWorld(bridgingPractice.getConfig().getString("defaults.world")).getSpawnLocation());
+ p.showPlayer(player);
+ }
+ }
+ Bukkit.unloadWorld(world, false);
+ try {
+ FileUtils.deleteDirectory(new File(Bukkit.getWorldContainer() + File.separator + "/" + worldName));
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ Bukkit.getConsoleSender().sendMessage(bridgingPractice.prefix + "Deleted world '" + worldName + "'");
+ bridgingPractice.getPlayerSpeed().stopPlayerSpeed(e.getPlayer());
+ hMaps.getSelectedWoolColor().remove(e.getPlayer());
+ hMaps.getAssignedWorld().remove(p);
+ bridgingPractice.getWorldArray().remove(worldName);
+ hMaps.getPlayerSchematic().remove(p);
+ }
+ }
+ p.getInventory().clear();
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/listeners/PlayerMove.java b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/PlayerMove.java
new file mode 100644
index 0000000..70313ae
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/listeners/PlayerMove.java
@@ -0,0 +1,50 @@
+package com.github.thethingyee.bridgingpractice.listeners;
+
+import com.github.thethingyee.bridgingpractice.BridgingPractice;
+import com.github.thethingyee.bridgingpractice.utils.HMaps;
+import com.github.thethingyee.bridgingpractice.utils.Offsets;
+import com.github.thethingyee.bridgingpractice.utils.WoolColor;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerMoveEvent;
+
+public class PlayerMove implements Listener {
+
+ private final BridgingPractice bridgingPractice;
+
+ public PlayerMove(BridgingPractice bridgingPractice) {
+ this.bridgingPractice = bridgingPractice;
+ }
+
+ @EventHandler
+ public void onMove(PlayerMoveEvent e) {
+ HMaps hMaps = bridgingPractice.gethMaps();
+ if(e.getPlayer().getWorld().getName().equalsIgnoreCase(e.getPlayer().getUniqueId().toString().replaceAll("-", ""))) {
+ if (e.getPlayer().getLocation().getBlockY() <= bridgingPractice.getConfig().getInt("defaults.kill-zone")) {
+ e.getPlayer().teleport(new Location(Bukkit.getWorld(e.getPlayer().getUniqueId().toString().replaceAll("-", "")), 0.0, 128.0, 0.0).add(Offsets.getOffsets(hMaps.getPlayerSchematic().get(e.getPlayer()))[0], Offsets.getOffsets(hMaps.getPlayerSchematic().get(e.getPlayer()))[1] + 1, Offsets.getOffsets(hMaps.getPlayerSchematic().get(e.getPlayer()))[2]));
+ if (hMaps.getBlockPlaced().containsKey(e.getPlayer())) {
+ for (Location loc : hMaps.getBlockPlaced().get(e.getPlayer())) {
+ e.getPlayer().getWorld().getBlockAt(loc).setType(Material.AIR);
+ }
+ }
+ e.getPlayer().getInventory().clear();
+ bridgingPractice.getGuiManager().giveInventoryItems(e.getPlayer(), hMaps.getSelectedWoolColor().get(e.getPlayer()), WoolColor.woolToDye(hMaps.getSelectedWoolColor().get(e.getPlayer())));
+ hMaps.getBlockPlaced().remove(e.getPlayer());
+ hMaps.getBlocksPlaced().put(e.getPlayer(), 0);
+ e.getPlayer().sendMessage(bridgingPractice.prefix + ChatColor.RED + "Oops! You fell down! Restarting..");
+ }
+ }
+ if(!e.getPlayer().getWorld().equals(Bukkit.getWorld(bridgingPractice.getConfig().getString("defaults.world")))) {
+ if (e.getPlayer().getLocation().getBlockY() <= bridgingPractice.getConfig().getInt("defaults.kill-zone")) {
+ Location loc = new Location(e.getPlayer().getWorld(), 0.0, 128.0, 0.0).add(Offsets.getOffsets(hMaps.getPlayerSchematic().get(hMaps.getSpectatingPlayer().get(e.getPlayer())))[0], Offsets.getOffsets(hMaps.getPlayerSchematic().get(hMaps.getSpectatingPlayer().get(e.getPlayer())))[1] + 1, Offsets.getOffsets(hMaps.getPlayerSchematic().get(hMaps.getSpectatingPlayer().get(e.getPlayer())))[2]);
+ e.getPlayer().teleport(loc);
+ e.getPlayer().sendMessage(loc.toString());
+ e.getPlayer().sendMessage(bridgingPractice.prefix + ChatColor.RED + "You fell down! Putting back to spawn.");
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/utils/ConfigExists.java b/src/main/java/com/github/thethingyee/bridgingpractice/utils/ConfigExists.java
new file mode 100644
index 0000000..04760d8
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/utils/ConfigExists.java
@@ -0,0 +1,30 @@
+package com.github.thethingyee.bridgingpractice.utils;
+
+import com.github.thethingyee.bridgingpractice.BridgingPractice;
+import org.bukkit.Bukkit;
+
+import java.io.File;
+
+public class ConfigExists {
+
+ private final BridgingPractice bridgingPractice;
+
+ public ConfigExists(BridgingPractice bridgingPractice) {
+ this.bridgingPractice = bridgingPractice;
+ }
+
+ public boolean schematicExists(String schematicName) {
+ if(bridgingPractice.getConfig().get("offset." + schematicName) != null) {
+ File file = new File(bridgingPractice.getDataFolder() + File.separator + "/schematics/" + schematicName + ".schematic");
+ return (file.exists());
+ }
+ return false;
+ }
+
+ public File getSchematicFile(String schematicName) {
+ if(schematicExists(schematicName)) {
+ return (new File(bridgingPractice.getDataFolder() + File.separator + "/schematics/" + schematicName + ".schematic"));
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/utils/HMaps.java b/src/main/java/com/github/thethingyee/bridgingpractice/utils/HMaps.java
new file mode 100644
index 0000000..d22c558
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/utils/HMaps.java
@@ -0,0 +1,59 @@
+package com.github.thethingyee.bridgingpractice.utils;
+
+import com.github.thethingyee.bridgingpractice.libraries.FastBoard;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class HMaps {
+
+ private final HashMap assignedWorld = new HashMap<>();
+ private final HashMap> blockPlaced = new HashMap<>();
+ private final HashMap blocksPlaced = new HashMap<>();
+ private final HashMap selectedWoolColor = new HashMap<>();
+ private final HashMap playerSpeed = new HashMap<>();
+ private final HashMap playerRunnable = new HashMap<>();
+ private final HashMap playerScoreboard = new HashMap<>();
+ private final HashMap playerSchematic = new HashMap<>();
+ private final HashMap spectatingPlayer = new HashMap<>();
+
+ public HashMap getAssignedWorld() {
+ return assignedWorld;
+ }
+
+ public HashMap> getBlockPlaced() {
+ return blockPlaced;
+ }
+
+ public HashMap getBlocksPlaced() {
+ return blocksPlaced;
+ }
+
+ public HashMap getSelectedWoolColor() {
+ return selectedWoolColor;
+ }
+
+ public HashMap getPlayerSpeed() {
+ return playerSpeed;
+ }
+
+ public HashMap getPlayerRunnable() {
+ return playerRunnable;
+ }
+
+ public HashMap getPlayerScoreboard() {
+ return playerScoreboard;
+ }
+
+ public HashMap getPlayerSchematic() {
+ return playerSchematic;
+ }
+
+ public HashMap getSpectatingPlayer() {
+ return spectatingPlayer;
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/utils/Offsets.java b/src/main/java/com/github/thethingyee/bridgingpractice/utils/Offsets.java
new file mode 100644
index 0000000..f53049e
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/utils/Offsets.java
@@ -0,0 +1,20 @@
+package com.github.thethingyee.bridgingpractice.utils;
+
+import com.github.thethingyee.bridgingpractice.BridgingPractice;
+
+public class Offsets {
+
+ private static BridgingPractice bridgingPractice;
+
+ public Offsets(BridgingPractice bridgingPractice) {
+ this.bridgingPractice = bridgingPractice;
+ }
+
+ public static double[] getOffsets(String schematicName) {
+ return new double[]{bridgingPractice.getConfig().getDouble("offset." + schematicName + ".x"), bridgingPractice.getConfig().getDouble("offset." + schematicName + ".y"), bridgingPractice.getConfig().getDouble("offset." + schematicName + ".z")};
+ }
+
+ public static int getRotation(String schematicName) {
+ return bridgingPractice.getConfig().getInt("offset." + schematicName + ".rotation");
+ }
+}
diff --git a/src/main/java/com/github/thethingyee/bridgingpractice/utils/WoolColor.java b/src/main/java/com/github/thethingyee/bridgingpractice/utils/WoolColor.java
new file mode 100644
index 0000000..4075fb6
--- /dev/null
+++ b/src/main/java/com/github/thethingyee/bridgingpractice/utils/WoolColor.java
@@ -0,0 +1,58 @@
+package com.github.thethingyee.bridgingpractice.utils;
+
+public class WoolColor {
+
+ public static int woolToDye(short durability) {
+ switch(durability) {
+ case 0: {
+ return 15;
+ }
+ case 1: {
+ return 14;
+ }
+ case 2: {
+ return 13;
+ }
+ case 3: {
+ return 12;
+ }
+ case 4: {
+ return 11;
+ }
+ case 5: {
+ return 10;
+ }
+ case 6: {
+ return 9;
+ }
+ case 7: {
+ return 8;
+ }
+ case 8: {
+ return 7;
+ }
+ case 9: {
+ return 6;
+ }
+ case 10: {
+ return 5;
+ }
+ case 11: {
+ return 4;
+ }
+ case 12: {
+ return 3;
+ }
+ case 13: {
+ return 2;
+ }
+ case 14: {
+ return 1;
+ }
+ case 15: {
+ return 0;
+ }
+ }
+ return 0;
+ }
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
new file mode 100644
index 0000000..338222a
--- /dev/null
+++ b/src/main/resources/config.yml
@@ -0,0 +1,17 @@
+defaults:
+ # Plugin defaults
+ world: "world"
+ # Name of schematic file along with the extension, make sure it is on BridgingPractice/schematics
+ schematic: "islandFinal2.schematic"
+ # Y coordinate of the kill zone / restart.
+ kill-zone: 110
+offset:
+ # Position player to the spawn of the schematic.
+ default:
+ x: -8.5
+ y: 3.0
+ z: -7.56
+ rotation: 0
+scoreboard:
+ server-ip: "thingyservers.xyz"
+
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..f85e63a
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,14 @@
+name: BridgingPractice
+version: ${project.version}
+main: com.github.thethingyee.bridgingpractice.BridgingPractice
+
+commands:
+ bridge:
+ aliases:
+ - bridging
+ - b
+ usage: "/ "
+ description: "The main command for the BridgingPractice Plugin."
+
+depend:
+ - WorldEdit
\ No newline at end of file