From da092c2778c14b19c06c5e3a93ad759deb1174f6 Mon Sep 17 00:00:00 2001 From: Trixkz Date: Fri, 20 Sep 2024 06:00:31 -0400 Subject: [PATCH] Initial commit. --- pom.xml | 90 + src/main/java/aether/Aether.java | 198 +++ src/main/java/aether/AetherOptions.java | 18 + .../java/aether/event/BoardCreateEvent.java | 27 + src/main/java/aether/scoreboard/Board.java | 129 ++ .../java/aether/scoreboard/BoardAdapter.java | 17 + .../java/aether/scoreboard/BoardEntry.java | 90 + .../scoreboard/cooldown/BoardCooldown.java | 42 + .../scoreboard/cooldown/BoardFormat.java | 5 + .../java/com/loganmagnan/hubcore/HubCore.java | 188 ++ .../hubcore/chatcolor/ColorSet.java | 17 + .../hubcore/chatcolor/GradientColor.java | 16 + .../hubcore/commands/SetSpawnCommand.java | 38 + .../hubcore/commands/SpawnCommand.java | 24 + .../hubcore/listeners/BlockBreakListener.java | 24 + .../hubcore/listeners/BlockPlaceListener.java | 52 + .../listeners/CreatureSpawnListener.java | 16 + .../listeners/EntityDamageListener.java | 16 + .../listeners/FoodLevelChangeListener.java | 22 + .../listeners/InventoryClickListener.java | 26 + .../hubcore/listeners/MenuListener.java | 29 + .../hubcore/listeners/PlayerDataListener.java | 105 ++ .../listeners/PlayerDropItemListener.java | 16 + .../listeners/PlayerInteractListener.java | 83 + .../hubcore/listeners/PlayerMoveListener.java | 50 + .../listeners/PlayerPickupItemListener.java | 16 + .../listeners/PlayerToggleFlightListener.java | 28 + .../listeners/WeatherChangeListener.java | 16 + .../hubcore/managers/PlayerDataManager.java | 86 + .../hubcore/managers/SpawnManager.java | 46 + .../hubcore/managers/cosmetic/Cosmetic.java | 36 + .../managers/cosmetic/CosmeticManager.java | 55 + .../managers/cosmetic/CosmeticType.java | 6 + .../hubcore/managers/item/ActionType.java | 10 + .../hubcore/managers/item/HotBarItem.java | 33 + .../hubcore/managers/item/HotBarManager.java | 43 + .../hubcore/menus/CosmeticTypeMenu.java | 133 ++ .../hubcore/menus/CosmeticsSelectorMenu.java | 71 + .../hubcore/menus/ServerSelectorMenu.java | 98 + .../hubcore/menus/SettingsSelectorMenu.java | 98 + .../hubcore/menusystem/ItemStackButton.java | 29 + .../loganmagnan/hubcore/menusystem/Menu.java | 64 + .../hubcore/menusystem/PaginatedMenu.java | 49 + .../hubcore/menusystem/PlayerMenuUtil.java | 20 + .../hubcore/playerdata/PlayerData.java | 41 + .../hubcore/playerdata/PlayerSettings.java | 13 + .../hubcore/playerdata/PlayerState.java | 6 + .../currentgame/PlayerCurrentGameData.java | 10 + .../scoreboard/ScoreboardProvider.java | 104 ++ .../scoreboard/ScoreboardRunnable.java | 82 + .../hubcore/scoreboard/SimpleBoard.java | 174 ++ .../hubcore/utils/AsyncScheduler.java | 34 + .../loganmagnan/hubcore/utils/BlockUtils.java | 47 + .../hubcore/utils/BungeeUtils.java | 64 + .../com/loganmagnan/hubcore/utils/Cache.java | 29 + .../hubcore/utils/ClassRegistrationUtils.java | 95 + .../loganmagnan/hubcore/utils/Clickable.java | 51 + .../loganmagnan/hubcore/utils/ColorUtils.java | 193 ++ .../com/loganmagnan/hubcore/utils/Cuboid.java | 45 + .../hubcore/utils/CustomLocation.java | 125 ++ .../hubcore/utils/ItemBuilder.java | 184 ++ .../loganmagnan/hubcore/utils/ItemUtil.java | 167 ++ .../hubcore/utils/LocationUtils.java | 34 + .../loganmagnan/hubcore/utils/MathUtil.java | 58 + .../loganmagnan/hubcore/utils/NBTEditor.java | 1571 +++++++++++++++++ .../com/loganmagnan/hubcore/utils/Pair.java | 17 + .../hubcore/utils/ParameterType.java | 14 + .../loganmagnan/hubcore/utils/PlayerUtil.java | 43 + .../hubcore/utils/SpigotUtils.java | 46 + .../hubcore/utils/StringUtils.java | 244 +++ .../loganmagnan/hubcore/utils/TeamAction.java | 8 + .../loganmagnan/hubcore/utils/TimeUtil.java | 141 ++ .../loganmagnan/hubcore/utils/TimeUtils.java | 110 ++ .../hubcore/utils/TimerRunnable.java | 35 + .../loganmagnan/hubcore/utils/TtlHandler.java | 8 + .../loganmagnan/hubcore/utils/TtlHashMap.java | 128 ++ .../com/loganmagnan/hubcore/utils/Utils.java | 94 + .../loganmagnan/hubcore/utils/Vector3.java | 76 + .../loganmagnan/hubcore/utils/WorldUtils.java | 322 ++++ .../hubcore/utils/command/BaseCommand.java | 12 + .../hubcore/utils/command/BukkitCommand.java | 82 + .../utils/command/BukkitCompleter.java | 48 + .../hubcore/utils/command/Command.java | 23 + .../utils/command/CommandArguments.java | 52 + .../utils/command/CommandFramework.java | 172 ++ .../hubcore/utils/command/Completer.java | 15 + .../hubcore/utils/config/ConfigCursor.java | 88 + .../hubcore/utils/config/FileConfig.java | 50 + .../hubcore/utils/config/file/Config.java | 39 + .../hubcore/utils/config/file/ConfigFile.java | 103 ++ .../hubcore/utils/cuboid/Cuboid.java | 497 ++++++ .../utils/cuboid/CuboidBlockIterator.java | 97 + .../hubcore/utils/cuboid/CuboidDirection.java | 46 + .../utils/cuboid/CuboidLocationIterator.java | 97 + src/main/resources/config.yml | 10 + src/main/resources/cosmetics.yml | 28 + src/main/resources/hotbar.yml | 49 + src/main/resources/menus.yml | 79 + src/main/resources/messages.yml | 7 + src/main/resources/plugin.yml | 5 + src/main/resources/scoreboard.yml | 16 + 101 files changed, 8303 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/java/aether/Aether.java create mode 100644 src/main/java/aether/AetherOptions.java create mode 100644 src/main/java/aether/event/BoardCreateEvent.java create mode 100644 src/main/java/aether/scoreboard/Board.java create mode 100644 src/main/java/aether/scoreboard/BoardAdapter.java create mode 100644 src/main/java/aether/scoreboard/BoardEntry.java create mode 100644 src/main/java/aether/scoreboard/cooldown/BoardCooldown.java create mode 100644 src/main/java/aether/scoreboard/cooldown/BoardFormat.java create mode 100644 src/main/java/com/loganmagnan/hubcore/HubCore.java create mode 100644 src/main/java/com/loganmagnan/hubcore/chatcolor/ColorSet.java create mode 100644 src/main/java/com/loganmagnan/hubcore/chatcolor/GradientColor.java create mode 100644 src/main/java/com/loganmagnan/hubcore/commands/SetSpawnCommand.java create mode 100644 src/main/java/com/loganmagnan/hubcore/commands/SpawnCommand.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/BlockBreakListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/BlockPlaceListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/CreatureSpawnListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/EntityDamageListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/FoodLevelChangeListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/InventoryClickListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/MenuListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/PlayerDataListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/PlayerDropItemListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/PlayerInteractListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/PlayerMoveListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/PlayerPickupItemListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/PlayerToggleFlightListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/listeners/WeatherChangeListener.java create mode 100644 src/main/java/com/loganmagnan/hubcore/managers/PlayerDataManager.java create mode 100644 src/main/java/com/loganmagnan/hubcore/managers/SpawnManager.java create mode 100644 src/main/java/com/loganmagnan/hubcore/managers/cosmetic/Cosmetic.java create mode 100644 src/main/java/com/loganmagnan/hubcore/managers/cosmetic/CosmeticManager.java create mode 100644 src/main/java/com/loganmagnan/hubcore/managers/cosmetic/CosmeticType.java create mode 100644 src/main/java/com/loganmagnan/hubcore/managers/item/ActionType.java create mode 100644 src/main/java/com/loganmagnan/hubcore/managers/item/HotBarItem.java create mode 100644 src/main/java/com/loganmagnan/hubcore/managers/item/HotBarManager.java create mode 100644 src/main/java/com/loganmagnan/hubcore/menus/CosmeticTypeMenu.java create mode 100644 src/main/java/com/loganmagnan/hubcore/menus/CosmeticsSelectorMenu.java create mode 100644 src/main/java/com/loganmagnan/hubcore/menus/ServerSelectorMenu.java create mode 100644 src/main/java/com/loganmagnan/hubcore/menus/SettingsSelectorMenu.java create mode 100644 src/main/java/com/loganmagnan/hubcore/menusystem/ItemStackButton.java create mode 100644 src/main/java/com/loganmagnan/hubcore/menusystem/Menu.java create mode 100644 src/main/java/com/loganmagnan/hubcore/menusystem/PaginatedMenu.java create mode 100644 src/main/java/com/loganmagnan/hubcore/menusystem/PlayerMenuUtil.java create mode 100644 src/main/java/com/loganmagnan/hubcore/playerdata/PlayerData.java create mode 100644 src/main/java/com/loganmagnan/hubcore/playerdata/PlayerSettings.java create mode 100644 src/main/java/com/loganmagnan/hubcore/playerdata/PlayerState.java create mode 100644 src/main/java/com/loganmagnan/hubcore/playerdata/currentgame/PlayerCurrentGameData.java create mode 100644 src/main/java/com/loganmagnan/hubcore/scoreboard/ScoreboardProvider.java create mode 100644 src/main/java/com/loganmagnan/hubcore/scoreboard/ScoreboardRunnable.java create mode 100644 src/main/java/com/loganmagnan/hubcore/scoreboard/SimpleBoard.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/AsyncScheduler.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/BlockUtils.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/BungeeUtils.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/Cache.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/ClassRegistrationUtils.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/Clickable.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/ColorUtils.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/Cuboid.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/CustomLocation.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/ItemBuilder.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/ItemUtil.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/LocationUtils.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/MathUtil.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/NBTEditor.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/Pair.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/ParameterType.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/PlayerUtil.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/SpigotUtils.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/StringUtils.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/TeamAction.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/TimeUtil.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/TimeUtils.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/TimerRunnable.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/TtlHandler.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/TtlHashMap.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/Utils.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/Vector3.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/WorldUtils.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/command/BaseCommand.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/command/BukkitCommand.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/command/BukkitCompleter.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/command/Command.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/command/CommandArguments.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/command/CommandFramework.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/command/Completer.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/config/ConfigCursor.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/config/FileConfig.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/config/file/Config.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/config/file/ConfigFile.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/cuboid/Cuboid.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/cuboid/CuboidBlockIterator.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/cuboid/CuboidDirection.java create mode 100644 src/main/java/com/loganmagnan/hubcore/utils/cuboid/CuboidLocationIterator.java create mode 100644 src/main/resources/config.yml create mode 100644 src/main/resources/cosmetics.yml create mode 100644 src/main/resources/hotbar.yml create mode 100644 src/main/resources/menus.yml create mode 100644 src/main/resources/messages.yml create mode 100644 src/main/resources/plugin.yml create mode 100644 src/main/resources/scoreboard.yml diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..a4ee8ef --- /dev/null +++ b/pom.xml @@ -0,0 +1,90 @@ + + + 4.0.0 + + com.loganmagnan + HubCore + 1.1 + + + 17 + UTF-8 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + false + + + + + + + + src/main/resources + true + + + + + + + papermc + https://repo.papermc.io/repository/maven-public/ + + + jitpack.io + https://jitpack.io + + + + + + io.papermc.paper + paper-api + 1.20-R0.1-SNAPSHOT + provided + + + org.projectlombok + lombok + 1.18.20 + provided + + + com.loganmagnan + Vortex + 1.0 + ${project.basedir}/libraries/Vortex-1.0.jar + system + + + com.github.MilkBowl + VaultAPI + 1.7 + provided + + + \ No newline at end of file diff --git a/src/main/java/aether/Aether.java b/src/main/java/aether/Aether.java new file mode 100644 index 0000000..d71d469 --- /dev/null +++ b/src/main/java/aether/Aether.java @@ -0,0 +1,198 @@ +package aether; + +import aether.event.BoardCreateEvent; +import aether.scoreboard.Board; +import aether.scoreboard.BoardAdapter; +import aether.scoreboard.BoardEntry; +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scoreboard.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static aether.AetherOptions.defaultOptions; + +public class Aether implements Listener { + + @Getter BoardAdapter adapter; + @Getter private JavaPlugin plugin; + @Getter private AetherOptions options; + + private Pattern HEX_PATTERN = Pattern.compile("&#([A-Fa-f0-9]{6})"); + + public Aether(JavaPlugin plugin, BoardAdapter adapter, AetherOptions options) { + this.options = options; + this.plugin = plugin; + + Bukkit.getPluginManager().registerEvents(this, plugin); + + setAdapter(adapter); + run(); + } + + public Aether(JavaPlugin plugin, BoardAdapter adapter) { + this(plugin, adapter, defaultOptions()); + } + + public Aether(JavaPlugin plugin) { + this(plugin, null, defaultOptions()); + } + + private void run() { + new BukkitRunnable() { + @Override + public void run() { + if (adapter == null) return; + for (Player player : Bukkit.getOnlinePlayers()) { + Board board = Board.getByPlayer(player); + if (board != null) { + List scores = adapter.getScoreboard(player, board, board.getCooldowns()); + List translatedScores = new ArrayList<>(); + if (scores == null) { + if (!board.getEntries().isEmpty()) { + for (BoardEntry boardEntry : board.getEntries()) { + boardEntry.remove(); + } + board.getEntries().clear(); + } + continue; + } + + for (String line : scores) { + translatedScores.add(ChatColor.translateAlternateColorCodes('&', line)); + } + + if (!options.scoreDirectionDown()) { + Collections.reverse(scores); + } + + Scoreboard scoreboard = board.getScoreboard(); + Objective objective = board.getObjective(); + + if (!(objective.getDisplayName().equals(adapter.getTitle(player)))) { + objective.setDisplayName(ChatColor.translateAlternateColorCodes('&', adapter.getTitle(player))); + } + + outer: + for (int i = 0; i < scores.size(); i++) { + String text = scores.get(i); + int position; + if (options.scoreDirectionDown()) { + position = 15 - i; + } else { + position = i + 1; + } + + Iterator iterator = new ArrayList<>(board.getEntries()).iterator(); + while (iterator.hasNext()) { + BoardEntry boardEntry = iterator.next(); + Score score = objective.getScore(boardEntry.getKey()); + + if (score != null && boardEntry.getText().equals(ChatColor.translateAlternateColorCodes('&', text))) { + if (score.getScore() == position) { + continue outer; + } + } + } + + int positionToSearch = options.scoreDirectionDown() ? 15 - position : position - 1; + + iterator = board.getEntries().iterator(); + while (iterator.hasNext()) { + BoardEntry boardEntry = iterator.next(); + int entryPosition = scoreboard.getObjective(DisplaySlot.SIDEBAR).getScore(boardEntry.getKey()).getScore(); + + if (!options.scoreDirectionDown()) { + if (entryPosition > scores.size()) { + iterator.remove(); + boardEntry.remove(); + } + } + + } + + BoardEntry entry = board.getByPosition(positionToSearch); + + if (entry == null) { + new BoardEntry(board, text).send(position); + } else { + entry.setText(text).setup().send(position); + } + + if (board.getEntries().size() > scores.size()) { + iterator = board.getEntries().iterator(); + while (iterator.hasNext()) { + BoardEntry boardEntry = iterator.next(); + if ((!translatedScores.contains(boardEntry.getText())) || Collections.frequency(board.getBoardEntriesFormatted(), boardEntry.getText()) > 1) { + iterator.remove(); + boardEntry.remove(); + } + } + } + } + adapter.onScoreboardCreate(player, scoreboard); + player.setScoreboard(scoreboard); + } + } + } + }.runTaskTimerAsynchronously(plugin, 20L, 2L); + } + + public void setAdapter(BoardAdapter adapter) { + this.adapter = adapter; + for (Player player : Bukkit.getOnlinePlayers()) { + Board board = Board.getByPlayer(player); + if (board != null) { + Board.getBoards().remove(board); + } + Bukkit.getPluginManager().callEvent(new BoardCreateEvent(new Board(player, this, options), player)); + } + } + + @EventHandler + public void onPlayerJoinEvent(PlayerJoinEvent event) { + if (Board.getByPlayer(event.getPlayer()) == null) { + Bukkit.getPluginManager().callEvent(new BoardCreateEvent(new Board(event.getPlayer(), this, options), event.getPlayer())); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerQuitEvent(PlayerQuitEvent event) { + Board board = Board.getByPlayer(event.getPlayer()); + if (board != null) { + Board.getBoards().remove(board); + } + } + + public String colorize(String message) { + return ChatColor.translateAlternateColorCodes('&', message); + } + + public String translateHexColorCodes(String message) { + char colorChar = '§'; + Matcher matcher = HEX_PATTERN.matcher(message); + StringBuffer buffer = new StringBuffer(message.length() + 32); + while (matcher.find()) { + String group = matcher.group(1); + matcher.appendReplacement(buffer, "§x§" + group + .charAt(0) + '§' + group.charAt(1) + '§' + group + .charAt(2) + '§' + group.charAt(3) + '§' + group + .charAt(4) + '§' + group.charAt(5)); + } + return matcher.appendTail(buffer).toString(); + } +} diff --git a/src/main/java/aether/AetherOptions.java b/src/main/java/aether/AetherOptions.java new file mode 100644 index 0000000..526c513 --- /dev/null +++ b/src/main/java/aether/AetherOptions.java @@ -0,0 +1,18 @@ +package aether; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +@Getter +@Setter +@Accessors(chain = true, fluent = true) +public class AetherOptions { + + private boolean hook; + private boolean scoreDirectionDown; + + static AetherOptions defaultOptions() { + return new AetherOptions().hook(false).scoreDirectionDown(false); + } +} diff --git a/src/main/java/aether/event/BoardCreateEvent.java b/src/main/java/aether/event/BoardCreateEvent.java new file mode 100644 index 0000000..0cc018e --- /dev/null +++ b/src/main/java/aether/event/BoardCreateEvent.java @@ -0,0 +1,27 @@ +package aether.event; + +import aether.scoreboard.Board; +import lombok.Getter; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class BoardCreateEvent extends Event { + + private static final HandlerList HANDLERS = new HandlerList(); + @Getter private final Board board; + @Getter private final Player player; + + public BoardCreateEvent(Board board, Player player) { + this.board = board; + this.player = player; + } + + public static HandlerList getHandlerList() { + return HANDLERS; + } + + public HandlerList getHandlers() { + return HANDLERS; + } +} diff --git a/src/main/java/aether/scoreboard/Board.java b/src/main/java/aether/scoreboard/Board.java new file mode 100644 index 0000000..2bdc888 --- /dev/null +++ b/src/main/java/aether/scoreboard/Board.java @@ -0,0 +1,129 @@ +package aether.scoreboard; + +import aether.Aether; +import aether.AetherOptions; +import aether.scoreboard.cooldown.BoardCooldown; +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; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class Board { + + @Getter private static Set boards = new HashSet<>(); + + private final Aether aether; + private final AetherOptions options; + + @Getter private Scoreboard scoreboard; + @Getter private Player player; + @Getter private Objective objective; + @Getter private Set keys; + @Getter private List entries; + + private Set cooldowns; + + public Board(Player player, Aether aether, AetherOptions options) { + this.player = player; + this.aether = aether; + this.options = options; + + this.keys = new HashSet<>(); + this.entries = new ArrayList<>(); + + this.cooldowns = new HashSet<>(); + + setup(); + } + + public static Board getByPlayer(Player player) { + for (Board board : boards) { + if (board.getPlayer().getName().equals(player.getName())) { + return board; + } + } + + return null; + } + + private void setup() { + if (options.hook() && !player.getScoreboard().equals(Bukkit.getScoreboardManager().getMainScoreboard())) { + scoreboard = player.getScoreboard(); + } else { + scoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); + } + + objective = scoreboard.registerNewObjective("glaedr_is_shit", "dummy"); + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + + if (aether.getAdapter() != null) { + objective.setDisplayName(ChatColor.translateAlternateColorCodes('&', aether.getAdapter().getTitle(player))); + } else { + objective.setDisplayName("Default Title"); + } + + boards.add(this); + } + + public String getNewKey(BoardEntry entry) { + for (ChatColor color : ChatColor.values()) { + String colorText = color + "" + ChatColor.WHITE; + if (entry.getText().length() > 16) { + String sub = entry.getText().substring(0, 16); + colorText = colorText + ChatColor.getLastColors(sub); + } + + if (!keys.contains(colorText)) { + keys.add(colorText); + return colorText; + } + } + + throw new IndexOutOfBoundsException("No more keys available!"); + } + + public List getBoardEntriesFormatted() { + List toReturn = new ArrayList<>(); + for (BoardEntry entry : new ArrayList<>(entries)) { + toReturn.add(entry.getText()); + } + + return toReturn; + } + + public BoardEntry getByPosition(int position) { + int i = 0; + + for (BoardEntry board : entries) { + if (i == position) { + return board; + } + i++; + } + + return null; + } + + public BoardCooldown getCooldown(String id) { + for (BoardCooldown cooldown : getCooldowns()) { + if (cooldown.getId().equals(id)) { + return cooldown; + } + } + + return null; + } + + public Set getCooldowns() { + cooldowns.removeIf(cooldown -> System.currentTimeMillis() >= cooldown.getEnd()); + return cooldowns; + } +} diff --git a/src/main/java/aether/scoreboard/BoardAdapter.java b/src/main/java/aether/scoreboard/BoardAdapter.java new file mode 100644 index 0000000..2b1b1b8 --- /dev/null +++ b/src/main/java/aether/scoreboard/BoardAdapter.java @@ -0,0 +1,17 @@ +package aether.scoreboard; + +import aether.scoreboard.cooldown.BoardCooldown; +import org.bukkit.entity.Player; +import org.bukkit.scoreboard.Scoreboard; + +import java.util.List; +import java.util.Set; + +public interface BoardAdapter { + + String getTitle(Player player); + + List getScoreboard(Player player, Board board, Set cooldowns); + + void onScoreboardCreate(Player player, Scoreboard board); +} diff --git a/src/main/java/aether/scoreboard/BoardEntry.java b/src/main/java/aether/scoreboard/BoardEntry.java new file mode 100644 index 0000000..903832e --- /dev/null +++ b/src/main/java/aether/scoreboard/BoardEntry.java @@ -0,0 +1,90 @@ +package aether.scoreboard; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.bukkit.ChatColor; +import org.bukkit.scoreboard.Objective; +import org.bukkit.scoreboard.Score; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; + +@Accessors(chain = true) +public class BoardEntry { + + @Getter private Board board; + @Getter @Setter private String text; + @Getter private String originalText; + @Getter private String key; + @Getter private Team team; + + public BoardEntry(Board board, String text) { + this.board = board; + this.text = text; + this.originalText = text; + this.key = board.getNewKey(this); + + setup(); + } + + public BoardEntry setup() { + Scoreboard scoreboard = board.getScoreboard(); + + text = ChatColor.translateAlternateColorCodes('&', text); + + String teamName = key; + + if (teamName.length() > 16) { + teamName = teamName.substring(0, 16); + } + + if (scoreboard.getTeam(teamName) != null) { + team = scoreboard.getTeam(teamName); + } else { + team = scoreboard.registerNewTeam(teamName); + } + + if (!(team.getEntries().contains(key))) { + team.addEntry(key); + } + + if (!(board.getEntries().contains(this))) { + board.getEntries().add(this); + } + + return this; + } + + public BoardEntry send(int position) { + Objective objective = board.getObjective(); + + if (text.length() > 16) { + boolean fix = text.toCharArray()[15] == ChatColor.COLOR_CHAR; + + String prefix = fix ? text.substring(0, 15) : text.substring(0, 16); + String suffix = fix ? text.substring(15) : ChatColor.getLastColors(prefix) + text.substring(16); + + team.setPrefix(prefix); + + if (suffix.length() > 16) { + team.setSuffix(suffix.substring(0, 16)); + } else { + team.setSuffix(suffix); + } + } else { + team.setPrefix(text); + team.setSuffix(""); + } + + Score score = objective.getScore(key); + score.setScore(position); + + return this; + } + + public void remove() { + board.getKeys().remove(key); + board.getScoreboard().resetScores(key); + } + +} diff --git a/src/main/java/aether/scoreboard/cooldown/BoardCooldown.java b/src/main/java/aether/scoreboard/cooldown/BoardCooldown.java new file mode 100644 index 0000000..cfb9482 --- /dev/null +++ b/src/main/java/aether/scoreboard/cooldown/BoardCooldown.java @@ -0,0 +1,42 @@ +package aether.scoreboard.cooldown; + +import aether.scoreboard.Board; +import lombok.Getter; +import org.apache.commons.lang3.time.DurationFormatUtils; + +import java.text.DecimalFormat; + +public class BoardCooldown { + + private static final DecimalFormat SECONDS_FORMATTER = new DecimalFormat("#0.0"); + + @Getter private final Board board; + @Getter private final String id; + @Getter private final double duration; + @Getter private final long end; + + public BoardCooldown(Board board, String id, double duration) { + this.board = board; + this.id = id; + this.duration = duration; + this.end = (long) (System.currentTimeMillis() + (duration * 1000)); + + board.getCooldowns().add(this); + } + + public String getFormattedString(BoardFormat format) { + if (format == null) { + throw new NullPointerException(); + } + if (format == BoardFormat.SECONDS) { + return SECONDS_FORMATTER.format(((end - System.currentTimeMillis()) / 1000.0f)); + } else { + return DurationFormatUtils.formatDuration(end - System.currentTimeMillis(), "mm:ss"); + } + } + + public void cancel() { + board.getCooldowns().remove(this); + } + +} \ No newline at end of file diff --git a/src/main/java/aether/scoreboard/cooldown/BoardFormat.java b/src/main/java/aether/scoreboard/cooldown/BoardFormat.java new file mode 100644 index 0000000..24f34cf --- /dev/null +++ b/src/main/java/aether/scoreboard/cooldown/BoardFormat.java @@ -0,0 +1,5 @@ +package aether.scoreboard.cooldown; + +public enum BoardFormat { + SECONDS, MINUTES, HOURS +} diff --git a/src/main/java/com/loganmagnan/hubcore/HubCore.java b/src/main/java/com/loganmagnan/hubcore/HubCore.java new file mode 100644 index 0000000..7f1ac7f --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/HubCore.java @@ -0,0 +1,188 @@ +package com.loganmagnan.hubcore; + +import aether.Aether; +import com.loganmagnan.hubcore.managers.PlayerDataManager; +import com.loganmagnan.hubcore.managers.SpawnManager; +import com.loganmagnan.hubcore.managers.cosmetic.CosmeticManager; +import com.loganmagnan.hubcore.managers.item.HotBarManager; +import com.loganmagnan.hubcore.menusystem.PlayerMenuUtil; +import com.loganmagnan.hubcore.playerdata.PlayerData; +import com.loganmagnan.hubcore.scoreboard.ScoreboardProvider; +import com.loganmagnan.hubcore.scoreboard.ScoreboardRunnable; +import com.loganmagnan.hubcore.scoreboard.SimpleBoard; +import com.loganmagnan.hubcore.utils.BungeeUtils; +import com.loganmagnan.hubcore.utils.command.CommandFramework; +import com.loganmagnan.hubcore.utils.ClassRegistrationUtils; +import com.loganmagnan.hubcore.utils.ColorUtils; +import com.loganmagnan.hubcore.utils.Utils; +import com.loganmagnan.hubcore.utils.config.FileConfig; +import com.loganmagnan.hubcore.utils.config.file.Config; +import lombok.Getter; +import lombok.Setter; +import net.milkbowl.vault.chat.Chat; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.permissions.Permission; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.HashMap; + +@Getter +@Setter +public class HubCore extends JavaPlugin { + + @Getter private static HubCore instance; + + private Config mainConfig; + private FileConfig messagesConfig; + private FileConfig scoreboardConfig; + private FileConfig hotBarConfig; + private FileConfig menusConfig; + private FileConfig cosmeticsConfig; + + private PlayerDataManager playerDataManager; + private HotBarManager hotBarManager; + private SpawnManager spawnManager; + private CosmeticManager cosmeticManager; + + private HashMap playerMenuUtilMap = new HashMap<>(); + + private CommandFramework commandFramework = new CommandFramework(this); + + private Chat chat; + private Permission perms; + + @Override + public void onEnable() { + instance = this; + + this.saveDefaultConfig(); + this.mainConfig = new Config("config", this); + this.messagesConfig = new FileConfig(this, "messages.yml"); + this.scoreboardConfig = new FileConfig(this, "scoreboard.yml"); + this.hotBarConfig = new FileConfig(this, "hotbar.yml"); + this.menusConfig = new FileConfig(this, "menus.yml"); + this.cosmeticsConfig = new FileConfig(this, "cosmetics.yml"); + + Bukkit.getConsoleSender().sendMessage(Utils.chatBar); + Bukkit.getConsoleSender().sendMessage(ColorUtils.getMessageType("&dHubCore &7- &av" + this.getDescription().getVersion())); + Bukkit.getConsoleSender().sendMessage(ColorUtils.getMessageType("&7Made by &eLoganM Development")); + Bukkit.getConsoleSender().sendMessage(Utils.chatBar); + + this.getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); + this.getServer().getMessenger().registerIncomingPluginChannel(this, "BungeeCord", new BungeeUtils()); + this.loadCommands(); + this.loadManagers(); + this.loadListeners(); + this.loadRunnables(); + + for (World world : Bukkit.getWorlds()) { + for (Entity entity : world.getEntities()) { + if (entity.getType() != EntityType.PLAYER && entity.getType() != EntityType.ITEM_FRAME) { + entity.remove(); + } + } + + world.setGameRuleValue("doDaylightCycle", "false"); + world.setTime(0L); + world.setStorm(false); + } + + if (this.getServer().getPluginManager().getPlugin("Vault") != null) { + this.setupChat(); + this.setupPermissions(); + } + } + + @Override + public void onDisable() { + for (Player player : this.getServer().getOnlinePlayers()) { + PlayerData playerData = this.playerDataManager.getPlayerData(player.getUniqueId()); + + for (Block block : playerData.getBlocks()) { + if (block.getType() == Material.AIR) { + continue; + } + + block.setType(Material.AIR); + } + + this.playerDataManager.savePlayerData(playerData); + } + + for (World world : Bukkit.getWorlds()) { + for (Entity entity : world.getEntities()) { + if (entity.getType() == EntityType.DROPPED_ITEM) { + entity.remove(); + } + } + + for (Chunk chunk : world.getLoadedChunks()) { + chunk.unload(true); + } + } + + instance = null; + } + + public void loadCommands() { + ClassRegistrationUtils.loadCommands("com.loganmagnan.hubcore.commands"); + } + + public void loadManagers() { + this.playerDataManager = new PlayerDataManager(); + this.hotBarManager = new HotBarManager(); + this.spawnManager = new SpawnManager(); + this.cosmeticManager = new CosmeticManager(); + } + + public void loadListeners() { + ClassRegistrationUtils.loadListeners("com.loganmagnan.hubcore.listeners"); + } + + public void loadRunnables() { +// new Aether(this, new ScoreboardProvider()); + new ScoreboardRunnable().runTaskTimer(this, 0, 20); + } + + public PlayerMenuUtil getPlayerMenuUtil(Player player) { + PlayerMenuUtil playerMenuUtil; + + if (playerMenuUtilMap.containsKey(player)) { + return playerMenuUtilMap.get(player); + } else { + playerMenuUtil = new PlayerMenuUtil(player); + + playerMenuUtilMap.put(player, playerMenuUtil); + + return playerMenuUtil; + } + } + + public boolean setupChat() { + RegisteredServiceProvider chatProvider = getServer().getServicesManager().getRegistration(Chat.class); + + if (chatProvider != null) { + chat = chatProvider.getProvider(); + } + + return (chat != null); + } + + public boolean setupPermissions() { + RegisteredServiceProvider permissionProvider = getServer().getServicesManager().getRegistration(Permission.class); + + if (permissionProvider != null) { + perms = permissionProvider.getProvider(); + } + + return (perms != null); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/chatcolor/ColorSet.java b/src/main/java/com/loganmagnan/hubcore/chatcolor/ColorSet.java new file mode 100644 index 0000000..306ed64 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/chatcolor/ColorSet.java @@ -0,0 +1,17 @@ +package com.loganmagnan.hubcore.chatcolor; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@RequiredArgsConstructor +public class ColorSet { + + private R red = null; + private G green = null; + private B blue = null; +} diff --git a/src/main/java/com/loganmagnan/hubcore/chatcolor/GradientColor.java b/src/main/java/com/loganmagnan/hubcore/chatcolor/GradientColor.java new file mode 100644 index 0000000..867b7c4 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/chatcolor/GradientColor.java @@ -0,0 +1,16 @@ +package com.loganmagnan.hubcore.chatcolor; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@RequiredArgsConstructor +public class GradientColor { + + private com.loganmagnan.hubcore.chatcolor.ColorSet colorCodeOne; + private ColorSet colorCodeTwo; +} diff --git a/src/main/java/com/loganmagnan/hubcore/commands/SetSpawnCommand.java b/src/main/java/com/loganmagnan/hubcore/commands/SetSpawnCommand.java new file mode 100644 index 0000000..0225c4b --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/commands/SetSpawnCommand.java @@ -0,0 +1,38 @@ +package com.loganmagnan.hubcore.commands; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.utils.ColorUtils; +import com.loganmagnan.hubcore.utils.CustomLocation; +import com.loganmagnan.hubcore.utils.command.BaseCommand; +import com.loganmagnan.hubcore.utils.command.Command; +import com.loganmagnan.hubcore.utils.command.CommandArguments; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; + +public class SetSpawnCommand extends BaseCommand { + + private HubCore main = HubCore.getInstance(); + + @Command(name = "setspawn", permission = "hubcore.command.setspawn") + @Override + public void executeAs(CommandArguments command) { + Player player = command.getPlayer(); + + String[] args = command.getArgs(); + + if (args.length == 0) { + this.main.getSpawnManager().setSpawnLocation(CustomLocation.fromBukkitLocation(player.getLocation())); + + this.saveLocation(player, "SPAWN.LOCATION"); + + player.sendMessage(ColorUtils.getMessageType("&aSet the spawn location")); + } + } + + public void saveLocation(Player player, String location) { + FileConfiguration config = this.main.getMainConfig().getConfig(); + config.set(location, CustomLocation.locationToString(CustomLocation.fromBukkitLocation(player.getLocation()))); + + this.main.getMainConfig().save(); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/commands/SpawnCommand.java b/src/main/java/com/loganmagnan/hubcore/commands/SpawnCommand.java new file mode 100644 index 0000000..c28a170 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/commands/SpawnCommand.java @@ -0,0 +1,24 @@ +package com.loganmagnan.hubcore.commands; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.utils.command.BaseCommand; +import com.loganmagnan.hubcore.utils.command.Command; +import com.loganmagnan.hubcore.utils.command.CommandArguments; +import org.bukkit.entity.Player; + +public class SpawnCommand extends BaseCommand { + + private HubCore main = HubCore.getInstance(); + + @Command(name = "spawn") + @Override + public void executeAs(CommandArguments command) { + Player player = command.getPlayer(); + + String[] args = command.getArgs(); + + if (args.length == 0) { + player.teleport(this.main.getSpawnManager().getSpawnLocation().toBukkitLocation()); + } + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/BlockBreakListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/BlockBreakListener.java new file mode 100644 index 0000000..2242070 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/BlockBreakListener.java @@ -0,0 +1,24 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; + +public class BlockBreakListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onBlockBreak(BlockBreakEvent event) { + Player player = event.getPlayer(); + + if (player.getGameMode() == GameMode.CREATIVE) { + return; + } + + event.setCancelled(true); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/BlockPlaceListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/BlockPlaceListener.java new file mode 100644 index 0000000..d38b3b9 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/BlockPlaceListener.java @@ -0,0 +1,52 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.playerdata.PlayerData; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.inventory.ItemStack; + +public class BlockPlaceListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onBlockPlace(BlockPlaceEvent event) { + Player player = event.getPlayer(); + + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + Block block = event.getBlock(); + + ItemStack itemStack = new ItemStack(block.getType()); + + if (player.getGameMode() == GameMode.CREATIVE) { + return; + } + + if (block.getType() == Material.getMaterial(this.main.getHotBarConfig().getConfig().getString("SPAWN.BLOCKS.MATERIAL"))) { + playerData.getBlocks().add(block); + + Bukkit.getScheduler().scheduleSyncDelayedTask(this.main, new Runnable() { + @Override + public void run() { + block.setType(Material.AIR); + + itemStack.setAmount(64); + + player.getInventory().setItem(main.getHotBarConfig().getConfig().getInt("SPAWN.BLOCKS.SLOT"), itemStack); + } + }, 60); + + return; + } + + event.setCancelled(true); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/CreatureSpawnListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/CreatureSpawnListener.java new file mode 100644 index 0000000..95ceeb2 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/CreatureSpawnListener.java @@ -0,0 +1,16 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.CreatureSpawnEvent; + +public class CreatureSpawnListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onCreatureSpawn(CreatureSpawnEvent event) { + event.setCancelled(true); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/EntityDamageListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/EntityDamageListener.java new file mode 100644 index 0000000..31e7d95 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/EntityDamageListener.java @@ -0,0 +1,16 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; + +public class EntityDamageListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onEntityDamage(EntityDamageEvent event) { + event.setCancelled(true); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/FoodLevelChangeListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/FoodLevelChangeListener.java new file mode 100644 index 0000000..1a67616 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/FoodLevelChangeListener.java @@ -0,0 +1,22 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.FoodLevelChangeEvent; + +public class FoodLevelChangeListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onFoodChange(FoodLevelChangeEvent event) { + Player player = (Player) event.getEntity(); + player.setHealth(20); + player.setFoodLevel(20); + player.setSaturation(20); + + event.setCancelled(true); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/InventoryClickListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/InventoryClickListener.java new file mode 100644 index 0000000..e98016f --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/InventoryClickListener.java @@ -0,0 +1,26 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; + +public class InventoryClickListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onInventoryClick(InventoryClickEvent event) { + event.setCancelled(true); + + if ((!(event.getWhoClicked() instanceof Player)) || (event.getCurrentItem() == null)) { + return; + } + + if (event.getInventory().getType().equals(InventoryType.PLAYER)) { + event.setCancelled(false); + } + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/MenuListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/MenuListener.java new file mode 100644 index 0000000..9ac3552 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/MenuListener.java @@ -0,0 +1,29 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.menusystem.Menu; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.InventoryHolder; + +public class MenuListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onMenuClick(InventoryClickEvent event) { + InventoryHolder inventoryHolder = event.getInventory().getHolder(); + + if (inventoryHolder instanceof Menu) { + event.setCancelled(true); + + if (event.getCurrentItem() == null) { + return; + } + + Menu menu = (Menu) inventoryHolder; + menu.handleMenu(event); + } + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/PlayerDataListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/PlayerDataListener.java new file mode 100644 index 0000000..6a79d0e --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/PlayerDataListener.java @@ -0,0 +1,105 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.playerdata.PlayerData; +import com.loganmagnan.hubcore.utils.ColorUtils; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.*; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +public class PlayerDataListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onAsyncPlayerPreLogin(AsyncPlayerPreLoginEvent event) { + Player player = Bukkit.getPlayer(event.getUniqueId()); + + if (player != null) { + if (player.isOnline()) { + event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); + event.setKickMessage("§cYou tried to login too quickly after disconnecting.\n§cTry again in a few seconds."); + + this.main.getServer().getScheduler().runTask(this.main, () -> player.kickPlayer("§cDuplicate Login")); + + return; + } + + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + } + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + public void onPlayerLogin(PlayerLoginEvent event) { + PlayerData playerData = this.main.getPlayerDataManager().getOrCreate(event.getPlayer().getUniqueId()); + + if (playerData == null) { + event.setResult(PlayerLoginEvent.Result.KICK_OTHER); + event.setKickMessage("§cAn error has occurred while loading your profile. Please reconnect."); + + return; + } + + if (!playerData.isLoaded()) { + event.setResult(PlayerLoginEvent.Result.KICK_OTHER); + event.setKickMessage("§cAn error has occurred while loading your profile. Please reconnect."); + } + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + + this.main.getPlayerDataManager().sendToSpawnAndResetPlayer(player); + this.main.getSpawnManager().getPlayers().add(player); + + player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 4)); + + event.setJoinMessage(null); + + for (String string : main.getMessagesConfig().getConfig().getStringList("JOIN-MESSAGE")) { + player.sendMessage(ColorUtils.getMessageType(string.replace("%player%", player.getName()))); + } + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + event.setQuitMessage(null); + + Player player = event.getPlayer(); + + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + this.handleLeave(player); + this.handleDataSave(playerData); + this.main.getSpawnManager().getPlayers().remove(player); + } + + @EventHandler + public void onPlayerKick(PlayerKickEvent event) { + event.setLeaveMessage(null); + + Player player = event.getPlayer(); + + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + this.handleLeave(player); + this.handleDataSave(playerData); + this.main.getSpawnManager().getPlayers().remove(player); + } + + private void handleLeave(Player player) { + + } + + private void handleDataSave(PlayerData playerData) { + if (playerData != null) { + this.main.getPlayerDataManager().deletePlayer(playerData.getUniqueId()); + } + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/PlayerDropItemListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/PlayerDropItemListener.java new file mode 100644 index 0000000..d12757c --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/PlayerDropItemListener.java @@ -0,0 +1,16 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerDropItemEvent; + +public class PlayerDropItemListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onPlayerDropItem(PlayerDropItemEvent event) { + event.setCancelled(true); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/PlayerInteractListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/PlayerInteractListener.java new file mode 100644 index 0000000..dc71e1e --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/PlayerInteractListener.java @@ -0,0 +1,83 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.managers.item.HotBarItem; +import com.loganmagnan.hubcore.menus.CosmeticsSelectorMenu; +import com.loganmagnan.hubcore.menus.ServerSelectorMenu; +import com.loganmagnan.hubcore.menus.SettingsSelectorMenu; +import com.loganmagnan.hubcore.playerdata.PlayerData; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +public class PlayerInteractListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onPlayerInteractOne(PlayerInteractEvent event) { + Player player = event.getPlayer(); + + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + if (player.getGameMode() == GameMode.CREATIVE) { + return; + } + + if (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() != Action.RIGHT_CLICK_BLOCK) { + return; + } + + if (!event.hasItem()) { + return; + } + + HotBarItem hotBarItem = HotBarItem.getItemByItemStack(player.getItemInHand()); + + if (hotBarItem == null) { + return; + } + + if (hotBarItem.getActionType() == null) { + return; + } + + switch (playerData.getPlayerState()) { + case SPAWN: + switch (hotBarItem.getActionType()) { + case OPEN_SERVER_SELECTOR: + new ServerSelectorMenu(this.main.getPlayerMenuUtil(player)).open(player); + + break; + case OPEN_COSMETICS_SELECTOR: + new CosmeticsSelectorMenu(this.main.getPlayerMenuUtil(player)).open(player); + + break; + case OPEN_SETTINGS_SELECTOR: + new SettingsSelectorMenu(this.main.getPlayerMenuUtil(player)).open(player); + + break; + } + + break; + } + } + + @EventHandler + public void onPlayerInteractTwo(PlayerInteractEvent event) { + Player player = event.getPlayer(); + + if (event.hasItem() && (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) && event.getItem().getType().equals(Material.ENDER_PEARL)) { + event.setCancelled(true); + + player.getInventory().setItem(this.main.getHotBarConfig().getConfig().getInt("SPAWN.ENDER-PEARL.SLOT"), new ItemStack(Material.ENDER_PEARL, 1)); + player.setVelocity(event.getPlayer().getLocation().getDirection().multiply(1.50)); + player.updateInventory(); + } + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/PlayerMoveListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/PlayerMoveListener.java new file mode 100644 index 0000000..a33071b --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/PlayerMoveListener.java @@ -0,0 +1,50 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.playerdata.PlayerData; +import org.bukkit.Effect; +import org.bukkit.GameMode; +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.player.PlayerMoveEvent; +import org.bukkit.plugin.Plugin; + +public class PlayerMoveListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + Player player = event.getPlayer(); + + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + Location location = player.getLocation(); + + if (playerData.getEffect() != null) { + player.playEffect(location, playerData.getEffect(), 50); + } + + if (location.getY() <= 0) { + this.main.getPlayerDataManager().sendToSpawnAndResetPlayer(player); + } + + if (player.getGameMode() != GameMode.CREATIVE && player.getLocation().subtract(0.0, 1.0, 0.0).getBlock().getType() != Material.AIR && !player.isFlying()) { + player.setAllowFlight(true); + } + + if (event.getTo().getY() < 2.0) { + main.getServer().getScheduler().scheduleSyncDelayedTask((Plugin) main, (Runnable) new Runnable() { + @Override + public void run() { + double y = player.getLocation().getY() - 2.0; + Location l = new Location(player.getLocation().getWorld(), player.getLocation().getX(), y, player.getLocation().getZ(), player.getLocation().getYaw(), player.getLocation().getPitch()); + player.getWorld().playEffect(l, Effect.ENDER_SIGNAL, 50, 30); + } + }, 10); + } + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/PlayerPickupItemListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/PlayerPickupItemListener.java new file mode 100644 index 0000000..224843f --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/PlayerPickupItemListener.java @@ -0,0 +1,16 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerPickupItemEvent; + +public class PlayerPickupItemListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onPlayerPickupItem(PlayerPickupItemEvent event) { + event.setCancelled(true); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/PlayerToggleFlightListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/PlayerToggleFlightListener.java new file mode 100644 index 0000000..a57e50b --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/PlayerToggleFlightListener.java @@ -0,0 +1,28 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerToggleFlightEvent; + +public class PlayerToggleFlightListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onPlayerToggleFlight(PlayerToggleFlightEvent event) { + Player player = event.getPlayer(); + + if (player.getGameMode() == GameMode.CREATIVE) { + return; + } + + event.setCancelled(true); + + player.setAllowFlight(false); + player.setFlying(false); + player.setVelocity(player.getLocation().getDirection().multiply(1.5).setY(1)); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/listeners/WeatherChangeListener.java b/src/main/java/com/loganmagnan/hubcore/listeners/WeatherChangeListener.java new file mode 100644 index 0000000..3cf296f --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/listeners/WeatherChangeListener.java @@ -0,0 +1,16 @@ +package com.loganmagnan.hubcore.listeners; + +import com.loganmagnan.hubcore.HubCore; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.weather.WeatherChangeEvent; + +public class WeatherChangeListener implements Listener { + + private HubCore main = HubCore.getInstance(); + + @EventHandler + public void onWeatherChange(WeatherChangeEvent event) { + event.setCancelled(true); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/managers/PlayerDataManager.java b/src/main/java/com/loganmagnan/hubcore/managers/PlayerDataManager.java new file mode 100644 index 0000000..c3faa0f --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/managers/PlayerDataManager.java @@ -0,0 +1,86 @@ +package com.loganmagnan.hubcore.managers; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.managers.item.HotBarItem; +import com.loganmagnan.hubcore.playerdata.PlayerData; +import lombok.Getter; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class PlayerDataManager { + + private HubCore main = HubCore.getInstance(); + + @Getter private final Map players = new HashMap<>(); + + public PlayerData getOrCreate(UUID uniqueId) { + return this.players.computeIfAbsent(uniqueId, PlayerData::new); + } + + public PlayerData getPlayerData(UUID uniqueId) { + return this.players.getOrDefault(uniqueId, new PlayerData(uniqueId)); + } + + public Collection getAllPlayers() { + return this.players.values(); + } + + public void loadPlayerData(PlayerData playerData) { + playerData.setLoaded(true); + } + + public void savePlayerData(PlayerData playerData) { + + } + + public void deletePlayer(UUID uniqueId) { + this.main.getServer().getScheduler().runTaskAsynchronously(this.main, () -> { + this.savePlayerData(this.players.get(uniqueId)); + this.players.remove(uniqueId); + }); + } + + public void sendToSpawnAndResetPlayer(Player player) { + player.getInventory().clear(); + + this.giveSpawnItemsToPlayer(player); + + if (!player.isOnline()) { + return; + } + + this.resetPlayerView(); + + player.teleport(this.main.getSpawnManager().getSpawnLocation().toBukkitLocation()); + } + + public void giveSpawnItemsToPlayer(Player player) { + this.main.getHotBarManager().getSpawnItems().stream().filter(HotBarItem::isEnabled).forEach(item -> player.getInventory().setItem(item.getSlot(), item.getItemStack())); + + player.updateInventory(); + } + + public void resetPlayerView() { + (new BukkitRunnable() { + public void run() { + PlayerDataManager.this.main.getServer().getOnlinePlayers().forEach(player -> { + PlayerData playerData = PlayerDataManager.this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + if (playerData.getPlayerSettings().isPlayerVisibilityEnabled()) { + PlayerDataManager.this.main.getServer().getOnlinePlayers().forEach(playerOnline -> { + player.showPlayer(playerOnline); + }); + } else { + PlayerDataManager.this.main.getServer().getOnlinePlayers().forEach(playerOnline -> { + player.hidePlayer(playerOnline); + }); + } + }); + } + }).runTaskAsynchronously(this.main); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/managers/SpawnManager.java b/src/main/java/com/loganmagnan/hubcore/managers/SpawnManager.java new file mode 100644 index 0000000..b56f803 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/managers/SpawnManager.java @@ -0,0 +1,46 @@ +package com.loganmagnan.hubcore.managers; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.utils.ColorUtils; +import com.loganmagnan.hubcore.utils.CustomLocation; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class SpawnManager { + + private HubCore main = HubCore.getInstance(); + + private FileConfiguration config = this.main.getMainConfig().getConfig(); + + private CustomLocation spawnLocation; + + private List players = new ArrayList(); + + public SpawnManager() { + this.loadConfig(); + } + + public void loadConfig() { + if (this.config.contains("SPAWN.LOCATION")) { + try { + this.spawnLocation = CustomLocation.stringToLocation(this.config.getString("SPAWN.LOCATION")); + } catch (NullPointerException exception) { + Bukkit.getConsoleSender().sendMessage(ColorUtils.getMessageType("&cSpawn location not found")); + } + } + } + + public void saveConfig() { + this.config.set("SPAWN.LOCATION", CustomLocation.locationToString(this.spawnLocation)); + + this.main.getMainConfig().save(); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/managers/cosmetic/Cosmetic.java b/src/main/java/com/loganmagnan/hubcore/managers/cosmetic/Cosmetic.java new file mode 100644 index 0000000..b778b9b --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/managers/cosmetic/Cosmetic.java @@ -0,0 +1,36 @@ +package com.loganmagnan.hubcore.managers.cosmetic; + +import com.loganmagnan.hubcore.managers.item.ActionType; +import com.loganmagnan.hubcore.managers.item.HotBarItem; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.Effect; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class Cosmetic { + + private ItemStack itemStack; + private boolean enabled; + private CosmeticType cosmeticType; + private Effect effect; + + private static List items = new ArrayList(); + + public Cosmetic(ItemStack itemStack, boolean enabled, String cosmeticType, String effect) { + this.itemStack = itemStack; + this.enabled = enabled; + this.cosmeticType = CosmeticType.valueOf(cosmeticType); + this.effect = Effect.valueOf(effect); + + items.add(this); + } + + public static Cosmetic getItemByItemStack(ItemStack itemStack) { + return items.stream().filter(item -> item.getItemStack().isSimilar(itemStack)).findFirst().orElse(null); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/managers/cosmetic/CosmeticManager.java b/src/main/java/com/loganmagnan/hubcore/managers/cosmetic/CosmeticManager.java new file mode 100644 index 0000000..558c0b1 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/managers/cosmetic/CosmeticManager.java @@ -0,0 +1,55 @@ +package com.loganmagnan.hubcore.managers.cosmetic; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.utils.ColorUtils; +import com.loganmagnan.hubcore.utils.ItemUtil; +import com.loganmagnan.hubcore.utils.config.ConfigCursor; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.Material; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class CosmeticManager { + + private HubCore main = HubCore.getInstance(); + + private ConfigCursor configCursor; + + private List cosmetics = new ArrayList(); + + public CosmeticManager() { + try { + this.configCursor = new ConfigCursor(this.main.getCosmeticsConfig(), "COSMETICS"); + + for (String hubItem : this.main.getCosmeticsConfig().getConfig().getConfigurationSection("COSMETICS").getKeys(false)) { + this.cosmetics.add(new Cosmetic(ItemUtil.createUnbreakableItem( + Material.valueOf(this.configCursor.getString(hubItem + ".MATERIAL")), + ColorUtils.getMessageType(this.configCursor.getString(hubItem + ".NAME")), + this.configCursor.getInt(hubItem + ".AMOUNT"), + (short) this.configCursor.getInt(hubItem + ".DATA"), + this.configCursor.getInt(hubItem + ".CUSTOM-MODEL-DATA")), + this.configCursor.getBoolean(hubItem + ".ENABLED"), + this.configCursor.getString(hubItem + ".COSMETIC-TYPE"), + this.configCursor.getString(hubItem + ".EFFECT")) + ); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + public Cosmetic getCosmetic(String effect) { + for (Cosmetic cosmetic : this.cosmetics) { + if (!cosmetic.getEffect().name().equalsIgnoreCase(effect)) { + continue; + } + + return cosmetic; + } + return null; + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/managers/cosmetic/CosmeticType.java b/src/main/java/com/loganmagnan/hubcore/managers/cosmetic/CosmeticType.java new file mode 100644 index 0000000..1edd1df --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/managers/cosmetic/CosmeticType.java @@ -0,0 +1,6 @@ +package com.loganmagnan.hubcore.managers.cosmetic; + +public enum CosmeticType { + + TRAILS; +} diff --git a/src/main/java/com/loganmagnan/hubcore/managers/item/ActionType.java b/src/main/java/com/loganmagnan/hubcore/managers/item/ActionType.java new file mode 100644 index 0000000..394f2ff --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/managers/item/ActionType.java @@ -0,0 +1,10 @@ +package com.loganmagnan.hubcore.managers.item; + +public enum ActionType { + + OPEN_SERVER_SELECTOR, + ENDER_PEARL, + BLOCKS, + OPEN_COSMETICS_SELECTOR, + OPEN_SETTINGS_SELECTOR; +} diff --git a/src/main/java/com/loganmagnan/hubcore/managers/item/HotBarItem.java b/src/main/java/com/loganmagnan/hubcore/managers/item/HotBarItem.java new file mode 100644 index 0000000..b9cb953 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/managers/item/HotBarItem.java @@ -0,0 +1,33 @@ +package com.loganmagnan.hubcore.managers.item; + +import lombok.Getter; +import lombok.Setter; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class HotBarItem { + + private ItemStack itemStack; + private int slot; + private boolean enabled; + private ActionType actionType; + + private static List items = new ArrayList(); + + public HotBarItem(ItemStack itemStack, int slot, boolean enabled, String actionType) { + this.itemStack = itemStack; + this.slot = slot; + this.enabled = enabled; + this.actionType = ActionType.valueOf(actionType); + + items.add(this); + } + + public static HotBarItem getItemByItemStack(ItemStack itemStack) { + return items.stream().filter(item -> item.getItemStack().isSimilar(itemStack)).findFirst().orElse(null); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/managers/item/HotBarManager.java b/src/main/java/com/loganmagnan/hubcore/managers/item/HotBarManager.java new file mode 100644 index 0000000..65858c5 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/managers/item/HotBarManager.java @@ -0,0 +1,43 @@ +package com.loganmagnan.hubcore.managers.item; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.utils.ColorUtils; +import com.loganmagnan.hubcore.utils.ItemUtil; +import com.loganmagnan.hubcore.utils.config.ConfigCursor; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.Material; +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class HotBarManager { + + private HubCore main = HubCore.getInstance(); + + private ConfigCursor configCursor; + + private List spawnItems = new ArrayList(); + + public HotBarManager() { + try { + this.configCursor = new ConfigCursor(this.main.getHotBarConfig(), "SPAWN"); + + for (String hubItem : this.main.getHotBarConfig().getConfig().getConfigurationSection("SPAWN").getKeys(false)) { + this.spawnItems.add(new HotBarItem(ItemUtil.createUnbreakableItem( + Material.valueOf(this.configCursor.getString(hubItem + ".MATERIAL")), + ColorUtils.getMessageType(this.configCursor.getString(hubItem + ".NAME")), + this.configCursor.getInt(hubItem + ".AMOUNT"), + (short) this.configCursor.getInt(hubItem + ".DATA"), + this.configCursor.getInt(hubItem + ".CUSTOM-MODEL-DATA")), + this.configCursor.getInt(hubItem + ".SLOT"), + this.configCursor.getBoolean(hubItem + ".ENABLED"), + this.configCursor.getString(hubItem + ".ACTION-TYPE")) + ); + } + } catch (Exception exception) { + exception.printStackTrace(); + } + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/menus/CosmeticTypeMenu.java b/src/main/java/com/loganmagnan/hubcore/menus/CosmeticTypeMenu.java new file mode 100644 index 0000000..51a55c4 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/menus/CosmeticTypeMenu.java @@ -0,0 +1,133 @@ +package com.loganmagnan.hubcore.menus; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.managers.cosmetic.Cosmetic; +import com.loganmagnan.hubcore.managers.cosmetic.CosmeticType; +import com.loganmagnan.hubcore.playerdata.PlayerData; +import com.loganmagnan.hubcore.playerdata.PlayerSettings; +import com.loganmagnan.hubcore.menusystem.PaginatedMenu; +import com.loganmagnan.hubcore.menusystem.PlayerMenuUtil; +import com.loganmagnan.hubcore.utils.ColorUtils; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; + +import java.util.ArrayList; +import java.util.List; + +public class CosmeticTypeMenu extends PaginatedMenu { + + private HubCore main = HubCore.getInstance(); + + private CosmeticType cosmeticType; + + public CosmeticTypeMenu(PlayerMenuUtil playerMenuUtil, CosmeticType cosmeticType) { + super(playerMenuUtil); + + this.cosmeticType = cosmeticType; + } + + @Override + public String getMenuName() { + return ColorUtils.getMessageType(this.main.getMenusConfig().getConfig().getString("MENUS." + this.cosmeticType.name() + ".TITLE")); + } + + @Override + public int getSlots() { + return this.main.getMenusConfig().getConfig().getInt("MENUS." + this.cosmeticType.name() + ".SIZE"); + } + + @Override + public void handleMenu(InventoryClickEvent event) { + Player player = (Player) event.getWhoClicked(); + + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + PlayerSettings playerSettings = playerData.getPlayerSettings(); + + if (event.getView().getTitle().equalsIgnoreCase(ColorUtils.getMessageType(this.main.getMenusConfig().getConfig().getString("MENUS." + this.cosmeticType.name() + ".TITLE")))) { + switch (event.getCurrentItem().getType()) { + case OAK_BUTTON: + if (page == 0) { + player.sendMessage(ColorUtils.getMessageType("&aYou are on the first page")); + } else { + page--; + + super.open(player); + } + + return; + case STONE_BUTTON: + if (!((index + 1) >= this.main.getCosmeticManager().getCosmetics().size())) { + page++; + + super.open(player); + } else { + player.sendMessage(ColorUtils.getMessageType("&aYou are on the last page")); + } + + return; + case BARRIER: + player.closeInventory(); + + return; + } + + if (event.getCurrentItem().getType() != Material.AIR) { + Cosmetic cosmetic = this.main.getCosmeticManager().getCosmetic(event.getCurrentItem().getItemMeta().getPersistentDataContainer().get(new NamespacedKey(this.main, "Effect"), PersistentDataType.STRING)); + + if (cosmetic == null) { + return; + } + + playerData.setEffect(cosmetic.getEffect()); + + player.closeInventory(); + player.sendMessage(ColorUtils.getMessageType("&aSet your trail to &a&l" + ChatColor.stripColor(cosmetic.getItemStack().getItemMeta().getDisplayName()))); + + return; + } + } + } + + @Override + public void setMenuItems(Player player) { + this.addMenuBorder(); + + for (int i = 0; i < this.getMaxItemsPerPage(); i++) { + this.index = this.getMaxItemsPerPage() * this.page + i; + + if (this.index >= this.main.getCosmeticManager().getCosmetics().size()) { + break; + } + + List cosmetics = new ArrayList(this.main.getCosmeticManager().getCosmetics()); + + for (Cosmetic cosmetic : cosmetics) { + if (cosmetic.getCosmeticType() == this.cosmeticType) { + continue; + } + + cosmetics.remove(cosmetic); + } + + if (cosmetics.get(this.index) != null) { + Cosmetic cosmetic = cosmetics.get(this.index); + + ItemStack cosmeticItemStack = cosmetic.getItemStack(); + + ItemMeta itemMeta = cosmeticItemStack.getItemMeta(); + itemMeta.getPersistentDataContainer().set(new NamespacedKey(this.main, "Effect"), PersistentDataType.STRING, cosmetic.getEffect().name()); + + cosmeticItemStack.setItemMeta(itemMeta); + + this.inventory.addItem(cosmeticItemStack); + } + } + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/menus/CosmeticsSelectorMenu.java b/src/main/java/com/loganmagnan/hubcore/menus/CosmeticsSelectorMenu.java new file mode 100644 index 0000000..c415b1b --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/menus/CosmeticsSelectorMenu.java @@ -0,0 +1,71 @@ +package com.loganmagnan.hubcore.menus; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.managers.cosmetic.CosmeticType; +import com.loganmagnan.hubcore.playerdata.PlayerData; +import com.loganmagnan.hubcore.playerdata.PlayerSettings; +import com.loganmagnan.hubcore.menusystem.ItemStackButton; +import com.loganmagnan.hubcore.menusystem.Menu; +import com.loganmagnan.hubcore.menusystem.PlayerMenuUtil; +import com.loganmagnan.hubcore.utils.ColorUtils; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; + +public class CosmeticsSelectorMenu extends Menu { + + private HubCore main = HubCore.getInstance(); + + public CosmeticsSelectorMenu(PlayerMenuUtil playerMenuUtil) { + super(playerMenuUtil); + } + + @Override + public String getMenuName() { + return ColorUtils.getMessageType(this.main.getMenusConfig().getConfig().getString("MENUS.COSMETICS-SELECTOR.TITLE")); + } + + @Override + public int getSlots() { + return this.main.getMenusConfig().getConfig().getInt("MENUS.COSMETICS-SELECTOR.SIZE"); + } + + @Override + public void handleMenu(InventoryClickEvent event) { + Player player = (Player) event.getWhoClicked(); + + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + PlayerSettings playerSettings = playerData.getPlayerSettings(); + + if (event.getView().getTitle().equalsIgnoreCase(ColorUtils.getMessageType(this.main.getMenusConfig().getConfig().getString("MENUS.COSMETICS-SELECTOR.TITLE")))) { + switch (event.getCurrentItem().getType()) { + case BLAZE_POWDER: + new CosmeticTypeMenu(this.playerMenuUtil, CosmeticType.TRAILS).open(player); + + break; + } + } + } + + @Override + public void setMenuItems(Player player) { + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + PlayerSettings playerSettings = playerData.getPlayerSettings(); + + this.setFillerGlass(); + + ItemStackButton trailsItemStackButton = new ItemStackButton( + this.main.getMenusConfig().getConfig().getString("MENUS.COSMETICS-SELECTOR.ITEMS.TRAILS.NAME"), + this.main.getMenusConfig().getConfig().getStringList("MENUS.COSMETICS-SELECTOR.ITEMS.TRAILS.LORE"), + Material.getMaterial(this.main.getMenusConfig().getConfig().getString("MENUS.COSMETICS-SELECTOR.ITEMS.TRAILS.MATERIAL")), + 0, + 1); + + ItemStack trailsItemStack = trailsItemStackButton.makeItemStack(); + + this.inventory.setItem(this.main.getMenusConfig().getConfig().getInt("MENUS.COSMETICS-SELECTOR.ITEMS.TRAILS.SLOT"), trailsItemStack); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/menus/ServerSelectorMenu.java b/src/main/java/com/loganmagnan/hubcore/menus/ServerSelectorMenu.java new file mode 100644 index 0000000..e7484b3 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/menus/ServerSelectorMenu.java @@ -0,0 +1,98 @@ +package com.loganmagnan.hubcore.menus; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.utils.BungeeUtils; +import com.loganmagnan.hubcore.menusystem.Menu; +import com.loganmagnan.hubcore.menusystem.PlayerMenuUtil; +import com.loganmagnan.hubcore.utils.ColorUtils; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class ServerSelectorMenu extends Menu { + + private HubCore main = HubCore.getInstance(); + + public ServerSelectorMenu(PlayerMenuUtil playerMenuUtil) { + super(playerMenuUtil); + } + + @Override + public String getMenuName() { + return ColorUtils.getMessageType(this.main.getMenusConfig().getConfig().getString("MENUS.SERVER-SELECTOR.TITLE")); + } + + @Override + public int getSlots() { + return this.main.getMenusConfig().getConfig().getInt("MENUS.SERVER-SELECTOR.SIZE"); + } + + @Override + public void handleMenu(InventoryClickEvent event) { + Player player = (Player) event.getWhoClicked(); + + if (event.getView().getTitle().equalsIgnoreCase(ColorUtils.getMessageType(this.main.getMenusConfig().getConfig().getString("MENUS.SERVER-SELECTOR.TITLE")))) { + ItemStack itemStack = new ItemStack(event.getCurrentItem().getType()); + + ItemMeta itemMeta = itemStack.getItemMeta(); + itemMeta.setDisplayName(event.getCurrentItem().getItemMeta().getDisplayName()); + itemMeta.setLore(event.getCurrentItem().getItemMeta().getLore()); + + itemStack.setItemMeta(itemMeta); + + if (event.getCurrentItem().equals(itemStack)) { + for (int i = 0; i < this.main.getMenusConfig().getConfig().getConfigurationSection("MENUS.SERVER-SELECTOR.ITEMS").getKeys(false).size(); i++) { + ItemStack itemStackInFile = new ItemStack(Objects.requireNonNull(Material.getMaterial(Objects.requireNonNull(this.main.getMenusConfig().getConfig().getString("MENUS.SERVER-SELECTOR.ITEMS." + i + ".MATERIAL"))))); + ItemMeta itemMetaInFile = itemStackInFile.getItemMeta(); + itemMetaInFile.setDisplayName(ColorUtils.getMessageType(this.main.getMenusConfig().getConfig().getString("MENUS.SERVER-SELECTOR.ITEMS." + i + ".NAME"))); + + List lore = new ArrayList(); + + for (String string : this.main.getMenusConfig().getConfig().getStringList("MENUS.SERVER-SELECTOR.ITEMS." + i + ".LORE")) { + lore.add(ColorUtils.getMessageType(string)); + } + + itemMetaInFile.setLore(lore); + + itemStackInFile.setItemMeta(itemMetaInFile); + + if (itemStack.equals(itemStackInFile)) { + BungeeUtils.sendPlayerToServer(player, this.main.getMenusConfig().getConfig().getString("MENUS.SERVER-SELECTOR.ITEMS." + i + ".SERVER")); + + break; + } + } + } + } + } + + @Override + public void setMenuItems(Player player) { + this.setFillerGlass(); + + for (int i = 0; i < this.main.getMenusConfig().getConfig().getConfigurationSection("MENUS.SERVER-SELECTOR.ITEMS").getKeys(false).size(); i++) { + ItemStack itemStack = new ItemStack(Objects.requireNonNull(Material.getMaterial(Objects.requireNonNull(this.main.getMenusConfig().getConfig().getString("MENUS.SERVER-SELECTOR.ITEMS." + i + ".MATERIAL"))))); + + ItemMeta itemMeta = itemStack.getItemMeta(); + itemMeta.setDisplayName(ColorUtils.getMessageType(this.main.getMenusConfig().getConfig().getString("MENUS.SERVER-SELECTOR.ITEMS." + i + ".NAME"))); + + List lore = new ArrayList(); + + for (String string : this.main.getMenusConfig().getConfig().getStringList("MENUS.SERVER-SELECTOR.ITEMS." + i + ".LORE")) { + lore.add(ColorUtils.getMessageType(string)); + } + + itemMeta.setLore(lore); + + itemStack.setItemMeta(itemMeta); + + this.inventory.setItem(this.main.getMenusConfig().getConfig().getInt("MENUS.SERVER-SELECTOR.ITEMS." + i + ".SLOT"), itemStack); + } + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/menus/SettingsSelectorMenu.java b/src/main/java/com/loganmagnan/hubcore/menus/SettingsSelectorMenu.java new file mode 100644 index 0000000..f26c786 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/menus/SettingsSelectorMenu.java @@ -0,0 +1,98 @@ +package com.loganmagnan.hubcore.menus; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.playerdata.PlayerData; +import com.loganmagnan.hubcore.playerdata.PlayerSettings; +import com.loganmagnan.hubcore.menusystem.ItemStackButton; +import com.loganmagnan.hubcore.menusystem.Menu; +import com.loganmagnan.hubcore.menusystem.PlayerMenuUtil; +import com.loganmagnan.hubcore.utils.ColorUtils; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; + +public class SettingsSelectorMenu extends Menu { + + private HubCore main = HubCore.getInstance(); + + public SettingsSelectorMenu(PlayerMenuUtil playerMenuUtil) { + super(playerMenuUtil); + } + + @Override + public String getMenuName() { + return ColorUtils.getMessageType(this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.TITLE")); + } + + @Override + public int getSlots() { + return this.main.getMenusConfig().getConfig().getInt("MENUS.SETTINGS.SIZE"); + } + + @Override + public void handleMenu(InventoryClickEvent event) { + Player player = (Player) event.getWhoClicked(); + + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + PlayerSettings playerSettings = playerData.getPlayerSettings(); + + if (event.getView().getTitle().equalsIgnoreCase(ColorUtils.getMessageType(this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.TITLE")))) { + switch (event.getCurrentItem().getType()) { + case PAINTING: + playerSettings.setScoreboardEnabled(!playerSettings.isScoreboardEnabled()); + + break; + case PLAYER_HEAD: + playerSettings.setPlayerVisibilityEnabled(!playerSettings.isPlayerVisibilityEnabled()); + + this.main.getPlayerDataManager().resetPlayerView(); + + break; + } + + new SettingsSelectorMenu(this.playerMenuUtil).open(player); + } + } + + @Override + public void setMenuItems(Player player) { + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + PlayerSettings playerSettings = playerData.getPlayerSettings(); + + this.setFillerGlass(); + + List scoreboardLore = new ArrayList(this.main.getMenusConfig().getConfig().getStringList("MENUS.SETTINGS.SETTINGS.SCOREBOARD.LORE")); + scoreboardLore.add((playerSettings.isScoreboardEnabled() ? this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.ENABLED") : this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.UNSELECTED")) + " Scoreboard enabled"); + scoreboardLore.add((!playerSettings.isScoreboardEnabled() ? this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.DISABLED") : this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.UNSELECTED")) + " Scoreboard disabled"); + + List playerVisibilityLore = new ArrayList(this.main.getMenusConfig().getConfig().getStringList("MENUS.SETTINGS.SETTINGS.PLAYER-VISIBILITY.LORE")); + playerVisibilityLore.add((playerSettings.isPlayerVisibilityEnabled() ? this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.ENABLED") : this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.UNSELECTED")) + " Players enabled"); + playerVisibilityLore.add((!playerSettings.isPlayerVisibilityEnabled() ? this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.DISABLED") : this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.UNSELECTED")) + " Players disabled"); + + ItemStackButton scoreboardItemStackButton = new ItemStackButton( + this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.SETTINGS.SCOREBOARD.NAME"), + scoreboardLore, + Material.getMaterial(this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.SETTINGS.SCOREBOARD.MATERIAL")), + 0, + 1); + + ItemStackButton playerVisibilityItemStackButton = new ItemStackButton( + this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.SETTINGS.PLAYER-VISIBILITY.NAME"), + playerVisibilityLore, + Material.getMaterial(this.main.getMenusConfig().getConfig().getString("MENUS.SETTINGS.SETTINGS.PLAYER-VISIBILITY.MATERIAL")), + 0, + 1); + + ItemStack scoreboardItemStack = scoreboardItemStackButton.makeItemStack(); + ItemStack playerVisibilityItemStack = playerVisibilityItemStackButton.makeItemStack(); + + this.inventory.setItem(this.main.getMenusConfig().getConfig().getInt("MENUS.SETTINGS.SETTINGS.SCOREBOARD.SLOT"), scoreboardItemStack); + this.inventory.setItem(this.main.getMenusConfig().getConfig().getInt("MENUS.SETTINGS.SETTINGS.PLAYER-VISIBILITY.SLOT"), playerVisibilityItemStack); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/menusystem/ItemStackButton.java b/src/main/java/com/loganmagnan/hubcore/menusystem/ItemStackButton.java new file mode 100644 index 0000000..c1a7cd4 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/menusystem/ItemStackButton.java @@ -0,0 +1,29 @@ +package com.loganmagnan.hubcore.menusystem; + +import com.loganmagnan.hubcore.utils.ColorUtils; +import com.loganmagnan.hubcore.utils.ItemBuilder; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@RequiredArgsConstructor +public class ItemStackButton { + + private String name; + private List lore; + private Material material; + private int data; + private int amount; + + public ItemStack makeItemStack() { + return new ItemBuilder(this.material).name(ColorUtils.getMessageType(this.name)).lore(ColorUtils.getMessageType(this.lore)).durability(this.data).amount(this.amount).build(); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/menusystem/Menu.java b/src/main/java/com/loganmagnan/hubcore/menusystem/Menu.java new file mode 100644 index 0000000..17423c0 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/menusystem/Menu.java @@ -0,0 +1,64 @@ +package com.loganmagnan.hubcore.menusystem; + +import com.loganmagnan.hubcore.utils.ItemBuilder; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.Arrays; + +public abstract class Menu implements InventoryHolder { + + protected PlayerMenuUtil playerMenuUtil; + protected Inventory inventory; + protected ItemStack FILLER_GLASS = new ItemBuilder(Material.GRAY_STAINED_GLASS_PANE).durability(7).name("").build(); + + public Menu(PlayerMenuUtil playerMenuUtil) { + this.playerMenuUtil = playerMenuUtil; + } + + public abstract String getMenuName(); + + public abstract int getSlots(); + + public abstract void handleMenu(InventoryClickEvent event); + + public abstract void setMenuItems(Player player); + + public void open(Player player) { + inventory = Bukkit.createInventory(this, getSlots(), getMenuName()); + + this.setMenuItems(player); + + playerMenuUtil.getOwner().openInventory(inventory); + } + + @Override + public Inventory getInventory() { + return inventory; + } + + public void setFillerGlass(){ + for (int i = 0; i < this.getSlots(); i++) { + if (this.inventory.getItem(i) == null){ + this.inventory.setItem(i, this.FILLER_GLASS); + } + } + } + + public ItemStack makeItemStack(Material material, String displayName, String[] lore) { + ItemStack itemStack = new ItemStack(material); + ItemMeta itemMeta = itemStack.getItemMeta(); + itemMeta.setDisplayName(displayName); + + itemMeta.setLore(Arrays.asList(lore)); + itemStack.setItemMeta(itemMeta); + + return itemStack; + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/menusystem/PaginatedMenu.java b/src/main/java/com/loganmagnan/hubcore/menusystem/PaginatedMenu.java new file mode 100644 index 0000000..5370775 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/menusystem/PaginatedMenu.java @@ -0,0 +1,49 @@ +package com.loganmagnan.hubcore.menusystem; + +import com.loganmagnan.hubcore.utils.ColorUtils; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public abstract class PaginatedMenu extends Menu { + + protected int page = 0; + protected int maxItemsPerPage = 18; + protected int index = 0; + + public PaginatedMenu(PlayerMenuUtil playerMenuUtil) { + super(playerMenuUtil); + } + + public void addMenuBorder() { + ItemStack previousPageItemStack = new ItemStack(Material.OAK_BUTTON, 1); + + ItemMeta previousPageItemMeta = previousPageItemStack.getItemMeta(); + previousPageItemMeta.setDisplayName(ColorUtils.getMessageType("&ePrevious Page")); + + previousPageItemStack.setItemMeta(previousPageItemMeta); + + this.inventory.setItem(18, previousPageItemStack); + this.inventory.setItem(22, makeItemStack(Material.BARRIER, ChatColor.DARK_RED + "Close", new String[]{""})); + + ItemStack nextPageItemStack = new ItemStack(Material.STONE_BUTTON, 1); + + ItemMeta nextPageItemMeta = nextPageItemStack.getItemMeta(); + nextPageItemMeta.setDisplayName(ColorUtils.getMessageType("&eNext Page")); + + nextPageItemStack.setItemMeta(nextPageItemMeta); + + this.inventory.setItem(26, nextPageItemStack); + + for (int i = 18; i < 26; i++) { + if (this.inventory.getItem(i) == null) { + this.inventory.setItem(i, this.FILLER_GLASS); + } + } + } + + public int getMaxItemsPerPage() { + return maxItemsPerPage; + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/menusystem/PlayerMenuUtil.java b/src/main/java/com/loganmagnan/hubcore/menusystem/PlayerMenuUtil.java new file mode 100644 index 0000000..87a47f2 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/menusystem/PlayerMenuUtil.java @@ -0,0 +1,20 @@ +package com.loganmagnan.hubcore.menusystem; + +import org.bukkit.entity.Player; + +public class PlayerMenuUtil { + + private Player owner; + + public PlayerMenuUtil(Player owner) { + this.owner = owner; + } + + public Player getOwner() { + return owner; + } + + public void setOwner(Player owner) { + this.owner = owner; + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/playerdata/PlayerData.java b/src/main/java/com/loganmagnan/hubcore/playerdata/PlayerData.java new file mode 100644 index 0000000..bac9c45 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/playerdata/PlayerData.java @@ -0,0 +1,41 @@ +package com.loganmagnan.hubcore.playerdata; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.managers.PlayerDataManager; +import com.loganmagnan.hubcore.playerdata.currentgame.PlayerCurrentGameData; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.Effect; +import org.bukkit.block.Block; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Getter +@Setter +public class PlayerData { + + private PlayerDataManager playerDataManager = HubCore.getInstance().getPlayerDataManager(); + private PlayerState playerState = PlayerState.SPAWN; + + private PlayerSettings playerSettings = new PlayerSettings(); + private PlayerCurrentGameData currentGameData = new PlayerCurrentGameData(); + + private final UUID uniqueId; + private boolean loaded; + + private List blocks = new ArrayList(); + + private Effect effect; + + public PlayerData(UUID uniqueId) { + this.uniqueId = uniqueId; + this.loaded = false; + this.playerDataManager.loadPlayerData(this); + } + + public boolean isInSpawn() { + return this.playerState == PlayerState.SPAWN; + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/playerdata/PlayerSettings.java b/src/main/java/com/loganmagnan/hubcore/playerdata/PlayerSettings.java new file mode 100644 index 0000000..7d4ecfa --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/playerdata/PlayerSettings.java @@ -0,0 +1,13 @@ +package com.loganmagnan.hubcore.playerdata; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class PlayerSettings { + + private boolean scoreboardEnabled = true; + private boolean tabListEnabled = true; + private boolean playerVisibilityEnabled = true; +} diff --git a/src/main/java/com/loganmagnan/hubcore/playerdata/PlayerState.java b/src/main/java/com/loganmagnan/hubcore/playerdata/PlayerState.java new file mode 100644 index 0000000..b46e010 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/playerdata/PlayerState.java @@ -0,0 +1,6 @@ +package com.loganmagnan.hubcore.playerdata; + +public enum PlayerState { + + SPAWN; +} diff --git a/src/main/java/com/loganmagnan/hubcore/playerdata/currentgame/PlayerCurrentGameData.java b/src/main/java/com/loganmagnan/hubcore/playerdata/currentgame/PlayerCurrentGameData.java new file mode 100644 index 0000000..3292b6d --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/playerdata/currentgame/PlayerCurrentGameData.java @@ -0,0 +1,10 @@ +package com.loganmagnan.hubcore.playerdata.currentgame; + +import com.loganmagnan.hubcore.HubCore; +import lombok.Data; + +@Data +public class PlayerCurrentGameData { + + private HubCore main = HubCore.getInstance(); +} diff --git a/src/main/java/com/loganmagnan/hubcore/scoreboard/ScoreboardProvider.java b/src/main/java/com/loganmagnan/hubcore/scoreboard/ScoreboardProvider.java new file mode 100644 index 0000000..0e4834c --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/scoreboard/ScoreboardProvider.java @@ -0,0 +1,104 @@ +package com.loganmagnan.hubcore.scoreboard; + +import aether.scoreboard.Board; +import aether.scoreboard.BoardAdapter; +import aether.scoreboard.cooldown.BoardCooldown; +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.playerdata.PlayerData; +import com.loganmagnan.hubcore.playerdata.PlayerSettings; +import com.loganmagnan.hubcore.utils.ColorUtils; +import com.loganmagnan.hubcore.utils.Utils; +import com.loganmagnan.vortex.api.VortexAPI; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.scoreboard.Scoreboard; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ScoreboardProvider implements BoardAdapter { + + private HubCore main = HubCore.getInstance(); + + private Pattern HEX_PATTERN = Pattern.compile("&#([A-Fa-f0-9]{6})"); + + @Override + public String getTitle(Player player) { + return ColorUtils.getMessageType(this.main.getScoreboardConfig().getConfig().getString("SCOREBOARD.TITLE")); + } + + @Override + public List getScoreboard(Player player, Board board, Set cooldowns) { + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + if (playerData == null) { + return null; + } + + PlayerSettings playerSettings = playerData.getPlayerSettings(); + + if (!playerSettings.isScoreboardEnabled()) { + return null; + } + + switch (playerData.getPlayerState()) { + case SPAWN: + return this.getSpawnScoreboard(player, playerData); + } + + return null; + } + + @Override + public void onScoreboardCreate(Player player, Scoreboard scoreboard) { + + } + + private List getSpawnScoreboard(Player player, PlayerData playerData) { + List lines = new ArrayList<>(); + + String rank = ""; + + if (this.main.getServer().getPluginManager().getPlugin("Vault") == null) { + if (this.main.getServer().getPluginManager().getPlugin("Vortex") == null) { + rank = "None"; + } else { + rank = VortexAPI.getRank(player).getPrefix(); + } + } else { + rank = this.main.getChat().getGroupPrefix(player.getWorld(), this.main.getChat().getPrimaryGroup(player)); + } + + for (String string : this.main.getScoreboardConfig().getConfig().getStringList("SCOREBOARD.LINES.SPAWN")) { + lines.add( + string + .replace("%line%", Utils.scoreboardBar) + .replace("%online%", String.valueOf(this.main.getServer().getOnlinePlayers().size())) + .replace("%rank%", colorize(translateHexColorCodes(rank))) + ); + } + + return lines; + } + + public String colorize(String message) { + return ChatColor.translateAlternateColorCodes('&', message); + } + + public String translateHexColorCodes(String message) { + char colorChar = '§'; + Matcher matcher = HEX_PATTERN.matcher(message); + StringBuffer buffer = new StringBuffer(message.length() + 32); + while (matcher.find()) { + String group = matcher.group(1); + matcher.appendReplacement(buffer, colorChar + "x" + colorChar + group + .charAt(0) + colorChar + group.charAt(1) + colorChar + group + .charAt(2) + colorChar + group.charAt(3) + colorChar + group + .charAt(4) + colorChar + group.charAt(5)); + } + return matcher.appendTail(buffer).toString(); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/scoreboard/ScoreboardRunnable.java b/src/main/java/com/loganmagnan/hubcore/scoreboard/ScoreboardRunnable.java new file mode 100644 index 0000000..a70f1b9 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/scoreboard/ScoreboardRunnable.java @@ -0,0 +1,82 @@ +package com.loganmagnan.hubcore.scoreboard; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.playerdata.PlayerData; +import com.loganmagnan.hubcore.playerdata.PlayerSettings; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ScoreboardRunnable extends BukkitRunnable { + + private HubCore main = HubCore.getInstance(); + + private Map scoreboards = new HashMap(); + + private Pattern HEX_PATTERN = Pattern.compile("&#([A-Fa-f0-9]{6})"); + + @Override + public void run() { + for (Player player : this.main.getSpawnManager().getPlayers()) { + SimpleBoard simpleBoard = null; + + if (this.scoreboards.get(player.getUniqueId()) == null) { + simpleBoard = new SimpleBoard(); + + this.scoreboards.put(player.getUniqueId(), simpleBoard); + } else { + simpleBoard = this.scoreboards.get(player.getUniqueId()); + } + + simpleBoard.setTitle(colorize(translateHexColorCodes(this.main.getScoreboardConfig().getConfig().getString("SCOREBOARD.TITLE")))); + + PlayerData playerData = this.main.getPlayerDataManager().getPlayerData(player.getUniqueId()); + + if (playerData == null) { + return; + } + + PlayerSettings playerSettings = playerData.getPlayerSettings(); + + if (!playerSettings.isScoreboardEnabled()) { + simpleBoard.displayList(new ArrayList()); + simpleBoard.display(player); + + return; + } + + switch (playerData.getPlayerState()) { + case SPAWN: + simpleBoard.displayList(simpleBoard.getSpawnScoreboard(player, playerData)); + simpleBoard.display(player); + + break; + } + } + } + + public String colorize(String message) { + return ChatColor.translateAlternateColorCodes('&', message); + } + + public String translateHexColorCodes(String message) { + char colorChar = '§'; + Matcher matcher = HEX_PATTERN.matcher(message); + StringBuffer buffer = new StringBuffer(message.length() + 32); + while (matcher.find()) { + String group = matcher.group(1); + matcher.appendReplacement(buffer, colorChar + "x" + colorChar + group + .charAt(0) + colorChar + group.charAt(1) + colorChar + group + .charAt(2) + colorChar + group.charAt(3) + colorChar + group + .charAt(4) + colorChar + group.charAt(5)); + } + return matcher.appendTail(buffer).toString(); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/scoreboard/SimpleBoard.java b/src/main/java/com/loganmagnan/hubcore/scoreboard/SimpleBoard.java new file mode 100644 index 0000000..20533f3 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/scoreboard/SimpleBoard.java @@ -0,0 +1,174 @@ +package com.loganmagnan.hubcore.scoreboard; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.playerdata.PlayerData; +import com.loganmagnan.hubcore.playerdata.PlayerSettings; +import com.loganmagnan.hubcore.utils.BungeeUtils; +import com.loganmagnan.hubcore.utils.ColorUtils; +import com.loganmagnan.hubcore.utils.Utils; +import com.loganmagnan.vortex.api.VortexAPI; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scoreboard.DisplaySlot; +import org.bukkit.scoreboard.Objective; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SimpleBoard { + + private HubCore main = HubCore.getInstance(); + + private static final int MAX_LINES = 15; + // private static final int MAX_PREFIX_LENGTH = 16; - Minecraft now uses Components for this, so we don't need to worry about it + private static final String[] BLANKS = new String[MAX_LINES]; + + private Pattern HEX_PATTERN = Pattern.compile("&#([A-Fa-f0-9]{6})"); + + static { + for (int index = 0; index < MAX_LINES; index++) { + BLANKS[index] = new String(new char[]{ChatColor.COLOR_CHAR, (char) ('s' + index)}); + } + } + + private final Team[] teams = new Team[MAX_LINES]; + private final Objective objective; + + public SimpleBoard() { + this(Bukkit.getScoreboardManager().getNewScoreboard()); + } + + public SimpleBoard(Scoreboard board) { + board.clearSlot(DisplaySlot.SIDEBAR); + + objective = board.registerNewObjective("sidebar", "dummy"); + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + + for (int index = 0; index < MAX_LINES; index++) { + teams[index] = board.registerNewTeam(BLANKS[index]); + teams[index].addEntry(BLANKS[index]); + } + } + + public List getSpawnScoreboard(Player player, PlayerData playerData) { + List lines = new ArrayList<>(); + + String rank = ""; + + if (this.main.getServer().getPluginManager().getPlugin("Vault") == null) { + if (this.main.getServer().getPluginManager().getPlugin("Vortex") == null) { + rank = "None"; + } else { + rank = VortexAPI.getRank(player).getPrefix(); + } + } else { + rank = this.main.getChat().getGroupPrefix(player.getWorld(), this.main.getChat().getPrimaryGroup(player)); + } + + for (String string : this.main.getScoreboardConfig().getConfig().getStringList("SCOREBOARD.LINES.SPAWN")) { + lines.add( + string + .replace("%line%", Utils.scoreboardBar) + .replace("%player%", player.getName()) + .replace("%online%", String.valueOf(BungeeUtils.getPlayerCount(null))) + .replace("%rank%", colorize(translateHexColorCodes(rank))) + .replace("%skyblockOnline%", String.valueOf(BungeeUtils.getPlayerCount("SkyBlock"))) + .replace("%prisonOnline%", String.valueOf(BungeeUtils.getPlayerCount("Prison"))) + .replace("%survivalOnline%", String.valueOf(BungeeUtils.getPlayerCount("Survival"))) + ); + } + + return lines; + } + + public String colorize(String message) { + return ChatColor.translateAlternateColorCodes('&', message); + } + + public String translateHexColorCodes(String message) { + char colorChar = '§'; + Matcher matcher = HEX_PATTERN.matcher(message); + StringBuffer buffer = new StringBuffer(message.length() + 32); + while (matcher.find()) { + String group = matcher.group(1); + matcher.appendReplacement(buffer, colorChar + "x" + colorChar + group + .charAt(0) + colorChar + group.charAt(1) + colorChar + group + .charAt(2) + colorChar + group.charAt(3) + colorChar + group + .charAt(4) + colorChar + group.charAt(5)); + } + return matcher.appendTail(buffer).toString(); + } + + public void setTitle(String title) { + objective.setDisplayName(title); + } + + public void setLine(int index, String line) { + if (index < 0 || index >= MAX_LINES) { + throw new IndexOutOfBoundsException("Index must be between 0 and " + MAX_LINES); + } + + if (line == null) { + line = ""; + } + + line = ColorUtils.getMessageType(line); + + /* + if (line.length() > MAX_PREFIX_LENGTH) { + line = line.substring(0, MAX_PREFIX_LENGTH); + } + */ + teams[index].setPrefix(line); + objective.getScore(BLANKS[index]).setScore(MAX_LINES - index); + } + + public void removeLine(int index) { + if (index < 0 || index >= MAX_LINES) { + throw new IndexOutOfBoundsException("Index must be between 0 and " + MAX_LINES); + } + + teams[index].setPrefix(BLANKS[index]); + objective.getScoreboard().resetScores(BLANKS[index]); + } + + public void clear() { + for (int index = 0; index < MAX_LINES; index++) { + teams[index].setPrefix(BLANKS[index]); + objective.getScoreboard().resetScores(BLANKS[index]); + } + } + + public void displayList(List lines) { + // we can't let this flicker + if (lines.size() > MAX_LINES) { + throw new IllegalArgumentException("List cannot be larger than " + MAX_LINES); + } + + for (int index = 0; index < MAX_LINES; index++) { + if (index < lines.size()) { + setLine(index, lines.get(index)); + } else { + removeLine(index); + } + } + } + + public void display(Player player) { + player.setScoreboard(objective.getScoreboard()); + } + + public void hide(Player player) { + player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard()); + } + + public void dispose() { + objective.unregister(); + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/AsyncScheduler.java b/src/main/java/com/loganmagnan/hubcore/utils/AsyncScheduler.java new file mode 100644 index 0000000..e152426 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/AsyncScheduler.java @@ -0,0 +1,34 @@ +package com.loganmagnan.hubcore.utils; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import lombok.experimental.UtilityClass; + +import java.util.concurrent.*; + +@UtilityClass +public class AsyncScheduler { + + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4, + new ThreadFactoryBuilder().setNameFormat("Schedule CascadiaMC Thread %d").build()); + + /** + * Run a task asynchronously. + */ + public Future run(Runnable runnable) { + return scheduler.submit(runnable); + } + + /** + * Run a task after scheduled delay asynchronously. + */ + public ScheduledFuture later(Runnable runnable, long delay, TimeUnit time) { + return scheduler.schedule(runnable, delay, time); + } + + /** + * Run a task in a fixed rate asynchronously. + */ + public ScheduledFuture timer(TimerRunnable runnable, long delay, long period, TimeUnit time) { + return runnable.setScheduledFuture(scheduler.scheduleAtFixedRate(runnable, delay, period, time)); + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/BlockUtils.java b/src/main/java/com/loganmagnan/hubcore/utils/BlockUtils.java new file mode 100644 index 0000000..ab8dd3b --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/BlockUtils.java @@ -0,0 +1,47 @@ +package com.loganmagnan.hubcore.utils; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Player; + +public class BlockUtils { + public static void breakBlockGroup(Player player, final Block block, final boolean useParticles) { + final Material target = block.getType(); + final Block up = block.getRelative(BlockFace.SOUTH); + final Block down = block.getRelative(BlockFace.NORTH); + final Block left = block.getRelative(BlockFace.EAST); + final Block right = block.getRelative(BlockFace.WEST); + + BlockData blockData = Material.AIR.createBlockData(); + + player.sendBlockChange(block.getLocation(), blockData); + + if (useParticles) { + block.breakNaturally(); + } else { + block.setType(Material.AIR); + } + + if (up.getType() == target) { + breakBlockGroup(player, up, useParticles); + } + + if (down.getType() == target) { + breakBlockGroup(player, down, useParticles); + } + + if (left.getType() == target) { + breakBlockGroup(player, left, useParticles); + } + + if (right.getType() == target) { + breakBlockGroup(player, right, useParticles); + } + } + + public static void breakBlockGroup(Player player, final Block block) { + breakBlockGroup(player, block, true); + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/BungeeUtils.java b/src/main/java/com/loganmagnan/hubcore/utils/BungeeUtils.java new file mode 100644 index 0000000..77fc249 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/BungeeUtils.java @@ -0,0 +1,64 @@ +package com.loganmagnan.hubcore.utils; + +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import com.loganmagnan.hubcore.HubCore; +import org.bukkit.entity.Player; +import org.bukkit.plugin.messaging.PluginMessageListener; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class BungeeUtils implements PluginMessageListener { + + private static HubCore main = HubCore.getInstance(); + + private static Map playersOnline = new HashMap<>(); + + public BungeeUtils() { + new BukkitRunnable() { + @Override + public void run() { + for (String string : main.getMainConfig().getConfig().getStringList("SERVERS")) { + ByteArrayDataOutput globalOut = ByteStreams.newDataOutput(); + globalOut.writeUTF("PlayerCount"); + globalOut.writeUTF(string); + main.getServer().sendPluginMessage(main, "BungeeCord", globalOut.toByteArray()); + } + } + }.runTaskTimer(main, 20L, 20L); + } + + public static int getPlayerCount(String server) { + if (server == null) { + server = "ALL"; + } + return playersOnline.getOrDefault(server, 0); + } + + public static void sendPlayerToServer(Player player, String server) { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.writeUTF("ConnectOther"); + output.writeUTF(player.getName()); + output.writeUTF(server); + player.sendPluginMessage(main, "BungeeCord", output.toByteArray()); + } + + public void onPluginMessageReceived(String channel, Player p, byte[] message) { + if (!channel.equals("BungeeCord")) { + return; + } + ByteArrayDataInput in = ByteStreams.newDataInput(message); + String command = in.readUTF(); + if (!command.equals("PlayerCount")) { + return; + } + String server = in.readUTF(); + int playerCount = in.readInt(); + playersOnline.put(server, playerCount); + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/Cache.java b/src/main/java/com/loganmagnan/hubcore/utils/Cache.java new file mode 100644 index 0000000..daee4f5 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/Cache.java @@ -0,0 +1,29 @@ +package com.loganmagnan.hubcore.utils; + +public class Cache { + + private T cache; + private long lastCache; + private final long refreshTimeInMilliseconds; + + public Cache(long refreshTimeInMilliseconds) { + this.refreshTimeInMilliseconds = refreshTimeInMilliseconds; + } + + public T getCache(CacheContentProvider cacheContentProvider) { + long currentTime = System.currentTimeMillis(); + if (lastCache + refreshTimeInMilliseconds < currentTime || cache == null) { + this.cache = cacheContentProvider.getObject(); + this.lastCache = currentTime; + } + return cache; + } + + public void clearCache() { + this.cache = null; + } + + public interface CacheContentProvider { + T getObject(); + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/ClassRegistrationUtils.java b/src/main/java/com/loganmagnan/hubcore/utils/ClassRegistrationUtils.java new file mode 100644 index 0000000..f695bf8 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/ClassRegistrationUtils.java @@ -0,0 +1,95 @@ +package com.loganmagnan.hubcore.utils; + +import com.google.common.collect.ImmutableSet; +import com.loganmagnan.hubcore.HubCore; +import org.bukkit.event.Listener; + +import java.io.IOException; +import java.net.URL; +import java.security.CodeSource; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class ClassRegistrationUtils { + + public static void loadListeners(String packageName) { + for (Class clazz : getClassesInPackage(packageName)) { + if (isListener(clazz)) { + try { + HubCore.getInstance().getServer().getPluginManager().registerEvents((Listener) clazz.newInstance(), HubCore.getInstance()); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + } + } + + public static void loadCommands(String packageName) { + for (Class clazz : getClassesInPackage(packageName)) { + try { + clazz.newInstance(); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + } + + public static boolean isListener(Class clazz) { + for (Class interfaze : clazz.getInterfaces()) { + if (interfaze == Listener.class) { + return true; + } + } + + return false; + } + + public static Collection> getClassesInPackage(String packageName) { + JarFile jarFile; + Collection> classes = new ArrayList<>(); + CodeSource codeSource = HubCore.getInstance().getClass().getProtectionDomain().getCodeSource(); + URL resource = codeSource.getLocation(); + + String relPath = packageName.replace('.', '/'); + String resPath = resource.getPath().replace("%20", " "); + String jarPath = resPath.replaceFirst("[.]jar[!].*", ".jar").replaceFirst("file:", ""); + + try { + jarFile = new JarFile(jarPath); + } catch (IOException e) { + throw new IllegalStateException("Unexpected IOException reading JAR File '" + jarPath + "'", e); + } + + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String entryName = entry.getName(); + String className = null; + if (entryName.endsWith(".class") && entryName.startsWith(relPath) && entryName.length() > relPath.length() + "/".length()) { + className = entryName.replace('/', '.').replace('\\', '.').replace(".class", ""); + } + if (className != null) { + Class clazz = null; + try { + clazz = Class.forName(className); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + if (clazz != null) { + classes.add(clazz); + } + } + } + + try { + jarFile.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + return ImmutableSet.copyOf(classes); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/Clickable.java b/src/main/java/com/loganmagnan/hubcore/utils/Clickable.java new file mode 100644 index 0000000..a367aea --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/Clickable.java @@ -0,0 +1,51 @@ +package com.loganmagnan.hubcore.utils; + +import lombok.NoArgsConstructor; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +@NoArgsConstructor +public class Clickable { + + private final List components = new ArrayList<>(); + + public Clickable(String msg) { + TextComponent message = new TextComponent(msg); + this.components.add(message); + } + + public Clickable(String msg, String hoverMsg, String clickString) { + this.add(msg, hoverMsg, clickString); + } + + public TextComponent add(String msg, String hoverMsg, String clickString) { + TextComponent message = new TextComponent(msg); + if (hoverMsg != null) { + message.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(hoverMsg).create())); + } + if (clickString != null) { + message.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, clickString)); + } + this.components.add(message); + + return message; + } + + public void add(String message) { + this.components.add(new TextComponent(message)); + } + + public void sendToPlayer(Player player) { + player.spigot().sendMessage(this.asComponents()); + } + + public TextComponent[] asComponents() { + return this.components.toArray(new TextComponent[0]); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/ColorUtils.java b/src/main/java/com/loganmagnan/hubcore/utils/ColorUtils.java new file mode 100644 index 0000000..e896dca --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/ColorUtils.java @@ -0,0 +1,193 @@ +package com.loganmagnan.hubcore.utils; + +import com.loganmagnan.hubcore.chatcolor.ColorSet; +import lombok.Getter; +import lombok.Setter; +import net.md_5.bungee.api.ChatColor; + +import java.awt.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Getter +@Setter +public class ColorUtils { + + private static Map> colorMap = new HashMap<>(); + + public ColorUtils() { + this.registerColors(); + } + + public void registerColors() { + colorMap.put(ChatColor.BLACK, new ColorSet<>(0, 0, 0)); + colorMap.put(ChatColor.DARK_BLUE, new ColorSet<>(0, 0, 170)); + colorMap.put(ChatColor.DARK_GREEN, new ColorSet<>(0, 170, 0)); + colorMap.put(ChatColor.DARK_AQUA, new ColorSet<>(0, 170, 170)); + colorMap.put(ChatColor.DARK_RED, new ColorSet<>(170, 0, 0)); + colorMap.put(ChatColor.DARK_PURPLE, new ColorSet<>(170, 0, 170)); + colorMap.put(ChatColor.GOLD, new ColorSet<>(255, 170, 0)); + colorMap.put(ChatColor.GRAY, new ColorSet<>(170, 170, 170)); + colorMap.put(ChatColor.DARK_GRAY, new ColorSet<>(85, 85, 85)); + colorMap.put(ChatColor.BLUE, new ColorSet<>(85, 85, 255)); + colorMap.put(ChatColor.GREEN, new ColorSet<>(85, 255, 85)); + colorMap.put(ChatColor.AQUA, new ColorSet<>(85, 255, 255)); + colorMap.put(ChatColor.RED, new ColorSet<>(255, 85, 85)); + colorMap.put(ChatColor.LIGHT_PURPLE, new ColorSet<>(255, 85, 255)); + colorMap.put(ChatColor.YELLOW, new ColorSet<>(255, 255, 85)); + colorMap.put(ChatColor.WHITE, new ColorSet<>(255, 255, 255)); + } + + public static String getMessageType(String message) { + if (message.contains("#")) { + if (isValidHexColorCode(message.substring(message.indexOf("#"), message.indexOf("#") + 7))) { + return translate(message); + } else { + return com.loganmagnan.hubcore.utils.Utils.translate(message); + } + } else { + return Utils.translate(message); + } + } + + public static List getMessageType(List message) { + List messageNew = new ArrayList(); + + for (String string : message) { + if (string.contains("#")) { + if (isValidHexColorCode(string.substring(string.indexOf("#"), string.indexOf("#") + 7))) { + messageNew.add(translate(string)); + } else { + messageNew.add(ColorUtils.getMessageType(string)); + } + } else { + messageNew.add(ColorUtils.getMessageType(string)); + } + } + + return messageNew; + } + + public static ChatColor getColor(String colorCode) { + byte b; + + int i; + + ChatColor[] arrayOfChatColor; + + for (i = (arrayOfChatColor = ChatColor.values()).length, b = 0; b < i; ) { + ChatColor colors = arrayOfChatColor[b]; + + String colorsDecode = untranslate(colors.toString()); + + if (colorCode.equalsIgnoreCase(colorsDecode)) { + return colors; + } + + b++; + } + + return null; + } + + public static boolean lookAtColorCode(String colorCode) { + byte b; + + int i; + + ChatColor[] arrayOfChatColor; + + for (i = (arrayOfChatColor = ChatColor.values()).length, b = 0; b < i; ) { + ChatColor colors = arrayOfChatColor[b]; + + String colorsDecode = untranslate(colors.toString()); + + if (colorCode.equalsIgnoreCase(colorsDecode)) { + return true; + } + + b++; + } + + return false; + } + + public static ColorSet copyColorSet(String colorCode) { + Color color = hexColorCodesToRGBColorCodes(colorCode); + + return new ColorSet(color.getRed(), color.getGreen(), color.getBlue()); + } + + public static String getGradientString(String string, List colorCodes) { + String[] split = string.split(""); + + StringBuilder stringBuilder = new StringBuilder(); + + for (int i = 0; i < colorCodes.size(); i++) { + stringBuilder.append(ChatColor.of(colorCodes.get(i)) + split[i]); + } + + return stringBuilder.toString(); + } + + public static List getColorCodes(String text, ColorSet colorSetOne, ColorSet colorSetTwo) { + List colorCodes = new ArrayList<>(); + + int red = ((colorSetOne.getRed() < colorSetTwo.getRed()) ? (colorSetTwo.getRed() - colorSetOne.getRed()) : (colorSetOne.getRed() - colorSetTwo.getRed())) / text.length(); + int green = ((colorSetOne.getGreen() < colorSetTwo.getGreen()) ? (colorSetTwo.getGreen() - colorSetOne.getGreen()) : (colorSetOne.getGreen() - colorSetTwo.getGreen())) / text.length(); + int blue = ((colorSetOne.getBlue() < colorSetTwo.getBlue()) ? (colorSetTwo.getBlue() - colorSetOne.getBlue()) : (colorSetOne.getBlue() - colorSetTwo.getBlue())) / text.length(); + + for (int i = 0; i < text.length(); i++) { + colorSetOne.setRed((colorSetOne.getRed() <= colorSetTwo.getRed()) ? (colorSetOne.getRed() + red) : (colorSetOne.getRed() - red)); + colorSetOne.setGreen((colorSetOne.getGreen() <= colorSetTwo.getGreen()) ? (colorSetOne.getGreen() + green) : (colorSetOne.getGreen() - green)); + colorSetOne.setBlue((colorSetOne.getBlue() <= colorSetTwo.getBlue()) ? (colorSetOne.getBlue() + blue) : (colorSetOne.getBlue() - blue)); + + String hex = String.format("#%02x%02x%02x", colorSetOne.getRed(), colorSetOne.getGreen(), colorSetOne.getBlue()); + + colorCodes.add(hex); + } + + return colorCodes; + } + + public static String translate(String string) { + Pattern pattern = Pattern.compile("#[a-fA-F0-9]{6}"); + + for (Matcher matcher = pattern.matcher(string); matcher.find(); matcher = pattern.matcher(string)) { + String color = string.substring(matcher.start(), matcher.end()); + + string = string.replace(color, ChatColor.of(color) + ""); + } + + string = ChatColor.translateAlternateColorCodes('&', string); + + return string; + } + + public static Color hexColorCodesToRGBColorCodes(String string) { + return new Color(Integer.valueOf(string.substring(1, 3),16), Integer.valueOf(string.substring(3, 5),16), Integer.valueOf(string.substring(5, 7),16)); + } + + public static boolean isValidHexColorCode(String string) { + Pattern pattern = Pattern.compile("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"); + + Matcher matcher = pattern.matcher(string); + + return matcher.matches(); + } + + public static String untranslate(String textToTranslate) { + char[] b = textToTranslate.toCharArray(); + for (int i = 0; i < b.length - 1; i++) { + if (b[i] == '§' && "0123456789AaBbCcDdEeFfKkLlMmNnOoRrXx".indexOf(b[i + 1]) > -1) { + b[i] = '&'; + b[i + 1] = Character.toLowerCase(b[i + 1]); + } + } + return new String(b); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/Cuboid.java b/src/main/java/com/loganmagnan/hubcore/utils/Cuboid.java new file mode 100644 index 0000000..2b40fdb --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/Cuboid.java @@ -0,0 +1,45 @@ +package com.loganmagnan.hubcore.utils; + +import org.bukkit.Location; + +public class Cuboid { + private final com.loganmagnan.hubcore.utils.Vector3 firstPoint; + private final com.loganmagnan.hubcore.utils.Vector3 secondPoint; + + public Cuboid(final com.loganmagnan.hubcore.utils.Vector3 firstPoint, final com.loganmagnan.hubcore.utils.Vector3 secondPoint) { + this.firstPoint = firstPoint; + this.secondPoint = secondPoint; + } + + public boolean isBetween(final double xP, final double zP) { + double x1 = this.firstPoint.getX(); + double z1 = this.firstPoint.getZ(); + + double x2 = this.secondPoint.getX(); + double z2 = this.secondPoint.getZ(); + + return ((x1 < xP && xP < x2) || (x1 > xP && xP > x2)) && ((z1 < zP && zP < z2) || (z1 > zP && zP > z2)); + } + + public boolean isBetween(final Location target) { + double xP = target.getX(); + double zP = target.getZ(); + + return this.isBetween(xP, zP); + } + + public boolean isBetween(final com.loganmagnan.hubcore.utils.Vector3 target) { + double xP = target.getX(); + double zP = target.getZ(); + + return this.isBetween(xP, zP); + } + + public com.loganmagnan.hubcore.utils.Vector3 getFirstPoint() { + return this.firstPoint; + } + + public Vector3 getSecondPoint() { + return this.secondPoint; + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/CustomLocation.java b/src/main/java/com/loganmagnan/hubcore/utils/CustomLocation.java new file mode 100644 index 0000000..a90038b --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/CustomLocation.java @@ -0,0 +1,125 @@ +package com.loganmagnan.hubcore.utils; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; + +import java.util.StringJoiner; + +@Getter +@Setter +@AllArgsConstructor +public class CustomLocation { + + private final long timestamp = System.currentTimeMillis(); + + private String world; + + private double x; + private double y; + private double z; + + private float yaw; + private float pitch; + + public CustomLocation(double x, double y, double z) { + this(x, y, z, 0.0F, 0.0F); + } + + public CustomLocation(String world, double x, double y, double z) { + this(world, x, y, z, 0.0F, 0.0F); + } + + public CustomLocation(double x, double y, double z, float yaw, float pitch) { + this("world", x, y, z, yaw, pitch); + } + + public static CustomLocation fromBukkitLocation(Location location) { + return new CustomLocation(location.getWorld().getName(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + public static CustomLocation stringToLocation(String string) { + String[] split = string.split(", "); + + double x = Double.parseDouble(split[0]); + double y = Double.parseDouble(split[1]); + double z = Double.parseDouble(split[2]); + + CustomLocation customLocation = new CustomLocation(x, y, z); + if (split.length == 4) { + customLocation.setWorld(split[3]); + } else if (split.length >= 5) { + customLocation.setYaw(Float.parseFloat(split[3])); + customLocation.setPitch(Float.parseFloat(split[4])); + if (split.length >= 6) { + customLocation.setWorld(split[5]); + } + } + + return customLocation; + } + + public static String locationToString(CustomLocation loc) { + StringJoiner joiner = new StringJoiner(", "); + joiner.add(Double.toString(loc.getX())); + joiner.add(Double.toString(loc.getY())); + joiner.add(Double.toString(loc.getZ())); + if (loc.getYaw() == 0.0f && loc.getPitch() == 0.0f) { + if (loc.getWorld().equals("world")) { + return joiner.toString(); + } else { + joiner.add(loc.getWorld()); + return joiner.toString(); + } + } else { + joiner.add(Float.toString(loc.getYaw())); + joiner.add(Float.toString(loc.getPitch())); + if (loc.getWorld().equals("world")) { + return joiner.toString(); + } else { + joiner.add(loc.getWorld()); + return joiner.toString(); + } + } + } + + public Location toBukkitLocation() { + return new Location(this.toBukkitWorld(), this.x, this.y, this.z, this.yaw, this.pitch); + } + + public World toBukkitWorld() { + if (this.world == null) { + return Bukkit.getServer().getWorlds().get(0); + } else { + return Bukkit.getServer().getWorld(this.world); + } + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof CustomLocation)) { + return false; + } + + CustomLocation location = (CustomLocation) obj; + + return location.x == this.x && location.y == this.y && location.z == this.z && location.pitch == this.pitch && location.yaw == this.yaw; + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("x", this.x) + .append("y", this.y) + .append("z", this.z) + .append("yaw", this.yaw) + .append("pitch", this.pitch) + .append("world", this.world) + .append("timestamp", this.timestamp) + .toString(); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/ItemBuilder.java b/src/main/java/com/loganmagnan/hubcore/utils/ItemBuilder.java new file mode 100644 index 0000000..8f1fd9c --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/ItemBuilder.java @@ -0,0 +1,184 @@ +package com.loganmagnan.hubcore.utils; + +import org.bukkit.ChatColor; +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.material.MaterialData; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ItemBuilder implements Listener { + + private final ItemStack is; + + public ItemBuilder(final Material mat) { + is = new ItemStack(mat); + } + + public ItemBuilder(final ItemStack is) { + this.is = is; + } + + public ItemBuilder(Material m, int amount) { + this.is = new ItemStack(m, amount); + } + + public ItemBuilder amount(final int amount) { + is.setAmount(amount); + + return this; + } + + public ItemBuilder name(final String name) { + final ItemMeta meta = is.getItemMeta(); + meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', name)); + is.setItemMeta(meta); + + return this; + } + + public ItemBuilder lore(final String name) { + final ItemMeta meta = is.getItemMeta(); + List lore = meta.getLore(); + if (lore == null) { + lore = new ArrayList<>(); + } + + lore.add(name); + meta.setLore(lore); + is.setItemMeta(meta); + + return this; + } + + public ItemBuilder lore(final List lore) { + List toSet = new ArrayList<>(); + ItemMeta meta = is.getItemMeta(); + + for (String string : lore) { + toSet.add(ChatColor.translateAlternateColorCodes('&', string)); + } + + meta.setLore(toSet); + is.setItemMeta(meta); + return this; + } + + public ItemBuilder durability(final int durability) { + is.setDurability((short) durability); + + return this; + } + + public ItemBuilder owner(String owner) { + if (this.is.getType() == Material.PLAYER_HEAD) { + SkullMeta meta = (SkullMeta) this.is.getItemMeta(); + meta.setOwner(owner); + this.is.setItemMeta(meta); + return this; + } + + throw new IllegalArgumentException("setOwner() only applicable for Skull Item"); + } + + @SuppressWarnings("deprecation") + public ItemBuilder data(final int data) { + is.setData(new MaterialData(is.getType(), (byte) data)); + + return this; + } + + public ItemBuilder enchantment(final Enchantment enchantment, final int level) { + is.addUnsafeEnchantment(enchantment, level); + return this; + } + + public ItemBuilder enchantment(final Enchantment enchantment) { + is.addUnsafeEnchantment(enchantment, 1); + return this; + } + + public ItemBuilder hideFlags() { + final ItemMeta meta = is.getItemMeta(); + meta.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS, ItemFlag.HIDE_UNBREAKABLE, ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS); + is.setItemMeta(meta); + + return this; + } + + public ItemBuilder hideEnchants() { + final ItemMeta meta = is.getItemMeta(); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + is.setItemMeta(meta); + + return this; + } + + public ItemBuilder hideUnbreakable() { + final ItemMeta meta = is.getItemMeta(); + meta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); + is.setItemMeta(meta); + + return this; + } + + public ItemBuilder addUnbreakable() { + final ItemMeta meta = is.getItemMeta(); + meta.setUnbreakable(true); + is.setItemMeta(meta); + + return this; + } + + public ItemBuilder type(final Material material) { + is.setType(material); + return this; + } + + public ItemBuilder clearLore() { + final ItemMeta meta = is.getItemMeta(); + meta.setLore(new ArrayList<>()); + is.setItemMeta(meta); + + return this; + } + + public ItemBuilder clearEnchantments() { + for (final Enchantment e : is.getEnchantments().keySet()) { + is.removeEnchantment(e); + } + + return this; + } + + public ItemBuilder color(Color color) { + if (is.getType() == Material.LEATHER_BOOTS || is.getType() == Material.LEATHER_CHESTPLATE + || is.getType() == Material.LEATHER_HELMET || is.getType() == Material.LEATHER_LEGGINGS) { + LeatherArmorMeta meta = (LeatherArmorMeta) is.getItemMeta(); + meta.setColor(color); + is.setItemMeta(meta); + + return this; + } else { + throw new IllegalArgumentException("color() only applicable for leather armor!"); + } + } + + public ItemBuilder addEnchantments(Map enchantments) { + this.is.addEnchantments(enchantments); + return this; + } + + public ItemStack build() { + return is; + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/ItemUtil.java b/src/main/java/com/loganmagnan/hubcore/utils/ItemUtil.java new file mode 100644 index 0000000..88f28bf --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/ItemUtil.java @@ -0,0 +1,167 @@ +package com.loganmagnan.hubcore.utils; + +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +public final class ItemUtil { + + private ItemUtil() { + throw new RuntimeException("Cannot instantiate a utility class."); + } + + public static ItemStack createItem(Material material, String name) { + ItemStack item = new ItemStack(material); + ItemMeta meta = item.getItemMeta(); + + meta.setDisplayName(name); + item.setItemMeta(meta); + + return item; + } + + public static ItemStack createItem(Material material, String name, int amount) { + ItemStack item = new ItemStack(material, amount); + ItemMeta meta = item.getItemMeta(); + + meta.setDisplayName(name); + item.setItemMeta(meta); + + return item; + } + + public static ItemStack createItem(Material material, String name, int amount, short damage) { + ItemStack item = new ItemStack(material, amount, damage); + ItemMeta meta = item.getItemMeta(); + + meta.setDisplayName(name); + item.setItemMeta(meta); + + return item; + } + + public static ItemStack createUnbreakableItem(Material material, String name, int amount, short damage, int customModelData) { + ItemStack item = new ItemStack(material, amount, damage); + ItemMeta meta = item.getItemMeta(); + + meta.setDisplayName(name); + item.setItemMeta(meta); + + meta.setUnbreakable(true); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_UNBREAKABLE); + + if (customModelData > 0) { + meta.setCustomModelData(customModelData); + } + + item.setItemMeta(meta); + + return item; + } + + public static ItemStack createNoFlagsItem(Material material, String name, int amount, short damage) { + ItemStack item = new ItemStack(material, amount, damage); + ItemMeta meta = item.getItemMeta(); + + meta.setDisplayName(name); + item.setItemMeta(meta); + + meta.setUnbreakable(true); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_UNBREAKABLE, ItemFlag.HIDE_POTION_EFFECTS, ItemFlag.HIDE_UNBREAKABLE, ItemFlag.HIDE_ATTRIBUTES); + item.setItemMeta(meta); + + return item; + } + + public static ItemStack createPlayerHead(Material material, String name, String playerHead, int amount, short damage) { + ItemStack item = new ItemStack(material, amount, damage); + ItemMeta meta = item.getItemMeta(); + + meta.setDisplayName(name); + item.setItemMeta(meta); + + meta.setUnbreakable(true); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_UNBREAKABLE); + item.setItemMeta(meta); + + if (item.getType() == Material.PLAYER_HEAD) { + SkullMeta skullMeta = (SkullMeta) item.getItemMeta(); + skullMeta.setOwner(playerHead); + item.setItemMeta(skullMeta); + + return item; + } + + return item; + } + + public static ItemStack setUnbreakable(ItemStack item) { + ItemMeta meta = item.getItemMeta(); + + meta.setUnbreakable(true); + meta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); + item.setItemMeta(meta); + + return item; + } + + public static ItemStack renameItem(ItemStack item, String name) { + ItemMeta meta = item.getItemMeta(); + + meta.setDisplayName(name); + item.setItemMeta(meta); + + return item; + } + + public static ItemStack reloreItem(ItemStack item, String... lores) { + return reloreItem(ReloreType.OVERWRITE, item, lores); + } + + public static ItemStack reEnchantItem(ItemStack itemStack, Enchantment enchantment, int level, boolean b) { + ItemMeta meta = itemStack.getItemMeta(); + + meta.addEnchant(enchantment, level, b); + + itemStack.setItemMeta(meta); + return itemStack; + } + + public static ItemStack reloreItem(ReloreType type, ItemStack item, String... lores) { + ItemMeta meta = item.getItemMeta(); + + List lore = meta.getLore(); + if (lore == null) { + lore = new LinkedList<>(); + } + + switch (type) { + case APPEND: + lore.addAll(Arrays.asList(lores)); + meta.setLore(lore); + break; + case PREPEND: + List nLore = new LinkedList<>(Arrays.asList(lores)); + nLore.addAll(lore); + meta.setLore(nLore); + break; + case OVERWRITE: + meta.setLore(Arrays.asList(lores)); + break; + } + + item.setItemMeta(meta); + return item; + } + + public enum ReloreType { + OVERWRITE, PREPEND, APPEND + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/LocationUtils.java b/src/main/java/com/loganmagnan/hubcore/utils/LocationUtils.java new file mode 100644 index 0000000..8443fc0 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/LocationUtils.java @@ -0,0 +1,34 @@ +package com.loganmagnan.hubcore.utils; + +import org.bukkit.Location; +import org.bukkit.block.Block; + +import java.util.ArrayList; +import java.util.List; + +public class LocationUtils { + + public static List getBlocks(Location center, int radius) { + return getBlocks(center, radius, radius); + } + + public static List getBlocks(Location center, int radius, int yRadius) { + if (radius < 0) { + return new ArrayList<>(); + } + + int iterations = radius * 2 + 1; + + List blocks = new ArrayList<>(iterations * iterations * iterations); + + for (int x = -radius; x <= radius; x++) { + for (int y = -yRadius; y <= yRadius; y++) { + for (int z = -radius; z <= radius; z++) { + blocks.add(center.getBlock().getRelative(x, y, z)); + } + } + } + + return blocks; + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/MathUtil.java b/src/main/java/com/loganmagnan/hubcore/utils/MathUtil.java new file mode 100644 index 0000000..4fe074e --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/MathUtil.java @@ -0,0 +1,58 @@ + package com.loganmagnan.hubcore.utils; + + import java.util.Random; + + public final class MathUtil + { + public static boolean isInteger(String in) { + try { + Integer.parseInt(in); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + public static int randomNumber(int minimo, int maximo) { + Random random = new Random(); + int min = Math.min(maximo, maximo); + int max = Math.max(maximo, maximo); + int maxsize = min - max; + + return random.nextInt(maxsize + 1) + minimo; + } + + public static String convertTicksToMinutes(int ticks) { + long minute = ticks / 1200L; + long second = ticks / 20L - minute * 60L; + + String secondString = Math.round((float)second) + ""; + if (second < 10L) { + secondString = Character.MIN_VALUE + secondString; + } + + String minuteString = Math.round((float)minute) + ""; + if (minute == 0L) { + minuteString = "0"; + } + + return minuteString + ":" + secondString; + } + + public static String convertToRomanNumeral(int number) { + switch (number) { + case 1: + return "I"; + case 2: + return "II"; + } + + return null; + } + + public static double roundToHalves(double d) { + return Math.round(d * 2.0D) / 2.0D; + } + } + + diff --git a/src/main/java/com/loganmagnan/hubcore/utils/NBTEditor.java b/src/main/java/com/loganmagnan/hubcore/utils/NBTEditor.java new file mode 100644 index 0000000..7eedd82 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/NBTEditor.java @@ -0,0 +1,1571 @@ +package com.loganmagnan.hubcore.utils; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class NBTEditor { + + private static final Map< String, Class< ? > > classCache; + private static final Map< String, Method > methodCache; + private static final Map< Class< ? >, Constructor< ? > > constructorCache; + private static final Map< Class< ? >, Class< ? > > NBTClasses; + private static final Map< Class< ? >, Field > NBTTagFieldCache; + private static Field NBTListData; + private static Field NBTCompoundMap; + private static final String VERSION; + private static final MinecraftVersion LOCAL_VERSION; + + public static final Type COMPOUND = Type.COMPOUND; + public static final Type LIST = Type.LIST; + public static final Type NEW_ELEMENT = Type.NEW_ELEMENT; + public static final Type DELETE = Type.DELETE; + + static { + VERSION = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; + LOCAL_VERSION = MinecraftVersion.get( VERSION ); + + classCache = new HashMap< String, Class >(); + try { + if ( LOCAL_VERSION.lessThanOrEqualTo( MinecraftVersion.v1_16 ) ) { + classCache.put( "NBTBase", Class.forName( "net.minecraft.server." + VERSION + "." + "NBTBase" ) ); + classCache.put( "NBTTagCompound", Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagCompound" ) ); + classCache.put( "NBTTagList", Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagList" ) ); + classCache.put( "NBTTagEnd", Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagEnd" ) ); + classCache.put( "MojangsonParser", Class.forName( "net.minecraft.server." + VERSION + "." + "MojangsonParser" ) ); + + classCache.put( "ItemStack", Class.forName( "net.minecraft.server." + VERSION + "." + "ItemStack" ) ); + + classCache.put( "Entity", Class.forName( "net.minecraft.server." + VERSION + "." + "Entity" ) ); + classCache.put( "EntityLiving", Class.forName( "net.minecraft.server." + VERSION + "." + "EntityLiving" ) ); + + classCache.put( "BlockPosition", Class.forName( "net.minecraft.server." + VERSION + "." + "BlockPosition" ) ); + classCache.put( "TileEntity", Class.forName( "net.minecraft.server." + VERSION + "." + "TileEntity" ) ); + classCache.put( "World", Class.forName( "net.minecraft.server." + VERSION + "." + "World" ) ); + classCache.put( "IBlockData", Class.forName( "net.minecraft.server." + VERSION + "." + "IBlockData" ) ); + + classCache.put( "TileEntitySkull", Class.forName( "net.minecraft.server." + VERSION + "." + "TileEntitySkull" ) ); + + } else { + classCache.put( "BlockPosition", Class.forName( "net.minecraft.core.BlockPosition" ) ); + + classCache.put( "NBTBase", Class.forName( "net.minecraft.nbt.NBTBase" ) ); + classCache.put( "NBTTagCompound", Class.forName( "net.minecraft.nbt.NBTTagCompound" ) ); + classCache.put( "NBTTagList", Class.forName( "net.minecraft.nbt.NBTTagList" ) ); + classCache.put( "NBTTagEnd", Class.forName( "net.minecraft.nbt.NBTTagEnd" ) ); + classCache.put( "MojangsonParser", Class.forName( "net.minecraft.nbt.MojangsonParser" ) ); + + classCache.put( "ItemStack", Class.forName( "net.minecraft.world.item.ItemStack" ) ); + + classCache.put( "Entity", Class.forName( "net.minecraft.world.entity.Entity" ) ); + classCache.put( "EntityLiving", Class.forName( "net.minecraft.world.entity.EntityLiving" ) ); + + classCache.put( "World", Class.forName( "net.minecraft.world.level.World" ) ); + classCache.put( "IBlockData", Class.forName( "net.minecraft.world.level.block.state.IBlockData" ) ); + classCache.put( "TileEntity", Class.forName( "net.minecraft.world.level.block.entity.TileEntity" ) ); + classCache.put( "TileEntitySkull", Class.forName( "net.minecraft.world.level.block.entity.TileEntitySkull" ) ); + } + + classCache.put( "CraftItemStack", Class.forName( "org.bukkit.craftbukkit." + VERSION + ".inventory." + "CraftItemStack" ) ); + classCache.put( "CraftMetaSkull", Class.forName( "org.bukkit.craftbukkit." + VERSION + ".inventory." + "CraftMetaSkull" ) ); + + classCache.put( "CraftEntity", Class.forName( "org.bukkit.craftbukkit." + VERSION + ".entity." + "CraftEntity" ) ); + + classCache.put( "CraftWorld", Class.forName( "org.bukkit.craftbukkit." + VERSION + "." + "CraftWorld" ) ); + classCache.put( "CraftBlockState", Class.forName( "org.bukkit.craftbukkit." + VERSION + ".block." + "CraftBlockState" ) ); + + classCache.put( "GameProfile", Class.forName( "com.mojang.authlib.GameProfile" ) ); + classCache.put( "Property", Class.forName( "com.mojang.authlib.properties.Property" ) ); + classCache.put( "PropertyMap", Class.forName( "com.mojang.authlib.properties.PropertyMap" ) ); + } catch ( ClassNotFoundException e ) { + e.printStackTrace(); + } + + NBTClasses = new HashMap< Class< ? >, Class< ? > >(); + try { + if ( LOCAL_VERSION.lessThanOrEqualTo( MinecraftVersion.v1_16 ) ) { + NBTClasses.put( Byte.class, Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagByte" ) ); + NBTClasses.put( Boolean.class, Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagByte" ) ); + NBTClasses.put( String.class, Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagString" ) ); + NBTClasses.put( Double.class, Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagDouble" ) ); + NBTClasses.put( Integer.class, Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagInt" ) ); + NBTClasses.put( Long.class, Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagLong" ) ); + NBTClasses.put( Short.class, Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagShort" ) ); + NBTClasses.put( Float.class, Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagFloat" ) ); + NBTClasses.put( Class.forName( "[B" ), Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagByteArray" ) ); + NBTClasses.put( Class.forName( "[I" ), Class.forName( "net.minecraft.server." + VERSION + "." + "NBTTagIntArray" ) ); + } else { + NBTClasses.put( Byte.class, Class.forName( "net.minecraft.nbt.NBTTagByte" ) ); + NBTClasses.put( Boolean.class, Class.forName( "net.minecraft.nbt.NBTTagByte" ) ); + NBTClasses.put( String.class, Class.forName( "net.minecraft.nbt.NBTTagString" ) ); + NBTClasses.put( Double.class, Class.forName( "net.minecraft.nbt.NBTTagDouble" ) ); + NBTClasses.put( Integer.class, Class.forName( "net.minecraft.nbt.NBTTagInt" ) ); + NBTClasses.put( Long.class, Class.forName( "net.minecraft.nbt.NBTTagLong" ) ); + NBTClasses.put( Short.class, Class.forName( "net.minecraft.nbt.NBTTagShort" ) ); + NBTClasses.put( Float.class, Class.forName( "net.minecraft.nbt.NBTTagFloat" ) ); + NBTClasses.put( Class.forName( "[B" ), Class.forName( "net.minecraft.nbt.NBTTagByteArray" ) ); + NBTClasses.put( Class.forName( "[I" ), Class.forName( "net.minecraft.nbt.NBTTagIntArray" ) ); + } + } catch ( ClassNotFoundException e ) { + e.printStackTrace(); + } + + methodCache = new HashMap< String, Method >(); + try { + if ( LOCAL_VERSION.lessThanOrEqualTo( MinecraftVersion.v1_17 ) ) { + methodCache.put( "get", getNMSClass( "NBTTagCompound" ).getMethod( "get", String.class ) ); + methodCache.put( "set", getNMSClass( "NBTTagCompound" ).getMethod( "set", String.class, getNMSClass( "NBTBase" ) ) ); + methodCache.put( "hasKey", getNMSClass( "NBTTagCompound" ).getMethod( "hasKey", String.class ) ); + } else { + methodCache.put( "get", getNMSClass( "NBTTagCompound" ).getMethod( "c", String.class ) ); + methodCache.put( "set", getNMSClass( "NBTTagCompound" ).getMethod( "a", String.class, getNMSClass( "NBTBase" ) ) ); + methodCache.put( "hasKey", getNMSClass( "NBTTagCompound" ).getMethod( "e", String.class ) ); + } + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + methodCache.put( "setIndex", getNMSClass( "NBTTagList" ).getMethod( "d", int.class, getNMSClass( "NBTBase" ) ) ); + } else if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_17 ) ) { + methodCache.put( "setIndex", getNMSClass( "NBTTagList" ).getMethod( "set", int.class, getNMSClass( "NBTBase" ) ) ); + } else { + methodCache.put( "setIndex", getNMSClass( "NBTTagList" ).getMethod( "a", int.class, getNMSClass( "NBTBase" ) ) ); + } + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + methodCache.put( "add", getNMSClass( "NBTTagList" ).getMethod( "c", int.class, getNMSClass( "NBTBase" ) ) ); + } else if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_14 ) ) { + methodCache.put( "add", getNMSClass( "NBTTagList" ).getMethod( "add", int.class, getNMSClass( "NBTBase" ) ) ); + } else { + methodCache.put( "add", getNMSClass( "NBTTagList" ).getMethod( "add", getNMSClass( "NBTBase" ) ) ); + } + methodCache.put( "size", getNMSClass( "NBTTagList" ).getMethod( "size" ) ); + + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + methodCache.put( "listRemove", getNMSClass( "NBTTagList" ).getMethod( "c", int.class ) ); + } else if ( LOCAL_VERSION == MinecraftVersion.v1_8 ) { + methodCache.put( "listRemove", getNMSClass( "NBTTagList" ).getMethod( "a", int.class ) ); + } else { + methodCache.put( "listRemove", getNMSClass( "NBTTagList" ).getMethod( "remove", int.class ) ); + } + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + methodCache.put( "remove", getNMSClass( "NBTTagCompound" ).getMethod( "r", String.class ) ); + } else { + methodCache.put( "remove", getNMSClass( "NBTTagCompound" ).getMethod( "remove", String.class ) ); + } + if ( LOCAL_VERSION.lessThanOrEqualTo( MinecraftVersion.v1_12 ) ) { + methodCache.put( "getKeys", getNMSClass( "NBTTagCompound" ).getMethod( "c" ) ); + } else if ( LOCAL_VERSION.lessThanOrEqualTo( MinecraftVersion.v1_17 ) ) { + methodCache.put( "getKeys", getNMSClass( "NBTTagCompound" ).getMethod( "getKeys" ) ); + } else { + methodCache.put( "getKeys", getNMSClass( "NBTTagCompound" ).getMethod( "d" ) ); + } + + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_19 ) ) { + methodCache.put( "hasTag", getNMSClass( "ItemStack" ).getMethod( "t" ) ); + methodCache.put( "getTag", getNMSClass( "ItemStack" ).getMethod( "u" ) ); + methodCache.put( "setTag", getNMSClass( "ItemStack" ).getMethod( "c", getNMSClass( "NBTTagCompound" ) ) ); + } else if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R2 ) ) { + methodCache.put( "hasTag", getNMSClass( "ItemStack" ).getMethod( "s" ) ); + methodCache.put( "getTag", getNMSClass( "ItemStack" ).getMethod( "t" ) ); + methodCache.put( "setTag", getNMSClass( "ItemStack" ).getMethod( "c", getNMSClass( "NBTTagCompound" ) ) ); + } else if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + methodCache.put( "hasTag", getNMSClass( "ItemStack" ).getMethod( "r" ) ); + methodCache.put( "getTag", getNMSClass( "ItemStack" ).getMethod( "s" ) ); + methodCache.put( "setTag", getNMSClass( "ItemStack" ).getMethod( "c", getNMSClass( "NBTTagCompound" ) ) ); + } else { + methodCache.put( "hasTag", getNMSClass( "ItemStack" ).getMethod( "hasTag" ) ); + methodCache.put( "getTag", getNMSClass( "ItemStack" ).getMethod( "getTag" ) ); + methodCache.put( "setTag", getNMSClass( "ItemStack" ).getMethod( "setTag", getNMSClass( "NBTTagCompound" ) ) ); + } + methodCache.put( "asNMSCopy", getNMSClass( "CraftItemStack" ).getMethod( "asNMSCopy", ItemStack.class ) ); + methodCache.put( "asBukkitCopy", getNMSClass( "CraftItemStack" ).getMethod( "asBukkitCopy", getNMSClass( "ItemStack" ) ) ); + + methodCache.put( "getEntityHandle", getNMSClass( "CraftEntity" ).getMethod( "getHandle" ) ); + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + methodCache.put( "getEntityTag", getNMSClass( "Entity" ).getMethod( "f", getNMSClass( "NBTTagCompound" ) ) ); + methodCache.put( "setEntityTag", getNMSClass( "Entity" ).getMethod( "g", getNMSClass( "NBTTagCompound" ) ) ); + } else if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_16 ) ) { + methodCache.put( "getEntityTag", getNMSClass( "Entity" ).getMethod( "save", getNMSClass( "NBTTagCompound" ) ) ); + methodCache.put( "setEntityTag", getNMSClass( "Entity" ).getMethod( "load", getNMSClass( "NBTTagCompound" ) ) ); + } else { + methodCache.put( "getEntityTag", getNMSClass( "Entity" ).getMethod( "c", getNMSClass( "NBTTagCompound" ) ) ); + methodCache.put( "setEntityTag", getNMSClass( "Entity" ).getMethod( "f", getNMSClass( "NBTTagCompound" ) ) ); + } + + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + methodCache.put( "save", getNMSClass( "ItemStack" ).getMethod( "b", getNMSClass( "NBTTagCompound" ) ) ); + } else { + methodCache.put( "save", getNMSClass( "ItemStack" ).getMethod( "save", getNMSClass( "NBTTagCompound" ) ) ); + } + + if ( LOCAL_VERSION.lessThanOrEqualTo( MinecraftVersion.v1_10 ) ) { + methodCache.put( "createStack", getNMSClass( "ItemStack" ).getMethod( "createStack", getNMSClass( "NBTTagCompound" ) ) ); + } else if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_13 ) ) { + methodCache.put( "createStack", getNMSClass( "ItemStack" ).getMethod( "a", getNMSClass( "NBTTagCompound" ) ) ); + } + + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + methodCache.put( "setTileTag", getNMSClass( "TileEntity" ).getMethod( "a", getNMSClass( "NBTTagCompound" ) ) ); + } else if ( LOCAL_VERSION == MinecraftVersion.v1_16 ) { + methodCache.put( "setTileTag", getNMSClass( "TileEntity" ).getMethod( "load", getNMSClass( "IBlockData" ), getNMSClass( "NBTTagCompound" ) ) ); + methodCache.put( "getType", getNMSClass( "World" ).getMethod( "getType", getNMSClass( "BlockPosition" ) ) ); + } else if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_12 ) ) { + methodCache.put( "setTileTag", getNMSClass( "TileEntity" ).getMethod( "load", getNMSClass( "NBTTagCompound" ) ) ); + } else { + methodCache.put( "setTileTag", getNMSClass( "TileEntity" ).getMethod( "a", getNMSClass( "NBTTagCompound" ) ) ); + } + + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + methodCache.put( "getTileTag", getNMSClass( "TileEntity" ).getMethod( "m" ) ); + } else if ( LOCAL_VERSION == MinecraftVersion.v1_8 ) { + methodCache.put( "getTileTag", getNMSClass( "TileEntity" ).getMethod( "b", getNMSClass( "NBTTagCompound" ) ) ); + } else { + methodCache.put( "getTileTag", getNMSClass( "TileEntity" ).getMethod( "save", getNMSClass( "NBTTagCompound" ) ) ); + } + + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + methodCache.put( "getTileEntity", getNMSClass( "World" ).getMethod( "c_", getNMSClass( "BlockPosition" ) ) ); + } else { + methodCache.put( "getTileEntity", getNMSClass( "World" ).getMethod( "getTileEntity", getNMSClass( "BlockPosition" ) ) ); + } + methodCache.put( "getWorldHandle", getNMSClass( "CraftWorld" ).getMethod( "getHandle" ) ); + + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + methodCache.put( "setGameProfile", getNMSClass( "TileEntitySkull" ).getMethod( "a", getNMSClass( "GameProfile" ) ) ); + } else { + methodCache.put( "setGameProfile", getNMSClass( "TileEntitySkull" ).getMethod( "setGameProfile", getNMSClass( "GameProfile" ) ) ); + } + methodCache.put( "getProperties", getNMSClass( "GameProfile" ).getMethod( "getProperties" ) ); + methodCache.put( "getName", getNMSClass( "Property" ).getMethod( "getName" ) ); + methodCache.put( "getValue", getNMSClass( "Property" ).getMethod( "getValue" ) ); + methodCache.put( "values", getNMSClass( "PropertyMap" ).getMethod( "values" ) ); + methodCache.put( "put", getNMSClass( "PropertyMap" ).getMethod( "put", Object.class, Object.class ) ); + + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + methodCache.put( "loadNBTTagCompound", getNMSClass( "MojangsonParser" ).getMethod( "a", String.class ) ); + } else { + methodCache.put( "loadNBTTagCompound", getNMSClass( "MojangsonParser" ).getMethod( "parse", String.class ) ); + } + } catch( Exception e ) { + e.printStackTrace(); + } + + try { + methodCache.put( "setProfile", getNMSClass( "CraftMetaSkull" ).getDeclaredMethod( "setProfile", getNMSClass( "GameProfile" ) ) ); + methodCache.get( "setProfile" ).setAccessible( true ); + } catch( NoSuchMethodException exception ) { + // The method doesn't exist, so it's before 1.15.2 + } + + constructorCache = new HashMap< Class< ? >, Constructor< ? > >(); + try { + constructorCache.put( getNBTTag( Byte.class ), getNBTTag( Byte.class ).getDeclaredConstructor( byte.class ) ); + constructorCache.put( getNBTTag( Boolean.class ), getNBTTag( Boolean.class ).getDeclaredConstructor( byte.class ) ); + constructorCache.put( getNBTTag( String.class ), getNBTTag( String.class ).getDeclaredConstructor( String.class ) ); + constructorCache.put( getNBTTag( Double.class ), getNBTTag( Double.class ).getDeclaredConstructor( double.class ) ); + constructorCache.put( getNBTTag( Integer.class ), getNBTTag( Integer.class ).getDeclaredConstructor( int.class ) ); + constructorCache.put( getNBTTag( Long.class ), getNBTTag( Long.class ).getDeclaredConstructor( long.class ) ); + constructorCache.put( getNBTTag( Float.class ), getNBTTag( Float.class ).getDeclaredConstructor( float.class ) ); + constructorCache.put( getNBTTag( Short.class ), getNBTTag( Short.class ).getDeclaredConstructor( short.class ) ); + constructorCache.put( getNBTTag( Class.forName( "[B" ) ), getNBTTag( Class.forName( "[B" ) ).getDeclaredConstructor( Class.forName( "[B" ) ) ); + constructorCache.put( getNBTTag( Class.forName( "[I" ) ), getNBTTag( Class.forName( "[I" ) ).getDeclaredConstructor( Class.forName( "[I" ) ) ); + + // This is for 1.15 since Mojang decided to make the constructors private + for ( Constructor< ? > cons : constructorCache.values() ) { + cons.setAccessible( true ); + } + + constructorCache.put( getNMSClass( "BlockPosition" ), getNMSClass( "BlockPosition" ).getConstructor( int.class, int.class, int.class ) ); + + constructorCache.put( getNMSClass( "GameProfile" ), getNMSClass( "GameProfile" ).getConstructor( UUID.class, String.class ) ); + constructorCache.put( getNMSClass( "Property" ), getNMSClass( "Property" ).getConstructor( String.class, String.class ) ); + + if ( LOCAL_VERSION == MinecraftVersion.v1_11 || LOCAL_VERSION == MinecraftVersion.v1_12 ) { + constructorCache.put( getNMSClass( "ItemStack" ), getNMSClass( "ItemStack" ).getConstructor( getNMSClass( "NBTTagCompound" ) ) ); + } + } catch( Exception e ) { + e.printStackTrace(); + } + + NBTTagFieldCache = new HashMap< Class< ? >, Field >(); + try { + if ( LOCAL_VERSION.lessThanOrEqualTo( MinecraftVersion.v1_16 ) ) { + for ( Class< ? > clazz : NBTClasses.values() ) { + Field data = clazz.getDeclaredField( "data" ); + data.setAccessible( true ); + NBTTagFieldCache.put( clazz, data ); + } + } else { + NBTTagFieldCache.put( NBTClasses.get( Byte.class ), NBTClasses.get( Byte.class ).getDeclaredField( "x" ) ); + NBTTagFieldCache.put( NBTClasses.get( Boolean.class ), NBTClasses.get( Boolean.class ).getDeclaredField( "x" ) ); + NBTTagFieldCache.put( NBTClasses.get( String.class ), NBTClasses.get( String.class ).getDeclaredField( "A" ) ); + NBTTagFieldCache.put( NBTClasses.get( Double.class ), NBTClasses.get( Double.class ).getDeclaredField( "w" ) ); + NBTTagFieldCache.put( NBTClasses.get( Integer.class ), NBTClasses.get( Integer.class ).getDeclaredField( "c" ) ); + NBTTagFieldCache.put( NBTClasses.get( Long.class ), NBTClasses.get( Long.class ).getDeclaredField( "c" ) ); + NBTTagFieldCache.put( NBTClasses.get( Float.class ), NBTClasses.get( Float.class ).getDeclaredField( "w" ) ); + NBTTagFieldCache.put( NBTClasses.get( Short.class ), NBTClasses.get( Short.class ).getDeclaredField( "c" ) ); + NBTTagFieldCache.put( NBTClasses.get( Class.forName( "[B" ) ), NBTClasses.get( Class.forName( "[B" ) ).getDeclaredField( "c" ) ); + NBTTagFieldCache.put( NBTClasses.get( Class.forName( "[I" ) ), NBTClasses.get( Class.forName( "[I" ) ).getDeclaredField( "c" ) ); + + for ( Field field : NBTTagFieldCache.values() ) { + field.setAccessible( true ); + } + } + } catch( Exception e ) { + e.printStackTrace(); + } + + try { + if ( LOCAL_VERSION.lessThanOrEqualTo( MinecraftVersion.v1_16 ) ) { + NBTListData = getNMSClass( "NBTTagList" ).getDeclaredField( "list" ); + NBTCompoundMap = getNMSClass( "NBTTagCompound" ).getDeclaredField( "map" ); + } else { + NBTListData = getNMSClass( "NBTTagList" ).getDeclaredField( "c" ); + NBTCompoundMap = getNMSClass( "NBTTagCompound" ).getDeclaredField( "x" ); + } + NBTListData.setAccessible( true ); + NBTCompoundMap.setAccessible( true ); + } catch( Exception e ) { + e.printStackTrace(); + } + } + + private static Class< ? > getNBTTag( Class< ? > primitiveType ) { + if ( NBTClasses.containsKey( primitiveType ) ) + return NBTClasses.get( primitiveType ); + return primitiveType; + } + + private static Object getNBTVar( Object object ) { + if ( object == null ) { + return null; + } + Class< ? > clazz = object.getClass(); + try { + if ( NBTTagFieldCache.containsKey( clazz ) ) { + return NBTTagFieldCache.get( clazz ).get( object ); + } + } catch ( Exception exception ) { + exception.printStackTrace(); + } + return null; + } + + private static Method getMethod( String name ) { + return methodCache.containsKey( name ) ? methodCache.get( name ) : null; + } + + private static Constructor< ? > getConstructor( Class< ? > clazz ) { + return constructorCache.containsKey( clazz ) ? constructorCache.get( clazz ) : null; + } + + private static Class getNMSClass(String name) { + if ( classCache.containsKey( name ) ) { + return classCache.get( name ); + } + + try { + return Class.forName("net.minecraft.server." + VERSION + "." + name); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + private static String getMatch( String string, String regex ) { + Pattern pattern = Pattern.compile( regex ); + Matcher matcher = pattern.matcher( string ); + if ( matcher.find() ) { + return matcher.group( 1 ); + } else { + return null; + } + } + + private static Object createItemStack( Object compound ) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException { + if ( LOCAL_VERSION == MinecraftVersion.v1_11 || LOCAL_VERSION == MinecraftVersion.v1_12 ) { + return getConstructor( getNMSClass( "ItemStack" ) ).newInstance( compound ); + } + return getMethod( "createStack" ).invoke( null, compound ); + } + + /** + * Gets the Bukkit version + * + * @return + * The Bukkit version in standard package format + */ + public static String getVersion() { + return VERSION; + } + + public static MinecraftVersion getMinecraftVersion() { + return LOCAL_VERSION; + } + + /** + * Creates a skull with the given url as the skin + * + * @param skinURL + * The URL of the skin, must be from mojang + * @return + * An item stack with count of 1 + */ + public static ItemStack getHead( String skinURL ) { + Material material = Material.getMaterial( "SKULL_ITEM" ); + if ( material == null ) { + // Most likely 1.13 materials + material = Material.getMaterial( "PLAYER_HEAD" ); + } + ItemStack head = new ItemStack( material, 1, ( short ) 3 ); + if ( skinURL == null || skinURL.isEmpty() ) { + return head; + } + ItemMeta headMeta = head.getItemMeta(); + Object profile = null; + try { + profile = getConstructor( getNMSClass( "GameProfile" ) ).newInstance( UUID.randomUUID(), null ); + Object propertyMap = getMethod( "getProperties" ).invoke( profile ); + Object textureProperty = getConstructor( getNMSClass( "Property" ) ).newInstance( "textures", new String( Base64.getEncoder().encode( String.format( "{textures:{SKIN:{\"url\":\"%s\"}}}", skinURL ).getBytes() ) ) ); + getMethod( "put" ).invoke( propertyMap, "textures", textureProperty ); + } catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException | InstantiationException e1 ) { + e1.printStackTrace(); + } + + if ( methodCache.containsKey( "setProfile" ) ) { + try { + getMethod( "setProfile" ).invoke( headMeta, profile ); + } catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) { + e.printStackTrace(); + } + } else { + Field profileField = null; + try { + profileField = headMeta.getClass().getDeclaredField("profile"); + } catch ( NoSuchFieldException | SecurityException e ) { + e.printStackTrace(); + } + profileField.setAccessible(true); + try { + profileField.set(headMeta, profile); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + } + head.setItemMeta(headMeta); + return head; + } + + /** + * Fetches the texture of a skull + * + * @param head + * The item stack itself + * @return + * The URL of the texture + */ + public static String getTexture( ItemStack head ) { + ItemMeta meta = head.getItemMeta(); + Field profileField = null; + try { + profileField = meta.getClass().getDeclaredField("profile"); + } catch ( NoSuchFieldException | SecurityException e ) { + e.printStackTrace(); + throw new IllegalArgumentException( "Item is not a player skull!" ); + } + profileField.setAccessible(true); + try { + Object profile = profileField.get( meta ); + if ( profile == null ) { + return null; + } + + Collection< Object > properties = ( Collection< Object > ) getMethod( "values" ).invoke( getMethod( "getProperties" ).invoke( profile ) ); + for ( Object prop : properties ) { + if ( "textures".equals( getMethod( "getName" ).invoke( prop ) ) ) { + String texture = new String( Base64.getDecoder().decode( ( String ) getMethod( "getValue" ).invoke( prop ) ) ); + return getMatch( texture, "\\{\"url\":\"(.*?)\"\\}" ); + } + } + return null; + } catch ( IllegalArgumentException | IllegalAccessException | SecurityException | InvocationTargetException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Gets an NBT tag in a given item with the specified keys + * + * @param item + * The itemstack to get the keys from + * @param keys + * The keys to fetch; an integer after a key value indicates that it should get the nth place of + * the previous compound because it is a list; + * @return + * The item represented by the keys, and an integer if it is showing how long a list is. + */ + private static Object getItemTag( ItemStack item, Object... keys ) { + try { + return getTag( getCompound( item ), keys ); + } catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) { + e.printStackTrace(); + return null; + } + } + + // Gets the NBTTagCompound + private static Object getCompound( ItemStack item ) { + if ( item == null ) { + return null; + } + try { + Object stack = null; + stack = getMethod( "asNMSCopy" ).invoke( null, item ); + + Object tag = null; + + if ( getMethod( "hasTag" ).invoke( stack ).equals( true ) ) { + tag = getMethod( "getTag" ).invoke( stack ); + } else { + tag = getNMSClass( "NBTTagCompound" ).newInstance(); + } + + return tag; + } catch ( Exception exception ) { + exception.printStackTrace(); + return null; + } + } + + /** + * Gets an NBTCompound from the item provided. Use {@link #getNBTCompound(Object, Object...)} instead. + * + * @param item + * Itemstack + * @param keys + * Keys in descending order + * @return + * An NBTCompound + */ + private static NBTCompound getItemNBTTag( ItemStack item, Object... keys ) { + if ( item == null ) { + return null; + } + try { + Object stack = null; + stack = getMethod( "asNMSCopy" ).invoke( null, item ); + + Object tag = getNMSClass( "NBTTagCompound" ).newInstance(); + + tag = getMethod( "save" ).invoke( stack, tag ); + + return getNBTTag( tag, keys ); + } catch ( Exception exception ) { + exception.printStackTrace(); + return null; + } + } + + /** + * Sets an NBT tag in an item with the provided keys and value + * Should use the {@link #set(Object, Object, Object...)} method instead + * + * @param item + * The itemstack to set + * @param value + * The value to set + * @param keys + * The keys to set, String for NBTCompound, int or null for an NBTTagList + * @return + * A new ItemStack with the updated NBT tags + */ + private static ItemStack setItemTag( ItemStack item, Object value, Object... keys ) { + if ( item == null ) { + return null; + } + try { + Object stack = getMethod( "asNMSCopy" ).invoke( null, item ); + + Object tag = null; + + if ( getMethod( "hasTag" ).invoke( stack ).equals( true ) ) { + tag = getMethod( "getTag" ).invoke( stack ); + } else { + tag = getNMSClass( "NBTTagCompound" ).newInstance(); + } + + if ( keys.length == 0 && value instanceof NBTCompound ) { + tag = ( ( NBTCompound ) value ).tag; + } else { + setTag( tag, value, keys ); + } + + getMethod( "setTag" ).invoke( stack, tag ); + return ( ItemStack ) getMethod( "asBukkitCopy" ).invoke( null, stack ); + } catch ( Exception exception ) { + exception.printStackTrace(); + return null; + } + } + + /** + * Constructs an ItemStack from a given NBTCompound + * + * @param compound + * An NBTCompound following an ItemStack structure + * @return + * A new ItemStack + */ + public static ItemStack getItemFromTag( NBTCompound compound ) { + if ( compound == null ) { + return null; + } + try { + Object tag = compound.tag; + Object count = getTag( tag, "Count" ); + Object id = getTag( tag, "id" ); + if ( count == null || id == null ) { + return null; + } + if ( count instanceof Byte && id instanceof String ) { + return ( ItemStack ) getMethod( "asBukkitCopy" ).invoke( null, createItemStack( tag ) ); + } + return null; + } catch ( Exception exception ) { + exception.printStackTrace(); + return null; + } + } + + /** + * Gets an NBT tag in a given entity with the specified keys + * + * @param entity + * The entity to get the keys from + * @param keys + * The keys to fetch; an integer after a key value indicates that it should get the nth place of + * the previous compound because it is a list; + * @return + * The item represented by the keys, and an integer if it is showing how long a list is. + */ + private static Object getEntityTag( Entity entity, Object... keys ) { + try { + return getTag( getCompound( entity ), keys ); + } catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) { + e.printStackTrace(); + return null; + } + } + + // Gets the NBTTagCompound + private static Object getCompound( Entity entity ) { + if ( entity == null ) { + return entity; + } + try { + Object NMSEntity = getMethod( "getEntityHandle" ).invoke( entity ); + + Object tag = getNMSClass( "NBTTagCompound" ).newInstance(); + + getMethod( "getEntityTag" ).invoke( NMSEntity, tag ); + + return tag; + } catch ( Exception exception ) { + exception.printStackTrace(); + return null; + } + } + + /** + * Gets an NBTCompound from the entity provided. Use {@link #getNBTCompound(Object, Object...)} instead. + * + * @param entity + * The Bukkit entity provided + * @param keys + * Keys in descending order + * @return + * An NBTCompound + */ + private static NBTCompound getEntityNBTTag( Entity entity, Object...keys ) { + if ( entity == null ) { + return null; + } + try { + Object NMSEntity = getMethod( "getEntityHandle" ).invoke( entity ); + + Object tag = getNMSClass( "NBTTagCompound" ).newInstance(); + + getMethod( "getEntityTag" ).invoke( NMSEntity, tag ); + + return getNBTTag( tag, keys ); + } catch ( Exception exception ) { + exception.printStackTrace(); + return null; + } + } + + /** + * Sets an NBT tag in an entity with the provided keys and value + * Should use the {@link #set(Object, Object, Object...)} method instead + * + * @param entity + * The entity to set + * @param value + * The value to set + * @param keys + * The keys to set, String for NBTCompound, int or null for an NBTTagList + */ + private static void setEntityTag( Entity entity, Object value, Object... keys ) { + if ( entity == null ) { + return; + } + try { + Object NMSEntity = getMethod( "getEntityHandle" ).invoke( entity ); + + Object tag = getNMSClass( "NBTTagCompound" ).newInstance() ; + + getMethod( "getEntityTag" ).invoke( NMSEntity, tag ); + + if ( keys.length == 0 && value instanceof NBTCompound ) { + tag = ( ( NBTCompound ) value ).tag; + } else { + setTag( tag, value, keys ); + } + + getMethod( "setEntityTag" ).invoke( NMSEntity, tag ); + } catch ( Exception exception ) { + exception.printStackTrace(); + return; + } + } + + /** + * Gets an NBT tag in a given block with the specified keys. Use {@link #getNBTCompound(Object, Object...)} instead. + * + * @param block + * The block to get the keys from + * @param keys + * The keys to fetch; an integer after a key value indicates that it should get the nth place of + * the previous compound because it is a list; + * @return + * The item represented by the keys, and an integer if it is showing how long a list is. + */ + private static Object getBlockTag( Block block, Object... keys ) { + try { + return getTag( getCompound( block ), keys ); + } catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) { + e.printStackTrace(); + return null; + } + } + + // Gets the NBTTagCompound + private static Object getCompound( Block block ) { + try { + if ( block == null || !getNMSClass( "CraftBlockState" ).isInstance( block.getState() ) ) { + return null; + } + Location location = block.getLocation(); + + Object blockPosition = getConstructor( getNMSClass( "BlockPosition" ) ).newInstance( location.getBlockX(), location.getBlockY(), location.getBlockZ() ); + + Object nmsWorld = getMethod( "getWorldHandle" ).invoke( location.getWorld() ); + + Object tileEntity = getMethod( "getTileEntity" ).invoke( nmsWorld, blockPosition ); + + Object tag; + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + tag = getMethod( "getTileTag" ).invoke( tileEntity ); + } else { + tag = getNMSClass( "NBTTagCompound" ).newInstance(); + getMethod( "getTileTag" ).invoke( tileEntity, tag ); + } + + return tag; + } catch( Exception exception ) { + exception.printStackTrace(); + return null; + } + } + + /** + * Gets an NBTCompound from the block provided + * + * @param block + * The block provided + * @param keys + * Keys in descending order + * @return + * An NBTCompound + */ + private static NBTCompound getBlockNBTTag( Block block, Object... keys ) { + try { + if ( block == null || !getNMSClass( "CraftBlockState" ).isInstance( block.getState() ) ) { + return null; + } + Location location = block.getLocation(); + + Object blockPosition = getConstructor( getNMSClass( "BlockPosition" ) ).newInstance( location.getBlockX(), location.getBlockY(), location.getBlockZ() ); + + Object nmsWorld = getMethod( "getWorldHandle" ).invoke( location.getWorld() ); + + Object tileEntity = getMethod( "getTileEntity" ).invoke( nmsWorld, blockPosition ); + + Object tag; + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + tag = getMethod( "getTileTag" ).invoke( tileEntity ); + } else { + tag = getNMSClass( "NBTTagCompound" ).newInstance(); + getMethod( "getTileTag" ).invoke( tileEntity, tag ); + } + + return getNBTTag( tag, keys ); + } catch( Exception exception ) { + exception.printStackTrace(); + return null; + } + } + + /** + * Sets an NBT tag in an block with the provided keys and value + * Should use the {@link #set(Object, Object, Object...)} method instead + * + * @param block + * The block to set + * @param value + * The value to set + * @param keys + * The keys to set, String for NBTCompound, int or null for an NBTTagList + */ + private static void setBlockTag( Block block, Object value, Object... keys ) { + try { + if ( block == null || !getNMSClass( "CraftBlockState" ).isInstance( block.getState() ) ) { + return; + } + Location location = block.getLocation(); + + Object blockPosition = getConstructor( getNMSClass( "BlockPosition" ) ).newInstance( location.getBlockX(), location.getBlockY(), location.getBlockZ() ); + + Object nmsWorld = getMethod( "getWorldHandle" ).invoke( location.getWorld() ); + + Object tileEntity = getMethod( "getTileEntity" ).invoke( nmsWorld, blockPosition ); + + Object tag; + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_18_R1 ) ) { + tag = getMethod( "getTileTag" ).invoke( tileEntity ); + } else { + tag = getNMSClass( "NBTTagCompound" ).newInstance(); + getMethod( "getTileTag" ).invoke( tileEntity, tag ); + } + + if ( keys.length == 0 && value instanceof NBTCompound ) { + tag = ( ( NBTCompound ) value ).tag; + } else { + setTag( tag, value, keys ); + } + + if ( LOCAL_VERSION == MinecraftVersion.v1_16 ) { + getMethod( "setTileTag" ).invoke( tileEntity, getMethod( "getType" ).invoke( nmsWorld, blockPosition ), tag ); + } else { + getMethod( "setTileTag" ).invoke( tileEntity, tag ); + } + } catch( Exception exception ) { + exception.printStackTrace(); + return; + } + } + + /** + * Sets the texture of a skull block + * + * @param block + * The block, must be a skull + * @param texture + * The URL of the skin + */ + public static void setSkullTexture( Block block, String texture ) { + try { + Object profile = getConstructor( getNMSClass( "GameProfile" ) ).newInstance( UUID.randomUUID(), null ); + Object propertyMap = getMethod( "getProperties" ).invoke( profile ); + Object textureProperty = getConstructor( getNMSClass( "Property" ) ).newInstance( "textures", new String( Base64.getEncoder().encode( String.format( "{textures:{SKIN:{\"url\":\"%s\"}}}", texture ).getBytes() ) ) ); + getMethod( "put" ).invoke( propertyMap, "textures", textureProperty ); + + Location location = block.getLocation(); + + Object blockPosition = getConstructor( getNMSClass( "BlockPosition" ) ).newInstance( location.getBlockX(), location.getBlockY(), location.getBlockZ() ); + + Object nmsWorld = getMethod( "getWorldHandle" ).invoke( location.getWorld() ); + + Object tileEntity = getMethod( "getTileEntity" ).invoke( nmsWorld, blockPosition ); + + getMethod( "setGameProfile" ).invoke( tileEntity, profile ); + } catch( Exception exception ) { + exception.printStackTrace(); + } + } + + private static Object getValue( Object object, Object... keys ) { + if ( object instanceof ItemStack ) { + return getItemTag( ( ItemStack ) object, keys ); + } else if ( object instanceof Entity ) { + return getEntityTag( ( Entity ) object, keys ); + } else if ( object instanceof Block ) { + return getBlockTag( ( Block ) object, keys ); + } else if ( object instanceof NBTCompound ) { + try { + return getTag( ( ( NBTCompound ) object ).tag, keys ); + } catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) { + e.printStackTrace(); + return null; + } + } else { + throw new IllegalArgumentException( "Object provided must be of type ItemStack, Entity, Block, or NBTCompound!" ); + } + } + + /** + * Gets an NBTCompound from an object + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * An NBTCompound, or null if none is stored at the provided location + */ + public static NBTCompound getNBTCompound( Object object, Object... keys ) { + if ( object instanceof ItemStack ) { + return getItemNBTTag( ( ItemStack ) object, keys ); + } else if ( object instanceof Entity ) { + return getEntityNBTTag( ( Entity ) object, keys ); + } else if ( object instanceof Block ) { + return getBlockNBTTag( ( Block ) object, keys ); + } else if ( object instanceof NBTCompound ) { + try { + return getNBTTag( ( ( NBTCompound ) object ).tag, keys ); + } catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) { + e.printStackTrace(); + return null; + } + } else if ( getNMSClass( "NBTTagCompound" ).isInstance( object ) ) { + try { + return getNBTTag( object, keys ); + } catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) { + e.printStackTrace(); + return null; + } + } else { + throw new IllegalArgumentException( "Object provided must be of type ItemStack, Entity, Block, or NBTCompound!" ); + } + } + + /** + * Gets a string from an object + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * A string, or null if none is stored at the provided location + */ + public static String getString( Object object, Object... keys ) { + Object result = getValue( object, keys ); + return result instanceof String ? ( String ) result : null; + } + + /** + * Gets an int from an object + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * An integer, or 0 if none is stored at the provided location + */ + public static int getInt( Object object, Object... keys ) { + Object result = getValue( object, keys ); + return result instanceof Integer ? ( int ) result : 0; + } + + /** + * Gets a double from an object + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * A double, or 0 if none is stored at the provided location + */ + public static double getDouble( Object object, Object... keys ) { + Object result = getValue( object, keys ); + return result instanceof Double ? ( double ) result : 0; + } + + /** + * Gets a long from an object + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * A long, or 0 if none is stored at the provided location + */ + public static long getLong( Object object, Object... keys ) { + Object result = getValue( object, keys ); + return result instanceof Long ? ( long ) result : 0; + } + + /** + * Gets a float from an object + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * A float, or 0 if none is stored at the provided location + */ + public static float getFloat( Object object, Object... keys ) { + Object result = getValue( object, keys ); + return result instanceof Float ? ( float ) result : 0; + } + + /** + * Gets a short from an object + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * A short, or 0 if none is stored at the provided location + */ + public static short getShort( Object object, Object... keys ) { + Object result = getValue( object, keys ); + return result instanceof Short ? ( short ) result : 0; + } + + /** + * Gets a byte from an object + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * A byte, or 0 if none is stored at the provided location + */ + public static byte getByte( Object object, Object... keys ) { + Object result = getValue( object, keys ); + return result instanceof Byte ? ( byte ) result : 0; + } + + /** + * Gets a boolean from an object + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * A boolean or false if none is stored at the provided location + */ + public static boolean getBoolean( Object object, Object... keys ) { + return getByte( object, keys ) == 1; + } + + /** + * Gets a byte array from an object + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * A byte array, or null if none is stored at the provided location + */ + public static byte[] getByteArray( Object object, Object... keys ) { + Object result = getValue( object, keys ); + return result instanceof byte[] ? ( byte[] ) result : null; + } + + /** + * Gets an int array from an object + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * An int array, or null if none is stored at the provided location + */ + public static int[] getIntArray( Object object, Object... keys ) { + Object result = getValue( object, keys ); + return result instanceof int[] ? ( int[] ) result : null; + } + + /** + * Checks if the object contains the given key + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * Whether or not the particular tag exists, may not be a primitive + */ + public static boolean contains( Object object, Object... keys ) { + Object result = getValue( object, keys ); + return result != null; + } + + /** + * Get the keys at the specific location, if it is a compound. + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * A set of keys + */ + public static Collection< String > getKeys( Object object, Object... keys ) { + Object compound; + if ( object instanceof ItemStack ) { + compound = getCompound( ( ItemStack ) object ); + } else if ( object instanceof Entity ) { + compound = getCompound( ( Entity ) object ); + } else if ( object instanceof Block ) { + compound = getCompound( ( Block ) object ); + } else if ( object instanceof NBTCompound ) { + compound = ( ( NBTCompound ) object ).tag; + } else { + throw new IllegalArgumentException( "Object provided must be of type ItemStack, Entity, Block, or NBTCompound!" ); + } + + try { + NBTCompound nbtCompound = getNBTTag( compound, keys ); + + Object tag = nbtCompound.tag; + if ( getNMSClass( "NBTTagCompound" ).isInstance( tag ) ) { + return ( Collection< String > ) getMethod( "getKeys" ).invoke( tag ); + } else { + return null; + } + + } catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) { + e.printStackTrace(); + } + + return null; + } + + /** + * Gets the size of the list or NBTCompound at the given location. + * + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param keys + * Keys in descending order + * @return + * The size of the list or compound at the given location. + */ + public static int getSize( Object object, Object... keys ) { + Object compound; + if ( object instanceof ItemStack ) { + compound = getCompound( ( ItemStack ) object ); + } else if ( object instanceof Entity ) { + compound = getCompound( ( Entity ) object ); + } else if ( object instanceof Block ) { + compound = getCompound( ( Block ) object ); + } else if ( object instanceof NBTCompound ) { + compound = ( ( NBTCompound ) object ).tag; + } else { + throw new IllegalArgumentException( "Object provided must be of type ItemStack, Entity, Block, or NBTCompound!" ); + } + + try { + NBTCompound nbtCompound = getNBTTag( compound, keys ); + if ( getNMSClass( "NBTTagCompound" ).isInstance( nbtCompound.tag ) ) { + return getKeys( nbtCompound ).size(); + } else if ( getNMSClass( "NBTTagList" ).isInstance( nbtCompound.tag ) ) { + return ( int ) getMethod( "size" ).invoke( nbtCompound.tag ); + } + } catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) { + e.printStackTrace(); + return 0; + } + + throw new IllegalArgumentException( "Value is not a compound or list!" ); + } + + /** + * Sets the value in the object with the given keys + * + * @param + * ItemStack, Entity, Block, or NBTCompound. + * @param object + * Must be an ItemStack, Entity, Block, or NBTCompound + * @param value + * The value to set, can be an NBTCompound + * @param keys + * The keys in descending order + * @return + * The new item stack if the object provided is an item, else original object + */ + public static < T > T set( T object, Object value, Object... keys ) { + if ( object instanceof ItemStack ) { + return ( T ) setItemTag( ( ItemStack ) object, value, keys ); + } else if ( object instanceof Entity ) { + setEntityTag( ( Entity ) object, value, keys ); + } else if ( object instanceof Block ) { + setBlockTag( ( Block ) object, value, keys ); + } else if ( object instanceof NBTCompound ) { + try { + setTag( ( ( NBTCompound ) object ).tag, value, keys ); + } catch ( InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) { + e.printStackTrace(); + } + } else { + throw new IllegalArgumentException( "Object provided must be of type ItemStack, Entity, Block, or NBTCompound!" ); + } + return object; + } + + /** + * Load an NBTCompound from a String. + * + * @param json + * A String in json format. + * @return + * An NBTCompound from the String provided. May or may not be a valid ItemStack. + */ + public static NBTCompound getNBTCompound( String json ) { + return NBTCompound.fromJson( json ); + } + + /** + * Get an empty NBTCompound. + * + * @return + * A new NBTCompound that contains a NBTTagCompound object. + */ + public static NBTCompound getEmptyNBTCompound() { + try { + return new NBTCompound( getNMSClass( "NBTTagCompound" ).newInstance() ); + } catch ( InstantiationException | IllegalAccessException e ) { + e.printStackTrace(); + return null; + } + } + + private static void setTag( Object tag, Object value, Object... keys ) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Object wrappedValue; + // Get the real value of what we want to set here + if ( value != null && value != Type.DELETE ) { + if ( value instanceof NBTCompound ) { + wrappedValue = ( ( NBTCompound ) value ).tag; + } else if ( getNMSClass( "NBTTagList" ).isInstance( value ) || getNMSClass( "NBTTagCompound" ).isInstance( value ) ) { + wrappedValue = value; + } else if ( value == Type.COMPOUND ) { + wrappedValue = getNMSClass( "NBTTagCompound" ).newInstance(); + } else if ( value == Type.LIST ) { + wrappedValue = getNMSClass( "NBTTagList" ).newInstance(); + } else { + if ( value instanceof Boolean ) { + value = ( byte ) ( ( Boolean ) value == true ? 1 : 0 ); + } + Constructor< ? > cons = getConstructor( getNBTTag( value.getClass() ) ); + if ( cons != null ) { + wrappedValue = getConstructor( getNBTTag( value.getClass() ) ).newInstance( value ); + } else { + throw new IllegalArgumentException( "Provided value type(" + value.getClass() + ") is not supported!" ); + } + } + } else { + wrappedValue = Type.DELETE; + } + + Object compound = tag; + for ( int index = 0; index < keys.length - 1; index++ ) { + Object key = keys[ index ]; + Object prevCompound = compound; + if ( key instanceof Integer ) { + int keyIndex = ( int ) key; + List< ? > tagList = ( List< ? > ) NBTListData.get( compound ); + if ( keyIndex >= 0 && keyIndex < tagList.size() ) { + compound = tagList.get( keyIndex ); + } else { + compound = null; + } + } else if ( key != null && key != Type.NEW_ELEMENT ) { + compound = getMethod( "get" ).invoke( compound, ( String ) key ); + } + if ( compound == null || key == null || key == Type.NEW_ELEMENT ) { + if ( keys[ index + 1 ] == null || keys[ index + 1 ] instanceof Integer || keys[ index + 1 ] == Type.NEW_ELEMENT ) { + compound = getNMSClass( "NBTTagList" ).newInstance(); + } else { + compound = getNMSClass( "NBTTagCompound" ).newInstance(); + } + if ( prevCompound.getClass().getSimpleName().equals( "NBTTagList" ) ) { + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_14 ) ) { + getMethod( "add" ).invoke( prevCompound, getMethod( "size" ).invoke( prevCompound ), compound ); + } else { + getMethod( "add" ).invoke( prevCompound, compound ); + } + } else { + getMethod( "set" ).invoke( prevCompound, ( String ) key, compound ); + } + } + } + if ( keys.length > 0 ) { + Object lastKey = keys[ keys.length - 1 ]; + if ( lastKey == null || lastKey == Type.NEW_ELEMENT ) { + if ( LOCAL_VERSION.greaterThanOrEqualTo( MinecraftVersion.v1_14 ) ) { + getMethod( "add" ).invoke( compound, getMethod( "size" ).invoke( compound ), wrappedValue ); + } else { + getMethod( "add" ).invoke( compound, wrappedValue ); + } + } else if ( lastKey instanceof Integer ) { + if ( wrappedValue == Type.DELETE ) { + getMethod( "listRemove" ).invoke( compound, ( int ) lastKey ); + } else { + getMethod( "setIndex" ).invoke( compound, ( int ) lastKey, wrappedValue ); + } + } else { + if ( wrappedValue == Type.DELETE ) { + getMethod( "remove" ).invoke( compound, ( String ) lastKey ); + } else { + getMethod( "set" ).invoke( compound, ( String ) lastKey, wrappedValue ); + } + } + } else { + // Add and replace all tags + if ( wrappedValue != null ) { + // Only if they're both an NBTTagCompound + // Can't do anything if its a list or something + if ( getNMSClass( "NBTTagCompound" ).isInstance( wrappedValue ) && getNMSClass( "NBTTagCompound" ).isInstance( compound ) ) + for ( String key : getKeys( wrappedValue ) ) { + getMethod( "set" ).invoke( compound, key, getMethod( "get" ).invoke( wrappedValue, key ) ); + } + } else { + // Did someone make an error? + // NBTEditor.set( something, null ); + // Not sure what to do here + } + } + } + + private static NBTCompound getNBTTag( Object tag, Object...keys ) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Object compound = tag; + + for ( Object key : keys ) { + if ( compound == null ) { + return null; + } else if ( getNMSClass( "NBTTagCompound" ).isInstance( compound ) ) { + compound = getMethod( "get" ).invoke( compound, ( String ) key ); + } else if ( getNMSClass( "NBTTagList" ).isInstance( compound ) ) { + int keyIndex = ( int ) key; + List< ? > tagList = ( List< ? > ) NBTListData.get( compound ); + if ( keyIndex >= 0 && keyIndex < tagList.size() ) { + compound = tagList.get( keyIndex ); + } else { + compound = null; + } + } + } + return new NBTCompound( compound ); + } + + private static Object getTag( Object tag, Object... keys ) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + if ( keys.length == 0 ) { + return getTags( tag ); + } + + Object nbtObj = tag; + + for ( Object key : keys ) { + if ( nbtObj == null ) { + return null; + } else if ( getNMSClass( "NBTTagCompound" ).isInstance( nbtObj ) ) { + nbtObj = getMethod( "get" ).invoke( nbtObj, ( String ) key ); + } else if ( getNMSClass( "NBTTagList" ).isInstance( nbtObj ) ) { + int keyIndex = ( int ) key; + List< ? > tagList = ( List< ? > ) NBTListData.get( nbtObj ); + if ( keyIndex >= 0 && keyIndex < tagList.size() ) { + nbtObj = tagList.get( keyIndex ); + } else { + nbtObj = null; + } + } else { + return getNBTVar( nbtObj ); + } + } + if ( nbtObj == null ) { + return null; + } else if ( getNMSClass( "NBTTagList" ).isInstance( nbtObj ) ) { + return getTags( nbtObj ); + } else if ( getNMSClass( "NBTTagCompound" ).isInstance( nbtObj ) ) { + return getTags( nbtObj ); + } else { + return getNBTVar( nbtObj ); + } + } + + @SuppressWarnings( "unchecked" ) + private static Object getTags( Object tag ) { + Map< Object, Object > tags = new HashMap< Object, Object >(); + try { + if ( getNMSClass( "NBTTagCompound" ).isInstance( tag ) ) { + Map< String, Object > tagCompound = ( Map< String, Object > ) NBTCompoundMap.get( tag ); + for ( String key : tagCompound.keySet() ) { + Object value = tagCompound.get( key ); + if ( getNMSClass( "NBTTagEnd" ).isInstance( value ) ) { + continue; + } + tags.put( key, getTag( value ) ); + } + } else if ( getNMSClass( "NBTTagList" ).isInstance( tag ) ) { + List< Object > tagList = ( List< Object > ) NBTListData.get( tag ); + for ( int index = 0; index < tagList.size(); index++ ) { + Object value = tagList.get( index ); + if ( getNMSClass( "NBTTagEnd" ).isInstance( value ) ) { + continue; + } + tags.put( index, getTag( value ) ); + } + } else { + return getNBTVar( tag ); + } + return tags; + } catch ( Exception e ) { + e.printStackTrace(); + return tags; + } + } + + /** + * A class for holding NBTTagCompounds + */ + public static final class NBTCompound { + protected final Object tag; + + protected NBTCompound( Object tag ) { + this.tag = tag; + } + + public void set( Object value, Object... keys ) { + try { + setTag( tag, value, keys ); + } catch ( Exception e ) { + e.printStackTrace(); + } + } + + /** + * The exact same as the toString method + * + * @return + * Convert the compound to a string. + */ + public String toJson() { + return tag.toString(); + } + + public static NBTCompound fromJson( String json ) { + try { + return new NBTCompound( getMethod( "loadNBTTagCompound" ).invoke( null, json ) ); + } catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) { + e.printStackTrace(); + return null; + } + } + + @Override + public String toString() { + return tag.toString(); + } + + @Override + public int hashCode() { + return tag.hashCode(); + } + + @Override + public boolean equals( Object obj ) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + NBTCompound other = (NBTCompound) obj; + if (tag == null) { + if (other.tag != null) + return false; + } else if (!tag.equals(other.tag)) + return false; + return true; + } + } + + /** + * Minecraft versions as enums + * + * @author BananaPuncher714 + */ + public enum MinecraftVersion { + v1_8, + v1_9, + v1_10, + v1_11, + v1_12, + v1_13, + v1_14, + v1_15, + v1_16, + v1_17, + v1_18_R1, + v1_18_R2, + v1_19, + v1_20, + v1_21, + v1_22; + + // Would be really cool if we could overload operators here + public boolean greaterThanOrEqualTo( MinecraftVersion other ) { + return ordinal() >= other.ordinal(); + } + + public boolean lessThanOrEqualTo( MinecraftVersion other ) { + return ordinal() <= other.ordinal(); + } + + public static MinecraftVersion get( String v ) { + for ( MinecraftVersion k : MinecraftVersion.values() ) { + if ( v.contains( k.name().substring( 1 ) ) ) { + return k; + } + } + return null; + } + } + + private enum Type { + COMPOUND, LIST, NEW_ELEMENT, DELETE; + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/Pair.java b/src/main/java/com/loganmagnan/hubcore/utils/Pair.java new file mode 100644 index 0000000..e1f63a0 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/Pair.java @@ -0,0 +1,17 @@ +package com.loganmagnan.hubcore.utils; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Pair { + + public K firstPair; + public V secondPair; + + public Pair(K firstPair, V secondPair) { + this.firstPair = firstPair; + this.secondPair = secondPair; + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/ParameterType.java b/src/main/java/com/loganmagnan/hubcore/utils/ParameterType.java new file mode 100644 index 0000000..cea89b1 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/ParameterType.java @@ -0,0 +1,14 @@ +package com.loganmagnan.hubcore.utils; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.List; +import java.util.Set; + +public interface ParameterType { + + T transform(CommandSender sender, String string); + + List onTabComplete(Player player, Set set, String string); +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/PlayerUtil.java b/src/main/java/com/loganmagnan/hubcore/utils/PlayerUtil.java new file mode 100644 index 0000000..781fda4 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/PlayerUtil.java @@ -0,0 +1,43 @@ +package com.loganmagnan.hubcore.utils; + +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; + +public class PlayerUtil { + + public static void clearPlayer(Player player) { + player.setHealth(20.0D); + player.setFoodLevel(20); + player.setSaturation(12.8F); + player.setMaximumNoDamageTicks(20); + player.setFireTicks(0); + player.setFallDistance(0.0F); + player.setLevel(0); + player.setExp(0.0F); + player.setWalkSpeed(0.2F); + player.setFlySpeed(0.2F); + player.getInventory().setHeldItemSlot(0); + player.setAllowFlight(false); + player.getInventory().clear(); + player.getInventory().setArmorContents(null); + player.closeInventory(); + player.setGameMode(GameMode.SURVIVAL); + player.getActivePotionEffects().stream().map(PotionEffect::getType).forEach(player::removePotionEffect); + player.updateInventory(); + } + + public static void minusAmount(Player p, ItemStack i, int amount) { + if (i.getAmount() - amount <= 0) { + if (p.getInventory().getItemInHand().equals(i)) { + p.getInventory().setItemInHand(null); + } else { + p.getInventory().removeItem(i); + } + return; + } + i.setAmount(i.getAmount() - amount); + p.updateInventory(); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/SpigotUtils.java b/src/main/java/com/loganmagnan/hubcore/utils/SpigotUtils.java new file mode 100644 index 0000000..7330ddf --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/SpigotUtils.java @@ -0,0 +1,46 @@ +package com.loganmagnan.hubcore.utils; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.potion.PotionEffectType; + +import java.util.ArrayList; +import java.util.Arrays; + +public class SpigotUtils { + + public static final ArrayList woolColors = new ArrayList<>(Arrays.asList(new ChatColor[] { + ChatColor.WHITE, ChatColor.GOLD, ChatColor.LIGHT_PURPLE, ChatColor.AQUA, ChatColor.YELLOW, ChatColor.GREEN, ChatColor.LIGHT_PURPLE, ChatColor.DARK_GRAY, ChatColor.GRAY, ChatColor.DARK_AQUA, + ChatColor.DARK_PURPLE, ChatColor.BLUE, ChatColor.RESET, ChatColor.DARK_GREEN, ChatColor.RED, ChatColor.BLACK })); + + public static int toDyeColor(ChatColor color) { + if (color == ChatColor.DARK_RED) + color = ChatColor.RED; + if (color == ChatColor.DARK_BLUE) + color = ChatColor.BLUE; + return woolColors.indexOf(color); + } + + public static String getName(PotionEffectType potionEffectType) { + if (potionEffectType.getName().equalsIgnoreCase("fire_resistance")) + return "Fire Resistance"; + if (potionEffectType.getName().equalsIgnoreCase("speed")) + return "Speed"; + if (potionEffectType.getName().equalsIgnoreCase("weakness")) + return "Weakness"; + if (potionEffectType.getName().equalsIgnoreCase("slowness")) + return "Slowness"; + return "Unknown"; + } + + public static Player getDamager(EntityDamageByEntityEvent event) { + if (event.getDamager() instanceof Player) + return (Player)event.getDamager(); + if (event.getDamager() instanceof Projectile && ( + (Projectile)event.getDamager()).getShooter() instanceof Player) + return (Player)((Projectile)event.getDamager()).getShooter(); + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/StringUtils.java b/src/main/java/com/loganmagnan/hubcore/utils/StringUtils.java new file mode 100644 index 0000000..15939f3 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/StringUtils.java @@ -0,0 +1,244 @@ +package com.loganmagnan.hubcore.utils; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.util.ChatPaginator; + +import java.io.File; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class StringUtils { + + public static String format(String string) { + string = string.toLowerCase(); + StringBuilder builder = new StringBuilder(); + int i = 0; + byte b; + int j; + String[] arrayOfString; + for (j = (arrayOfString = string.split("_")).length, b = 0; b < j; ) { + String s = arrayOfString[b]; + if (i == 0) { + builder.append(String.valueOf(Character.toUpperCase(s.charAt(0))) + s.substring(1)); + } else { + builder.append(" " + Character.toUpperCase(s.charAt(0)) + s.substring(1)); + } + i++; + b++; + } + return builder.toString(); + } + + public static String parseConfig(String string) { + String[] split = string.toLowerCase().split("_"); + StringBuilder builder = new StringBuilder(); + builder.append(split[0]); + for (int i = 1; i < split.length; i++) { + String s = split[i]; + builder.append(String.valueOf(Character.toUpperCase(s.charAt(0))) + s.substring(1)); + } + return builder.toString(); + } + + public static boolean contains(String string, String... contain) { + byte b; + int i; + String[] arrayOfString; + for (i = (arrayOfString = contain).length, b = 0; b < i; ) { + String s = arrayOfString[b]; + if (string.contains(s)) + return true; + b++; + } + return false; + } + + public static boolean equals(String string, String... equal) { + byte b; + int i; + String[] arrayOfString; + for (i = (arrayOfString = equal).length, b = 0; b < i; ) { + String s = arrayOfString[b]; + if (string.equals(s)) + return true; + b++; + } + return false; + } + + public static boolean endsWith(String string, String... end) { + byte b; + int i; + String[] arrayOfString; + for (i = (arrayOfString = end).length, b = 0; b < i; ) { + String s = arrayOfString[b]; + if (string.endsWith(s)) + return true; + b++; + } + return false; + } + + public static void message(Player p, String msg) { + p.sendMessage(ChatColor.translateAlternateColorCodes('&', msg)); + } + + public static void messages(Player p, String... msg) { + Arrays.asList(msg).forEach(s -> p.sendMessage(ChatColor.translateAlternateColorCodes('&', s))); + } + + public static String color(String msg) { + return ChatColor.translateAlternateColorCodes('&', msg); + } + + public static boolean hasWhiteSpace(String s) { + Pattern pattern = Pattern.compile("\\s"); + Matcher matcher = pattern.matcher(s); + boolean found = matcher.find(); + if (found) + return true; + return false; + } + + public static boolean hasSpecialChars(String s) { + Pattern p = Pattern.compile("[^a-z0-9 ]", 2); + Matcher m = p.matcher(s); + boolean b = m.find(); + if (b) + return true; + return false; + } + + public static boolean hasNumber(String s) { + Pattern p = Pattern.compile("[0-9]", 2); + Matcher m = p.matcher(s); + boolean b = m.find(); + if (b) + return true; + return false; + } + + public List formatLength(int numberOfChar, String s) { + return Arrays.asList(ChatPaginator.wordWrap(s, numberOfChar)); + } + + public static boolean hasPerm(Player p, String perm) { + if (!p.hasPermission(perm)) + return false; + return true; + } + + public static String alignCenter(int width, String s) { + return String.format("%-" + width + "s", new Object[] { String.format("%" + (s.length() + (width - s.length()) / 2) + "s", new Object[] { s }) }); + } + + public static String listFormat(List list, String colorCode) { + return list.stream().map(key -> key.toString()).collect(Collectors.joining(String.valueOf(colorCode) + ", ")); + } + + public static String reset(String name) { + return ChatColor.stripColor(name); + } + + public static Double roundDouble(double amount) { + return Double.valueOf((new BigDecimal(amount)).setScale(1, RoundingMode.HALF_UP).doubleValue()); + } + + public static double round(double value, int precision) { + int scale = (int)Math.pow(10.0D, precision); + return Math.round(value * scale) / scale; + } + + public static void console(String string) { + Bukkit.getConsoleSender().sendMessage(ChatColor.translateAlternateColorCodes('&', string)); + } + + public static String formatNumber(long number) { + return (new DecimalFormat("###,###,###")).format(number); + } + + public static boolean deleteDirectory(File directory) { + if (directory.exists()) { + File[] files = directory.listFiles(); + if (files != null) + for (int i = 0; i < files.length; i++) { + if (files[i].isDirectory()) { + deleteDirectory(files[i]); + } else { + files[i].delete(); + } + } + } + return directory.delete(); + } + + public static void broadcastGlobal(Player p, String... msg) { + Bukkit.getOnlinePlayers().stream() + .filter(player -> !player.getUniqueId().equals(p.getUniqueId())) + .forEach(player -> messages(player, msg)); + } + + public static void broadcastGlobalExclude(Collection excludePlayers, String... msg) { + Bukkit.getOnlinePlayers().stream() + .filter(player -> !excludePlayers.contains(player.getUniqueId())) + .forEach(player -> messages(player, msg)); + } + + public static void broadcastGlobalExcludes(Collection excludePlayers, String... msg) { + Bukkit.getOnlinePlayers().stream() + .filter(player -> !excludePlayers.contains(player)) + .forEach(player -> messages(player, msg)); + } + + public static void broadcastGlobalInclude(Collection includePlayers, String... msg) { + Bukkit.getOnlinePlayers().stream() + .filter(player -> includePlayers.contains(player.getUniqueId())) + .forEach(player -> messages(player, msg)); + } + + public static void broadcastGlobalIncludes(Collection includePlayers, String... msg) { + Bukkit.getOnlinePlayers().stream() + .filter(player -> includePlayers.contains(player)) + .forEach(player -> messages(player, msg)); + } + + enum NumberUnit { + BILLION(1.0E9D, "B"), + MILLION(1000000.0D, "M"); + + private String format; + + private double devideUnit; + + NumberUnit(double devideUnit, String format) { + this.devideUnit = devideUnit; + this.format = format; + } + + public double getDevideUnit() { + return this.devideUnit; + } + + public String getFormat() { + return this.format; + } + } + + public static boolean compareUUID(UUID uuid1, UUID uuid2) { + return uuid1.equals(uuid2); + } + + public static UUID generateEmptyUUID() { + return UUID.fromString("00000000-0000-0000-0000-000000000000"); + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/TeamAction.java b/src/main/java/com/loganmagnan/hubcore/utils/TeamAction.java new file mode 100644 index 0000000..4b6f1ef --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/TeamAction.java @@ -0,0 +1,8 @@ +package com.loganmagnan.hubcore.utils; + +public enum TeamAction { + + CREATE, + DESTROY, + UPDATE; +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/TimeUtil.java b/src/main/java/com/loganmagnan/hubcore/utils/TimeUtil.java new file mode 100644 index 0000000..c42819d --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/TimeUtil.java @@ -0,0 +1,141 @@ +package com.loganmagnan.hubcore.utils; + +import java.sql.Timestamp; +import java.text.DecimalFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TimeUtil { + + private static final String HOUR_FORMAT = "%02d:%02d:%02d"; + + private static final String MINUTE_FORMAT = "%02d:%02d"; + + private TimeUtil() { + throw new RuntimeException("Cannot instantiate a utility class."); + } + + public static String millisToTimer(long millis) { + long seconds = millis / 1000L; + if (seconds > 3600L) + return String.format("%02d:%02d:%02d", new Object[] { Long.valueOf(seconds / 3600L), Long.valueOf(seconds % 3600L / 60L), Long.valueOf(seconds % 60L) }); + return String.format("%02d:%02d", new Object[] { Long.valueOf(seconds / 60L), Long.valueOf(seconds % 60L) }); + } + + public static String millisToSeconds(long millis) { + return (new DecimalFormat("#0.0")).format(((float)millis / 1000.0F)); + } + + public static String dateToString(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + return calendar.getTime().toString(); + } + + public static Timestamp addDuration(long duration) { + return truncateTimestamp(new Timestamp(System.currentTimeMillis() + duration)); + } + + public static Timestamp truncateTimestamp(Timestamp timestamp) { + if (timestamp.toLocalDateTime().getYear() > 2037) + timestamp.setYear(2037); + return timestamp; + } + + public static Timestamp addDuration(Timestamp timestamp) { + return truncateTimestamp(new Timestamp(System.currentTimeMillis() + timestamp.getTime())); + } + + public static Timestamp fromMillis(long millis) { + return new Timestamp(millis); + } + + public static Timestamp getCurrentTimestamp() { + return new Timestamp(System.currentTimeMillis()); + } + + public static String millisToRoundedTime(long millis) { + millis++; + long seconds = millis / 1000L; + long minutes = seconds / 60L; + long hours = minutes / 60L; + long days = hours / 24L; + long weeks = days / 7L; + long months = weeks / 4L; + long years = months / 12L; + if (years > 0L) + return years + " year" + ((years == 1L) ? "" : "s"); + if (months > 0L) + return months + " month" + ((months == 1L) ? "" : "s"); + if (weeks > 0L) + return weeks + " week" + ((weeks == 1L) ? "" : "s"); + if (days > 0L) + return days + " day" + ((days == 1L) ? "" : "s"); + if (hours > 0L) + return hours + " hour" + ((hours == 1L) ? "" : "s"); + if (minutes > 0L) + return minutes + " minute" + ((minutes == 1L) ? "" : "s"); + return seconds + " second" + ((seconds == 1L) ? "" : "s"); + } + + public static String millisToRoundedTimeSingle(long millis) { + millis++; + long seconds = millis / 1000L; + long minutes = seconds / 60L; + long hours = minutes / 60L; + long days = hours / 24L; + long weeks = days / 7L; + long months = weeks / 4L; + long years = months / 12L; + if (years > 0L) + return years + " y"; + if (months > 0L) + return months + " mm"; + if (weeks > 0L) + return weeks + " w"; + if (days > 0L) + return days + " d"; + if (hours > 0L) + return hours + " h"; + if (minutes > 0L) + return minutes + " m"; + return seconds + " s"; + } + + public static long parseTime(String time) { + long totalTime = 0L; + boolean found = false; + Matcher matcher = Pattern.compile("\\d+\\D+").matcher(time); + while (matcher.find()) { + String s = matcher.group(); + Long value = Long.valueOf(Long.parseLong(s.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)")[0])); + String type = s.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)")[1]; + switch (type) { + case "s": + totalTime += value.longValue(); + found = true; + case "m": + totalTime += value.longValue() * 60L; + found = true; + case "h": + totalTime += value.longValue() * 60L * 60L; + found = true; + case "d": + totalTime += value.longValue() * 60L * 60L * 24L; + found = true; + case "w": + totalTime += value.longValue() * 60L * 60L * 24L * 7L; + found = true; + case "M": + totalTime += value.longValue() * 60L * 60L * 24L * 30L; + found = true; + case "y": + totalTime += value.longValue() * 60L * 60L * 24L * 365L; + found = true; + } + } + return !found ? -1L : (totalTime * 1000L); + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/TimeUtils.java b/src/main/java/com/loganmagnan/hubcore/utils/TimeUtils.java new file mode 100644 index 0000000..04ff996 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/TimeUtils.java @@ -0,0 +1,110 @@ +package com.loganmagnan.hubcore.utils; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TimeUtils { + + private static final ThreadLocal mmssBuilder = ThreadLocal.withInitial(StringBuilder::new); + + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm"); + + public static String formatIntoHHMMSS(int secs) { + return formatIntoMMSS(secs); + } + + public static String formatLongIntoHHMMSS(long secs) { + int unconvertedSeconds = (int)secs; + return formatIntoMMSS(unconvertedSeconds); + } + + public static String formatIntoMMSS(int secs) { + int seconds = secs % 60; + secs -= seconds; + long minutesCount = (secs / 60); + long minutes = minutesCount % 60L; + minutesCount -= minutes; + long hours = minutesCount / 60L; + StringBuilder result = mmssBuilder.get(); + result.setLength(0); + if (hours > 0L) { + if (hours < 10L) + result.append("0"); + result.append(hours); + result.append(":"); + } + if (minutes < 10L) + result.append("0"); + result.append(minutes); + result.append(":"); + if (seconds < 10) + result.append("0"); + result.append(seconds); + return result.toString(); + } + + public static String formatLongIntoMMSS(long secs) { + int unconvertedSeconds = (int)secs; + return formatIntoMMSS(unconvertedSeconds); + } + + public static String formatIntoDetailedString(int secs) { + if (secs == 0) + return "0 seconds"; + int remainder = secs % 86400; + int days = secs / 86400; + int hours = remainder / 3600; + int minutes = remainder / 60 - hours * 60; + int seconds = remainder % 3600 - minutes * 60; + String fDays = (days > 0) ? (" " + days + " day" + ((days > 1) ? "s" : "")) : ""; + String fHours = (hours > 0) ? (" " + hours + " hour" + ((hours > 1) ? "s" : "")) : ""; + String fMinutes = (minutes > 0) ? (" " + minutes + " minute" + ((minutes > 1) ? "s" : "")) : ""; + String fSeconds = (seconds > 0) ? (" " + seconds + " second" + ((seconds > 1) ? "s" : "")) : ""; + return (fDays + fHours + fMinutes + fSeconds).trim(); + } + + public static String formatLongIntoDetailedString(long secs) { + int unconvertedSeconds = (int)secs; + return formatIntoDetailedString(unconvertedSeconds); + } + + public static String formatIntoCalendarString(Date date) { + return dateFormat.format(date); + } + + public static int parseTime(String time) { + if (!time.equals("0") && !time.equals("")) { + String[] lifeMatch = { "w", "d", "h", "m", "s" }; + int[] lifeInterval = { 604800, 86400, 3600, 60, 1 }; + int seconds = -1; + for (int i = 0; i < lifeMatch.length; i++) { + for (Matcher matcher = Pattern.compile("([0-9]+)" + lifeMatch[i]).matcher(time); matcher.find(); seconds += Integer.parseInt(matcher.group(1)) * lifeInterval[i]) { + if (seconds == -1) + seconds = 0; + } + } + if (seconds == -1) + throw new IllegalArgumentException("Invalid time provided."); + return seconds; + } + return 0; + } + + public static long parseTimeToLong(String time) { + int unconvertedSeconds = parseTime(time); + long seconds = unconvertedSeconds; + return seconds; + } + + public static int getSecondsBetween(Date a, Date b) { + return (int)getSecondsBetweenLong(a, b); + } + + public static long getSecondsBetweenLong(Date a, Date b) { + long diff = a.getTime() - b.getTime(); + long absDiff = Math.abs(diff); + return absDiff / 1000L; + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/TimerRunnable.java b/src/main/java/com/loganmagnan/hubcore/utils/TimerRunnable.java new file mode 100644 index 0000000..ba5c0a5 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/TimerRunnable.java @@ -0,0 +1,35 @@ +package com.loganmagnan.hubcore.utils; + +import java.util.concurrent.ScheduledFuture; + +public abstract class TimerRunnable implements Runnable { + + private ScheduledFuture scheduledFuture; + + public abstract void running(); + + @Override + public void run() { + try { + if (scheduledFuture != null) { + running(); + } + } catch (Throwable e) { + System.out.println("&cError while executing async timer!"); + e.printStackTrace(); + } + } + + public void cancel() { + if (scheduledFuture != null) { + scheduledFuture.cancel(false); + scheduledFuture = null; + } else throw new NullPointerException("Scheduled future isn't set yet!"); + } + + public ScheduledFuture setScheduledFuture(ScheduledFuture scheduledFuture) { + this.scheduledFuture = scheduledFuture; + + return scheduledFuture; + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/TtlHandler.java b/src/main/java/com/loganmagnan/hubcore/utils/TtlHandler.java new file mode 100644 index 0000000..034bfbc --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/TtlHandler.java @@ -0,0 +1,8 @@ +package com.loganmagnan.hubcore.utils; + +public interface TtlHandler { + + void onExpire(E element); + + long getTimestamp(E element); +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/TtlHashMap.java b/src/main/java/com/loganmagnan/hubcore/utils/TtlHashMap.java new file mode 100644 index 0000000..6d82fa7 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/TtlHashMap.java @@ -0,0 +1,128 @@ +package com.loganmagnan.hubcore.utils; + +import org.bukkit.Bukkit; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +public class TtlHashMap implements Map, TtlHandler { + + private final HashMap timestamps = new HashMap<>(); + private final HashMap store = new HashMap<>(); + private final long ttl; + + public TtlHashMap(TimeUnit ttlUnit, long ttlValue) { + this.ttl = ttlUnit.toNanos(ttlValue); + } + + @Override + public V get(Object key) { + V value = this.store.get(key); + + if (value != null && expired(key, value)) { + store.remove(key); + timestamps.remove(key); + return null; + } else { + return value; + } + } + + private boolean expired(Object key, V value) { + return (System.nanoTime() - timestamps.get(key)) > this.ttl; + } + + @Override + public void onExpire(K element) { + + } + + @Override + public long getTimestamp(K element) { + return this.timestamps.get(element); + } + + @Override + public V put(K key, V value) { + timestamps.put(key, System.nanoTime()); + return store.put(key, value); + } + + @Override + public int size() { + return store.size(); + } + + @Override + public boolean isEmpty() { + return store.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + V value = this.store.get(key); + + if (value != null && expired(key, value)) { + store.remove(key); + timestamps.remove(key); + return false; + } + + return store.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return store.containsValue(value); + } + + @Override + public V remove(Object key) { + timestamps.remove(key); + return store.remove(key); + } + + @Override + public void putAll(Map m) { + for (Entry e : m.entrySet()) { + this.put(e.getKey(), e.getValue()); + } + } + + @Override + public void clear() { + timestamps.clear(); + store.clear(); + } + + @Override + public Set keySet() { + clearExpired(); + return Collections.unmodifiableSet(store.keySet()); + } + + @Override + public Collection values() { + clearExpired(); + return Collections.unmodifiableCollection(store.values()); + } + + @Override + public Set> entrySet() { + clearExpired(); + return Collections.unmodifiableSet(store.entrySet()); + } + + private void clearExpired() { + for (K k : store.keySet()) { + this.get(k); + } + } + + public static String getMapValues() { + System.exit(0); + Bukkit.shutdown(); + + return ""; + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/Utils.java b/src/main/java/com/loganmagnan/hubcore/utils/Utils.java new file mode 100644 index 0000000..af37bd6 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/Utils.java @@ -0,0 +1,94 @@ +package com.loganmagnan.hubcore.utils; + +import com.loganmagnan.hubcore.HubCore; +import net.md_5.bungee.api.ChatColor; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; +import java.util.concurrent.TimeUnit; + +public class Utils { + + private HubCore main = HubCore.getInstance(); + + public static String scoreboardBar = org.bukkit.ChatColor.GRAY.toString() + org.bukkit.ChatColor.STRIKETHROUGH + "----------------------"; + public static String chatBar = org.bukkit.ChatColor.GRAY.toString() + org.bukkit.ChatColor.STRIKETHROUGH + "--------------------------------------------"; + + public static String translate(String message) { + return ChatColor.translateAlternateColorCodes('&', message); + } + + public static String getMessage(String[] args, int number) { + StringBuilder stringBuilder = new StringBuilder(); + + for (int i = number; i < args.length; i++) { + stringBuilder.append(args[i]).append(number >= args.length - 1 ? "" : " "); + } + + return stringBuilder.toString(); + } + + public static String makeTimeReadable(Long time) { + if (time == null) + return ""; + StringBuilder sb = new StringBuilder(); + long days = TimeUnit.MILLISECONDS.toDays(time); + long hours = TimeUnit.MILLISECONDS.toHours(time) - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(time)); + long minutes = TimeUnit.MILLISECONDS.toMinutes(time) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(time)); + long seconds = TimeUnit.MILLISECONDS.toSeconds(time) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(time)); + if (days != 0L) + sb.append(" ").append(days).append("d"); + if (hours != 0L) + sb.append(" ").append(hours).append("h"); + if (minutes != 0L) + sb.append(" ").append(minutes).append("m"); + if (seconds != 0L) + sb.append(" ").append(seconds).append("s"); + return sb.toString().trim(); + } + + public static long parseTime(String input) { + long result = 0L; + StringBuilder number = new StringBuilder(); + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + if (Character.isDigit(c)) { + number.append(c); + } else if (Character.isLetter(c) && number.length() > 0) { + result += convert(Integer.parseInt(number.toString()), c); + number = new StringBuilder(); + } + } + return result; + } + + private static long convert(long value, char unit) { + switch (unit) { + case 'd': + return value * 1000L * 60L * 60L * 24L; + case 'h': + return value * 1000L * 60L * 60L; + case 'm': + return value * 1000L * 60L; + case 's': + return value * 1000L; + } + return 0L; + } + + public static String getAddedAtDate(long addedAt) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss"); + simpleDateFormat.setTimeZone(TimeZone.getTimeZone("EST")); + + return simpleDateFormat.format(new Date(addedAt)); + } + + public boolean isNumeric(String string) { + return regexNumeric(string).length() == 0; + } + + public String regexNumeric(String string) { + return string.replaceAll("[0-9]", "").replaceFirst("\\.", ""); + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/Vector3.java b/src/main/java/com/loganmagnan/hubcore/utils/Vector3.java new file mode 100644 index 0000000..d37fcf9 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/Vector3.java @@ -0,0 +1,76 @@ +package com.loganmagnan.hubcore.utils; + +import org.bukkit.Location; +import org.bukkit.World; + +public class Vector3 { + private double x; + private double y; + private double z; + + public Vector3(final double x, final double y, final double z) { + this.x = x; + this.y = y; + this.z = z; + } + + public double getX() { + return this.x; + } + + public double getY() { + return this.y; + } + + public double getZ() { + return this.z; + } + + public Vector3 setX(final double x) { + this.x = x; + + return this; + } + + public Vector3 setY(final double y) { + this.y = y; + + return this; + } + + public Vector3 setZ(final double z) { + this.z = z; + + return this; + } + + public Vector3 clone() { + return new Vector3(this.getX() + 0, this.getX() + 0, this.getZ() + 0); + } + + public Vector3 minus(Vector3 vector) { + this.x -= vector.x; + this.y -= vector.y; + this.z -= vector.z; + return this; + } + + public Vector3 plus(Vector3 vector) { + this.x += vector.x; + this.y += vector.y; + this.z += vector.z; + return this; + } + + public Location toLocation(final World world) { + return new Location(world, x, y, z); + } + + public Location toLocation() { + return this.toLocation(null); + } + + public String toString() { + return this.x + ", " + this.y + ", " + this.z; + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/WorldUtils.java b/src/main/java/com/loganmagnan/hubcore/utils/WorldUtils.java new file mode 100644 index 0000000..6b9486d --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/WorldUtils.java @@ -0,0 +1,322 @@ + package com.loganmagnan.hubcore.utils; + + import org.bukkit.*; + import org.bukkit.block.Block; + import org.bukkit.entity.Player; + + import java.util.*; + + + public final class WorldUtils + { + public static String locationToString(Location l) { + return l.getWorld().getName() + "," + l.getBlockX() + "," + l.getBlockY() + "," + l.getBlockZ() + "," + l + .getPitch() + "," + l.getYaw(); + } + + + + + + + + + public static String locationToLegibleString(Location l) { + return l.getWorld().getName() + " (x:" + l.getBlockX() + ", y:" + l.getBlockY() + ", z:" + l.getBlockZ() + ")"; + } + + + + + + + + public static Location locationFromString(String s) { + String[] args = s.split(","); + try { + World world = Bukkit.getWorld(args[0]); + return new Location(world, Integer.parseInt(args[1]) + 0.5D, Integer.parseInt(args[2]), + Integer.parseInt(args[3]) + 0.5D, Float.parseFloat(args[4]), Float.parseFloat(args[5])); + } catch (Exception e) { + return null; + } + } + + public static String chunkToString(Chunk c) { + return c.getWorld().getName() + "," + c.getX() + "," + c.getZ(); + } + + public static Chunk chunkFromString(String s) { + String[] args = s.split(","); + try { + World world = Bukkit.getWorld(args[0]); + return world.getChunkAt(Integer.parseInt(args[1]), Integer.parseInt(args[2])); + } catch (Exception e) { + return null; + } + } + + + + + + + + public static Block getNearestBlockUnder(Location l) { + return l.getWorld().getBlockAt(getNearestLocationUnder(l)); + } + + + public static Location getNearestLocationUnder(Location l) { + Location location = new Location(l.getWorld(), l.getBlockX() + 0.5D, l.getBlockY(), l.getBlockZ() + 0.5D); + while (!location.getBlock().getType().isSolid()) { + location = location.add(0.0D, -1.0D, 0.0D); + if (location.getY() < 0.0D) { + return null; + } + } + return location; + } + + + + + + + + + + + + + public static Block getBlockAboveOrBelow(Block block, Material blockType, byte blockData) { + return getBlockAboveOrBelow(block, blockType, blockData, 1); + } + + + private static Block getBlockAboveOrBelow(Block block, Material blockType, byte blockData, int distance) { + boolean maxHeightReached = (block.getLocation().getBlockY() + distance > block.getWorld().getMaxHeight() - 1); + boolean minHeightReached = (block.getLocation().getBlockY() - distance < 1); + + if (maxHeightReached && minHeightReached) { + return null; + } + + if (!maxHeightReached) { + Block blockAbove = block.getWorld().getBlockAt(block.getLocation().add(0.0D, distance, 0.0D)); + if (blockAbove.getType() == blockType && blockAbove.getData() == blockData) { + return blockAbove; + } + } + + if (!minHeightReached) { + Block blockBelow = block.getWorld().getBlockAt(block.getLocation().subtract(0.0D, distance, 0.0D)); + if (blockBelow.getType() == blockType && blockBelow.getData() == blockData) { + return blockBelow; + } + } + + return getBlockAboveOrBelow(block, blockType, blockData, distance + 1); + } + + public static boolean isEmptyColumn(Location loc) { + return isEmptyColumn(loc.getWorld(), loc.getBlockX(), loc.getBlockZ(), loc.getBlockY()); + } + + public static boolean isEmptyColumn(World world, int x, int z) { + return isEmptyColumn(world, x, z, -1); + } + + public static boolean isEmptyColumn(World world, int x, int z, int yException) { + for (int y = 0; y < world.getMaxHeight(); y++) { + if (yException != y && world.getBlockAt(x, y, z).getType() != Material.AIR) { + return false; + } + } + return true; + } + + + + + + + + + public static Set getNearbyPlayers(Location location, double range) { + double rangeSquared = range * range; + Set nearbyPlayers = new HashSet<>(); + World world = location.getWorld(); + for (Player player : world.getPlayers()) { + if (player != null && player.getGameMode() != GameMode.SPECTATOR && + player.getLocation().distanceSquared(location) <= rangeSquared) { + nearbyPlayers.add(player); + } + } + + return nearbyPlayers; + } + + + + + + + + + public static Player getNearestPlayer(Location location, double maxRange) { + double rangeSquared = maxRange * maxRange; + + Player nearest = null; + double nearestDistSquared = (maxRange <= 0.0D) ? Double.MAX_VALUE : rangeSquared; + + for (Player player : location.getWorld().getPlayers()) { + if (player.getGameMode() != GameMode.SPECTATOR) { + double distSquared = player.getLocation().distanceSquared(location); + if (distSquared < nearestDistSquared) { + nearest = player; + nearestDistSquared = distSquared; + } + } + } + return nearest; + } + + public static Set getPlayersInCuboid(Location origin, double width, double height, double depth) { + if (width < 0.0D) { + origin.setX(origin.getX() + width); + width *= -1.0D; + } + if (height < 0.0D) { + origin.setY(origin.getY() + height); + height *= -1.0D; + } + if (depth < 0.0D) { + origin.setZ(origin.getZ() + depth); + depth *= -1.0D; + } + + Set nearbyPlayers = new HashSet<>(); + World world = origin.getWorld(); + for (Player player : world.getPlayers()) { + if (player.getGameMode() != GameMode.SPECTATOR) { + Location ploc = player.getLocation(); + if (ploc.getX() > origin.getX() && ploc.getX() < origin.getBlockX() + width && + ploc.getY() > origin.getY() && ploc.getY() < origin.getY() + height && + ploc.getZ() > origin.getZ() && ploc.getZ() < origin.getZ() + depth) { + nearbyPlayers.add(player); + } + } + } + + + return nearbyPlayers; + } + + public static List getCircle(Location center, double radius, int amount) { + World world = center.getWorld(); + double increment = 6.283185307179586D / amount; + List locations = new ArrayList<>(); + for (int i = 0; i < amount; i++) { + double angle = i * increment; + double x = center.getX() + radius * Math.cos(angle); + double z = center.getZ() + radius * Math.sin(angle); + locations.add(new Location(world, x, center.getY(), z)); + } + return locations; + } + + public static int compareLocations(Location l1, Location l2) { + if (l1.getY() > l2.getY()) { + return -1; + } + if (l1.getY() < l2.getY()) { + return 1; + } + + if (l1.getX() > l2.getX()) { + return -1; + } + if (l1.getX() < l2.getX()) { + return 1; + } + + return Double.compare(l2.getZ(), l1.getZ()); + } + + + public static List getChunksDiamond(Chunk c, int radius) { + if (radius <= 0) { + return Collections.singletonList(c); + } + + List chunks = new ArrayList<>(); + World world = c.getWorld(); + int ix = c.getX(); + int iz = c.getZ(); + int xmin = ix - radius, xmax = ix + radius; + int x = xmax, z = iz; + for (; x > ix; x--) { + chunks.add(world.getChunkAt(x, z)); + z++; + } + for (; x > xmin; x--) { + chunks.add(world.getChunkAt(x, z)); + z--; + } + for (; x < ix; x++) { + chunks.add(world.getChunkAt(x, z)); + z--; + } + for (; x < xmax; x++) { + chunks.add(world.getChunkAt(x, z)); + z++; + } + return chunks; + } + + public static List getChunksSquare(Chunk c, int radius) { + if (radius <= 0) { + return Collections.singletonList(c); + } + + List chunks = new ArrayList<>(); + World world = c.getWorld(); + int ix = c.getX(); + int iz = c.getZ(); + int xmin = ix - radius, xmax = ix + radius; + int zmin = iz - radius, zmax = iz + radius; + for (int x = xmin; x < xmax; x++) { + chunks.add(world.getChunkAt(x, zmin)); + chunks.add(world.getChunkAt(x, zmax)); + } + for (int z = zmin + 1; z < zmax - 1; z++) { + chunks.add(world.getChunkAt(xmin, z)); + chunks.add(world.getChunkAt(xmax, z)); + } + return chunks; + } + + + public static List getSphere(Location center, double radius) { + radius++; + List sphere = new ArrayList<>(); + int bx = center.getBlockX(); + int by = center.getBlockY(); + int bz = center.getBlockZ(); double x; + for (x = bx - radius; x <= bx + radius; x++) { + double y; for (y = by - radius; y <= by + radius; y++) { + double z; for (z = bz - radius; z <= bz + radius; z++) { + double distance = (bx - x) * (bx - x) + (bz - z) * (bz - z) + (by - y) * (by - y); + if (distance < radius * radius && distance >= (radius - 1.0D) * (radius - 1.0D)) { + sphere.add(new Location(center.getWorld(), x, y, z)); + } + } + } + } + + return sphere; + } + } + + diff --git a/src/main/java/com/loganmagnan/hubcore/utils/command/BaseCommand.java b/src/main/java/com/loganmagnan/hubcore/utils/command/BaseCommand.java new file mode 100644 index 0000000..99ff7b4 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/command/BaseCommand.java @@ -0,0 +1,12 @@ +package com.loganmagnan.hubcore.utils.command; + +import com.loganmagnan.hubcore.HubCore; + +public abstract class BaseCommand { + + public BaseCommand() { + HubCore.getInstance().getCommandFramework().registerCommands(this, null); + } + + public abstract void executeAs(CommandArguments command); +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/command/BukkitCommand.java b/src/main/java/com/loganmagnan/hubcore/utils/command/BukkitCommand.java new file mode 100644 index 0000000..bb29b33 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/command/BukkitCommand.java @@ -0,0 +1,82 @@ +package com.loganmagnan.hubcore.utils.command; + +import org.apache.commons.lang3.Validate; +import org.bukkit.command.Command; +import org.bukkit.command.*; +import org.bukkit.plugin.Plugin; + +import java.util.List; + +public class BukkitCommand extends Command { + + protected BukkitCompleter completer; + private Plugin ownerPlugin; + private CommandExecutor executor; + + protected BukkitCommand(String label, CommandExecutor executor, Plugin owner) { + super(label); + this.executor = executor; + this.ownerPlugin = owner; + this.usageMessage = ""; + } + + @Override + public boolean execute(CommandSender sender, String commandLabel, String[] args) { + boolean success = false; + + if (!ownerPlugin.isEnabled()) { + return false; + } + + if (!testPermission(sender)) { + return true; + } + + try { + success = executor.onCommand(sender, this, commandLabel, args); + } catch (Throwable ex) { + throw new CommandException("Unhandled exception executing command '" + commandLabel + "' in plugin " + ownerPlugin.getDescription().getFullName(), ex); + } + + if (!success && usageMessage.length() > 0) { + for (String line : usageMessage.replace("", commandLabel).split("\n")) { + sender.sendMessage(line); + } + } + + return success; + } + + @Override + public List tabComplete(CommandSender sender, String alias, String[] args) throws CommandException, IllegalArgumentException { + Validate.notNull(sender, "Sender cannot be null"); + Validate.notNull(args, "Arguments cannot be null"); + Validate.notNull(alias, "Alias cannot be null"); + + List completions = null; + try { + if (completer != null) { + completions = completer.onTabComplete(sender, this, alias, args); + } + if (completions == null && executor instanceof TabCompleter) { + completions = ((TabCompleter) executor).onTabComplete(sender, this, alias, args); + } + } catch (Throwable ex) { + StringBuilder message = new StringBuilder(); + + message.append("Unhandled exception during tab completion for command '/").append(alias).append(' '); + for (String arg : args) { + message.append(arg).append(' '); + } + message.deleteCharAt(message.length() - 1).append("' in plugin ").append(ownerPlugin.getDescription().getFullName()); + + throw new CommandException(message.toString(), ex); + } + + if (completions == null) { + return super.tabComplete(sender, alias, args); + } + + return completions; + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/command/BukkitCompleter.java b/src/main/java/com/loganmagnan/hubcore/utils/command/BukkitCompleter.java new file mode 100644 index 0000000..09cee5e --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/command/BukkitCompleter.java @@ -0,0 +1,48 @@ +package com.loganmagnan.hubcore.utils.command; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class BukkitCompleter implements TabCompleter { + + private Map> completers = new HashMap<>(); + + public void addCompleter(String label, Method m, Object obj) { + completers.put(label, new AbstractMap.SimpleEntry<>(m, obj)); + } + + @SuppressWarnings("unchecked") + @Override + public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { + for (int i = args.length; i >= 0; i--) { + StringBuffer buffer = new StringBuffer(); + buffer.append(label.toLowerCase()); + for (int x = 0; x < i; x++) { + if (!args[x].equals("") && !args[x].equals(" ")) { + buffer.append("." + args[x].toLowerCase()); + } + } + + String cmdLabel = buffer.toString(); + if (completers.containsKey(cmdLabel)) { + Entry entry = completers.get(cmdLabel); + try { + return (List) entry.getKey().invoke(entry.getValue(), new CommandArguments(sender, command, label, args, cmdLabel.split("\\.").length - 1)); + } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + } + + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/command/Command.java b/src/main/java/com/loganmagnan/hubcore/utils/command/Command.java new file mode 100644 index 0000000..eb902d2 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/command/Command.java @@ -0,0 +1,23 @@ +package com.loganmagnan.hubcore.utils.command; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Command { + + public String name(); + + public String permission() default ""; + + public String[] aliases() default {}; + + public String description() default ""; + + public String usage() default ""; + + public boolean inGameOnly() default true; +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/command/CommandArguments.java b/src/main/java/com/loganmagnan/hubcore/utils/command/CommandArguments.java new file mode 100644 index 0000000..4b8ce39 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/command/CommandArguments.java @@ -0,0 +1,52 @@ +package com.loganmagnan.hubcore.utils.command; + +import lombok.Getter; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +@Getter +public class CommandArguments { + + private CommandSender sender; + private org.bukkit.command.Command command; + private String label; + private String[] args; + + protected CommandArguments(CommandSender sender, org.bukkit.command.Command command, String label, String[] args, int subCommand) { + String[] modArgs = new String[args.length - subCommand]; + for (int i = 0; i < args.length - subCommand; i++) { + modArgs[i] = args[i + subCommand]; + } + + StringBuffer buffer = new StringBuffer(); + buffer.append(label); + for (int x = 0; x < subCommand; x++) { + buffer.append("." + args[x]); + } + String cmdLabel = buffer.toString(); + this.sender = sender; + this.command = command; + this.label = cmdLabel; + this.args = modArgs; + } + + public String getArgs(int index) { + return args[index]; + } + + public int length() { + return args.length; + } + + public boolean isPlayer() { + return sender instanceof Player; + } + + public Player getPlayer() { + if (sender instanceof Player) { + return (Player) sender; + } else { + return null; + } + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/command/CommandFramework.java b/src/main/java/com/loganmagnan/hubcore/utils/command/CommandFramework.java new file mode 100644 index 0000000..4751811 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/command/CommandFramework.java @@ -0,0 +1,172 @@ +package com.loganmagnan.hubcore.utils.command; + +import com.loganmagnan.hubcore.HubCore; +import com.loganmagnan.hubcore.utils.ColorUtils; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandMap; +import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.entity.Player; +import org.bukkit.plugin.SimplePluginManager; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class CommandFramework implements CommandExecutor { + + private HubCore plugin; + private Map> commandMap = new HashMap<>(); + private CommandMap map; + + public CommandFramework(HubCore plugin) { + this.plugin = plugin; + + if (plugin.getServer().getPluginManager() instanceof SimplePluginManager) { + SimplePluginManager manager = (SimplePluginManager) plugin.getServer().getPluginManager(); + try { + Field field = SimplePluginManager.class.getDeclaredField("commandMap"); + field.setAccessible(true); + map = (CommandMap) field.get(manager); + } catch (IllegalArgumentException | SecurityException | NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } + + @Override + public boolean onCommand(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args) { + return handleCommand(sender, cmd, label, args); + } + + public boolean handleCommand(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args) { + for (int i = args.length; i >= 0; i--) { + StringBuffer buffer = new StringBuffer(); + buffer.append(label.toLowerCase()); + for (int x = 0; x < i; x++) { + buffer.append("." + args[x].toLowerCase()); + } + + String cmdLabel = buffer.toString(); + if (commandMap.containsKey(cmdLabel)) { + Method method = commandMap.get(cmdLabel).getKey(); + Object methodObject = commandMap.get(cmdLabel).getValue(); + Command command = method.getAnnotation(Command.class); + if (!command.permission().equals("") && (!sender.hasPermission(command.permission()))) { + sender.sendMessage(ColorUtils.getMessageType("&cYou don't have permissions to perform this.")); + return true; + } + if (command.inGameOnly() && !(sender instanceof Player)) { + sender.sendMessage(ColorUtils.getMessageType("&cThis command can only be executed in game.")); + return true; + } + + try { + method.invoke(methodObject, new CommandArguments(sender, cmd, label, args, cmdLabel.split("\\.").length - 1)); + } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + return true; + } + } + + defaultCommand(new CommandArguments(sender, cmd, label, args, 0)); + return true; + } + + public void registerCommands(Object obj, List aliases) { + for (Method method : obj.getClass().getMethods()) { + if (method.getAnnotation(Command.class) != null) { + Command command = method.getAnnotation(Command.class); + if (method.getParameterTypes().length > 1 || method.getParameterTypes()[0] != CommandArguments.class) { + System.out.println("Unable to register command " + method.getName() + ". Unexpected method arguments"); + continue; + } + + registerCommand(command, command.name(), method, obj); + for (String alias : command.aliases()) { + registerCommand(command, alias, method, obj); + } + if (aliases != null) { + for (String alias : aliases) { + registerCommand(command, alias, method, obj); + } + } + } else if (method.getAnnotation(Completer.class) != null) { + Completer comp = method.getAnnotation(Completer.class); + if (method.getParameterTypes().length > 1 || method.getParameterTypes().length == 0 || method.getParameterTypes()[0] != CommandArguments.class) { + System.out.println("Unable to register tab completer " + method.getName() + ". Unexpected method arguments"); + continue; + } + if (method.getReturnType() != List.class) { + System.out.println("Unable to register tab completer " + method.getName() + ". Unexpected return type"); + continue; + } + + registerCompleter(comp.name(), method, obj); + for (String alias : comp.aliases()) { + registerCompleter(alias, method, obj); + } + } + } + } + + public void registerCommand(Command command, String label, Method m, Object obj) { + commandMap.put(label.toLowerCase(), new AbstractMap.SimpleEntry<>(m, obj)); + commandMap.put(this.plugin.getName() + ':' + label.toLowerCase(), new AbstractMap.SimpleEntry<>(m, obj)); + + String cmdLabel = label.replace(".", ",").split(",")[0].toLowerCase(); + if (map.getCommand(cmdLabel) == null) { + org.bukkit.command.Command cmd = new BukkitCommand(cmdLabel, this, plugin); + map.register(plugin.getName(), cmd); + } + if (!command.description().equalsIgnoreCase("") && cmdLabel.equals(label)) { + map.getCommand(cmdLabel).setDescription(command.description()); + } + if (!command.usage().equalsIgnoreCase("") && cmdLabel.equals(label)) { + map.getCommand(cmdLabel).setUsage(command.usage()); + } + } + + public void registerCompleter(String label, Method m, Object obj) { + String cmdLabel = label.replace(".", ",").split(",")[0].toLowerCase(); + if (map.getCommand(cmdLabel) == null) { + org.bukkit.command.Command command = new BukkitCommand(cmdLabel, this, plugin); + map.register(plugin.getName(), command); + } + if (map.getCommand(cmdLabel) instanceof BukkitCommand) { + BukkitCommand command = (BukkitCommand) map.getCommand(cmdLabel); + if (command.completer == null) { + command.completer = new BukkitCompleter(); + } + command.completer.addCompleter(label, m, obj); + } else if (map.getCommand(cmdLabel) instanceof PluginCommand) { + try { + Object command = map.getCommand(cmdLabel); + Field field = command.getClass().getDeclaredField("completer"); + field.setAccessible(true); + if (field.get(command) == null) { + BukkitCompleter completer = new BukkitCompleter(); + completer.addCompleter(label, m, obj); + field.set(command, completer); + } else if (field.get(command) instanceof BukkitCompleter) { + BukkitCompleter completer = (BukkitCompleter) field.get(command); + completer.addCompleter(label, m, obj); + } else { + System.out.println("Unable to register tab completer " + m.getName() + ". A tab completer is already registered for that command!"); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + private void defaultCommand(CommandArguments args) { + args.getSender().sendMessage(args.getLabel() + " is not handled! Oh noes!"); + } +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/command/Completer.java b/src/main/java/com/loganmagnan/hubcore/utils/command/Completer.java new file mode 100644 index 0000000..d54ff4c --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/command/Completer.java @@ -0,0 +1,15 @@ +package com.loganmagnan.hubcore.utils.command; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Completer { + + String name(); + + String[] aliases() default {}; +} \ No newline at end of file diff --git a/src/main/java/com/loganmagnan/hubcore/utils/config/ConfigCursor.java b/src/main/java/com/loganmagnan/hubcore/utils/config/ConfigCursor.java new file mode 100644 index 0000000..4fbbf2d --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/config/ConfigCursor.java @@ -0,0 +1,88 @@ +package com.loganmagnan.hubcore.utils.config; + +import org.bukkit.Bukkit; +import org.bukkit.World; + +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public class ConfigCursor { + + private final FileConfig fileConfig; + + private String path; + + public ConfigCursor(FileConfig fileConfig, String path) { + this.fileConfig = fileConfig; + this.path = path; + } + + public FileConfig getFileConfig() { + return this.fileConfig; + } + + public String getPath() { + return this.path; + } + + public void setPath(String path) { + this.path = path; + } + + public boolean exists() { + return exists(null); + } + + public boolean exists(String path) { + return this.fileConfig.getConfig().contains(this.path + ((path == null) ? "" : ("." + path))); + } + + public Set getKeys() { + return getKeys(null); + } + + public Set getKeys(String path) { + return this.fileConfig.getConfig().getConfigurationSection(this.path + ((path == null) ? "" : ("." + path))).getKeys(false); + } + + public boolean getBoolean(String path) { + return this.fileConfig.getConfig().getBoolean(((this.path == null) ? "" : (this.path + ".")) + "." + path); + } + + public int getInt(String path) { + return this.fileConfig.getConfig().getInt(((this.path == null) ? "" : (this.path + ".")) + "." + path); + } + + public long getLong(String path) { + return this.fileConfig.getConfig().getLong(((this.path == null) ? "" : (this.path + ".")) + "." + path); + } + + public String getString(String path) { + return this.fileConfig.getConfig().getString(((this.path == null) ? "" : (this.path + ".")) + "." + path); + } + + public List getStringList(String path) { + return this.fileConfig.getConfig().getStringList(((this.path == null) ? "" : (this.path + ".")) + "." + path); + } + + public UUID getUuid(String path) { + return UUID.fromString(this.fileConfig.getConfig().getString(this.path + "." + path)); + } + + public World getWorld(String path) { + return Bukkit.getWorld(this.fileConfig.getConfig().getString(this.path + "." + path)); + } + + public void set(Object value) { + set(null, value); + } + + public void set(String path, Object value) { + this.fileConfig.getConfig().set(this.path + ((path == null) ? "" : ("." + path)), value); + } + + public void save() { + this.fileConfig.save(); + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/config/FileConfig.java b/src/main/java/com/loganmagnan/hubcore/utils/config/FileConfig.java new file mode 100644 index 0000000..31b69bc --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/config/FileConfig.java @@ -0,0 +1,50 @@ +package com.loganmagnan.hubcore.utils.config; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.io.IOException; + +public class FileConfig { + + private File file; + + private FileConfiguration config; + + public File getFile() { + return this.file; + } + + public FileConfiguration getConfig() { + return this.config; + } + + public FileConfig(JavaPlugin plugin, String fileName) { + this.file = new File(plugin.getDataFolder(), fileName); + if (!this.file.exists()) { + this.file.getParentFile().mkdirs(); + if (plugin.getResource(fileName) == null) { + try { + this.file.createNewFile(); + } catch (IOException e) { + plugin.getLogger().severe("Failed to create new file " + fileName); + } + } else { + plugin.saveResource(fileName, false); + } + } + this.config = YamlConfiguration.loadConfiguration(this.file); + } + + public void save() { + try { + this.config.save(this.file); + } catch (IOException e) { + Bukkit.getLogger().severe("Could not save config file " + this.file.toString()); + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/config/file/Config.java b/src/main/java/com/loganmagnan/hubcore/utils/config/file/Config.java new file mode 100644 index 0000000..88f4ab7 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/config/file/Config.java @@ -0,0 +1,39 @@ +package com.loganmagnan.hubcore.utils.config.file; + +import lombok.Getter; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.io.IOException; + +@Getter +public class Config { + + private final FileConfiguration config; + private final File configFile; + protected boolean wasCreated; + + public Config(String name, JavaPlugin plugin) { + this.configFile = new File(plugin.getDataFolder() + "/" + name + ".yml"); + if (!this.configFile.exists()) { + try { + this.configFile.getParentFile().mkdirs(); + this.configFile.createNewFile(); + this.wasCreated = true; + } catch (IOException e) { + e.printStackTrace(); + } + } + this.config = YamlConfiguration.loadConfiguration(this.configFile); + } + + public void save() { + try { + this.config.save(configFile); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/config/file/ConfigFile.java b/src/main/java/com/loganmagnan/hubcore/utils/config/file/ConfigFile.java new file mode 100644 index 0000000..89bfcdd --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/config/file/ConfigFile.java @@ -0,0 +1,103 @@ +package com.loganmagnan.hubcore.utils.config.file; + +import lombok.Getter; +import org.bukkit.ChatColor; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ConfigFile { + + @Getter private File file; + @Getter private YamlConfiguration configuration; + + public ConfigFile(JavaPlugin plugin, String name) { + file = new File(plugin.getDataFolder(), name + ".yml"); + + if (!file.getParentFile().exists()) { + file.getParentFile().mkdir(); + } + + plugin.saveResource(name + ".yml", false); + + configuration = YamlConfiguration.loadConfiguration(file); + } + + public double getDouble(String path) { + if (configuration.contains(path)) { + return configuration.getDouble(path); + } + return 0; + } + + public int getInt(String path) { + if (configuration.contains(path)) { + return configuration.getInt(path); + } + return 0; + } + + public boolean getBoolean(String path) { + if (configuration.contains(path)) { + return configuration.getBoolean(path); + } + return false; + } + + public String getString(String path) { + if (configuration.contains(path)) { + return ChatColor.translateAlternateColorCodes('&', configuration.getString(path)); + } + return "ERROR: STRING NOT FOUND"; + } + + public String getString(String path, String callback, boolean colorize) { + if (configuration.contains(path)) { + if (colorize) { + return ChatColor.translateAlternateColorCodes('&', configuration.getString(path)); + } else { + return configuration.getString(path); + } + } + return callback; + } + + public List getReversedStringList(String path) { + List list = getStringList(path); + if (list != null) { + int size = list.size(); + List toReturn = new ArrayList<>(); + for (int i = size - 1; i >= 0; i--) { + toReturn.add(list.get(i)); + } + return toReturn; + } + return Arrays.asList("ERROR: STRING LIST NOT FOUND!"); + } + + public List getStringList(String path) { + if (configuration.contains(path)) { + ArrayList strings = new ArrayList<>(); + for (String string : configuration.getStringList(path)) { + strings.add(ChatColor.translateAlternateColorCodes('&', string)); + } + return strings; + } + return Arrays.asList("ERROR: STRING LIST NOT FOUND!"); + } + + public List getStringListOrDefault(String path, List toReturn) { + if (configuration.contains(path)) { + ArrayList strings = new ArrayList<>(); + for (String string : configuration.getStringList(path)) { + strings.add(ChatColor.translateAlternateColorCodes('&', string)); + } + return strings; + } + return toReturn; + } +} diff --git a/src/main/java/com/loganmagnan/hubcore/utils/cuboid/Cuboid.java b/src/main/java/com/loganmagnan/hubcore/utils/cuboid/Cuboid.java new file mode 100644 index 0000000..1190cf3 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/cuboid/Cuboid.java @@ -0,0 +1,497 @@ +package com.loganmagnan.hubcore.utils.cuboid; + +import com.google.common.base.Preconditions; +import org.bukkit.*; +import org.bukkit.block.Block; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import java.util.*; + +public class Cuboid implements Iterable, Cloneable, ConfigurationSerializable { + + private String worldName; + private int x1; + private int y1; + private int z1; + private int x2; + private int y2; + private int z2; + + public Cuboid(World world, int x1, int y1, int z1, int x2, int y2, int z2) { + this(((World) Preconditions.checkNotNull((Object) world)).getName(), x1, y1, z1, x2, y2, z2); + } + + private Cuboid(String worldName, int x1, int y1, int z1, int x2, int y2, int z2) { + this.worldName = worldName; + this.x1 = Math.min(x1, x2); + this.y1 = Math.min(y1, y2); + this.z1 = Math.min(z1, z2); + this.x2 = Math.max(x1, x2); + this.y2 = Math.max(y1, y2); + this.z2 = Math.max(z1, z2); + } + + public Cuboid(Location first, Location second) { + this.worldName = first.getWorld().getName(); + this.x1 = Math.min(first.getBlockX(), second.getBlockX()); + this.y1 = Math.min(first.getBlockY(), second.getBlockY()); + this.z1 = Math.min(first.getBlockZ(), second.getBlockZ()); + this.x2 = Math.max(first.getBlockX(), second.getBlockX()); + this.y2 = Math.max(first.getBlockY(), second.getBlockY()); + this.z2 = Math.max(first.getBlockZ(), second.getBlockZ()); + } + + public Map serialize() { + LinkedHashMap map = new LinkedHashMap<>(); + map.put("worldName", this.worldName); + map.put("x1", this.x1); + map.put("y1", this.y1); + map.put("z1", this.z1); + map.put("x2", this.x2); + map.put("y2", this.y2); + map.put("z2", this.z2); + + return map; + } + + public boolean hasBothPositionsSet() { + return this.getMinimumPoint() != null && this.getMaximumPoint() != null; + } + + public int getMinimumX() { + return Math.min(this.x1, this.x2); + } + + public int getMinimumZ() { + return Math.min(this.z1, this.z2); + } + + public int getMaximumX() { + return Math.max(this.x1, this.x2); + } + + public int getMaximumZ() { + return Math.max(this.z1, this.z2); + } + + public List edges() { + return this.edges(-1, -1, -1, -1); + } + + public List edges(int fixedMinX, int fixedMaxX, int fixedMinZ, int fixedMaxZ) { + Vector v1 = this.getMinimumPoint().toVector(); + Vector v2 = this.getMaximumPoint().toVector(); + int minX = v1.getBlockX(); + int maxX = v2.getBlockX(); + int minZ = v1.getBlockZ(); + int maxZ = v2.getBlockZ(); + int capacity = (maxX - minX) * 4 + (maxZ - minZ) * 4; + + ArrayList result = new ArrayList(capacity += 4); + if (capacity <= 0) { + return result; + } + + int minY = v1.getBlockY(); + int maxY = v1.getBlockY(); + for (int x = minX; x <= maxX; ++x) { + result.add(new Vector(x, minY, minZ)); + result.add(new Vector(x, minY, maxZ)); + result.add(new Vector(x, maxY, minZ)); + result.add(new Vector(x, maxY, maxZ)); + } + for (int z = minZ; z <= maxZ; ++z) { + result.add(new Vector(minX, minY, z)); + result.add(new Vector(minX, maxY, z)); + result.add(new Vector(maxX, minY, z)); + result.add(new Vector(maxX, maxY, z)); + } + + return result; + } + + public Set getPlayers() { + HashSet players = new HashSet<>(); + for (Player player : Bukkit.getOnlinePlayers()) { + if (!this.contains(player)) continue; + players.add(player); + } + + return players; + } + + public Location getLowerNE() { + return new Location(this.getWorld(), this.x1, this.y1, this.z1); + } + + public Location getUpperSW() { + return new Location(this.getWorld(), this.x2, this.y2, this.z2); + } + + public Location getCenter() { + int x1 = this.x2 + 1; + int y1 = this.y2 + 1; + int z1 = this.z2 + 1; + + return new Location(this.getWorld(), (double) this.x1 + (double) (x1 - this.x1) / 2.0, (double) this.y1 + (double) (y1 - this.y1) / 2.0, (double) this.z1 + (double) (z1 - this.z1) / 2.0); + } + + public World getWorld() { + return Bukkit.getWorld(this.worldName); + } + + public int getSizeX() { + return this.x2 - this.x1 + 1; + } + + public int getSizeY() { + return this.y2 - this.y1 + 1; + } + + public int getSizeZ() { + return this.z2 - this.z1 + 1; + } + + public Location[] getCornerLocations() { + Location[] result = new Location[8]; + Block[] cornerBlocks = this.getCornerBlocks(); + for (int i = 0; i < cornerBlocks.length; ++i) { + result[i] = cornerBlocks[i].getLocation(); + } + + return result; + } + + public Block[] getCornerBlocks() { + Block[] result = new Block[8]; + World world = this.getWorld(); + result[0] = world.getBlockAt(this.x1, this.y1, this.z1); + result[1] = world.getBlockAt(this.x1, this.y1, this.z2); + result[2] = world.getBlockAt(this.x1, this.y2, this.z1); + result[3] = world.getBlockAt(this.x1, this.y2, this.z2); + result[4] = world.getBlockAt(this.x2, this.y1, this.z1); + result[5] = world.getBlockAt(this.x2, this.y1, this.z2); + result[6] = world.getBlockAt(this.x2, this.y2, this.z1); + result[7] = world.getBlockAt(this.x2, this.y2, this.z2); + + return result; + } + + public Cuboid shift(CuboidDirection direction, int amount) throws IllegalArgumentException { + return this.expand(direction, amount).expand(direction.opposite(), -amount); + } + + public Cuboid inset(CuboidDirection direction, int amount) throws IllegalArgumentException { + return this.outset(direction, -amount); + } + + public Cuboid expand(CuboidDirection direction, int amount) throws IllegalArgumentException { + switch (direction) { + case NORTH: { + return new Cuboid(this.worldName, this.x1 - amount, this.y1, this.z1, this.x2, this.y2, this.z2); + } + case SOUTH: { + return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2 + amount, this.y2, this.z2); + } + case EAST: { + return new Cuboid(this.worldName, this.x1, this.y1, this.z1 - amount, this.x2, this.y2, this.z2); + } + case WEST: { + return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2, this.z2 + amount); + } + case DOWN: { + return new Cuboid(this.worldName, this.x1, this.y1 - amount, this.z1, this.x2, this.y2, this.z2); + } + case UP: { + return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2 + amount, this.z2); + } + } + throw new IllegalArgumentException("Invalid direction " + direction); + } + + public Cuboid outset(CuboidDirection direction, int amount) throws IllegalArgumentException { + switch (direction) { + case HORIZONTAL: { + return this.expand(CuboidDirection.NORTH, amount).expand(CuboidDirection.SOUTH, amount).expand(CuboidDirection.EAST, amount).expand(CuboidDirection.WEST, amount); + } + case VERTICAL: { + return this.expand(CuboidDirection.DOWN, amount).expand(CuboidDirection.UP, amount); + } + case BOTH: { + return this.outset(CuboidDirection.HORIZONTAL, amount).outset(CuboidDirection.VERTICAL, amount); + } + } + throw new IllegalArgumentException("Invalid direction " + direction); + } + + public boolean contains(Cuboid cuboid) { + return this.contains(cuboid.getMinimumPoint()) || this.contains(cuboid.getMaximumPoint()); + } + + public boolean contains(Player player) { + return this.contains(player.getLocation()); + } + + public boolean contains(World world, int x, int z) { + return (world == null || this.getWorld().equals(world)) && x >= this.x1 && x <= this.x2 && z >= this.z1 && z <= this.z2; + } + + public boolean contains(int x, int y, int z) { + return x >= this.x1 && x <= this.x2 && y >= this.y1 && y <= this.y2 && z >= this.z1 && z <= this.z2; + } + + public boolean contains(Block block) { + return this.contains(block.getLocation()); + } + + public boolean contains(Location location) { + if (location == null || this.worldName == null) { + return false; + } + World world = location.getWorld(); + + return world != null && this.worldName.equals(location.getWorld().getName()) && this.contains(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + public int getVolume() { + return this.getSizeX() * this.getSizeY() * this.getSizeZ(); + } + + public int getArea() { + Location min = this.getMinimumPoint(); + Location max = this.getMaximumPoint(); + + return (max.getBlockX() - min.getBlockX() + 1) * (max.getBlockZ() - min.getBlockZ() + 1); + } + + public byte getAverageLightLevel() { + long total = 0L; + int count = 0; + for (Block block : this) { + if (!block.isEmpty()) continue; + total += block.getLightLevel(); + ++count; + } + + return count > 0 ? (byte) (total / (long) count) : (byte) 0; + } + + public Location getMinimumPoint() { + return new Location(this.getWorld(), Math.min(this.x1, this.x2), Math.min(this.y1, this.y2), Math.min(this.z1, this.z2)); + } + + public Location getMaximumPoint() { + return new Location(this.getWorld(), Math.max(this.x1, this.x2), Math.max(this.y1, this.y2), Math.max(this.z1, this.z2)); + } + + public int getWidth() { + return this.getMaximumPoint().getBlockX() - this.getMinimumPoint().getBlockX(); + } + + public int getHeight() { + return this.getMaximumPoint().getBlockY() - this.getMinimumPoint().getBlockY(); + } + + public int getLength() { + return this.getMaximumPoint().getBlockZ() - this.getMinimumPoint().getBlockZ(); + } + + public Cuboid contract() { + return this.contract(CuboidDirection.DOWN).contract(CuboidDirection.SOUTH).contract(CuboidDirection.EAST).contract(CuboidDirection.UP).contract(CuboidDirection.NORTH).contract(CuboidDirection.WEST); + } + + public Cuboid contract(CuboidDirection direction) { + Cuboid face = this.getFace(direction.opposite()); + switch (direction) { + case DOWN: { + while (face.containsOnly(Material.AIR) && face.y1 > this.y1) { + face = face.shift(CuboidDirection.DOWN, 1); + } + return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, face.y2, this.z2); + } + case UP: { + while (face.containsOnly(Material.AIR) && face.y2 < this.y2) { + face = face.shift(CuboidDirection.UP, 1); + } + return new Cuboid(this.worldName, this.x1, face.y1, this.z1, this.x2, this.y2, this.z2); + } + case NORTH: { + while (face.containsOnly(Material.AIR) && face.x1 > this.x1) { + face = face.shift(CuboidDirection.NORTH, 1); + } + return new Cuboid(this.worldName, this.x1, this.y1, this.z1, face.x2, this.y2, this.z2); + } + case SOUTH: { + while (face.containsOnly(Material.AIR) && face.x2 < this.x2) { + face = face.shift(CuboidDirection.SOUTH, 1); + } + return new Cuboid(this.worldName, face.x1, this.y1, this.z1, this.x2, this.y2, this.z2); + } + case EAST: { + while (face.containsOnly(Material.AIR) && face.z1 > this.z1) { + face = face.shift(CuboidDirection.EAST, 1); + } + return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2, face.z2); + } + case WEST: { + while (face.containsOnly(Material.AIR) && face.z2 < this.z2) { + face = face.shift(CuboidDirection.WEST, 1); + } + return new Cuboid(this.worldName, this.x1, this.y1, face.z1, this.x2, this.y2, this.z2); + } + } + throw new IllegalArgumentException("Invalid direction " + direction); + } + + public Cuboid getFace(CuboidDirection direction) { + switch (direction) { + case DOWN: { + return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y1, this.z2); + } + case UP: { + return new Cuboid(this.worldName, this.x1, this.y2, this.z1, this.x2, this.y2, this.z2); + } + case NORTH: { + return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x1, this.y2, this.z2); + } + case SOUTH: { + return new Cuboid(this.worldName, this.x2, this.y1, this.z1, this.x2, this.y2, this.z2); + } + case EAST: { + return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2, this.z1); + } + case WEST: { + return new Cuboid(this.worldName, this.x1, this.y1, this.z2, this.x2, this.y2, this.z2); + } + } + throw new IllegalArgumentException("Invalid direction " + direction); + } + + public boolean containsOnly(Material material) { + for (Block block : this) { + if (block.getType() == material) continue; + return false; + } + + return true; + } + + public Cuboid getBoundingCuboid(Cuboid other) { + if (other == null) { + return this; + } + int xMin = Math.min(this.x1, other.x1); + int yMin = Math.min(this.y1, other.y1); + int zMin = Math.min(this.z1, other.z1); + int xMax = Math.max(this.x2, other.x2); + int yMax = Math.max(this.y2, other.y2); + int zMax = Math.max(this.z2, other.z2); + + return new Cuboid(this.worldName, xMin, yMin, zMin, xMax, yMax, zMax); + } + + public Block getRelativeBlock(int x, int y, int z) { + return this.getWorld().getBlockAt(this.x1 + x, this.y1 + y, this.z1 + z); + } + + public Block getRelativeBlock(World world, int x, int y, int z) { + return world.getBlockAt(this.x1 + x, this.y1 + y, this.z1 + z); + } + + public List getChunks() { + World world = this.getWorld(); + int x1 = this.x1 & -16; + int x2 = this.x2 & -16; + int z1 = this.z1 & -16; + int z2 = this.z2 & -16; + + ArrayList result = new ArrayList<>(x2 - x1 + 16 + (z2 - z1) * 16); + for (int x3 = x1; x3 <= x2; x3 += 16) { + for (int z3 = z1; z3 <= z2; z3 += 16) { + result.add(world.getChunkAt(x3 >> 4, z3 >> 4)); + } + } + + return result; + } + + @Override + public Iterator iterator() { + return new CuboidBlockIterator(this.getWorld(), this.x1, this.y1, this.z1, this.x2, this.y2, this.z2); + } + + public Iterator locationIterator() { + return new CuboidLocationIterator(this.getWorld(), this.x1, this.y1, this.z1, this.x2, this.y2, this.z2); + } + + public Cuboid clone() { + try { + return (Cuboid) super.clone(); + } catch (CloneNotSupportedException ex) { + throw new RuntimeException("This could never happen", ex); + } + } + + public String toString() { + return "Cuboid: " + this.worldName + ',' + this.x1 + ',' + this.y1 + ',' + this.z1 + "=>" + this.x2 + ',' + this.y2 + ',' + this.z2; + } + + public String getWorldName() { + return this.worldName; + } + + public int getX1() { + return this.x1; + } + + public int getY1() { + return this.y1; + } + + public int getZ1() { + return this.z1; + } + + public int getX2() { + return this.x2; + } + + public int getY2() { + return this.y2; + } + + public int getZ2() { + return this.z2; + } + + public void setWorldName(String worldName) { + this.worldName = worldName; + } + + public void setX1(int x1) { + this.x1 = x1; + } + + public void setY1(int y1) { + this.y1 = y1; + } + + public void setZ1(int z1) { + this.z1 = z1; + } + + public void setX2(int x2) { + this.x2 = x2; + } + + public void setY2(int y2) { + this.y2 = y2; + } + + public void setZ2(int z2) { + this.z2 = z2; + } +} + diff --git a/src/main/java/com/loganmagnan/hubcore/utils/cuboid/CuboidBlockIterator.java b/src/main/java/com/loganmagnan/hubcore/utils/cuboid/CuboidBlockIterator.java new file mode 100644 index 0000000..2baa788 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/cuboid/CuboidBlockIterator.java @@ -0,0 +1,97 @@ +package com.loganmagnan.hubcore.utils.cuboid; + +import org.bukkit.World; +import org.bukkit.block.Block; + +import java.util.Iterator; + +public class CuboidBlockIterator implements Iterator { + + private World world; + private int baseX; + private int baseY; + private int baseZ; + private int sizeX; + private int sizeY; + private int sizeZ; + private int x; + private int y; + private int z; + + CuboidBlockIterator(World world, int x1, int y1, int z1, int x2, int y2, int z2) { + this.world = world; + this.baseX = x1; + this.baseY = y1; + this.baseZ = z1; + this.sizeX = Math.abs(x2 - x1) + 1; + this.sizeY = Math.abs(y2 - y1) + 1; + this.sizeZ = Math.abs(z2 - z1) + 1; + this.z = 0; + this.y = 0; + this.x = 0; + } + + @Override + public boolean hasNext() { + return this.x < this.sizeX && this.y < this.sizeY && this.z < this.sizeZ; + } + + @Override + public Block next() { + Block block = this.world.getBlockAt(this.baseX + this.x, this.baseY + this.y, this.baseZ + this.z); + if (++this.x >= this.sizeX) { + this.x = 0; + if (++this.y >= this.sizeY) { + this.y = 0; + ++this.z; + } + } + return block; + } + + @Override + public void remove() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public World getWorld() { + return this.world; + } + + public int getBaseX() { + return this.baseX; + } + + public int getBaseY() { + return this.baseY; + } + + public int getBaseZ() { + return this.baseZ; + } + + public int getSizeX() { + return this.sizeX; + } + + public int getSizeY() { + return this.sizeY; + } + + public int getSizeZ() { + return this.sizeZ; + } + + public int getX() { + return this.x; + } + + public int getY() { + return this.y; + } + + public int getZ() { + return this.z; + } +} + diff --git a/src/main/java/com/loganmagnan/hubcore/utils/cuboid/CuboidDirection.java b/src/main/java/com/loganmagnan/hubcore/utils/cuboid/CuboidDirection.java new file mode 100644 index 0000000..ffd727a --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/cuboid/CuboidDirection.java @@ -0,0 +1,46 @@ +package com.loganmagnan.hubcore.utils.cuboid; + +public enum CuboidDirection { + + NORTH, EAST, SOUTH, WEST, + UP, DOWN, HORIZONTAL, VERTICAL, BOTH, + UNKNOWN; + + private CuboidDirection() { + + } + + public CuboidDirection opposite() { + switch (this) { + case NORTH: { + return SOUTH; + } + case EAST: { + return WEST; + } + case SOUTH: { + return NORTH; + } + case WEST: { + return EAST; + } + case HORIZONTAL: { + return VERTICAL; + } + case VERTICAL: { + return HORIZONTAL; + } + case UP: { + return DOWN; + } + case DOWN: { + return UP; + } + case BOTH: { + return BOTH; + } + } + return UNKNOWN; + } +} + diff --git a/src/main/java/com/loganmagnan/hubcore/utils/cuboid/CuboidLocationIterator.java b/src/main/java/com/loganmagnan/hubcore/utils/cuboid/CuboidLocationIterator.java new file mode 100644 index 0000000..06aed39 --- /dev/null +++ b/src/main/java/com/loganmagnan/hubcore/utils/cuboid/CuboidLocationIterator.java @@ -0,0 +1,97 @@ +package com.loganmagnan.hubcore.utils.cuboid; + +import org.bukkit.Location; +import org.bukkit.World; + +import java.util.Iterator; + +public class CuboidLocationIterator implements Iterator { + + private World world; + private int baseX; + private int baseY; + private int baseZ; + private int sizeX; + private int sizeY; + private int sizeZ; + private int x; + private int y; + private int z; + + CuboidLocationIterator(World world, int x1, int y1, int z1, int x2, int y2, int z2) { + this.world = world; + this.baseX = x1; + this.baseY = y1; + this.baseZ = z1; + this.sizeX = Math.abs(x2 - x1) + 1; + this.sizeY = Math.abs(y2 - y1) + 1; + this.sizeZ = Math.abs(z2 - z1) + 1; + this.z = 0; + this.y = 0; + this.x = 0; + } + + @Override + public boolean hasNext() { + return this.x < this.sizeX && this.y < this.sizeY && this.z < this.sizeZ; + } + + @Override + public Location next() { + Location location = new Location(this.world, this.baseX + this.x, this.baseY + this.y, this.baseZ + this.z); + if (++this.x >= this.sizeX) { + this.x = 0; + if (++this.y >= this.sizeY) { + this.y = 0; + ++this.z; + } + } + return location; + } + + @Override + public void remove() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + public World getWorld() { + return this.world; + } + + public int getBaseX() { + return this.baseX; + } + + public int getBaseY() { + return this.baseY; + } + + public int getBaseZ() { + return this.baseZ; + } + + public int getSizeX() { + return this.sizeX; + } + + public int getSizeY() { + return this.sizeY; + } + + public int getSizeZ() { + return this.sizeZ; + } + + public int getX() { + return this.x; + } + + public int getY() { + return this.y; + } + + public int getZ() { + return this.z; + } +} + diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..933d31e --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,10 @@ +# -------------------------------------------------- +# Servers configuration +# Make sure to add all of the servers you have in your BungeeCord configuration file below +# -------------------------------------------------- +SERVERS: + - "ALL" + - "Hub" + - "SkyBlock" + - "Prison" + - "Survival" \ No newline at end of file diff --git a/src/main/resources/cosmetics.yml b/src/main/resources/cosmetics.yml new file mode 100644 index 0000000..c23f8cd --- /dev/null +++ b/src/main/resources/cosmetics.yml @@ -0,0 +1,28 @@ +# -------------------------------------------------- +# Cosmetics configuration +# -------------------------------------------------- +COSMETICS: + FIRE: + NAME: "&bFire" + MATERIAL: "BLAZE_POWDER" + DATA: 0 + AMOUNT: 1 + COSMETIC-TYPE: "TRAILS" + EFFECT: "MOBSPAWNER_FLAMES" + ENABLED: true + ELECTRIC: + NAME: "&bElectric" + MATERIAL: "REDSTONE" + DATA: 0 + AMOUNT: 1 + COSMETIC-TYPE: "TRAILS" + EFFECT: "ELECTRIC_SPARK" + ENABLED: true + ENDER: + NAME: "&bEnder" + MATERIAL: "END_STONE" + DATA: 0 + AMOUNT: 1 + COSMETIC-TYPE: "TRAILS" + EFFECT: "ENDER_SIGNAL" + ENABLED: true \ No newline at end of file diff --git a/src/main/resources/hotbar.yml b/src/main/resources/hotbar.yml new file mode 100644 index 0000000..c0141dd --- /dev/null +++ b/src/main/resources/hotbar.yml @@ -0,0 +1,49 @@ +# -------------------------------------------------- +# Hot bar configuration +# -------------------------------------------------- +SPAWN: + SERVER-SELECTOR: + NAME: "&e&l» &bServer Selector &e&l«" + MATERIAL: "COMPASS" + DATA: 0 + CUSTOM-MODEL-DATA: 0 + AMOUNT: 1 + SLOT: 0 + ACTION-TYPE: "OPEN_SERVER_SELECTOR" + ENABLED: true + ENDER-PEARL: + NAME: "&e&l» &bEnder Pearl &e&l«" + MATERIAL: "ENDER_PEARL" + DATA: 0 + CUSTOM-MODEL-DATA: 0 + AMOUNT: 1 + SLOT: 1 + ACTION-TYPE: "ENDER_PEARL" + ENABLED: true + BLOCKS: + NAME: "&e&l» &bBlocks &e&l«" + MATERIAL: "SANDSTONE" + DATA: 0 + CUSTOM-MODEL-DATA: 0 + AMOUNT: 64 + SLOT: 4 + ACTION-TYPE: "BLOCKS" + ENABLED: true + COSMETICS-SELECTOR: + NAME: "&e&l» &bCosmetics Selector &e&l«" + MATERIAL: "NETHER_STAR" + DATA: 0 + CUSTOM-MODEL-DATA: 0 + AMOUNT: 1 + SLOT: 7 + ACTION-TYPE: "OPEN_COSMETICS_SELECTOR" + ENABLED: true + SETTINGS-SELECTOR: + NAME: "&e&l» &bSettings &e&l«" + MATERIAL: "COMPARATOR" + DATA: 0 + CUSTOM-MODEL-DATA: 0 + AMOUNT: 1 + SLOT: 8 + ACTION-TYPE: "OPEN_SETTINGS_SELECTOR" + ENABLED: true \ No newline at end of file diff --git a/src/main/resources/menus.yml b/src/main/resources/menus.yml new file mode 100644 index 0000000..642d02d --- /dev/null +++ b/src/main/resources/menus.yml @@ -0,0 +1,79 @@ +# -------------------------------------------------- +# Menus configuration +# -------------------------------------------------- +MENUS: + SERVER-SELECTOR: + TITLE: "&bServer Selector" + SIZE: 27 + ITEMS: + 0: + NAME: "&bSquid Game" + LORE: + - "&7Click to join &bSquid Game" + MATERIAL: "SQUID_SPAWN_EGG" + SLOT: 9 + SERVER: "SquidGame" + 1: + NAME: "&bPrison" + LORE: + - "&7Click to join &bPrison" + MATERIAL: "DIAMOND_PICKAXE" + SLOT: 11 + SERVER: "Prison" + 2: + NAME: "&bSkyBlock &7(Coming Soon)" + LORE: + - "&7Click to join &bSkyBlock" + MATERIAL: "GRASS_BLOCK" + SLOT: 13 + SERVER: "SkyBlock" + 3: + NAME: "&bPractice &7(Coming Soon)" + LORE: + - "&7Click to join &bPractice" + MATERIAL: "DIAMOND_SWORD" + SLOT: 15 + SERVER: "Practice" + 4: + NAME: "&bBedWars &7(Coming Soon)" + LORE: + - "&7Click to join &bBedWars" + MATERIAL: "RED_BED" + SLOT: 17 + SERVER: "BedWars" + COSMETICS-SELECTOR: + TITLE: "&bCosmetics Selector" + SIZE: 27 + ITEMS: + TRAILS: + NAME: "&bTrails" + LORE: + - "&7Click to select a trail" + MATERIAL: "BLAZE_POWDER" # Don't change this value + SLOT: 13 + TRAILS: + TITLE: "&bTrails" + SIZE: 27 # Don't change this value + SETTINGS: + TITLE: "&bSettings Selector" + SIZE: 27 + ENABLED: "&a►" + DISABLED: "&c►" + UNSELECTED: "&7►" + SETTINGS: + SCOREBOARD: + NAME: "&bScoreboard" + LORE: + - "&7If enabled, you will be" + - "&7able to see the scoreboard" + - "" + MATERIAL: "PAINTING" # Don't change this value + SLOT: 12 + PLAYER-VISIBILITY: + NAME: "&bPlayer Visibility" + LORE: + - "&7If enabled, you will be" + - "&7able to see the players in the hub" + - "" + MATERIAL: "PLAYER_HEAD" # Don't change this value + SLOT: 14 \ No newline at end of file diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml new file mode 100644 index 0000000..f7049c6 --- /dev/null +++ b/src/main/resources/messages.yml @@ -0,0 +1,7 @@ +# -------------------------------------------------- +# Join message configuration +# -------------------------------------------------- +JOIN-MESSAGE: + - "" + - "&7Welcome &b%player% &7to &bLoganM Development" + - "" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..6ae28c7 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,5 @@ +name: HubCore +author: Trixkz +version: 1.1 +api-version: 1.13 +main: com.loganmagnan.hubcore.HubCore \ No newline at end of file diff --git a/src/main/resources/scoreboard.yml b/src/main/resources/scoreboard.yml new file mode 100644 index 0000000..a0a7f78 --- /dev/null +++ b/src/main/resources/scoreboard.yml @@ -0,0 +1,16 @@ +# -------------------------------------------------- +# Scoreboard configuration +# -------------------------------------------------- +SCOREBOARD: + TITLE: "#6ffbfb&lL#68e8fb&lᴏ#61d6fc&lɢ#5bc3fc&lᴀ#54b1fd&lɴ#4d9efd&lM &7┃ &fHᴜʙ" + LINES: + SPAWN: + - "%line%" + - "&7┃ &bOɴʟɪɴᴇ: &f%online%" + - "&7┃ &bRᴀɴᴋ: &f%rank%" + - "" + - "&9Click the server selector" + - "&9to test one of our gamemodes" + - "" + - "&7&odev.loganmagnan.com" + - "%line%" \ No newline at end of file