diff --git a/pom.xml b/pom.xml
index 015b5f7a0..a351f034e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -206,13 +206,6 @@
${paper.version}
provided
-
-
- com.mojang
- authlib
- 3.16.29
- provided
-
org.bstats
diff --git a/src/main/java/world/bentobox/bentobox/util/heads/HeadCache.java b/src/main/java/world/bentobox/bentobox/util/heads/HeadCache.java
index 794aa7d1b..63086fddb 100644
--- a/src/main/java/world/bentobox/bentobox/util/heads/HeadCache.java
+++ b/src/main/java/world/bentobox/bentobox/util/heads/HeadCache.java
@@ -1,16 +1,12 @@
package world.bentobox.bentobox.util.heads;
-import java.lang.reflect.Field;
import java.util.UUID;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-import com.mojang.authlib.GameProfile;
-import com.mojang.authlib.properties.Property;
-
-import world.bentobox.bentobox.BentoBox;
+import org.bukkit.inventory.meta.SkullMeta;
+import org.bukkit.profile.PlayerProfile;
/**
@@ -35,9 +31,9 @@ public class HeadCache
private final UUID userId;
/**
- * Base64 Encoded texture link to given player skin.
+ * Player profile for cached head.
*/
- public final String encodedTextureLink;
+ public final PlayerProfile playerProfile;
/**
* Time when head was created. Setting it to 0 will result in keeping head in cache
@@ -54,31 +50,31 @@ public class HeadCache
/**
* Constructor HeadCache creates a new HeadCache instance.
*
- * @param userName of type String
- * @param userId of type String
- * @param encodedTextureLink of type String
+ * @param userName of type String
+ * @param userId of type String
+ * @param playerProfile of type PlayerProfile
*/
- public HeadCache(String userName, UUID userId, String encodedTextureLink)
+ public HeadCache(String userName, UUID userId, PlayerProfile playerProfile)
{
- this(userName, userId, encodedTextureLink, System.currentTimeMillis());
+ this(userName, userId, playerProfile, System.currentTimeMillis());
}
/**
* Constructor HeadCache creates a new HeadCache instance.
*
- * @param userName of type String
- * @param userId of type UUID
- * @param encodedTextureLink of type String
- * @param timestamp of type long
+ * @param userName of type String
+ * @param userId of type UUID
+ * @param playerProfile of type String
+ * @param timestamp of type long
*/
public HeadCache(String userName,
UUID userId,
- String encodedTextureLink,
+ PlayerProfile playerProfile,
long timestamp)
{
this.userName = userName;
- this.encodedTextureLink = encodedTextureLink;
+ this.playerProfile = playerProfile;
this.userId = userId;
this.timestamp = timestamp;
}
@@ -99,26 +95,13 @@ public class HeadCache
public ItemStack getPlayerHead()
{
ItemStack item = new ItemStack(Material.PLAYER_HEAD);
- ItemMeta meta = item.getItemMeta();
+ SkullMeta meta = (SkullMeta) item.getItemMeta();
// Set correct Skull texture
- if (meta != null && this.encodedTextureLink != null && !this.encodedTextureLink.isEmpty())
+ if (meta != null && this.playerProfile != null)
{
- GameProfile profile = new GameProfile(this.userId, this.userName);
- profile.getProperties().put("textures",
- new Property("textures", this.encodedTextureLink));
-
- try
- {
- Field profileField = meta.getClass().getDeclaredField("profile");
- profileField.setAccessible(true);
- profileField.set(meta, profile);
- item.setItemMeta(meta);
- }
- catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e)
- {
- BentoBox.getInstance().log("Error while creating Skull Icon");
- }
+ meta.setOwnerProfile(this.playerProfile);
+ item.setItemMeta(meta);
}
return item;
diff --git a/src/main/java/world/bentobox/bentobox/util/heads/HeadGetter.java b/src/main/java/world/bentobox/bentobox/util/heads/HeadGetter.java
index 04012b0e1..e0a47a929 100644
--- a/src/main/java/world/bentobox/bentobox/util/heads/HeadGetter.java
+++ b/src/main/java/world/bentobox/bentobox/util/heads/HeadGetter.java
@@ -4,6 +4,7 @@ import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
+import java.util.Base64;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -14,6 +15,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
+import org.bukkit.profile.PlayerProfile;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
@@ -165,7 +167,7 @@ public class HeadGetter {
// Create new cache object.
cache = new HeadCache(userName,
playerSkin.getKey(),
- playerSkin.getValue());
+ HeadGetter.createProfile(userName, playerSkin.getKey(), playerSkin.getValue()));
}
else
{
@@ -178,14 +180,14 @@ public class HeadGetter {
// Create new cache object.
cache = new HeadCache(userName,
userId,
- HeadGetter.getTextureFromUUID(userId));
+ HeadGetter.createProfile(userName, userId, HeadGetter.getTextureFromUUID(userId)));
}
// Save in cache
HeadGetter.cachedHeads.put(userName, cache);
// Tell requesters the head came in, but only if the texture is usable.
- if (cache.encodedTextureLink != null && HeadGetter.headRequesters.containsKey(userName))
+ if (cache.playerProfile != null && HeadGetter.headRequesters.containsKey(userName))
{
for (HeadRequester req : HeadGetter.headRequesters.get(userName))
{
@@ -397,4 +399,40 @@ public class HeadGetter {
return returnValue;
}
+
+ private static URL getSkinURLFromBase64(String base64) {
+ /*
+ * Base64 encoded string is in format:
+ * {
+ * "timestamp": 0,
+ * "profileId": "UUID",
+ * "profileName": "USERNAME",
+ * "textures": {
+ * "SKIN": {
+ * "url": "https://textures.minecraft.net/texture/TEXTURE_ID"
+ * },
+ * "CAPE": {
+ * "url": "https://textures.minecraft.net/texture/TEXTURE_ID"
+ * }
+ * }
+ * }
+ */
+ try {
+ String decoded = new String(Base64.getDecoder().decode(base64));
+ JsonObject json = new Gson().fromJson(decoded, JsonObject.class);
+ String url = json.getAsJsonObject("textures").getAsJsonObject("SKIN").get("url").getAsString();
+ return new URL(url);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private static PlayerProfile createProfile(@NonNull String userName, @NonNull UUID uuid, @Nullable String encodedBase64Texture) {
+ PlayerProfile profile = Bukkit.createPlayerProfile(uuid, userName);
+ if (encodedBase64Texture != null && !encodedBase64Texture.isEmpty()) {
+ URL skinURL = HeadGetter.getSkinURLFromBase64(encodedBase64Texture);
+ profile.getTextures().setSkin(skinURL);
+ }
+ return profile;
+ }
}