diff --git a/src/main/java/com/songoda/epicheads/EpicHeads.java b/src/main/java/com/songoda/epicheads/EpicHeads.java index e607ecd..b6458a7 100644 --- a/src/main/java/com/songoda/epicheads/EpicHeads.java +++ b/src/main/java/com/songoda/epicheads/EpicHeads.java @@ -1,9 +1,15 @@ package com.songoda.epicheads; import com.songoda.epicheads.command.CommandManager; +import com.songoda.epicheads.head.Head; +import com.songoda.epicheads.head.HeadManager; +import com.songoda.epicheads.head.Tag; +import com.songoda.epicheads.listeners.ItemListeners; +import com.songoda.epicheads.players.PlayerManager; import com.songoda.epicheads.utils.Methods; import com.songoda.epicheads.utils.ServerVersion; import com.songoda.epicheads.utils.SettingsManager; +import com.songoda.epicheads.utils.gui.AbstractGUI; import com.songoda.epicheads.utils.updateModules.LocaleModule; import com.songoda.update.Plugin; import com.songoda.update.SongodaUpdate; @@ -11,6 +17,15 @@ import org.apache.commons.lang.ArrayUtils; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.plugin.java.JavaPlugin; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.io.*; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.Optional; public class EpicHeads extends JavaPlugin { private static CommandSender console = Bukkit.getConsoleSender(); @@ -19,6 +34,8 @@ public class EpicHeads extends JavaPlugin { private ServerVersion serverVersion = ServerVersion.fromPackageName(Bukkit.getServer().getClass().getPackage().getName()); + private HeadManager headManager; + private PlayerManager playerManager; private SettingsManager settingsManager; private CommandManager commandManager; @@ -53,8 +70,20 @@ public class EpicHeads extends JavaPlugin { this.references = new References(); // Setup Managers + this.headManager = new HeadManager(); + this.playerManager = new PlayerManager(); this.commandManager = new CommandManager(this); + // Register Listeners + AbstractGUI.initializeListeners(this); + Bukkit.getPluginManager().registerEvents(new ItemListeners(this), this); + + // Download Heads + downloadHeads(); + + // Load Heads + loadHeads(); + console.sendMessage(Methods.formatText("&a=============================")); } @@ -66,6 +95,76 @@ public class EpicHeads extends JavaPlugin { console.sendMessage(Methods.formatText("&a=============================")); } + + private void downloadHeads() { + try { + InputStream is = new URL("http://www.head-db.com/dump").openStream(); + BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); + String jsonText = readAll(rd); + JSONParser parser = new JSONParser(); + JSONArray json = (JSONArray) parser.parse(jsonText); + + try (FileWriter file = new FileWriter(getDataFolder() + "/heads.json")) { + file.write(json.toJSONString()); + } + } catch (Exception e) { + System.out.println("Failed to download heads."); + } + } + + private boolean loadHeads() { + try { + JSONParser parser = new JSONParser(); + JSONArray jsonArray = (JSONArray) parser.parse(new FileReader(getDataFolder() + "/heads.json")); + + for (Object o : jsonArray) { + JSONObject jsonObject = (JSONObject) o; + + String tags = (String) jsonObject.get("tags"); + Optional tagOptional = headManager.getTags().stream().filter(t -> t.getName().equalsIgnoreCase(tags)).findFirst(); + + Tag tag = tagOptional.orElseGet(() -> new Tag(tags, -1)); + + Head head = new Head(Integer.parseInt((String) jsonObject.get("id")), + (String) jsonObject.get("name"), + (String) jsonObject.get("url"), + tag, + Byte.parseByte((String) jsonObject.get("staff_picked"))); + + if (head.getName() == null || + head.getName().equals("null")) continue; + + if (!tagOptional.isPresent()) + headManager.addTag(tag); + headManager.addHead(head); + } + + for (Tag tag : headManager.getTags()) { + tag.setCount(Math.toIntExact(headManager.getHeads().stream().filter(head -> head.getTag() == tag).count())); + } + + System.out.println("loaded " + headManager.getHeads().size() + " Heads."); + + } catch (IOException e) { + System.out.println("Heads file not found. Plugin disabling."); + return false; + } catch (ParseException e) { + System.out.println("Failed to parse heads file. Plugin disabling."); + return false; + } + return true; + } + + private static String readAll(Reader rd) throws IOException { + StringBuilder sb = new StringBuilder(); + int cp; + while ((cp = rd.read()) != -1) { + sb.append((char) cp); + } + return sb.toString(); + } + + public ServerVersion getServerVersion() { return serverVersion; } @@ -102,6 +201,14 @@ public class EpicHeads extends JavaPlugin { return references; } + public HeadManager getHeadManager() { + return headManager; + } + + public PlayerManager getPlayerManager() { + return playerManager; + } + public CommandManager getCommandManager() { return commandManager; } diff --git a/src/main/java/com/songoda/epicheads/gui/GUIHeads.java b/src/main/java/com/songoda/epicheads/gui/GUIHeads.java new file mode 100644 index 0000000..3756e5c --- /dev/null +++ b/src/main/java/com/songoda/epicheads/gui/GUIHeads.java @@ -0,0 +1,203 @@ +package com.songoda.epicheads.gui; + +import com.songoda.epicheads.EpicHeads; +import com.songoda.epicheads.head.Head; +import com.songoda.epicheads.head.Tag; +import com.songoda.epicheads.players.EPlayer; +import com.songoda.epicheads.utils.AbstractChatConfirm; +import com.songoda.epicheads.utils.gui.AbstractGUI; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +public class GUIHeads extends AbstractGUI { + + private final EpicHeads plugin; + + private List heads; + private int page = 0; + + private int maxPage; + + private String query; + + public GUIHeads(EpicHeads plugin, Player player, String query, List heads) { + super(player); + this.plugin = plugin; + this.query = query; + + List favorites = plugin.getPlayerManager().getPlayer(player).getFavorites(); + this.heads = heads.stream() + .sorted(Comparator.comparing(Head::getName)) + .sorted(Comparator.comparingInt(head -> (head.getStaffPicked() == 1 ? 0 : 1))) + .sorted(Comparator.comparingInt(head -> (favorites.contains(head.getId()) ? 0 : 1))) + .collect(Collectors.toList()); + + updateTitle(); + } + + private void updateTitle() { + + + int numHeads = this.heads.size(); + if (numHeads == 0) { + player.sendMessage("No heads found."); + return; + } + Tag tag = heads.get(0).getTag(); + + this.maxPage = (int) Math.floor(numHeads / 45.0); + init((query != null ? "Query: " + query : tag.getName()) + " (" + numHeads + ") Page " + (page + 1) + "/" + (maxPage + 1), 54); + constructGUI(); + } + + @Override + protected void constructGUI() { + resetClickables(); + registerClickables(); + List heads = this.heads.stream().skip(page * 45).limit(45) + .collect(Collectors.toList()); + + if (page - 2 > 0) { + createButton(0, Material.ARROW, "Back"); + registerClickable(0, ((player1, inventory1, cursor, slot, type) -> { + page -= 3; + updateTitle(); + })); + inventory.getItem(0).setAmount(page - 2); + } + + if (page - 1 > 0) { + createButton(1, Material.ARROW, "Back"); + registerClickable(1, ((player1, inventory1, cursor, slot, type) -> { + page -= 2; + updateTitle(); + })); + inventory.getItem(1).setAmount(page - 1); + } + + if (page != 0) { + createButton(2, Material.ARROW, "Back"); + registerClickable(2, ((player1, inventory1, cursor, slot, type) -> { + page--; + updateTitle(); + })); + inventory.getItem(2).setAmount(page); + } + + createButton(3, Material.COMPASS, "Create Search"); + + createButton(4, Material.MAP, "Back To Categories"); + inventory.getItem(4).setAmount(page + 1); + + if (heads.size() > 1) + createButton(5, Material.COMPASS, "Refine Search"); + + if (page != maxPage) { + createButton(6, Material.ARROW, "Next"); + registerClickable(6, ((player1, inventory1, cursor, slot, type) -> { + page++; + updateTitle(); + })); + inventory.getItem(6).setAmount(page + 2); + } + + if (page + 1 < maxPage) { + createButton(7, Material.ARROW, "Next"); + registerClickable(7, ((player1, inventory1, cursor, slot, type) -> { + page += 2; + updateTitle(); + })); + inventory.getItem(7).setAmount(page + 3); + } + + if (page + 2 < maxPage) { + createButton(8, Material.ARROW, "Next"); + registerClickable(8, ((player1, inventory1, cursor, slot, type) -> { + page += 3; + updateTitle(); + })); + inventory.getItem(8).setAmount(page + 4); + } + + List favorites = plugin.getPlayerManager().getPlayer(player).getFavorites(); + + for (int i = 0; i < heads.size(); i++) { + Head head = heads.get(i); + + if (head.getName() == null) continue; + + ItemStack item = head.asItemStack(favorites.contains(head.getId())); + + inventory.setItem(i + 9, item); + + registerClickable(i + 9, ((player1, inventory1, cursor, slot, type) -> { + if (type == ClickType.SHIFT_LEFT || type == ClickType.SHIFT_RIGHT) { + EPlayer ePlayer = plugin.getPlayerManager().getPlayer(player); + if (!ePlayer.getFavorites().contains(head.getId())) + ePlayer.addFavorite(head.getId()); + else + ePlayer.removeFavorite(head.getId()); + updateTitle(); + return; + } + + ItemMeta meta = item.getItemMeta(); + meta.setLore(new ArrayList<>()); + item.setItemMeta(meta); + + player.getInventory().addItem(item); + })); + } + } + + @Override + protected void registerClickables() { + registerClickable(4, ((player1, inventory1, cursor, slot, type) -> + new GUIOverview(plugin, player))); + + registerClickable(3, ((player1, inventory1, cursor, slot, type) -> + doSearch(player1))); + + if (heads.size() > 1) { + registerClickable(5, ((player1, inventory1, cursor, slot, type) -> { + + player.sendMessage("Refine your search..."); + AbstractChatConfirm abstractChatConfirm = new AbstractChatConfirm(player, event -> { + this.page = 0; + this.heads = this.heads.stream().filter(head -> head.getName().toLowerCase() + .contains(event.getMessage().toLowerCase())).collect(Collectors.toList()); + if (query == null) + this.query = event.getMessage(); + else + this.query += ", " + event.getMessage(); + }); + abstractChatConfirm.setOnClose(this::updateTitle); + })); + } + } + + @Override + protected void registerOnCloses() { + + } + + public static void doSearch(Player player) { + player.sendMessage("Enter your query..."); + new AbstractChatConfirm(player, event -> { + List heads = EpicHeads.getInstance().getHeadManager().getHeads().stream() + .filter(head -> head.getName().toLowerCase().contains(event.getMessage().toLowerCase())) + .collect(Collectors.toList()); + Bukkit.getScheduler().scheduleSyncDelayedTask(EpicHeads.getInstance(), () -> + new GUIHeads(EpicHeads.getInstance(), player, event.getMessage(), heads), 0L); + }); + } +} diff --git a/src/main/java/com/songoda/epicheads/gui/GUIOverview.java b/src/main/java/com/songoda/epicheads/gui/GUIOverview.java index 3e31920..bd5da4d 100644 --- a/src/main/java/com/songoda/epicheads/gui/GUIOverview.java +++ b/src/main/java/com/songoda/epicheads/gui/GUIOverview.java @@ -1,9 +1,14 @@ package com.songoda.epicheads.gui; import com.songoda.epicheads.EpicHeads; +import com.songoda.epicheads.head.Tag; +import com.songoda.epicheads.utils.Methods; import com.songoda.epicheads.utils.gui.AbstractGUI; +import org.bukkit.Material; import org.bukkit.entity.Player; +import java.util.List; + public class GUIOverview extends AbstractGUI { private final EpicHeads plugin; @@ -12,17 +17,63 @@ public class GUIOverview extends AbstractGUI { super(player); this.plugin = plugin; - init("Heads", 54); + init("EpicHeads (" + plugin.getHeadManager().getHeads().size() + " heads)", 45); } @Override protected void constructGUI() { - + + createButton(5, Material.STONE, "&6&lView Favorites", + "Shift click any head", + "to save as a favorite."); + + inventory.setItem(0, Methods.getBackgroundGlass(true)); + inventory.setItem(1, Methods.getBackgroundGlass(true)); + inventory.setItem(9, Methods.getBackgroundGlass(true)); + + inventory.setItem(7, Methods.getBackgroundGlass(true)); + inventory.setItem(8, Methods.getBackgroundGlass(true)); + inventory.setItem(17, Methods.getBackgroundGlass(true)); + + inventory.setItem(27, Methods.getBackgroundGlass(true)); + inventory.setItem(36, Methods.getBackgroundGlass(true)); + inventory.setItem(37, Methods.getBackgroundGlass(true)); + + inventory.setItem(35, Methods.getBackgroundGlass(true)); + inventory.setItem(43, Methods.getBackgroundGlass(true)); + inventory.setItem(44, Methods.getBackgroundGlass(true)); + + inventory.setItem(2, Methods.getBackgroundGlass(false)); + inventory.setItem(6, Methods.getBackgroundGlass(false)); + inventory.setItem(38, Methods.getBackgroundGlass(false)); + inventory.setItem(42, Methods.getBackgroundGlass(false)); + + List tags = plugin.getHeadManager().getTags(); + int add = 0; + for (int i = 0; i < tags.size(); i++) { + if (i + add == 7 || i + add == 16) add = add + 2; + + Tag tag = plugin.getHeadManager().getTags().get(i); + createButton(i + 10 + add, Material.STONE, "&c&l" + tag.getName(), "&e" + tag.getCount() + " heads"); + + registerClickable(i + 10 + add, ((player1, inventory1, cursor, slot, type) -> new GUIHeads(plugin, player, null, plugin.getHeadManager().getHeadsByTag(tag)))); + } + + createButton(39, Material.COMPASS, "Search"); + + createButton(41, Material.STONE, + "Add or request new heads", + "in our discord server."); + } @Override protected void registerClickables() { + registerClickable(5, ((player1, inventory1, cursor, slot, type) -> + new GUIHeads(plugin, player, null, plugin.getPlayerManager().getPlayer(player).getFavoritesAsHeads()))); + registerClickable(39, ((player1, inventory1, cursor, slot, type) -> + GUIHeads.doSearch(player1))); } @Override diff --git a/src/main/java/com/songoda/epicheads/head/Head.java b/src/main/java/com/songoda/epicheads/head/Head.java new file mode 100644 index 0000000..37aefd6 --- /dev/null +++ b/src/main/java/com/songoda/epicheads/head/Head.java @@ -0,0 +1,79 @@ +package com.songoda.epicheads.head; + + +import com.songoda.epicheads.utils.Methods; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.List; + +public class Head { + + private final int id; + private final String name; + private final String URL; + private final byte staffPicked; + + private final Tag tag; + + public Head(int id, String name, String URL, Tag tag, byte staffPicked) { + this.id = id; + this.name = name; + this.URL = URL; + this.tag = tag; + this.staffPicked = staffPicked; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public String getURL() { + return URL; + } + + public Tag getTag() { + return tag; + } + + public byte getStaffPicked() { + return staffPicked; + } + + public ItemStack asItemStack() { + return asItemStack(false); + } + + public ItemStack asItemStack(boolean favorite) { + ItemStack item = Methods.addTexture(new ItemStack(Material.PLAYER_HEAD, 1, (byte) 3), + this.URL); + + ItemMeta meta = item.getItemMeta(); + meta.setDisplayName(Methods.formatText((favorite ? "&6⭐ " : "") + "&9" + name)); + List lore = new ArrayList<>(); + if (this.staffPicked == 1) + lore.add(Methods.formatText("&8Staff Favorite")); + lore.add(Methods.formatText("&8ID: &7" + this.id)); + + meta.setLore(lore); + item.setItemMeta(meta); + return item; + } + + @Override + public String toString() { + return "Head:{" + + "Id:\"" + id + "\"," + + "Name:\"" + name + "\"," + + "URL:\"" + URL + "\"," + + "Tags:\"" + tag.getName() + "\"," + + "StaffPicked:\"" + staffPicked + "\"" + + "}"; + } +} diff --git a/src/main/java/com/songoda/epicheads/head/HeadManager.java b/src/main/java/com/songoda/epicheads/head/HeadManager.java new file mode 100644 index 0000000..fd0d48f --- /dev/null +++ b/src/main/java/com/songoda/epicheads/head/HeadManager.java @@ -0,0 +1,57 @@ +package com.songoda.epicheads.head; + +import java.util.*; +import java.util.stream.Collectors; + +public class HeadManager { + + private static final Set registeredHeads = new HashSet<>(); + private static final List registeredTags = new ArrayList<>(); + + public Head addHead(Head head) { + registeredHeads.add(head); + return head; + } + + public void addHeads(Head... heads) { + registeredHeads.addAll(Arrays.asList(heads)); + } + + public void addHeads(Collection heads) { + registeredHeads.addAll(heads); + } + + public Head getHead(String name) { + return registeredHeads.stream().filter(head -> head.getName().equals(name)).findFirst().orElse(null); + } + + public List getHeadsByQuery(String query) { + List result = registeredHeads.stream().filter(head -> head.getName().contains(query)).collect(Collectors.toList()); + + if (result.isEmpty()) { + for (Tag tag : registeredTags) { + if (!tag.getName().equalsIgnoreCase(query)) continue; + return registeredHeads.stream().filter(head -> head.getTag() == tag).collect(Collectors.toList()); + + } + } + return result; + } + + public List getHeadsByTag(Tag tag) { + return registeredHeads.stream().filter(head -> head.getTag() == tag).collect(Collectors.toList()); + } + + public Set getHeads() { + return Collections.unmodifiableSet(registeredHeads); + } + + public Tag addTag(Tag tag) { + registeredTags.add(tag); + return tag; + } + + public List getTags() { + return Collections.unmodifiableList(registeredTags); + } +} diff --git a/src/main/java/com/songoda/epicheads/head/Tag.java b/src/main/java/com/songoda/epicheads/head/Tag.java new file mode 100644 index 0000000..d22ea1b --- /dev/null +++ b/src/main/java/com/songoda/epicheads/head/Tag.java @@ -0,0 +1,24 @@ +package com.songoda.epicheads.head; + +public class Tag { + + private final String name; + private int count; + + public Tag(String name, int count) { + this.name = name; + this.count = count; + } + + public String getName() { + return name; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } +} diff --git a/src/main/java/com/songoda/epicheads/listeners/ItemListeners.java b/src/main/java/com/songoda/epicheads/listeners/ItemListeners.java new file mode 100644 index 0000000..6b625a6 --- /dev/null +++ b/src/main/java/com/songoda/epicheads/listeners/ItemListeners.java @@ -0,0 +1,57 @@ +package com.songoda.epicheads.listeners; + +import com.songoda.epicheads.EpicHeads; +import com.songoda.epicheads.head.Head; +import com.songoda.epicheads.utils.Methods; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityPickupItemEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.metadata.FixedMetadataValue; + +import java.util.ArrayList; +import java.util.Optional; + +public class ItemListeners implements Listener { + + private final EpicHeads plugin; + + public ItemListeners(EpicHeads plugin) { + this.plugin = plugin; + } + + @EventHandler + public void itemPickupEvent(EntityPickupItemEvent event) { + + ItemStack item = event.getItem().getItemStack(); + + if (item.getType() != Material.PLAYER_HEAD || event.getItem().hasMetadata("EHE")) return; + + event.getItem().removeMetadata("EHE", plugin); + + String url = Methods.getDecodedTexture(item); + + if (url == null) return; + Optional optional = plugin.getHeadManager().getHeads().stream() + .filter(head -> url.equals(head.getURL())).findFirst(); + + if (optional.isPresent()) { + event.setCancelled(true); + event.getItem().setMetadata("EHE", new FixedMetadataValue(plugin, true)); + + ItemStack itemNew = optional.get().asItemStack(); + itemNew.setAmount(item.getAmount()); + + ItemMeta meta = itemNew.getItemMeta(); + meta.setLore(new ArrayList<>()); + itemNew.setItemMeta(meta); + + event.getItem().getWorld().dropItemNaturally(event.getEntity().getLocation().add(1, 1, 0), itemNew.clone()); + + event.getItem().setItemStack(itemNew); + } + } + +} diff --git a/src/main/java/com/songoda/epicheads/players/EPlayer.java b/src/main/java/com/songoda/epicheads/players/EPlayer.java new file mode 100644 index 0000000..ed11f5a --- /dev/null +++ b/src/main/java/com/songoda/epicheads/players/EPlayer.java @@ -0,0 +1,42 @@ +package com.songoda.epicheads.players; + +import com.songoda.epicheads.EpicHeads; +import com.songoda.epicheads.head.Head; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class EPlayer { + + private final UUID uuid; + + private List favorites = new ArrayList<>(); + + public EPlayer(UUID uuid) { + this.uuid = uuid; + } + + public UUID getUuid() { + return uuid; + } + + public List getFavorites() { + return new ArrayList<>(favorites); + } + + public List getFavoritesAsHeads() { + return EpicHeads.getInstance().getHeadManager().getHeads().stream() + .filter(head -> favorites.contains(head.getId())).collect(Collectors.toList()); + } + + public void addFavorite(Integer integer) { + favorites.add(integer); + } + + public void removeFavorite(Integer integer) { + favorites.remove(integer); + } + +} diff --git a/src/main/java/com/songoda/epicheads/players/PlayerManager.java b/src/main/java/com/songoda/epicheads/players/PlayerManager.java new file mode 100644 index 0000000..66097c3 --- /dev/null +++ b/src/main/java/com/songoda/epicheads/players/PlayerManager.java @@ -0,0 +1,21 @@ +package com.songoda.epicheads.players; + +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class PlayerManager { + + private static final Map registeredHeads = new HashMap<>(); + + public EPlayer getPlayer(UUID uuid) { + return registeredHeads.computeIfAbsent(uuid, u -> new EPlayer(uuid)); + } + + public EPlayer getPlayer(Player player) { + return getPlayer(player.getUniqueId()); + } + +} diff --git a/src/main/java/com/songoda/epicheads/utils/Methods.java b/src/main/java/com/songoda/epicheads/utils/Methods.java index d1a5a0d..3ac55de 100644 --- a/src/main/java/com/songoda/epicheads/utils/Methods.java +++ b/src/main/java/com/songoda/epicheads/utils/Methods.java @@ -1,13 +1,59 @@ package com.songoda.epicheads.utils; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; import com.songoda.epicheads.EpicHeads; +import org.apache.commons.lang.StringUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; + +import java.lang.reflect.Field; +import java.util.Base64; +import java.util.Iterator; +import java.util.UUID; public class Methods { + public static ItemStack addTexture(ItemStack item, String headURL) { + SkullMeta meta = (SkullMeta) item.getItemMeta(); + + GameProfile profile = new GameProfile(UUID.nameUUIDFromBytes(headURL.getBytes()), null); + byte[] encodedData = Base64.getEncoder().encode(String.format("{textures:{SKIN:{url:\"http://textures.minecraft.net/texture/%s\"}}}", new Object[]{headURL}).getBytes()); + profile.getProperties().put("textures", new Property("textures", new String(encodedData))); + + Field profileField; + try { + profileField = meta.getClass().getDeclaredField("profile"); + profileField.setAccessible(true); + profileField.set(meta, profile); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + item.setItemMeta(meta); + return item; + } + + public static String getDecodedTexture(ItemStack item) { + try { + SkullMeta localSkullMeta = (SkullMeta) item.getItemMeta(); + Field localField = localSkullMeta.getClass().getDeclaredField("profile"); + localField.setAccessible(true); + GameProfile localGameProfile = (GameProfile) localField.get(localSkullMeta); + Iterator localIterator = localGameProfile.getProperties().get("textures").iterator(); + if (localIterator.hasNext()) { + Property localProperty = (Property) localIterator.next(); + byte[] decoded = Base64.getDecoder().decode(localProperty.getValue()); + return StringUtils.substringBetween(new String(decoded), "texture/", "\""); + } + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + return null; + } + public static ItemStack getGlass() { EpicHeads instance = EpicHeads.getInstance(); return Methods.getGlass(instance.getConfig().getBoolean("Interfaces.Replace Glass Type 1 With Rainbow Glass"), instance.getConfig().getInt("Interfaces.Glass Type 1"));