diff --git a/pom.xml b/pom.xml index e29316d..26aad1b 100644 --- a/pom.xml +++ b/pom.xml @@ -63,8 +63,8 @@ https://repo.dmulloy2.net/repository/public/ - skullcreator-repo - https://github.com/deanveloper/SkullCreator/raw/mvn-repo/ + minecraft-repo + https://libraries.minecraft.net/ @@ -72,7 +72,7 @@ org.spigotmc spigot-api - 1.18.1-R0.1-SNAPSHOT + 1.21.1-R0.1-SNAPSHOT provided @@ -102,9 +102,9 @@ compile - dev.dbassett - skullcreator - 3.0.1 + com.mojang + authlib + 1.5.21 compile diff --git a/src/main/java/grafnus/portalshard/engine/events/PlayerInteractRespawnAnchor.java b/src/main/java/grafnus/portalshard/engine/events/PlayerInteractRespawnAnchor.java index 00cd113..db7f20f 100644 --- a/src/main/java/grafnus/portalshard/engine/events/PlayerInteractRespawnAnchor.java +++ b/src/main/java/grafnus/portalshard/engine/events/PlayerInteractRespawnAnchor.java @@ -107,12 +107,16 @@ private void tryPortalUpgrade(PlayerInteractEvent event, ItemStack itemInHand, I int newLevel = requiredLevel + 1; connection.setLevel(newLevel); + // Recharge when upgraded + connection.setCharges(20); ConnectionDAO.saveConnection(connection); String actionbar = ChatColor.LIGHT_PURPLE + "Upgraded! Portal Level: " + ChatColor.GOLD + (newLevel); event.getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(actionbar)); event.getPlayer().getInventory().getItemInMainHand().setAmount((event.getPlayer().getInventory().getItemInMainHand().getAmount() - 1)); + + TaskFactory.createTask(new UpdatePortalCharges(loc)); } private boolean doChecks(PlayerInteractEvent event) { @@ -187,8 +191,8 @@ private void openMenu(PlayerInteractEvent event) { HibernatePortal portal = PortalDAO.getPortalByLocation(loc); if (portal == null) return; + event.setCancelled(true); PortalOverviewUI ui = new PortalOverviewUI(event.getPlayer(), portal); ui.openMenu(); - event.setCancelled(true); } } diff --git a/src/main/java/grafnus/portalshard/engine/task/CreatePortalITask.java b/src/main/java/grafnus/portalshard/engine/task/CreatePortalITask.java index 67a9b28..5578db1 100644 --- a/src/main/java/grafnus/portalshard/engine/task/CreatePortalITask.java +++ b/src/main/java/grafnus/portalshard/engine/task/CreatePortalITask.java @@ -48,6 +48,8 @@ public void run() { upperOrientable.setAxis(Axis.Z); } upperPortal.setBlockData(upperOrientable); + + TaskFactory.createTask(new UpdatePortalCharges(location)); } }; } diff --git a/src/main/java/grafnus/portalshard/gui/PortalOverviewUI.java b/src/main/java/grafnus/portalshard/gui/PortalOverviewUI.java index cadc857..de9e98e 100644 --- a/src/main/java/grafnus/portalshard/gui/PortalOverviewUI.java +++ b/src/main/java/grafnus/portalshard/gui/PortalOverviewUI.java @@ -1,10 +1,9 @@ package grafnus.portalshard.gui; -import dev.dbassett.skullcreator.SkullCreator; -import grafnus.portalshard.PERMISSION; import grafnus.portalshard.data.HibernateDO.HibernateConnection; import grafnus.portalshard.data.HibernateDO.HibernatePortal; import grafnus.portalshard.util.skulls.SKULL_SYMBOLS; +import grafnus.portalshard.util.skulls.SkullCreator; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.entity.Player; diff --git a/src/main/java/grafnus/portalshard/gui/PortalPlayerAddListUI.java b/src/main/java/grafnus/portalshard/gui/PortalPlayerAddListUI.java index 391c647..0a3c4c1 100644 --- a/src/main/java/grafnus/portalshard/gui/PortalPlayerAddListUI.java +++ b/src/main/java/grafnus/portalshard/gui/PortalPlayerAddListUI.java @@ -1,6 +1,6 @@ package grafnus.portalshard.gui; -import dev.dbassett.skullcreator.SkullCreator; +import grafnus.portalshard.util.skulls.SkullCreator; import grafnus.portalshard.data.DAO.PlayerPermissionDAO; import grafnus.portalshard.data.HibernateDO.HibernateConnection; import grafnus.portalshard.data.HibernateDO.HibernatePlayerPermission; diff --git a/src/main/java/grafnus/portalshard/gui/PortalPlayerListUI.java b/src/main/java/grafnus/portalshard/gui/PortalPlayerListUI.java index 7833ab9..27c43ac 100644 --- a/src/main/java/grafnus/portalshard/gui/PortalPlayerListUI.java +++ b/src/main/java/grafnus/portalshard/gui/PortalPlayerListUI.java @@ -1,6 +1,6 @@ package grafnus.portalshard.gui; -import dev.dbassett.skullcreator.SkullCreator; +import grafnus.portalshard.util.skulls.SkullCreator; import grafnus.portalshard.data.DAO.PlayerPermissionDAO; import grafnus.portalshard.data.HibernateDO.HibernateConnection; import grafnus.portalshard.data.HibernateDO.HibernatePlayerPermission; diff --git a/src/main/java/grafnus/portalshard/gui/PortalPlayerUI.java b/src/main/java/grafnus/portalshard/gui/PortalPlayerUI.java index 15e28cd..c96b954 100644 --- a/src/main/java/grafnus/portalshard/gui/PortalPlayerUI.java +++ b/src/main/java/grafnus/portalshard/gui/PortalPlayerUI.java @@ -1,6 +1,6 @@ package grafnus.portalshard.gui; -import dev.dbassett.skullcreator.SkullCreator; +import grafnus.portalshard.util.skulls.SkullCreator; import grafnus.portalshard.PERMISSION; import grafnus.portalshard.data.DAO.PlayerPermissionDAO; import grafnus.portalshard.data.HibernateDO.HibernateConnection; diff --git a/src/main/java/grafnus/portalshard/listeners/PlayerPortalListener.java b/src/main/java/grafnus/portalshard/listeners/PlayerPortalListener.java index 7a5fb5b..87b549b 100644 --- a/src/main/java/grafnus/portalshard/listeners/PlayerPortalListener.java +++ b/src/main/java/grafnus/portalshard/listeners/PlayerPortalListener.java @@ -11,8 +11,10 @@ import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityPortalEnterEvent; +import org.bukkit.event.entity.EntityPortalEvent; import org.bukkit.event.entity.EntityPortalExitEvent; import org.bukkit.event.player.PlayerPortalEvent; @@ -37,10 +39,32 @@ public void onEntityPortalTouch(EntityPortalEnterEvent event) { } } - @EventHandler - public void onPlayerTeleport(PlayerPortalEvent event) { + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onPlayerPortalFix(PlayerPortalEvent event) { + Bukkit.getLogger().log(Level.INFO, "Event Called"); + + Pair resultsLocationFix = fixNetherPortalExitLocation(event.getSearchRadius(), event.getTo()); + Location fixedLocation = resultsLocationFix.getFirst(); + boolean isPlayerPortalInRange = resultsLocationFix.getSecond(); + + if (isPlayerPortalInRange && Objects.isNull(fixedLocation)) { + event.setSearchRadius(1); + return; + } + + event.setTo(fixedLocation); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onEntityPortalFix(EntityPortalEvent event) { Bukkit.getLogger().log(Level.INFO, "Event Called"); + if (!(event.getEntity() instanceof Player)) { + if (RelativePosition.getLocationAboveN(event.getEntity().getLocation(), 2).getBlock().getType().equals(Material.RESPAWN_ANCHOR)) { + event.setCancelled(true); + } + } + Pair resultsLocationFix = fixNetherPortalExitLocation(event.getSearchRadius(), event.getTo()); Location fixedLocation = resultsLocationFix.getFirst(); boolean isPlayerPortalInRange = resultsLocationFix.getSecond(); diff --git a/src/main/java/grafnus/portalshard/listeners/PortalInterceptFixListener.java b/src/main/java/grafnus/portalshard/listeners/PortalInterceptFixListener.java new file mode 100644 index 0000000..76db7ee --- /dev/null +++ b/src/main/java/grafnus/portalshard/listeners/PortalInterceptFixListener.java @@ -0,0 +1,4 @@ +package grafnus.portalshard.listeners; + +public class PortalInterceptFixListener { +} diff --git a/src/main/java/grafnus/portalshard/portals/PortalHandler.java b/src/main/java/grafnus/portalshard/portals/PortalHandler.java index b7eb609..7145c63 100644 --- a/src/main/java/grafnus/portalshard/portals/PortalHandler.java +++ b/src/main/java/grafnus/portalshard/portals/PortalHandler.java @@ -7,6 +7,7 @@ import grafnus.portalshard.data.HibernateDO.HibernatePortal; import grafnus.portalshard.engine.task.CreatePortalITask; import grafnus.portalshard.engine.task.TaskFactory; +import grafnus.portalshard.engine.task.UpdatePortalCharges; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.Player; diff --git a/src/main/java/grafnus/portalshard/util/skulls/SkullCreator.java b/src/main/java/grafnus/portalshard/util/skulls/SkullCreator.java new file mode 100644 index 0000000..99836b9 --- /dev/null +++ b/src/main/java/grafnus/portalshard/util/skulls/SkullCreator.java @@ -0,0 +1,325 @@ +package grafnus.portalshard.util.skulls; + +// Copyright (c) 2017 deanveloper (see LICENSE.md for more info) + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.SkullType; +import org.bukkit.block.Block; +import org.bukkit.block.Skull; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Base64; +import java.util.UUID; + +/** + * A library for the Bukkit API to create player skulls + * from names, base64 strings, and texture URLs. + *

