From e129e1363d3fa36c00ac41ac52870b187cba01a8 Mon Sep 17 00:00:00 2001 From: Devin Lin Date: Thu, 4 Jul 2024 00:09:48 -0400 Subject: [PATCH] Update heads support to 1.20.6 --- pom.xml | 5 + .../protectionstones/utils/BlockUtil.java | 94 +++++++++++-------- 2 files changed, 60 insertions(+), 39 deletions(-) diff --git a/pom.xml b/pom.xml index 74d1019..3794095 100644 --- a/pom.xml +++ b/pom.xml @@ -267,5 +267,10 @@ commons-lang3 3.14.0 + + com.googlecode.json-simple + json-simple + 1.1.1 + diff --git a/src/main/java/dev/espi/protectionstones/utils/BlockUtil.java b/src/main/java/dev/espi/protectionstones/utils/BlockUtil.java index a50535b..58f8659 100644 --- a/src/main/java/dev/espi/protectionstones/utils/BlockUtil.java +++ b/src/main/java/dev/espi/protectionstones/utils/BlockUtil.java @@ -27,9 +27,17 @@ import org.bukkit.entity.Entity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.profile.PlayerProfile; +import org.bukkit.profile.PlayerTextures; +import java.net.MalformedURLException; +import java.net.URL; import java.util.HashMap; import java.util.UUID; +import java.util.Base64; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; public class BlockUtil { static final int MAX_USERNAME_LENGTH = 16; @@ -117,19 +125,54 @@ public static void setHeadType(String psType, Block b) { } } + public static PlayerProfile getProfile(String uuid, String base64) { + String name = uuid.substring(0, 16); + PlayerProfile profile = Bukkit.getServer().createPlayerProfile(UUID.fromString(uuid), name); + PlayerTextures textures = profile.getTextures(); + + // decode base64 to URL + byte[] decodedBytes = Base64.getDecoder().decode(base64); + String decodedString = new String(decodedBytes); + + // read decoded string as JSON object + // sample: {"textures":{"SKIN":{"url":"http://textures.minecraft.net/texture/..."}}} + String url = ""; + try { + JSONParser parser = new JSONParser(); + JSONObject object = (JSONObject) parser.parse(decodedString); + JSONObject jsonTextures = (JSONObject) object.get("textures"); + JSONObject jsonSkin = (JSONObject) jsonTextures.get("SKIN"); + url = (String) jsonSkin.get("url"); + } catch (ParseException exception) { + throw new RuntimeException("Invalid JSON retrieved from base64 " + decodedString, exception); + } + + URL urlObject; + try { + urlObject = new URL(url); + } catch (MalformedURLException exception) { + throw new RuntimeException("Invalid decoded URL from head data: " + url, exception); + } + + textures.setSkin(urlObject); + profile.setTextures(textures); + return profile; + } + public static ItemStack setHeadType(String psType, ItemStack item) { String name = psType.split(":")[1]; if (name.length() > MAX_USERNAME_LENGTH) { // base 64 head String uuid = name; - // if 1.16 or above, use new uuid format - if (Integer.parseInt(MiscUtil.getVersionString().split("\\.")[1]) >= 16 || !MiscUtil.getVersionString().split("\\.")[0].equals("1")) { - uuid = MiscUtil.getUniqueIdIntArray(UUID.fromString(uuid)); - } else { // quotes are needed for pre 1.16 uuids - uuid = "\"" + uuid + "\""; - } + // decode base64 to URL + String base64 = uuidToBase64Head.get(name); + PlayerProfile profile = getProfile(uuid, base64); + + SkullMeta meta = (SkullMeta) item.getItemMeta(); + meta.setOwnerProfile(profile); + item.setItemMeta(meta); - return Bukkit.getUnsafe().modifyItemStack(item, "{SkullOwner:{Name:\"" + name + "\",Id:" + uuid + ",Properties:{textures:[{Value:\"" + uuidToBase64Head.get(name) + "\"}]}}}"); + return item; } else { // normal name head SkullMeta sm = (SkullMeta) item.getItemMeta(); sm.setOwningPlayer(Bukkit.getOfflinePlayer(name)); @@ -138,40 +181,13 @@ public static ItemStack setHeadType(String psType, ItemStack item) { } } - // Note: this code is really weird private static void blockWithBase64(Block block, String uuid) { - String base64 = uuidToBase64Head.get(uuid), args; - - // if 1.16 or above, use new uuid format - if (Integer.parseInt(MiscUtil.getVersionString().split("\\.")[1]) >= 16 || !MiscUtil.getVersionString().split("\\.")[0].equals("1")) { - uuid = MiscUtil.getUniqueIdIntArray(UUID.fromString(uuid)); - args = String.format( - "%d %d %d %s", - block.getX(), - block.getY(), - block.getZ(), - "{SkullOwner:{Name:\"" + uuid + "\",Id:" + uuid + ",Properties:{textures:[{Value:\"" + base64 + "\"}]}}}" - ); - } else { // tag was different pre 1.16 - args = String.format( - "%d %d %d %s", - block.getX(), - block.getY(), - block.getZ(), - "{Owner:{Name:\"" + uuid + "\",Id:\"" + uuid + "\",Properties:{textures:[{Value:\"" + base64 + "\"}]}}}" - ); - } - - // fake entity to run command at its location - Entity e = block.getWorld().spawn(new Location(block.getWorld(), 0, 0, 0), ArmorStand.class, ent -> { - ent.setCustomName("mrpig"); - ent.setInvulnerable(true); - ent.setVisible(false); - }); + String base64 = uuidToBase64Head.get(uuid); + PlayerProfile profile = getProfile(uuid, base64); - // run data command to change block using the pig's world - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "execute at @e[type=armor_stand,nbt={CustomName:'{\"extra\":[{\"text\":\"" + e.getName() + "\"}],\"text\":\"\"}'}] run data merge block " + args); - e.remove(); + Skull skull = (Skull) block.getState(); + skull.setOwnerProfile(profile); + skull.update(false); } public static boolean isBase64PSHead(String type) {