Finally tested some things and totally switched some things up... whoops

Version Detection should be fixed now
Player Head now should return the right Material
Completely misunderstood how DataComponents work... Should be fixed now
Added partial Descriptions for NBT Util Classes
This commit is contained in:
IHasName 2024-09-01 03:49:19 +02:00
parent 5ee693b787
commit 4906d8e4bc
15 changed files with 139 additions and 39 deletions

View File

@ -8,6 +8,8 @@ package de.likewhat.customheads.utils;
*/
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import com.mojang.authlib.properties.PropertyMap;
import de.likewhat.customheads.CustomHeads;
import de.likewhat.customheads.api.CustomHeadsAPI;
import de.likewhat.customheads.api.CustomHeadsPlayer;
@ -15,6 +17,7 @@ import de.likewhat.customheads.category.Category;
import de.likewhat.customheads.category.CustomHead;
import de.likewhat.customheads.headwriter.HeadFontType;
import de.likewhat.customheads.headwriter.HeadWriter;
import de.likewhat.customheads.utils.reflection.helpers.DataComponentTypes;
import de.likewhat.customheads.utils.reflection.helpers.ReflectionUtils;
import de.likewhat.customheads.utils.reflection.helpers.Version;
import de.likewhat.customheads.utils.reflection.helpers.wrappers.instances.ClassWrappers;
@ -35,6 +38,7 @@ import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Random;
import java.util.logging.Level;
@ -57,6 +61,14 @@ public class APIHandler implements CustomHeadsAPI {
throw new NullPointerException("Item cannot be null");
}
try {
if(Version.getCurrentVersion().isNewerThan(Version.V1_20_R3)) {
Object profile = MethodWrappers.ITEMSTACK_DATA_GET.invokeOn(ItemNBTUtils.asNMSCopy(itemStack), DataComponentTypes.PROFILE.getInstance());
Method propertyMapMethod = ReflectionUtils.getDeclaredMethod("properties", ClassWrappers.RESOLVABLE_PROFILE.resolve());
PropertyMap properties = (PropertyMap) ReflectionUtils.invokeMethod(propertyMapMethod, profile);
Property property = (Property) properties.get("textures").toArray()[0];
Method propertyValueMethod = ReflectionUtils.getDeclaredMethod("value", Property.class);
return (String) ReflectionUtils.invokeMethod(propertyValueMethod, property);
} else {
return ItemNBTUtils.getTagFromItem(itemStack)
.getCompound("SkullOwner")
.getCompound("Properties")
@ -64,6 +76,7 @@ public class APIHandler implements CustomHeadsAPI {
.get(0)
.asCompound()
.getString("Value");
}
// Object tag = ItemNBTUtils.getTagFromItem(itemStack);
// Object skullOwner = NBTTagCompoundWrapper.GET_COMPOUND.invokeOn(tag, "SkullOwner");
// Object properties = NBTTagCompoundWrapper.GET_COMPOUND.invokeOn(skullOwner, "Properties");

View File

@ -39,7 +39,7 @@ public class JsonToItem {
// Auto-Fix Issue with Legacy Skull Items
material = Utils.getPlayerHeadMaterial();
} else {
material = Material.getMaterial(materialName);
material = Material.matchMaterial(materialName);
}
if(material == null) {
@ -102,13 +102,13 @@ public class JsonToItem {
}
if (meta instanceof SkullMeta) {
SkullMeta skullMeta = (SkullMeta) meta;
if (skullMeta.hasOwner()) {
if (Utils.hasCustomTexture(itemStack)) {
itemObject.addProperty("texture", CustomHeads.getApi().getSkullTexture(itemStack));
} else if (skullMeta.hasOwner()) {
itemObject.addProperty("skullOwner", skullMeta.getOwner());
}
}
if (Utils.hasCustomTexture(itemStack)) {
itemObject.addProperty("texture", CustomHeads.getApi().getSkullTexture(itemStack));
}
}
return itemObject;
}

View File

@ -68,6 +68,18 @@ public class Utils {
public static final String TEXT_JSON_FORMAT = "{\"text\":\"%s\"}";
private static final Material PLAYER_HEAD_MATERIAL;
static {
Material headMaterial;
try {
headMaterial = Material.SKULL_ITEM;
} catch (Exception e) {
headMaterial = Material.getMaterial("PLAYER_HEAD");
}
PLAYER_HEAD_MATERIAL = headMaterial;
}
public static String getTextureFromProfile(GameProfile profile) {
String value = "";
for (Property prop : profile.getProperties().get("textures")) {
@ -450,18 +462,14 @@ public class Utils {
}
public static Material getPlayerHeadMaterial() {
if (Version.getCurrentVersion().isOlderThan(Version.V1_13_R1)) {
return Material.SKULL_ITEM;
} else {
return Material.getMaterial("PLAYER_HEAD");
}
return PLAYER_HEAD_MATERIAL;
}
public static ItemStack createPlayerHeadItemStack() {
if (Version.getCurrentVersion().isOlderThan(Version.V1_13_R1)) {
if (PLAYER_HEAD_MATERIAL.name().equals("SKULL_ITEM")) {
return new ItemStack(Material.SKULL_ITEM, 1, (short) 3);
} else {
return new ItemStack(Material.getMaterial("PLAYER_HEAD"));
return new ItemStack(getPlayerHeadMaterial());
}
}

View File

@ -177,7 +177,7 @@ public class ReflectionUtils {
}
/**
* Check whether the given Method exists or not
* Check whether the given Method exists or not via {@link Class#getMethod}
* @param clazz The Class where the Method could be
* @param methodName The Method Name
* @param params Optional Method Parameters
@ -335,5 +335,4 @@ public class ReflectionUtils {
return defaultValue;
}
}

View File

@ -20,29 +20,37 @@ public enum Version {
V1_18_R1(1181), V1_18_R2(1182),
V1_19_R1(1191), V1_19_R2(1192), V1_19_R3(1193),
V1_20_R1(1201), V1_20_R2(1202), V1_20_R3(1203),
V1_20_5(1205), V1_20_6(1206), V1_21_0(1210),
V1_20_5(1205), V1_20_6(1206),
V1_21_0(1210),
LATEST(Integer.MAX_VALUE),
LATEST_UPDATE(V1_20_R3);
LATEST_UPDATE(V1_21_0);
private static final String PACKET_NAME = Bukkit.getServer().getClass().getPackage().getName();
private static final String RAW_VERSION;
static {
String packetVersion = PACKET_NAME.substring(PACKET_NAME.lastIndexOf('.') + 1);
if(packetVersion.isEmpty()) { // We don't have a Craftbukkit Packet Version so we use the Server Version itself (since 1.20.5)
String versionString;
try {
Integer.parseInt(packetVersion.replaceAll("\\D+", ""));
versionString = packetVersion;
} catch(NumberFormatException e) {
String bukkitVersionString = Bukkit.getBukkitVersion();
RAW_VERSION = bukkitVersionString.substring(0, bukkitVersionString.indexOf("-") - 1);
} else {
RAW_VERSION = packetVersion;
versionString = bukkitVersionString.substring(0, bukkitVersionString.indexOf("-"));
}
RAW_VERSION = versionString;
}
public static Version getCurrentVersion() {
if(currentVersion != null) {
return currentVersion;
}
currentVersion = fromValue(Integer.parseInt(RAW_VERSION.replaceAll("\\D+", "")));
String versionString = RAW_VERSION.replaceAll("\\D+", "");
if(versionString.equals("121")) { // Something something 1.21 and not 1.21.0
versionString += "0";
}
currentVersion = fromValue(Integer.parseInt(versionString));
return currentVersion;
}

View File

@ -59,6 +59,10 @@ public class MethodWrapper<T> extends WrapperBase<MethodWrapper<?>, Method> {
this.parameters = Arrays.stream(parametersWrapper).map(WrapperBase::resolve).toArray(Class[]::new);
}
if(ReflectionUtils.methodExists(targetClass, methodName, parameters)) {
return ReflectionUtils.getMethod(methodName, targetClass, parameters);
}
return ReflectionUtils.getDeclaredMethod(methodName, targetClass, parameters);
}
@ -75,4 +79,8 @@ public class MethodWrapper<T> extends WrapperBase<MethodWrapper<?>, Method> {
MethodWrapper<T> actualResolver = (MethodWrapper<T>) this.getResolver();
return "MethodWrapper{method=" + LoggingUtils.methodLikeString(actualResolver.methodName, actualResolver.parameters) + " fromVersion=" + actualResolver.from + " toVersion=" + actualResolver.to + "}";
}
public Class<?> getTargetClass() {
return targetClassWrapper == null ? targetClass : targetClassWrapper.resolve();
}
}

View File

@ -51,7 +51,7 @@ public abstract class WrapperBase<M extends WrapperBase<M, T>, T> {
throw new UnsupportedOperationException("Version " + current.name() + " isn't supported yet (from " + from.name() + ")");
} else if(current.isNewerThan(to)) {
if(replacedBy == null) {
throw new UnsupportedOperationException("This " + wrapperType.getTypeClass().getName() + " hasn't been implemented yet for " + current.name() + (current == Version.LATEST ? ("( " + Version.getCurrentVersionRaw() + ")") : ""));
throw new UnsupportedOperationException("This " + wrapperType.getTypeClass().getName() + " hasn't been implemented yet for " + current.name() + " (Up to " + to + ")" + (current == Version.LATEST ? (" ( " + Version.getCurrentVersionRaw() + ")") : ""));
} else {
resolvedValue = replacedBy.getResolver().resolve();
return resolvedValue;
@ -80,7 +80,7 @@ public abstract class WrapperBase<M extends WrapperBase<M, T>, T> {
throw new UnsupportedOperationException("Version " + current.name() + " isn't supported yet (from " + from.name() + ")");
} else if(current.isNewerThan(to)) {
if(replacedBy == null) {
throw new UnsupportedOperationException("This " + wrapperType.getTypeClass().getSimpleName() + " hasn't been implemented yet for " + current.name() + (current == Version.LATEST ? ("( " + Version.getCurrentVersionRaw() + ")") : ""));
throw new UnsupportedOperationException("This " + wrapperType.getTypeClass().getName() + " hasn't been implemented yet for " + current.name() + (current == Version.LATEST ? ("( " + Version.getCurrentVersionRaw() + ")") : ""));
} else {
return replacedBy.getResolver();
}

View File

@ -66,6 +66,8 @@ public class ClassWrappers {
// Item Components
public static final MinecraftServerClassWrapper COMPONENT_CUSTOM_DATA = new MinecraftServerClassWrapper(Version.V1_20_5, null, "CustomData", "world.item.component");
public static final MinecraftServerClassWrapper RESOLVABLE_PROFILE = new MinecraftServerClassWrapper(Version.V1_20_5, null, "ResolvableProfile", "world.item.component");
// CraftBukkit
public static final CraftBukkitClassWrapper CRAFTBUKKIT_ITEMSTACK = new CraftBukkitClassWrapper("inventory.CraftItemStack");
public static final CraftBukkitClassWrapper CRAFTBUKKIT_CRAFT_PLAYER = new CraftBukkitClassWrapper("entity.CraftPlayer");

View File

@ -33,7 +33,9 @@ public class MethodWrappers {
public static final MethodWrapper<Boolean> ITEMSTACK_DATA_HAS = new MethodWrapper<>(Version.V1_20_5, null, "has", ClassWrappers.MINECRAFT_ITEMSTACK, ClassWrappers.DATA_COMPONENT_TYPE);
public static final MethodWrapper<Void> ITEMSTACK_DATA_SET = new MethodWrapper<>(Version.V1_20_5, null, "set", ClassWrappers.MINECRAFT_ITEMSTACK, ClassWrappers.DATA_COMPONENT_TYPE, ClassWrappers.COMPONENT_CUSTOM_DATA);
public static final MethodWrapper<Void> ITEMSTACK_DATA_SET = new MethodWrapper<>(Version.V1_20_5, null, "set", ClassWrappers.MINECRAFT_ITEMSTACK, ClassWrappers.DATA_COMPONENT_TYPE, ClassWrapper.from(Object.class)); // ClassWrappers.COMPONENT_CUSTOM_DATA
public static final MethodWrapper<Object> ITEMSTACK_GET_COMPONENTS = new MethodWrapper<>(Version.V1_20_5, null, "getComponents", ClassWrappers.MINECRAFT_ITEMSTACK);
public static final MethodWrapper<Object> COMPONENT_CUSTOM_DATA_OF = new MethodWrapper<>(Version.V1_20_5, null, "of", ClassWrappers.COMPONENT_CUSTOM_DATA.resolve(), NBTType.COMPOUND.getNBTClass());
@ -41,7 +43,7 @@ public class MethodWrappers {
public static final MethodWrapper<Object> COMPONENT_CUSTOM_DATA_COPY_TAG = new MethodWrapper<>(Version.V1_20_5, null, "copyTag", ClassWrappers.COMPONENT_CUSTOM_DATA);
// GameProfile
public static final MethodWrapper<Object> GAMEPROFILE_SERIALIZE = new MethodWrapper<>(Version.V1_18_R1, Version.V1_20_R3, "a", ClassWrappers.GAMEPROFILE_SERIALIZER.resolve(), NBTType.COMPOUND.getNBTClass(), GameProfile.class);
public static final MethodWrapper<Object> GAMEPROFILE_SERIALIZE = new MethodWrapper<>(Version.V1_18_R1, Version.V1_20_R3, "a", ClassWrappers.GAMEPROFILE_SERIALIZER, ClassWrapper.from(NBTType.COMPOUND.getNBTClass()), ClassWrapper.from(GameProfile.class));
// Player Packet Handling
private static final MethodWrapper<Void> PLAYER_SEND_PACKET_V1205 = new MethodWrapper<>(Version.V1_20_5, null, "send", ClassWrappers.PLAYER_CONNECTION.resolve(), ClassWrappers.PACKET.resolve()); // Inherited from ServerPlayerConnection

View File

@ -7,24 +7,44 @@ import de.likewhat.customheads.utils.reflection.nbt.NBTType;
*/
public interface NBTBaseWrapper {
/**
* @return The NBTType of this Instance
*/
NBTType getType();
/**
* @return The Raw NBT Instance of this Instance
*/
Object getNBTObject();
boolean isCompound();
boolean isList();
/**
* @return Whether this Instance is a Generic/Primitive Type
*/
boolean isGeneric();
/**
* @throws de.likewhat.customheads.utils.reflection.nbt.errors.NBTException when the Instance if not a Compound
* @return The Instance as {@link NBTTagCompoundWrapper}
*/
default NBTTagCompoundWrapper asCompound() {
return new NBTTagCompoundWrapper(this.getNBTObject());
}
/**
* @throws de.likewhat.customheads.utils.reflection.nbt.errors.NBTException when the Instance is not a List
* @return The Instance as {@link NBTTagListWrapper}
*/
default NBTTagListWrapper asList() {
return new NBTTagListWrapper(this.getNBTObject());
}
/**
* @return The Instance as {@link NBTTagCompoundWrapper}
*/
default NBTGenericWrapper asGeneric() {
return new NBTGenericWrapper(this.getNBTObject());
}

View File

@ -8,6 +8,9 @@ import de.likewhat.customheads.utils.reflection.nbt.NBTType;
import lombok.Getter;
import org.apache.commons.lang3.ArrayUtils;
/**
* A Helper Class for NBT Primitive Type wrapping
*/
@Getter
public class NBTGenericWrapper implements NBTBaseWrapper {
@ -79,7 +82,14 @@ public class NBTGenericWrapper implements NBTBaseWrapper {
this.type = nbtType;
}
/**
* @throws java.lang.IllegalArgumentException When the nbtObject is not an Instance of NBTBase (Tag since 1.20.5)
* @param nbtObject The NBT Object to be wrapped
*/
public NBTGenericWrapper(Object nbtObject) {
if(!ClassWrappers.NBT_BASE.resolve().isInstance(nbtObject)) {
throw new IllegalArgumentException("Generic Type has to be instance of " + ClassWrappers.NBT_BASE.getFinalClassName() + " got: " + nbtObject);
}
this.nbtObject = nbtObject;
this.type = NBTType.getNBTTypeFromInstance(nbtObject);
}
@ -99,6 +109,11 @@ public class NBTGenericWrapper implements NBTBaseWrapper {
return true;
}
/**
* Static Caller for Instance Creation
* @param nbtObject The NBT Object to be wrapped
* @return A new {@link de.likewhat.customheads.utils.reflection.helpers.wrappers.instances.nbt.NBTGenericWrapper} Instance of nbtObject
*/
public static NBTGenericWrapper of(Object nbtObject) {
return new NBTGenericWrapper(nbtObject);
}

View File

@ -12,6 +12,9 @@ import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.logging.Level;
/**
* A Helper Class for NBT Compound wrapping
*/
public class NBTTagCompoundWrapper implements NBTBaseWrapper {
// Misc
@ -184,7 +187,7 @@ public class NBTTagCompoundWrapper implements NBTBaseWrapper {
@Override
public boolean isList() {
return true;
return false;
}
@Override
@ -192,6 +195,11 @@ public class NBTTagCompoundWrapper implements NBTBaseWrapper {
return false;
}
/**
* Static Caller for Instance Creation
* @param nbtObject The NBT Object to be wrapped
* @return A new {@link de.likewhat.customheads.utils.reflection.helpers.wrappers.instances.nbt.NBTTagCompoundWrapper} Instance of nbtObject
*/
public static NBTTagCompoundWrapper of(Object nbtObject) {
return new NBTTagCompoundWrapper(nbtObject);
}

View File

@ -10,6 +10,9 @@ import org.apache.commons.lang3.ArrayUtils;
import javax.annotation.Nullable;
import java.util.AbstractList;
/**
* A Helper Class for NBT List wrapping
*/
public class NBTTagListWrapper extends AbstractList<NBTGenericWrapper> implements NBTBaseWrapper {
public static final MethodWrapper<Integer> SIZE = new MethodWrapper<>(null, null, "size", NBTType.LIST.getNBTClass());
@ -109,10 +112,18 @@ public class NBTTagListWrapper extends AbstractList<NBTGenericWrapper> implement
return false;
}
/**
* Static Caller for Instance Creation
* @param nbtObject The NBT Object to be wrapped
* @return A new {@link de.likewhat.customheads.utils.reflection.helpers.wrappers.instances.nbt.NBTTagListWrapper} Instance of nbtObject
*/
public static NBTTagListWrapper of(Object nbtObject) {
return new NBTTagListWrapper(nbtObject);
}
/**
* @return The NBTType contained in this List
*/
public NBTType getListType() {
return NBTType.getById(ReflectionUtils.callWrapperAndGetOrDefault(this.nbtObject, GET_LIST_ELEMENTS_TYPE, (byte) -1));
}

View File

@ -40,9 +40,9 @@ public class ItemNBTUtils {
try {
if(nmsItem != null) {
if(Version.getCurrentVersion().isNewerThan(Version.V1_20_R3)) {
return MethodWrappers.ITEMSTACK_HASTAG.invokeOn(nmsItem);
} else {
return MethodWrappers.ITEMSTACK_DATA_HAS.invokeOn(nmsItem, DataComponentTypes.CUSTOM_DATA.getInstance());
} else {
return MethodWrappers.ITEMSTACK_HASTAG.invokeOn(nmsItem);
}
}
} catch (IllegalAccessException | InvocationTargetException e) {
@ -66,10 +66,10 @@ public class ItemNBTUtils {
try {
Object tag;
if(Version.getCurrentVersion().isNewerThan(Version.V1_20_R3)) {
tag = MethodWrappers.ITEMSTACK_GETTAG.invokeOn(nmsItem);
} else {
Object customData = MethodWrappers.ITEMSTACK_DATA_GET.invokeOn(nmsItem, DataComponentTypes.CUSTOM_DATA.getInstance());
tag = MethodWrappers.COMPONENT_CUSTOM_DATA_COPY_TAG.invokeOn(customData);
} else {
tag = MethodWrappers.ITEMSTACK_GETTAG.invokeOn(nmsItem);
}
return NBTTagCompoundWrapper.of(tag);
} catch(InvocationTargetException | IllegalAccessException e) {
@ -86,9 +86,9 @@ public class ItemNBTUtils {
public static void setTagOnItem(Object nmsItem, Object nbt) throws NBTException, NBTVerifyException {
try {
if(Version.getCurrentVersion().isNewerThan(Version.V1_20_R3)) {
MethodWrappers.ITEMSTACK_SETTAG.invokeOn(nmsItem, nbt);
MethodWrappers.ITEMSTACK_DATA_SET.invokeOn(nmsItem, DataComponentTypes.CUSTOM_DATA.getInstance(), NBTTagUtils.nbtToCustomData(nbt));
} else {
MethodWrappers.ITEMSTACK_DATA_SET.invokeOn(nmsItem, nbt);
MethodWrappers.ITEMSTACK_SETTAG.invokeOn(nmsItem, nbt);
}
// Verify NBT Set

View File

@ -12,12 +12,14 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import de.likewhat.customheads.CustomHeads;
import de.likewhat.customheads.utils.reflection.helpers.wrappers.instances.MethodWrappers;
import de.likewhat.customheads.utils.reflection.helpers.wrappers.instances.nbt.NBTBaseWrapper;
import de.likewhat.customheads.utils.reflection.helpers.wrappers.instances.nbt.NBTGenericWrapper;
import de.likewhat.customheads.utils.reflection.helpers.wrappers.instances.nbt.NBTTagCompoundWrapper;
import de.likewhat.customheads.utils.reflection.helpers.wrappers.instances.nbt.NBTTagListWrapper;
import de.likewhat.customheads.utils.reflection.nbt.errors.NBTException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
public class NBTTagUtils {
@ -174,4 +176,8 @@ public class NBTTagUtils {
return null;
}
public static Object nbtToCustomData(Object nbt) throws InvocationTargetException, IllegalAccessException {
return MethodWrappers.COMPONENT_CUSTOM_DATA_OF.invokeOn(null, nbt);
}
}