Switch to Spigot's PlayerProfile on HeadGetter (#2231)

* Switch to Spigot's PlayerProfile on HeadGetter

Remove AuthLib

* forgot to set meta back

* should check if the texture is not empty
This commit is contained in:
Huynh Tien 2023-11-24 23:15:20 +07:00 committed by GitHub
parent 1cf7ccbb99
commit 5de7302469
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 46 deletions

View File

@ -206,13 +206,6 @@
<version>${paper.version}</version>
<scope>provided</scope>
</dependency>
<!-- AuthLib. Used for Head Getter. -->
<dependency>
<groupId>com.mojang</groupId>
<artifactId>authlib</artifactId>
<version>3.16.29</version>
<scope>provided</scope>
</dependency>
<!-- Metrics -->
<dependency>
<groupId>org.bstats</groupId>

View File

@ -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;

View File

@ -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;
}
}