package me.loganb1max.minions.util; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Skull; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; 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 Dean B on 12/28/2016. */ public class SkullCreator { /** * Creates a player skull 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 */ @Deprecated public static ItemStack itemFromName(String name) { ItemStack item = getPlayerSkullItem(); return itemWithName(item, name); } /** * Creates a player skull based on a player's name. * * @param item The item to apply the name to * @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"); return Bukkit.getUnsafe().modifyItemStack(item, "{SkullOwner:\"" + name + "\"}" ); } /** * Creates a player skull with a UUID. 1.13 only. * * @param id The Player's UUID * @return The head of the Player */ public static ItemStack itemFromUuid(UUID id) { ItemStack item = getPlayerSkullItem(); return itemWithUuid(item, id); } /** * Creates a player skull based on a UUID. 1.13 only. * * @param item The item to apply the name to * @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.setOwner(Bukkit.getOfflinePlayer(id).getName()); item.setItemMeta(meta); return item; } /** * Creates a player skull based on a Mojang server URL. * * @param url The URL of the Mojang skin * @return The head associated with the URL */ public static ItemStack itemFromUrl(String url) { ItemStack item = getPlayerSkullItem(); return itemWithUrl(item, url); } /** * Creates a player skull based on a Mojang server URL. * * @param item The item to apply the skin to * @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)); } /** * Creates a player skull based on a base64 string containing the link to the skin. * * @param base64 The base64 string containing the texture * @return The head with a custom texture */ public static ItemStack itemFromBase64(String base64) { ItemStack item = getPlayerSkullItem(); return itemWithBase64(item, base64); } /** * Applies the base64 string to the ItemStack. * * @param item The ItemStack to put the base64 onto * @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"); UUID hashAsId = new UUID(base64.hashCode(), base64.hashCode()); return Bukkit.getUnsafe().modifyItemStack(item, "{SkullOwner:{Id:\"" + hashAsId + "\",Properties:{textures:[{Value:\"" + base64 + "\"}]}}}" ); } /** * 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"); setBlockType(block); ((Skull) block.getState()).setOwner(name); } /** * 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"); setBlockType(block); ((Skull) block.getState()).setOwner(Bukkit.getOfflinePlayer(id).getName()); } /** * Sets the block to a skull with the given UUID. * * @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 given UUID. * * @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"); UUID hashAsId = new UUID(base64.hashCode(), base64.hashCode()); String args = String.format( "%d %d %d %s", block.getX(), block.getY(), block.getZ(), "{Owner:{Id:\"" + hashAsId + "\",Properties:{textures:[{Value:\"" + base64 + "\"}]}}}" ); if (newerApi()) { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "data merge block " + args); } else { Bukkit.dispatchCommand(Bukkit.getConsoleSender(),"blockdata " + args); } } private static boolean newerApi() { try { Material.valueOf("PLAYER_HEAD"); return true; } catch (IllegalArgumentException e) { // If PLAYER_HEAD doesn't exist return false; } } private static ItemStack getPlayerSkullItem() { if (newerApi()) { return new ItemStack(Material.valueOf("PLAYER_HEAD")); } else { return new ItemStack(Material.valueOf("SKULL_ITEM"), 1, (byte) 3); } } private static void setBlockType(Block block) { try { block.setType(Material.valueOf("PLAYER_HEAD"), false); } catch (IllegalArgumentException e) { block.setType(Material.valueOf("SKULL"), 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()); } } /* Format for skull { display:{ Name:"Cheese" }, SkullOwner:{ Id:"9c919b83-f3fe-456f-a824-7d1d08cc8bd2", Properties:{ textures:[ { Value:"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTU1ZDYxMWE4NzhlODIxMjMxNzQ5YjI5NjU3MDhjYWQ5NDI2NTA2NzJkYjA5ZTI2ODQ3YTg4ZTJmYWMyOTQ2In19fQ==" } ] } } } */