diff --git a/pom.xml b/pom.xml
index 45105d2..e8c6f8f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -87,11 +87,6 @@
gson
2.8.7
-
- com.github.NoSequel
- ScoreboardAPI
- d86c2c6d87
-
com.sk89q
worldedit
diff --git a/src/main/java/io/github/thatkawaiisam/assemble/Assemble.java b/src/main/java/io/github/thatkawaiisam/assemble/Assemble.java
new file mode 100644
index 0000000..499f94a
--- /dev/null
+++ b/src/main/java/io/github/thatkawaiisam/assemble/Assemble.java
@@ -0,0 +1,115 @@
+package io.github.thatkawaiisam.assemble;
+
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import io.github.thatkawaiisam.assemble.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/io/github/thatkawaiisam/assemble/AssembleAdapter.java b/src/main/java/io/github/thatkawaiisam/assemble/AssembleAdapter.java
new file mode 100644
index 0000000..5288854
--- /dev/null
+++ b/src/main/java/io/github/thatkawaiisam/assemble/AssembleAdapter.java
@@ -0,0 +1,24 @@
+package io.github.thatkawaiisam.assemble;
+
+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/io/github/thatkawaiisam/assemble/AssembleBoard.java b/src/main/java/io/github/thatkawaiisam/assemble/AssembleBoard.java
new file mode 100644
index 0000000..2357c60
--- /dev/null
+++ b/src/main/java/io/github/thatkawaiisam/assemble/AssembleBoard.java
@@ -0,0 +1,130 @@
+package io.github.thatkawaiisam.assemble;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import io.github.thatkawaiisam.assemble.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/io/github/thatkawaiisam/assemble/AssembleBoardEntry.java b/src/main/java/io/github/thatkawaiisam/assemble/AssembleBoardEntry.java
new file mode 100644
index 0000000..5e792f7
--- /dev/null
+++ b/src/main/java/io/github/thatkawaiisam/assemble/AssembleBoardEntry.java
@@ -0,0 +1,91 @@
+package io.github.thatkawaiisam.assemble;
+
+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/io/github/thatkawaiisam/assemble/AssembleException.java b/src/main/java/io/github/thatkawaiisam/assemble/AssembleException.java
new file mode 100644
index 0000000..83c0e0c
--- /dev/null
+++ b/src/main/java/io/github/thatkawaiisam/assemble/AssembleException.java
@@ -0,0 +1,14 @@
+package io.github.thatkawaiisam.assemble;
+
+public class AssembleException extends RuntimeException {
+
+ /**
+ * Assemble Exception.
+ *
+ * @param message attributed to exception.
+ */
+ public AssembleException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/io/github/thatkawaiisam/assemble/AssembleListener.java b/src/main/java/io/github/thatkawaiisam/assemble/AssembleListener.java
new file mode 100644
index 0000000..9d98a98
--- /dev/null
+++ b/src/main/java/io/github/thatkawaiisam/assemble/AssembleListener.java
@@ -0,0 +1,57 @@
+package io.github.thatkawaiisam.assemble;
+
+import io.github.thatkawaiisam.assemble.events.AssembleBoardCreateEvent;
+import io.github.thatkawaiisam.assemble.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/io/github/thatkawaiisam/assemble/AssembleStyle.java b/src/main/java/io/github/thatkawaiisam/assemble/AssembleStyle.java
new file mode 100644
index 0000000..b5b53e3
--- /dev/null
+++ b/src/main/java/io/github/thatkawaiisam/assemble/AssembleStyle.java
@@ -0,0 +1,38 @@
+package io.github.thatkawaiisam.assemble;
+
+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/io/github/thatkawaiisam/assemble/AssembleThread.java b/src/main/java/io/github/thatkawaiisam/assemble/AssembleThread.java
new file mode 100644
index 0000000..2c6f933
--- /dev/null
+++ b/src/main/java/io/github/thatkawaiisam/assemble/AssembleThread.java
@@ -0,0 +1,127 @@
+package io.github.thatkawaiisam.assemble;
+
+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/io/github/thatkawaiisam/assemble/AssembleUtils.java b/src/main/java/io/github/thatkawaiisam/assemble/AssembleUtils.java
new file mode 100644
index 0000000..f7dd1b4
--- /dev/null
+++ b/src/main/java/io/github/thatkawaiisam/assemble/AssembleUtils.java
@@ -0,0 +1,35 @@
+package io.github.thatkawaiisam.assemble;
+
+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/io/github/thatkawaiisam/assemble/events/AssembleBoardCreateEvent.java b/src/main/java/io/github/thatkawaiisam/assemble/events/AssembleBoardCreateEvent.java
new file mode 100644
index 0000000..8ebe3c1
--- /dev/null
+++ b/src/main/java/io/github/thatkawaiisam/assemble/events/AssembleBoardCreateEvent.java
@@ -0,0 +1,31 @@
+package io.github.thatkawaiisam.assemble.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/io/github/thatkawaiisam/assemble/events/AssembleBoardCreatedEvent.java b/src/main/java/io/github/thatkawaiisam/assemble/events/AssembleBoardCreatedEvent.java
new file mode 100644
index 0000000..2f7341f
--- /dev/null
+++ b/src/main/java/io/github/thatkawaiisam/assemble/events/AssembleBoardCreatedEvent.java
@@ -0,0 +1,30 @@
+package io.github.thatkawaiisam.assemble.events;
+
+import io.github.thatkawaiisam.assemble.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/io/github/thatkawaiisam/assemble/events/AssembleBoardDestroyEvent.java b/src/main/java/io/github/thatkawaiisam/assemble/events/AssembleBoardDestroyEvent.java
new file mode 100644
index 0000000..3f68628
--- /dev/null
+++ b/src/main/java/io/github/thatkawaiisam/assemble/events/AssembleBoardDestroyEvent.java
@@ -0,0 +1,31 @@
+package io.github.thatkawaiisam.assemble.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/land/battle/practice/Practice.java b/src/main/java/land/battle/practice/Practice.java
index 7ee5870..3de7dd8 100644
--- a/src/main/java/land/battle/practice/Practice.java
+++ b/src/main/java/land/battle/practice/Practice.java
@@ -7,7 +7,7 @@ import com.solexgames.lib.commons.command.context.CommonsPlayer;
import com.solexgames.lib.processor.config.ConfigFactory;
import com.solexgames.shop.Shop;
import com.solexgames.shop.category.impl.configurable.KillEffectShopCategory;
-import io.github.nosequel.scoreboard.ScoreboardHandler;
+import io.github.thatkawaiisam.assemble.Assemble;
import land.battle.practice.arena.Arena;
import land.battle.practice.board.BoardAdapter;
import land.battle.practice.commands.*;
@@ -115,7 +115,8 @@ public class Practice extends ExtendedJavaPlugin {
this.loadingString.equals(".") ? ".." :
this.loadingString.equals("..") ? "..." : ".", 10L, 10L);
- new ScoreboardHandler(this, new BoardAdapter(), 2L);
+ Assemble assemble = new Assemble(this, new BoardAdapter());
+ assemble.setTicks(2);
CorePlugin.getInstance().addNewSettingHandler(new PracticeSettingsImpl());
diff --git a/src/main/java/land/battle/practice/PracticeConstants.java b/src/main/java/land/battle/practice/PracticeConstants.java
index 028a205..f0f9273 100644
--- a/src/main/java/land/battle/practice/PracticeConstants.java
+++ b/src/main/java/land/battle/practice/PracticeConstants.java
@@ -6,7 +6,6 @@ import land.battle.practice.player.PlayerData;
import land.battle.practice.state.PlayerStateAdapter;
import land.battle.practice.state.impl.*;
import land.battle.practice.util.CC;
-import io.github.nosequel.scoreboard.element.ScoreboardElement;
import lombok.experimental.UtilityClass;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
@@ -58,7 +57,7 @@ public class PracticeConstants {
BOARD_ADAPTERS.put("editor", new EditorBoardAdapter());
}
- public static void handleAdapter(String id, ScoreboardElement element, Player player, PlayerData playerData, Party party) {
+ public static void handleAdapter(String id, List element, Player player, PlayerData playerData, Party party) {
final PlayerStateAdapter adapter = PracticeConstants.BOARD_ADAPTERS.get(id);
if (adapter != null) {
diff --git a/src/main/java/land/battle/practice/arena/Arena.java b/src/main/java/land/battle/practice/arena/Arena.java
index 36c8bb0..00c5013 100644
--- a/src/main/java/land/battle/practice/arena/Arena.java
+++ b/src/main/java/land/battle/practice/arena/Arena.java
@@ -3,6 +3,7 @@ package land.battle.practice.arena;
import land.battle.practice.arena.type.StandaloneArena;
import land.battle.practice.flags.Flag;
import land.battle.practice.location.impl.impl.AsyncLocation;
+import land.battle.practice.util.cuboid.Cuboid;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
diff --git a/src/main/java/land/battle/practice/board/BoardAdapter.java b/src/main/java/land/battle/practice/board/BoardAdapter.java
index 6e1b33e..2ec1d88 100644
--- a/src/main/java/land/battle/practice/board/BoardAdapter.java
+++ b/src/main/java/land/battle/practice/board/BoardAdapter.java
@@ -3,6 +3,7 @@ package land.battle.practice.board;
import com.solexgames.core.CorePlugin;
import com.solexgames.core.player.PotPlayer;
import com.solexgames.core.util.Color;
+import io.github.thatkawaiisam.assemble.AssembleAdapter;
import land.battle.practice.Practice;
import land.battle.practice.PracticeConstants;
import land.battle.practice.party.Party;
@@ -10,77 +11,80 @@ import land.battle.practice.player.PlayerData;
import land.battle.practice.player.PlayerState;
import land.battle.practice.util.Animation;
import land.battle.practice.util.CC;
-import io.github.nosequel.scoreboard.element.ScoreboardElement;
-import io.github.nosequel.scoreboard.element.ScoreboardElementHandler;
import org.bukkit.entity.Player;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* @author BattleLand Team
* @since 8/14/2021
*/
-public class BoardAdapter implements ScoreboardElementHandler {
+public class BoardAdapter implements AssembleAdapter {
+
+ public boolean isState(PlayerData playerData, PlayerState playerState) {
+ return playerData.getPlayerState().equals(playerState);
+ }
@Override
- public ScoreboardElement getElement(Player player) {
- final ScoreboardElement element = new ScoreboardElement();
+ public String getTitle(Player player) {
+ return CC.GOLD + CC.BOLD + (!Practice.getInstance().isHolanda() ? "Battle " + CC.GRAY + "⏐" + CC.WHITE + " Practice" : "Practice");
+ }
+ @Override
+ public List getLines(Player player) {
+ List lines = new ArrayList<>();
final PlayerData playerData = Practice.getInstance().getPlayerManager()
.getPlayerData(player.getUniqueId());
- element.setTitle(CC.GOLD + CC.BOLD + (!Practice.getInstance().isHolanda() ? "Battle " + CC.GRAY + "⏐" + CC.WHITE + " Practice" : "Practice"));
-
if (playerData == null || !playerData.getOptions().isScoreboardEnabled()) {
- return element;
+ return null;
}
final Party party = Practice.getInstance().getPartyManager().getParty(player.getUniqueId());
switch (playerData.getOptions().getScoreboardStyle()) {
case MODERN:
- element.add("");
+ lines.add("");
break;
case OLD:
- element.add(CC.SB_LINE);
+ lines.add(CC.SB_LINE);
break;
}
final boolean queued = this.isState(playerData, PlayerState.QUEUE);
if (this.isState(playerData, PlayerState.SPAWN) || queued) {
- PracticeConstants.handleAdapter("spawn", element, player, playerData, party);
+ PracticeConstants.handleAdapter("spawn", lines, player, playerData, party);
if (queued) {
- PracticeConstants.handleAdapter("queue", element, player, playerData, party);
+ PracticeConstants.handleAdapter("queue", lines, player, playerData, party);
}
if (party != null) {
- PracticeConstants.handleAdapter("party", element, player, playerData, party);
+ PracticeConstants.handleAdapter("party", lines, player, playerData, party);
}
} else if (this.isState(playerData, PlayerState.FIGHTING)) {
- PracticeConstants.handleAdapter("match", element, player, playerData, party);
+ PracticeConstants.handleAdapter("match", lines, player, playerData, party);
} else if (this.isState(playerData, PlayerState.SPECTATING)) {
- PracticeConstants.handleAdapter("spectator", element, player, playerData, party);
+ PracticeConstants.handleAdapter("spectator", lines, player, playerData, party);
} else if (this.isState(playerData, PlayerState.EDITING)) {
- PracticeConstants.handleAdapter("editor", element, player, playerData, party);
+ PracticeConstants.handleAdapter("editor", lines, player, playerData, party);
}
switch (playerData.getOptions().getScoreboardStyle()) {
case MODERN:
- element.add("");
- element.add(CC.GOLD + (Practice.getInstance().isHolanda() ? CC.translate(Animation.getScoreboardFooter()) : "battle.land") + " " + CC.GRAY + " " + CC.GRAY + " ");
+ lines.add("");
+ lines.add(CC.GOLD + (Practice.getInstance().isHolanda() ? CC.translate(Animation.getScoreboardFooter()) : "battle.land") + " " + CC.GRAY + " " + CC.GRAY + " ");
break;
case OLD:
- element.add("");
- element.add(CC.GOLD + (Practice.getInstance().isHolanda() ? CC.translate(Animation.getScoreboardFooter()) : "battle.land"));
- element.add(CC.SB_LINE);
+ lines.add("");
+ lines.add(CC.GOLD + (Practice.getInstance().isHolanda() ? CC.translate(Animation.getScoreboardFooter()) : "battle.land"));
+ lines.add(CC.SB_LINE);
break;
}
- return element;
- }
-
- public boolean isState(PlayerData playerData, PlayerState playerState) {
- return playerData.getPlayerState().equals(playerState);
+ return lines;
}
}
diff --git a/src/main/java/land/battle/practice/listeners/EntityListener.java b/src/main/java/land/battle/practice/listeners/EntityListener.java
index c050539..f55e109 100644
--- a/src/main/java/land/battle/practice/listeners/EntityListener.java
+++ b/src/main/java/land/battle/practice/listeners/EntityListener.java
@@ -79,6 +79,7 @@ public class EntityListener implements Listener {
@EventHandler
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
+ if (!(event.getEntity() instanceof Player || event.getDamager() instanceof Player)) return;
Player whoWasHit = (Player)event.getEntity();
Player whoHit = (Player)event.getDamager();
diff --git a/src/main/java/land/battle/practice/listeners/MovementListener.java b/src/main/java/land/battle/practice/listeners/MovementListener.java
index 06c8cba..418c268 100644
--- a/src/main/java/land/battle/practice/listeners/MovementListener.java
+++ b/src/main/java/land/battle/practice/listeners/MovementListener.java
@@ -8,6 +8,7 @@ import land.battle.practice.player.PlayerData;
import land.battle.practice.player.PlayerState;
import land.battle.practice.util.BlockUtil;
import io.papermc.lib.PaperLib;
+import land.battle.practice.util.cuboid.Cuboid;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
diff --git a/src/main/java/land/battle/practice/listeners/PlayerListener.java b/src/main/java/land/battle/practice/listeners/PlayerListener.java
index b76b36b..240ccb7 100644
--- a/src/main/java/land/battle/practice/listeners/PlayerListener.java
+++ b/src/main/java/land/battle/practice/listeners/PlayerListener.java
@@ -6,6 +6,8 @@ import com.solexgames.core.player.PotPlayer;
import com.solexgames.core.player.prefixes.Prefix;
import com.solexgames.core.util.Color;
import com.solexgames.core.util.StringUtil;
+import com.solexgames.shop.menu.ShopCategoryMenu;
+import io.papermc.lib.PaperLib;
import land.battle.practice.Practice;
import land.battle.practice.PracticeConstants;
import land.battle.practice.PracticeServerType;
@@ -15,7 +17,6 @@ import land.battle.practice.kit.Kit;
import land.battle.practice.kit.PlayerKit;
import land.battle.practice.match.Match;
import land.battle.practice.match.MatchState;
-import land.battle.practice.menu.EventHostMenu;
import land.battle.practice.menu.JoinQueueMenu;
import land.battle.practice.menu.LeaderboardsMenu;
import land.battle.practice.menu.SpectateMenu;
@@ -27,19 +28,15 @@ import land.battle.practice.player.PlayerData;
import land.battle.practice.player.PlayerState;
import land.battle.practice.queue.QueueType;
import land.battle.practice.settings.PracticeSettingsMenu;
+import land.battle.practice.util.BlockCheck;
import land.battle.practice.util.CC;
-import land.battle.practice.util.DeathUtils;
import land.battle.practice.util.PlayerUtil;
-import com.solexgames.shop.menu.ShopCategoryMenu;
-import io.papermc.lib.PaperLib;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.GameMode;
-import org.bukkit.Material;
+import org.bukkit.*;
import org.bukkit.block.Sign;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.*;
import org.bukkit.event.inventory.CraftItemEvent;
@@ -49,10 +46,8 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
-import org.bukkit.util.Vector;
-import java.util.Map;
-import java.util.UUID;
+import java.util.*;
public class PlayerListener implements Listener {
@@ -140,27 +135,27 @@ public class PlayerListener implements Listener {
switch (serverType) {
case PROD_WHITELISTED:
Practice.getInstance().fetchNitroReward(player).whenComplete((aBoolean, throwable) -> {
- if (throwable != null) {
- throwable.printStackTrace();
- }
+ if (throwable != null) {
+ throwable.printStackTrace();
+ }
- final PotPlayer potPlayer = CorePlugin.getInstance()
- .getPlayerManager().getPlayer(player);
+ final PotPlayer potPlayer = CorePlugin.getInstance()
+ .getPlayerManager().getPlayer(player);
- if (aBoolean && !potPlayer.getAllPrefixes().contains("Booster")) {
- final Prefix prefix = Prefix.getByName("Booster");
+ if (aBoolean && !potPlayer.getAllPrefixes().contains("Booster")) {
+ final Prefix prefix = Prefix.getByName("Booster");
- if (prefix != null) {
- potPlayer.getAllPrefixes().add(prefix.getName());
- potPlayer.saveWithoutRemove();
+ if (prefix != null) {
+ potPlayer.getAllPrefixes().add(prefix.getName());
+ potPlayer.saveWithoutRemove();
- player.sendMessage(ChatColor.GREEN + "You've been given access to the " + Color.translate(prefix.getDisplayName()) + ChatColor.GREEN + " prefix.");
- }
+ player.sendMessage(ChatColor.GREEN + "You've been given access to the " + Color.translate(prefix.getDisplayName()) + ChatColor.GREEN + " prefix.");
+ }
- CorePlugin.getInstance().getJedisManager().runCommand(jedis -> {
- jedis.hdel(PracticeConstants.JEDIS_DISCORD_REWARD_CATEGORY, player.getUniqueId().toString());
- });
- }
+ CorePlugin.getInstance().getJedisManager().runCommand(jedis -> {
+ jedis.hdel(PracticeConstants.JEDIS_DISCORD_REWARD_CATEGORY, player.getUniqueId().toString());
+ });
+ }
});
case PROD_RELEASE_DAY:
if (!PracticeConstants.CHANGELOG.isEmpty()) {
@@ -301,7 +296,7 @@ public class PlayerListener implements Listener {
}
}
if (event.getClickedBlock().getType() == Material.CHEST
- || event.getClickedBlock().getType() == Material.ENDER_CHEST) {
+ || event.getClickedBlock().getType() == Material.ENDER_CHEST) {
event.setCancelled(true);
}
}
@@ -698,6 +693,56 @@ public class PlayerListener implements Listener {
}
}
+ @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
+ public void onEvent(PlayerTeleportEvent event) {
+ if (event.getCause().equals(PlayerTeleportEvent.TeleportCause.ENDER_PEARL)) {
+ event.getTo().setX(Math.floor(event.getTo().getX()) + 0.5f);
+ event.getTo().setY(Math.floor(event.getTo().getY()) + 0.5f);
+ event.getTo().setZ(Math.floor(event.getTo().getZ()) + 0.5f);
+ BlockCheck landing = new BlockCheck(event.getTo().getBlock());
+ boolean cancelTeleport = true;
+ if ((event.getFrom().getWorld() == event.getTo().getWorld()) && (event.getFrom().distanceSquared(event.getTo()) < 32768)) {
+ cancelTeleport = false;
+ if (landing.isSafe) {
+ event.getTo().setY(Math.floor(event.getTo().getY()) + landing.adjustY);
+ } else {
+ cancelTeleport = true;
+ double xMin = Math.min(event.getFrom().getX(), event.getTo().getX());
+ double xMax = Math.max(event.getFrom().getX(), event.getTo().getX());
+ double yMin = Math.min(event.getFrom().getY(), event.getTo().getY());
+ double yMax = Math.max(event.getFrom().getY(), event.getTo().getY());
+ double zMin = Math.min(event.getFrom().getZ(), event.getTo().getZ());
+ double zMax = Math.max(event.getFrom().getZ(), event.getTo().getZ());
+ List locations = new ArrayList();
+ for (double x = xMin; x < xMax; x++) {
+ for (double y = yMin; y < yMax; y++) {
+ for (double z = zMin; z < zMax; z++) {
+ locations.add(new Location(event.getTo().getWorld(), Math.floor(x) + 0.5f, Math.floor(y) + 0.5f, Math.floor(z) + 0.5f));
+ }
+ }
+ }
+ locations.sort(Comparator.comparing(location -> event.getTo().distanceSquared(location)));
+ for (Location location : locations) {
+ BlockCheck blockCheck = new BlockCheck(location.getBlock());
+ if (blockCheck.isSafe) {
+ location.setYaw(event.getTo().getYaw());
+ location.setPitch(event.getTo().getPitch());
+ location.setY(Math.floor(location.getY()) + blockCheck.adjustY);
+ event.setTo(location);
+ cancelTeleport = false;
+ break;
+ }
+ }
+ }
+ }
+ if ((cancelTeleport) || (event.getTo().equals(event.getFrom()))) {
+ event.setCancelled(true);
+ event.getPlayer().getInventory().addItem(new ItemStack(Material.ENDER_PEARL, 1));
+ event.getPlayer().updateInventory();
+ }
+ }
+ }
+
@EventHandler
public void onCraft(CraftItemEvent event) {
event.setCancelled(true);
diff --git a/src/main/java/land/battle/practice/menu/duel/DuelMenu.java b/src/main/java/land/battle/practice/menu/duel/DuelMenu.java
index 4984956..5f53c1b 100644
--- a/src/main/java/land/battle/practice/menu/duel/DuelMenu.java
+++ b/src/main/java/land/battle/practice/menu/duel/DuelMenu.java
@@ -23,10 +23,8 @@ import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.lang.reflect.Array;
+import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -109,7 +107,7 @@ public class DuelMenu extends Menu {
)
.toUpdatingButton((player1, clickType) -> {
if (this.kit == null) {
- player.sendMessage(CC.RED + "Voce deve selecionar o kit antes de selecionar a arena");
+ player.sendMessage(CC.RED + "You must select a kit before switching to the arena inventory");
return;
}
@@ -117,23 +115,29 @@ public class DuelMenu extends Menu {
})
);
+ List lore = Practice.getInstance().isHolanda() ? Arrays.asList(
+ CC.GRAY + "Confirm your settings and send",
+ CC.GRAY + "the duel to out.",
+ "",
+ (this.arena == null || this.kit == null ? CC.RED + "[Cannot send duel right now]" : CC.YELLOW + "[Click to send duel to player]")
+ ) : Arrays.asList(
+ CC.GRAY + "Confirmar suas configuraçoes e mandar",
+ CC.GRAY + "o duel para ele.",
+ "",
+ (this.arena == null || this.kit == null ? CC.RED + "[Selecione antes!]" : CC.YELLOW + "[Clique para mandar o duelo]"));
+
buttonMap.put(50, new ItemBuilder(Material.INK_SACK)
- .setDisplayName(CC.GOLD + CC.BOLD + "Confirmar Duel")
- .addLore(
- CC.GRAY + "Confirmar suas configuraçoes e mandar",
- CC.GRAY + "o duel para ele.",
- "",
- (this.arena == null || this.kit == null ? CC.RED + "[Selecione antes!]" : CC.YELLOW + "[Clique para mandar o duelo]")
- )
+ .setDisplayName(CC.GOLD + CC.BOLD + "Confirm Duel")
+ .addLore(lore)
.setDurability(this.arena == null || this.kit == null ? 8 : 10)
.toButton((player1, clickType) -> {
if (this.arena == null) {
- player.sendMessage(CC.RED + "Voce deve selecionar uma arena antes de confirmar o duel.");
+ player.sendMessage(CC.RED + (Practice.getInstance().isHolanda() ? "You must select an arena before confirming the duel." : "Voce deve selecionar uma arena antes de confirmar o duel."));
return;
}
if (this.kit == null) {
- player.sendMessage(CC.RED + "Voce deve selecionar um kit antes de confirmar o duel.");
+ player.sendMessage(CC.RED + (Practice.getInstance().isHolanda() ? "You must select a kit before confirming the duel." : "Voce deve selecionar um kit antes de confirmar o duel."));
return;
}
@@ -194,11 +198,11 @@ public class DuelMenu extends Menu {
final List lore = new ArrayList<>();
if (arena != null && arena.getName().equals(newArena.getName())) {
- lore.add(CC.GRAY + "Voce tem essa arena selecionada.");
+ lore.add(CC.GRAY + (Practice.getInstance().isHolanda() ? "You have this arena selected." : "Voce tem essa arena selecionada."));
lore.add(" ");
}
- lore.add(CC.YELLOW + "[Clique para duelar com essa arena]");
+ lore.add(CC.YELLOW + (Practice.getInstance().isHolanda() ? "[Click to duel with this arena]" : "[Clique para duelar com essa arena]"));
final ItemBuilder itemBuilder = new ItemBuilder(this.newArena.getIcon() == null ? Material.PAPER : this.newArena.getIcon())
.setDisplayName(Color.MAIN_COLOR + CC.BOLD + this.newArena.getName())
@@ -233,11 +237,11 @@ public class DuelMenu extends Menu {
final List lore = new ArrayList<>();
if (kit != null && kit.getName().equals(queue.getName())) {
- lore.add(CC.GRAY + "Voce tem esse kit selecionado.");
+ lore.add(CC.GRAY + (Practice.getInstance().isHolanda() ? "You have this kit selected." : "Voce tem esse kit selecionado."));
lore.add(" ");
}
- lore.add(CC.YELLOW + "[Clique para mandar com esse kit!]");
+ lore.add(CC.YELLOW + (Practice.getInstance().isHolanda() ? "[Click to duel with this kit]" : "[Clique para mandar com esse kit!]"));
final ItemBuilder itemBuilder = new ItemBuilder(this.queue.getIcon().clone())
.setDisplayName(Color.MAIN_COLOR + CC.BOLD + this.queue.getName())
diff --git a/src/main/java/land/battle/practice/util/BlockCheck.java b/src/main/java/land/battle/practice/util/BlockCheck.java
new file mode 100644
index 0000000..29d23fe
--- /dev/null
+++ b/src/main/java/land/battle/practice/util/BlockCheck.java
@@ -0,0 +1,302 @@
+package land.battle.practice.util;
+
+import org.bukkit.block.Block;
+import org.bukkit.material.Openable;
+
+@SuppressWarnings("deprecation")
+public class BlockCheck {
+ public boolean isSafe;
+ public double adjustY;
+
+ public BlockCheck(Block block) {
+ isSafe = false;
+ adjustY = 0;
+ Block above = block.getLocation().clone().add(0, 1, 0).getBlock();
+ Block below = block.getLocation().clone().add(0, -1, 0).getBlock();
+ Block upTwo = block.getLocation().clone().add(0, 2, 0).getBlock();
+ Block downTwo = block.getLocation().clone().add(0, -2, 0).getBlock();
+ if (isSafe(block) && isSafe(above)) {
+ isSafe = true;
+ } else if (isSafe(block) && isSafe(below)) {
+ isSafe = true;
+ adjustY = -1.0f;
+ } else if (isSafe(block)) {
+ if (!isSolid(above) && (isOpenDoor(above) || isTopDoor(above))) {
+ isSafe = true;
+ } else if (!isSolid(below) && ((isTrapDoor(below) && !isTopDoor(below)) || isOpenDoor(below))) {
+ isSafe = true;
+ adjustY = -0.8125f;
+ } else if (!isSolid(above) && !isSolid(below) && isTopSlab(above) && (isSlab(below) && !isTopSlab(below))) {
+ isSafe = true;
+ adjustY = -0.5f;
+ }
+ } else if (isTrapDoor(block) && !isTopDoor(block) && isSafe(above)) {
+ isSafe = true;
+ adjustY = 0.1875f;
+ } else if (isTopDoor(block) && isSafe(below)) {
+ isSafe = true;
+ adjustY = -1.0f;
+ } else if (isSlab(block) && !isTopSlab(block) && isSafe(above)) {
+ if (isSafe(upTwo)) {
+ isSafe = true;
+ } else if (isTopSlab(upTwo) || isTopDoor(upTwo)) {
+ isSafe = true;
+ }
+ if (isSafe) {
+ adjustY = .5f;
+ }
+ } else if (isTopSlab(block) && isSafe(below)) {
+ if (isSafe(downTwo)) {
+ isSafe = true;
+ adjustY = -2.0f;
+ } else if (isSlab(downTwo) && !isTopSlab(downTwo)) {
+ isSafe = true;
+ adjustY = -1.5f;
+ } else if (isTrapDoor(downTwo) && !isTopDoor(downTwo)) {
+ isSafe = true;
+ adjustY = -1.8125f;
+ }
+ }
+ }
+
+ public boolean isSolid(Block block) {
+ int type = block.getType().getId();
+ switch (type) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 7:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 29:
+ case 34:
+ case 33:
+ case 35:
+ case 36:
+ case 41:
+ case 42:
+ case 43:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 52:
+ case 53:
+ case 54:
+ case 56:
+ case 57:
+ case 58:
+ case 60:
+ case 61:
+ case 62:
+ case 64:
+ case 65:
+ case 67:
+ case 71:
+ case 73:
+ case 74:
+ case 78:
+ case 79:
+ case 80:
+ case 81:
+ case 82:
+ case 84:
+ case 85:
+ case 86:
+ case 87:
+ case 88:
+ case 89:
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 97:
+ case 98:
+ case 99:
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 106:
+ case 107:
+ case 108:
+ case 109:
+ case 110:
+ case 111:
+ case 112:
+ case 113:
+ case 114:
+ case 116:
+ case 117:
+ case 118:
+ case 120:
+ case 121:
+ case 122:
+ case 123:
+ case 124:
+ case 125:
+ case 127:
+ case 128:
+ case 129:
+ case 130:
+ case 133:
+ case 134:
+ case 135:
+ case 136:
+ case 137:
+ case 138:
+ case 139:
+ case 140:
+ case 144:
+ case 145:
+ case 146:
+ case 149:
+ case 150:
+ case 151:
+ case 152:
+ case 153:
+ case 154:
+ case 155:
+ case 156:
+ case 158:
+ case 159:
+ case 160:
+ case 161:
+ case 162:
+ case 163:
+ case 164:
+ case 165:
+ case 166:
+ case 168:
+ case 169:
+ case 170:
+ case 171:
+ case 172:
+ case 173:
+ case 174:
+ case 178:
+ case 179:
+ case 180:
+ case 181:
+ case 183:
+ case 184:
+ case 185:
+ case 186:
+ case 187:
+ case 188:
+ case 189:
+ case 190:
+ case 191:
+ case 192:
+ case 193:
+ case 194:
+ case 195:
+ case 196:
+ case 197:
+ case 198:
+ case 199:
+ case 200:
+ case 201:
+ case 202:
+ case 203:
+ case 204:
+ case 206:
+ case 207:
+ case 208:
+ case 210:
+ case 211:
+ case 212:
+ case 213:
+ case 214:
+ case 215:
+ case 216:
+ case 218:
+ case 219:
+ case 220:
+ case 221:
+ case 222:
+ case 223:
+ case 224:
+ case 225:
+ case 226:
+ case 227:
+ case 228:
+ case 229:
+ case 230:
+ case 231:
+ case 232:
+ case 233:
+ case 234:
+ case 235:
+ case 236:
+ case 237:
+ case 238:
+ case 239:
+ case 240:
+ case 241:
+ case 242:
+ case 243:
+ case 244:
+ case 245:
+ case 246:
+ case 247:
+ case 248:
+ case 249:
+ case 250:
+ case 251:
+ case 252:
+ case 255:
+ case 397:
+ case 355:
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isSlab(Block block) {
+ return block.getType().getId() == 44 || block.getType().getId() == 126 || block.getType().getId() == 182;
+ }
+
+ private boolean isTrapDoor(Block block) {
+ return block.getType().getId() == 96 || block.getType().getId() == 167;
+ }
+
+ private boolean isOpenDoor(Block block) {
+ return (isTrapDoor(block) && ((Openable) block.getState().getData()).isOpen());
+ }
+
+ private boolean isTopDoor(Block block) {
+ if (!isTrapDoor(block)) {
+ return false;
+ }
+ return block.getData() == 8 || block.getData() == 9 || block.getData() == 10 || block.getData() == 11;
+ }
+
+ private boolean isTopSlab(Block block) {
+ if (!isSlab(block)) {
+ return false;
+ }
+ return block.getData() == 8 || block.getData() == 9 || block.getData() == 10 || block.getData() == 11 || block.getData() == 12 || block.getData() == 13 || block.getData() == 14 || block.getData() == 15;
+ }
+
+ private boolean isSafe(Block block) {
+ return !isSolid(block) && !isSlab(block) && (!isTrapDoor(block) || isOpenDoor(block));
+ }
+}
\ No newline at end of file