diff --git a/src/main/java/com/artillexstudios/axgraves/grave/Grave.java b/src/main/java/com/artillexstudios/axgraves/grave/Grave.java index 15f64d5..4bf2ad9 100644 --- a/src/main/java/com/artillexstudios/axgraves/grave/Grave.java +++ b/src/main/java/com/artillexstudios/axgraves/grave/Grave.java @@ -92,7 +92,13 @@ public Grave(Location loc, @NotNull OfflinePlayer offlinePlayer, @NotNull ItemSt } entity = NMSHandlers.getNmsHandler().createEntity(EntityType.ARMOR_STAND, location.clone().add(0, 1 + CONFIG.getFloat("head-height", -1.2f), 0)); - entity.setItem(EquipmentSlot.HELMET, WrappedItemStack.wrap(Utils.getPlayerHead(offlinePlayer))); + final ItemStack head; + if (CONFIG.getBoolean("custom-skull", false)) { + head = Utils.getBase64Skull(CONFIG.getString("custom-skull-value")); + } else { + head = Utils.getPlayerHead(offlinePlayer); + } + entity.setItem(EquipmentSlot.HELMET, WrappedItemStack.wrap(head)); final ArmorStandMeta meta = (ArmorStandMeta) entity.meta(); meta.small(true); meta.invisible(true); diff --git a/src/main/java/com/artillexstudios/axgraves/utils/Utils.java b/src/main/java/com/artillexstudios/axgraves/utils/Utils.java index b5ad2b4..37a4d76 100644 --- a/src/main/java/com/artillexstudios/axgraves/utils/Utils.java +++ b/src/main/java/com/artillexstudios/axgraves/utils/Utils.java @@ -1,11 +1,23 @@ package com.artillexstudios.axgraves.utils; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.profile.PlayerProfile; +import org.bukkit.profile.PlayerTextures; import org.jetbrains.annotations.NotNull; +import java.net.URI; +import java.net.URL; +import java.util.Base64; +import java.util.UUID; +import java.util.logging.Level; + public class Utils { @NotNull @@ -15,7 +27,50 @@ public static ItemStack getPlayerHead(@NotNull OfflinePlayer player) { skullMeta.setOwningPlayer(player); it.setItemMeta(skullMeta); } - return it; } + + + @NotNull + public static ItemStack getBase64Skull(@NotNull String b64Texture) { + ItemStack head = new ItemStack(Material.PLAYER_HEAD); + try { + JsonObject jsonObject = new Gson().fromJson(new String(Base64.getDecoder().decode(b64Texture)), JsonObject.class); + + if (!jsonObject.has("textures") + || !jsonObject.getAsJsonObject("textures").has("SKIN") + || !jsonObject.getAsJsonObject("textures").getAsJsonObject("SKIN").has("url")) { + Bukkit.getLogger().log(Level.WARNING, "[AxGraves] Missing data in custom base64 skull texture when decoded-to JSON."); + return head; + } + + String urlString = jsonObject.getAsJsonObject("textures").getAsJsonObject("SKIN").get("url").getAsString(); + URL urlObject = URI.create(urlString).toURL(); + + PlayerProfile profile = Bukkit.createPlayerProfile(UUID.randomUUID()); + PlayerTextures texturesProfile = profile.getTextures(); + texturesProfile.setSkin(urlObject); + profile.setTextures(texturesProfile); + + if (head.getItemMeta() instanceof SkullMeta meta) { + meta.setOwnerProfile(profile); + head.setItemMeta(meta); + return head; + } + + // if we reach here, it the item meta is not SkullMeta for some reason + Bukkit.getLogger().log(Level.WARNING, "[AxGraves] Failed to set custom skull texture."); + return head; + + } catch (IllegalArgumentException e) { + Bukkit.getLogger().log(Level.WARNING, "[AxGraves] Invalid Base64 custom skull texture string provided.", e); + return head; + } catch (JsonSyntaxException e) { + Bukkit.getLogger().log(Level.WARNING, "[AxGraves] Invalid JSON in decoded custom skull texture data.", e); + return head; + } catch (Exception e) { + Bukkit.getLogger().log(Level.SEVERE, "[AxGraves] An unexpected error occurred while creating custom texture skull.", e); + return head; + } + } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index de2195e..ffe8d79 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -46,6 +46,12 @@ auto-rotation: enabled: false speed: 10.0 +# should the head use a custom base64 texture instead of the player's skin?: +custom-skull: false + +# if custom-skull is true, this is the base64 value to set +custom-skull-value: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2Q5OGNmMzA2NmY3MmIyYjdmYjhlYTg3ZGI1MjVmNmYwYjUxNGZiOGIwZGRiMzc0OWZkMTIzYzAzZTAyNDFiNiJ9fX0=" + # true: only the person who died and people with axgraves.admin can open the grave # false: everyone can open the grave interact-only-own: false