Cache player skull heads

Discussion in 'Spigot Plugin Development' started by sinnlosername, May 14, 2016.

  1. Hi,

    is there a way to cache player skull head items (with skin texture)?
     
  2. Save the name of the texture in an hashmap.
     
  3. Can you expand on this? Do you mean save the head, or get a textured head?
     
  4. I'll save the texture because everytime I create a new inventory every head loads the texture
     
  5. Well, im still not sure, but you can create a array list and split the array to get a string and add it to the inventory, and repeat this for all the heads. Explain a little more, because I'm still not sure what you are asking.:eek:
     
  6. Bukkit doesn't cache skin textures on player head items. I want to cache them.
     
  7. This creates a head with a certain skin, and then just renames the name to something. I think this is what you want. You can just add this to a players inventory also:

    Code (Text):
    ItemStack item = new ItemStack(Material.SKULL_ITEM, 1, (short) SkullType.PLAYER.ordinal());
    SkullMeta meta = (SkullMeta) item.getItemMeta();
    meta.setOwner("tokyojack");
    meta.setDisplayName("Warp 1");
    item.setItemMeta(meta);
    player.getInventory().addItem(item);
     
  8. You can grab custom skulls from a url. Here is a sample Base64 encoding you can use.
    Code (Text):

        public static ItemStack getSkull(String url) {
            ItemStack head = new ItemStack(Material.SKULL_ITEM, 1, (short)3);
            if(url.isEmpty())return head;
         
         
            SkullMeta headMeta = (SkullMeta) head.getItemMeta();
            GameProfile profile = new GameProfile(UUID.randomUUID(), null);
            byte[] encodedData = Base64.encodeBase64(String.format("{textures:{SKIN:{url:\"%s\"}}}", url).getBytes());
            profile.getProperties().put("textures", new Property("textures", new String(encodedData)));
            Field profileField = null;
            try
            {
                profileField = headMeta.getClass().getDeclaredField("profile");
                profileField.setAccessible(true);
                profileField.set(headMeta, profile);
            }
            catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e)
            {
                e.printStackTrace();
            }
            head.setItemMeta(headMeta);
            return head;
        }
     

    Now, of course, you would need to grab a skin url from someplace. You could possibly use texture.minecraft.net. With this being said, you can utilize the url in this way.

    Code (Text):

    ItemStack helmet = getSkull("http://textures.minecraft.net/texture/4c298b7aaa9925ca5419ba92573395a276a827e717d8547fef3e43e630eb3e8e");
     
    I am not entirely sure if this is what you are looking for. You are not quite clear on what you are expecting or looking for.
     
    • Informative Informative x 2
    • Like Like x 1
    • Agree Agree x 1
    • Useful Useful x 1
  9. If you open the inventory it takes a while until the head skins load. Everytime I open the inventory.
     
  10. I don't think you can get around that..
     
  11. I'm currently having the same problem.
    Apparently some big servers managed to do it without the skin taking time to load but I'm not 100% sure if they even use bukkit/spigot.

    Either way, I'll attempt to cache it and post results here if I find anything.
     
  12. If you know the skulls you want to use you can save their textures on enable as well as save players textures when they join into the map with a key of their name
     
  13. Sorry for beating around a dead bush here..But when searching this up, this is the most popular thread, and I figure that people should know. Whether spoon fed or not.

    I had remade the code up in the previous parts of the thread to grab the players texture and encode it, caching the texture for later use.
    public static Map<String, String> cached = new HashMap<String, String>();

    @SuppressWarnings("deprecation")
    public static ItemStack getHead(OfflinePlayer player) {
    String skinURL = null;
    loadSkin: if (cached.containsKey(player.getName()))
    skinURL = cached.get(player.getName());
    else {
    try {
    GameProfile profile = new GameProfile(player.getUniqueId(), player.getName());
    Field field;
    field = MinecraftServer.class.getDeclaredField("W"); //This will obviously break on next Minecraft update....
    field.setAccessible(true);
    Object value = field.get(MinecraftServer.getServer());
    if (!(value instanceof MinecraftSessionService))
    break loadSkin;
    MinecraftSessionService ss = (MinecraftSessionService) value;
    ss.fillProfileProperties(profile, true);
    Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> textures = ss.getTextures(profile, true);
    if (textures.containsKey(MinecraftProfileTexture.Type.SKIN)) {
    MinecraftProfileTexture tex = textures.get(MinecraftProfileTexture.Type.SKIN);
    skinURL = tex.getUrl();
    }
    } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
    e.printStackTrace();
    }
    }
    ItemStack head = new ItemStack(Material.SKULL_ITEM, 1, (short) 3);
    if (skinURL == null)
    return head;
    cached.put(player.getName(), skinURL);
    ItemMeta headMeta = head.getItemMeta();
    GameProfile profile = new GameProfile(UUID.randomUUID(), null);
    byte[] encodedData = Base64.getEncoder()
    .encode((String.format("{\"textures\":{\"SKIN\":{\"url\":\"%s\"}}}", skinURL).getBytes()));
    profile.getProperties().put("textures", new Property("textures", new String(encodedData)));
    Field profileField = null;
    try {
    profileField = headMeta.getClass().getDeclaredField("profile");
    profileField.setAccessible(true);
    profileField.set(headMeta, profile);
    } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
    e.printStackTrace();
    }
    head.setItemMeta(headMeta);
    return head;
    }

    I do not know if this is a good way of going about this, but this is how I load up player heads instantly in inventories. Also, this will most likely break on the next update because of the reflection to get the MinecraftSessionService. I'll be honest..I did not really look into seeing if there were any other ways of getting to it.
     
    • Informative Informative x 4