+ * Does not use any NMS code, and should work across all versions. + * + * @author deanveloper on 12/28/2016. + */ +public class SkullCreator { + + private SkullCreator() {} + + private static boolean warningPosted = false; + + // some reflection stuff to be used when setting a skull's profile + private static Field blockProfileField; + private static Method metaSetProfileMethod; + private static Field metaProfileField; + + /** + * Creates a player skull, should work in both legacy and new Bukkit APIs. + */ + public static ItemStack createSkull() { + checkLegacy(); + + try { + return new ItemStack(Material.valueOf("PLAYER_HEAD")); + } catch (IllegalArgumentException e) { + return new ItemStack(Material.valueOf("SKULL_ITEM"), 1, (byte) 3); + } + } + + /** + * Creates a player skull item with the skin based on a player's name. + * + * @param name The Player's name. + * @return The head of the Player. + * @deprecated names don't make for good identifiers. + */ + public static ItemStack itemFromName(String name) { + return itemWithName(createSkull(), name); + } + + /** + * Creates a player skull item with the skin based on a player's UUID. + * + * @param id The Player's UUID. + * @return The head of the Player. + */ + public static ItemStack itemFromUuid(UUID id) { + return itemWithUuid(createSkull(), id); + } + + /** + * Creates a player skull item with the skin at a Mojang URL. + * + * @param url The Mojang URL. + * @return The head of the Player. + */ + public static ItemStack itemFromUrl(String url) { + return itemWithUrl(createSkull(), url); + } + + /** + * Creates a player skull item with the skin based on a base64 string. + * + * @param base64 The Base64 string. + * @return The head of the Player. + */ + public static ItemStack itemFromBase64(String base64) { + return itemWithBase64(createSkull(), base64); + } + + /** + * Modifies a skull to use the skin of the player with a given name. + * + * @param item The item to apply the name to. Must be a player skull. + * @param name The Player's name. + * @return The head of the Player. + * @deprecated names don't make for good identifiers. + */ + @Deprecated + public static ItemStack itemWithName(ItemStack item, String name) { + notNull(item, "item"); + notNull(name, "name"); + + SkullMeta meta = (SkullMeta) item.getItemMeta(); + meta.setOwner(name); + item.setItemMeta(meta); + + return item; + } + + /** + * Modifies a skull to use the skin of the player with a given UUID. + * + * @param item The item to apply the name to. Must be a player skull. + * @param id The Player's UUID. + * @return The head of the Player. + */ + public static ItemStack itemWithUuid(ItemStack item, UUID id) { + notNull(item, "item"); + notNull(id, "id"); + + SkullMeta meta = (SkullMeta) item.getItemMeta(); + meta.setOwningPlayer(Bukkit.getOfflinePlayer(id)); + item.setItemMeta(meta); + + return item; + } + + /** + * Modifies a skull to use the skin at the given Mojang URL. + * + * @param item The item to apply the skin to. Must be a player skull. + * @param url The URL of the Mojang skin. + * @return The head associated with the URL. + */ + public static ItemStack itemWithUrl(ItemStack item, String url) { + notNull(item, "item"); + notNull(url, "url"); + + return itemWithBase64(item, urlToBase64(url)); + } + + /** + * Modifies a skull to use the skin based on the given base64 string. + * + * @param item The ItemStack to put the base64 onto. Must be a player skull. + * @param base64 The base64 string containing the texture. + * @return The head with a custom texture. + */ + public static ItemStack itemWithBase64(ItemStack item, String base64) { + notNull(item, "item"); + notNull(base64, "base64"); + + if (!(item.getItemMeta() instanceof SkullMeta)) { + return null; + } + SkullMeta meta = (SkullMeta) item.getItemMeta(); + mutateItemMeta(meta, base64); + item.setItemMeta(meta); + + return item; + } + + /** + * Sets the block to a skull with the given name. + * + * @param block The block to set. + * @param name The player to set it to. + * @deprecated names don't make for good identifiers. + */ + @Deprecated + public static void blockWithName(Block block, String name) { + notNull(block, "block"); + notNull(name, "name"); + + Skull state = (Skull) block.getState(); + state.setOwningPlayer(Bukkit.getOfflinePlayer(name)); + state.update(false, false); + } + + /** + * Sets the block to a skull with the given UUID. + * + * @param block The block to set. + * @param id The player to set it to. + */ + public static void blockWithUuid(Block block, UUID id) { + notNull(block, "block"); + notNull(id, "id"); + + setToSkull(block); + Skull state = (Skull) block.getState(); + state.setOwningPlayer(Bukkit.getOfflinePlayer(id)); + state.update(false, false); + } + + /** + * Sets the block to a skull with the skin found at the provided mojang URL. + * + * @param block The block to set. + * @param url The mojang URL to set it to use. + */ + public static void blockWithUrl(Block block, String url) { + notNull(block, "block"); + notNull(url, "url"); + + blockWithBase64(block, urlToBase64(url)); + } + + /** + * Sets the block to a skull with the skin for the base64 string. + * + * @param block The block to set. + * @param base64 The base64 to set it to use. + */ + public static void blockWithBase64(Block block, String base64) { + notNull(block, "block"); + notNull(base64, "base64"); + + setToSkull(block); + Skull state = (Skull) block.getState(); + mutateBlockState(state, base64); + state.update(false, false); + } + + private static void setToSkull(Block block) { + checkLegacy(); + + try { + block.setType(Material.valueOf("PLAYER_HEAD"), false); + } catch (IllegalArgumentException e) { + block.setType(Material.valueOf("SKULL"), false); + Skull state = (Skull) block.getState(); + state.setSkullType(SkullType.PLAYER); + state.update(false, false); + } + } + + private static void notNull(Object o, String name) { + if (o == null) { + throw new NullPointerException(name + " should not be null!"); + } + } + + private static String urlToBase64(String url) { + + URI actualUrl; + try { + actualUrl = new URI(url); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + String toEncode = "{\"textures\":{\"SKIN\":{\"url\":\"" + actualUrl.toString() + "\"}}}"; + return Base64.getEncoder().encodeToString(toEncode.getBytes()); + } + + private static GameProfile makeProfile(String b64) { + // random uuid based on the b64 string + UUID id = new UUID( + b64.substring(b64.length() - 20).hashCode(), + b64.substring(b64.length() - 10).hashCode() + ); + GameProfile profile = new GameProfile(id, "Player"); + profile.getProperties().put("textures", new Property("textures", b64)); + + return profile; + } + + private static void mutateBlockState(Skull block, String b64) { + try { + if (blockProfileField == null) { + blockProfileField = block.getClass().getDeclaredField("profile"); + blockProfileField.setAccessible(true); + } + blockProfileField.set(block, makeProfile(b64)); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + private static void mutateItemMeta(SkullMeta meta, String b64) { + try { + if (metaSetProfileMethod == null) { + metaSetProfileMethod = meta.getClass().getDeclaredMethod("setProfile", GameProfile.class); + metaSetProfileMethod.setAccessible(true); + } + metaSetProfileMethod.invoke(meta, makeProfile(b64)); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { + // if in an older API where there is no setProfile method, + // we set the profile field directly. + try { + if (metaProfileField == null) { + metaProfileField = meta.getClass().getDeclaredField("profile"); + metaProfileField.setAccessible(true); + } + metaProfileField.set(meta, makeProfile(b64)); + + } catch (NoSuchFieldException | IllegalAccessException ex2) { + ex2.printStackTrace(); + } + } + } + + // suppress warning since PLAYER_HEAD doesn't exist in 1.12.2, + // but we expect this and catch the error at runtime. + @SuppressWarnings("JavaReflectionMemberAccess") + private static void checkLegacy() { + try { + // if both of these succeed, then we are running + // in a legacy api, but on a modern (1.13+) server. + Material.class.getDeclaredField("PLAYER_HEAD"); + Material.valueOf("SKULL"); + + if (!warningPosted) { + Bukkit.getLogger().warning("SKULLCREATOR API - Using the legacy bukkit API with 1.13+ bukkit versions is not supported!"); + warningPosted = true; + } + } catch (NoSuchFieldException | IllegalArgumentException ignored) {} + } +} \ No newline at end of file