Skip to content

Commit

Permalink
Merge pull request #245 from Olzie-12/fixes/resolvable-profile
Browse files Browse the repository at this point in the history
Fix resolvable profile error for setting/getting textures.
  • Loading branch information
d0by1 authored Nov 9, 2024
2 parents 3f96bac + ea4a668 commit 4b5af19
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 8 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
defaultTasks "build"

group "eu.decentsoftware.holograms"
version "2.8.11"
version "2.8.12"
description "A lightweight yet very powerful hologram plugin with many features and configuration options."

repositories {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import com.mojang.authlib.properties.Property;
import com.mojang.authlib.properties.PropertyMap;
import eu.decentsoftware.holograms.api.utils.Log;
import eu.decentsoftware.holograms.api.utils.reflect.ReflectionUtil;
import eu.decentsoftware.holograms.api.utils.reflect.Version;
import lombok.NonNull;
import lombok.experimental.UtilityClass;
import org.bukkit.Bukkit;
import org.bukkit.SkullType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
Expand All @@ -18,6 +20,7 @@

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Expand All @@ -42,9 +45,24 @@ public final class SkullUtils {
private static Method SET_PROFILE_METHOD;
private static boolean INITIALIZED = false;

private static Constructor<?> RESOLVABLE_PROFILE_CONSTRUCTOR;
private static Field GAME_PROFILE_FIELD_RESOLVABLE_PROFILE;

private static Method PROPERTY_VALUE_METHOD;
private static Function<Property, String> VALUE_RESOLVER;

static {
try {
Class<?> resolvableProfileClass = ReflectionUtil.getNMClass("world.item.component.ResolvableProfile");
RESOLVABLE_PROFILE_CONSTRUCTOR = resolvableProfileClass == null ? null : resolvableProfileClass.getConstructor(GameProfile.class);

// find the game profile field in the resolvable profile class
GAME_PROFILE_FIELD_RESOLVABLE_PROFILE = ReflectionUtil.findField(resolvableProfileClass, GameProfile.class);
} catch ( NoSuchMethodException ignored) {
// old version, no resolvable profile class.
}
}

/**
* Get the Base64 texture of the given skull ItemStack.
*
Expand All @@ -58,16 +76,17 @@ public static String getSkullTexture(@NonNull ItemStack itemStack) {
if (!(meta instanceof SkullMeta)) {
return null;
}
// private ResolvableProfile profile;

if (PROFILE_FIELD == null) {
PROFILE_FIELD = meta.getClass().getDeclaredField("profile");
PROFILE_FIELD.setAccessible(true);
}
Object profileObject = PROFILE_FIELD.get(meta);
if (profileObject == null) return null;

GameProfile profile = (GameProfile) PROFILE_FIELD.get(meta);
if (profile == null) {
return null;
}
GameProfile profile = (GameProfile) (GAME_PROFILE_FIELD_RESOLVABLE_PROFILE == null ? profileObject : GAME_PROFILE_FIELD_RESOLVABLE_PROFILE.get(profileObject));
if (profile == null) return null;

if (VALUE_RESOLVER == null) {
try {
Expand Down Expand Up @@ -128,12 +147,11 @@ public static void setSkullTexture(@NonNull ItemStack itemStack, @NonNull String

PropertyMap properties = profile.getProperties();
properties.put("textures", property);

if (SET_PROFILE_METHOD == null && !INITIALIZED) {
try {
// This method only exists in versions 1.16 and up. For older versions, we use reflection
// to set the profile field directly.
SET_PROFILE_METHOD = meta.getClass().getDeclaredMethod("setProfile", GameProfile.class);
SET_PROFILE_METHOD = meta.getClass().getDeclaredMethod("setProfile", RESOLVABLE_PROFILE_CONSTRUCTOR == null ? GameProfile.class : RESOLVABLE_PROFILE_CONSTRUCTOR.getDeclaringClass());
SET_PROFILE_METHOD.setAccessible(true);
} catch (NoSuchMethodException e) {
// Server is running an older version.
Expand All @@ -142,7 +160,7 @@ public static void setSkullTexture(@NonNull ItemStack itemStack, @NonNull String
}

if (SET_PROFILE_METHOD != null) {
SET_PROFILE_METHOD.invoke(meta, profile);
SET_PROFILE_METHOD.invoke(meta, RESOLVABLE_PROFILE_CONSTRUCTOR == null ? profile : RESOLVABLE_PROFILE_CONSTRUCTOR.newInstance(profile));
} else {
if (PROFILE_FIELD == null) {
PROFILE_FIELD = meta.getClass().getDeclaredField("profile");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,28 @@ public static <T> T getFieldValue(final @NotNull Object object, final @NotNull S
return null;
}

/**
* Find a field with in a class with a specific type.
* <p>
* If the field is not found, this method will return null.
*
* @param clazz The class to get the field from.
* @param type The class type of the field.
* @return The field, or null if the field was not found.
*/
public static Field findField(Class<?> clazz, Class<?> type) {
if (clazz == null) return null;

Field[] methods = clazz.getDeclaredFields();
for (Field method : methods) {
if (!method.getType().equals(type)) continue;

method.setAccessible(true);
return method;
}
return null;
}

/**
* Get a field with the given name from the given class.
* <p>
Expand Down

0 comments on commit 4b5af19

Please sign in to comment.