Solved Create a skull item stack with a custom texture (Base64)

Discussion in 'Spigot Plugin Development' started by val59000, Aug 1, 2015.

Thread Status:
Not open for further replies.
  1. In minecraft, with command blocks, you can create skull item with custom encoded texture like :

    /give @p skull 1 3 {display:{Name:"bff"},SkullOwner:{Id:"0f834cc7-d039-4f82-979f-cd538de2b521",Properties:{textures:[{Value:"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmM2NDVhNDI1OTg3ZjNiN2MyZmFjMDIwNmNlOThiYTVlMjNiOWM0ODUyZmVhNWIxOTc4Zjc0NjdlOGQzMTMifX19"}]}}}

    How to do that in my plugin. I found that I need to use NMS but I'm not very familiar with working directly with Minecraft code. Can someone help me write a simple method to store the base64 texture string in the item stack ?


    I have so far written this part :
    Code (Text):
    GameProfile newSkinProfile = new GameProfile(UUID.randomUUID(), null);
    newSkinProfile.getProperties().put("textures", new Property("textures", Base64Coder.encodeString("{textures:[{Value:\"" + skullTexture + "\"}]}")));
                   
    But I need help on how to store it in a skull item stack.


    Thank
     
  2. You should be able to create a normal ItemStack of skulls, then set the metadata to have the skin you want associated with it
     
  3. How ? I know about the setOwner in SkullMeta but here I'm trying to add a custom texture of a non existing player. I know it is possible because we can do it with a command block.
     
  4. You probablly wont find support for this in the api. You will need to look into the nms classes.
     
  5. I know it's not in the API. Can you help me use the nms classes to do that ?
     
    • Like Like x 1
  6. You could also do something like Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "give player skull and stuff {name val59000}") if you just wanted to give a player the skulls. If you were doing inventory menus or something else, however, you would have to go with some advice above.
     
  7. It appears you are just adding an nbt tag. Try grabbing the item's tag and just adding the values you are adding in the command.
     
  8. You are right, it's in an inventory GUI so I can't use the command dispatcher.

    I'll look into that, thank for the suggestion. I don't know how to edit the nbt tags but I think I've seen somewhere how to do it.
     
  9. You're on the right track. Once you have the game profile, you can use GameProfileSerializer#serialize(NBTTagCompound, GameProfile) to serialize the game profile to an NBT tag. After that you'll need to add the NBT tag to the item stack with "SkullOwner" as the key.

    Let me know if you get stuck. :)
     
    #11 Disoriented, Aug 2, 2015
    Last edited: Aug 2, 2015
    • Informative Informative x 1
  10. It makes my client crash.
    Code (Text):
    ---- Minecraft Crash Report ----
    // This doesn't make any sense!

    Time: 02/08/15 11:34
    Description: Rendering item

    com.google.common.util.concurrent.UncheckedExecutionException: java.lang.NullPointerException
        at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2201)
        at com.google.common.cache.LocalCache.get(LocalCache.java:3934)
        at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3938)
        at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4821)
        at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4827)
        at bnp.a(SourceFile:126)
        at bhk.a(SourceFile:76)
        at bfi.a(SourceFile:52)
        at bjh.a(SourceFile:122)
        at bjh.a(SourceFile:323)
        at bjh.b(SourceFile:359)
        at ayl.a(SourceFile:249)
        at ayl.a(SourceFile:107)
        at bfk.a(EntityRenderer.java:1324)
        at ave.av(SourceFile:914)
        at ave.a(SourceFile:325)
        at net.minecraft.client.main.Main.main(SourceFile:124)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at magic.launcher.Launcher.main(SourceFile:214)
    Caused by: java.lang.NullPointerException
        at com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService.isWhitelistedDomain(YggdrasilMinecraftSessionService.java:210)
        at com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService.getTextures(YggdrasilMinecraftSessionService.java:149)
        at bnp$1.a(SourceFile:47)
        at bnp$1.load(SourceFile:44)
        at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3524)
        at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2317)
        at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2280)
        at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2195)
        ... 21 more


    A detailed walkthrough of the error, its code path and all known details is as follows:
    ---------------------------------------------------------------------------------------

    -- Head --
    Stacktrace:
        at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2201)
        at com.google.common.cache.LocalCache.get(LocalCache.java:3934)
        at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3938)
        at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4821)
        at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4827)
        at bnp.a(SourceFile:126)
        at bhk.a(SourceFile:76)
        at bfi.a(SourceFile:52)
        at bjh.a(SourceFile:122)
        at bjh.a(SourceFile:323)

    -- Item being rendered --
    Details:
        Item Type: [email protected]
        Item Aux: 3
        Item NBT: {Unbreakable:1b,SkullOwner:{Id:"5f65add3-0a59-477a-99f8-66ffefd33cce",Properties:{textures:[0:{Value:"e3RleHR1cmVzOntTS0lOOnt1cmw6InRydWUifX19"}]}},display:{Lore:[0:"§1§f§3§a§d§b§4§e§4§3§f§6§5§8§8§6§a§6§e§e§b§4§3§8§2§a§d§9§b§a§2§e§6"]}}
        Item Foil: false
    Stacktrace:
        at bjh.b(SourceFile:359)
        at ayl.a(SourceFile:249)
        at ayl.a(SourceFile:107)

    -- Screen render details --
    Details:
        Screen name: ayr
        Mouse location: Scaled: (213, 119). Absolute: (427, 240)
        Screen size: Scaled: (427, 240). Absolute: (854, 480). Scale factor of 2

    -- Affected level --
    Details:
        Level name: MpServer
        All players: 1 total; [bew['val59000'/57, l='MpServer', x=71,50, y=79,00, z=141,50]]
        Chunk stats: MultiplayerChunkCache: 400, 400
        Level seed: 0
        Level generator: ID 01 - flat, ver 0. Features enabled: false
        Level generator options:
        Level spawn location: 71,00,79,00,141,00 - World: (71,79,141), Chunk: (at 7,4,13 in 4,8; contains blocks 64,0,128 to 79,255,143), Region: (0,0; contains chunks 0,0 to 31,31, blocks 0,0,0 to 511,255,511)
        Level time: 48595122 game time, 41730000 day time
        Level dimension: 0
        Level storage version: 0x00000 - Unknown?
        Level weather: Rain time: 0 (now: false), thunder time: 0 (now: false)
        Level game mode: Game mode: survival (ID 0). Hardcore: false. Cheats: false
        Forced entities: 1 total; [bew['val59000'/57, l='MpServer', x=71,50, y=79,00, z=141,50]]
        Retry entities: 0 total; []
        Server brand: Spigot
        Server type: Non-integrated multiplayer server
    Stacktrace:
        at bdb.a(WorldClient.java:401)
        at ave.b(SourceFile:2293)
        at ave.a(SourceFile:334)
        at net.minecraft.client.main.Main.main(SourceFile:124)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at magic.launcher.Launcher.main(SourceFile:214)

    -- System Details --
    Details:
        Minecraft Version: 1.8.7
        Operating System: Windows 8.1 (amd64) version 6.3
        CPU: 8x Intel(R) Core(TM) i7-4700HQ CPU @ 2.40GHz
        Java Version: 1.8.0_45, Oracle Corporation
        Java VM Version: Java HotSpot(TM) 64-Bit Server VM (mixed mode), Oracle Corporation
        Memory: 941420160 bytes (897 MB) / 1305477120 bytes (1245 MB) up to 1305477120 bytes (1245 MB)
        JVM Flags: 3 total; -Xms1300m -Xmx1300m -XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump
        IntCache: cache: 0, tcache: 0, allocated: 13, tallocated: 95
        Launched Version: 1.8.7
        LWJGL: 2.9.4
        OpenGL: GeForce GTX 860M/PCIe/SSE2 GL version 4.5.0 NVIDIA 352.86, NVIDIA Corporation
        GL Caps: Using GL 1.3 multitexturing.
    Using GL 1.3 texture combiners.
    Using framebuffer objects because OpenGL 3.0 is supported and separate blending is supported.
    Shaders are available because OpenGL 2.1 is supported.
    VBOs are available because OpenGL 1.5 is supported.

        Using VBOs: No
        Is Modded: Very likely; Jar signature invalidated
        Type: Client (map_client.txt)
        Resource Packs: [faithful32pack 1.8.zip]
        Current Language: English (US)
        Profiler Position: N/A (disabled)
     
  11. I think I found what was going on. Since 1.8.4 you can't use other texture source than mojang official website. THis is why the client crashed with :
    at com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService.isWhitelistedDomain(YggdrasilMinecraftSessionService.java:210)

    To fix that, I need to change the texture on a real account. Spawn his head, then grab his texture URL with a command_block (entitydata @e {} )
    Then use that url in my code.

    I'll try that.
     
  12. That is correct. You can also use Mojang's API to fetch the texture.
     
  13. Ok finally got it working :

    Code (Text):
    GameProfile profile = new GameProfile(UUID.randomUUID(), null);
                    byte[] encodedData = Base64.getEncoder().encode(String.format("{textures:{SKIN:{url:\"%s\"}}}", this.playerSkullTexture).getBytes());
                    profile.getProperties().put("textures", new Property("textures", new String(encodedData)));
                    Field profileField = null;
                    try {
                        profileField = im.getClass().getDeclaredField("profile");
                        profileField.setAccessible(true);
                        profileField.set(im, profile);
                    } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e1) {
                        e1.printStackTrace();
                    }

    Note: In the code sample, the variable "im" is the SkullMeta of the skull item stack



    the url MUST be from mojang !
    Example: http://textures.minecraft.net/textu...e1e273e3025617d8071516f953251b52545da8d3e8db8

    To get such a URL you may use this website to get the base64 encoded url :
    http://heads.freshcoal.com/index.php

    Then use this website to decode it :
    https://www.base64decode.org/

    The good thing is that the URL never changes and Mojang said of reddit that they don't delete old skin url.
    So you can change your own skin with a custom image, get the url and change it back to your current skin.
     
    #15 val59000, Aug 2, 2015
    Last edited: Nov 4, 2015
    • Useful Useful x 10
    • Like Like x 2
    • Winner Winner x 1
  14. I know this thread is old, but what is "im"?

    I'm getting a NoSuchFieldException if im is the item's SkullMeta


    EDIT: already got it
     
    #16 FisheyLP, Aug 10, 2016
    Last edited: Aug 10, 2016
Thread Status:
Not open for further replies.