From 0ce7d1dd6ca20adc6bcf257ab7579182ba876cec Mon Sep 17 00:00:00 2001 From: Auxilor Date: Fri, 3 Sep 2021 12:28:03 +0100 Subject: [PATCH] Added texture: to Items.lookup --- .../java/com/willfp/eco/core/items/Items.java | 85 ++++++++++++++----- .../java/com/willfp/eco/util/SkullUtils.java | 26 +++++- .../com/willfp/eco/proxy/v1_16_R3/Skull.kt | 41 +++++---- .../com/willfp/eco/proxy/v1_17_R1/Skull.kt | 38 ++++++--- .../com/willfp/eco/spigot/EcoSpigotPlugin.kt | 5 +- .../kotlin/com/willfp/eco/proxy/SkullProxy.kt | 4 + 6 files changed, 147 insertions(+), 52 deletions(-) diff --git a/eco-api/src/main/java/com/willfp/eco/core/items/Items.java b/eco-api/src/main/java/com/willfp/eco/core/items/Items.java index 50f0240b..b5806aec 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/items/Items.java +++ b/eco-api/src/main/java/com/willfp/eco/core/items/Items.java @@ -5,6 +5,7 @@ import com.willfp.eco.core.recipe.parts.MaterialTestableItem; import com.willfp.eco.core.recipe.parts.ModifiedTestableItem; import com.willfp.eco.core.recipe.parts.TestableStack; import com.willfp.eco.util.NamespacedKeyUtils; +import com.willfp.eco.util.SkullUtils; import lombok.experimental.UtilityClass; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -12,6 +13,7 @@ import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,6 +22,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * Class to manage all custom and vanilla items. @@ -29,7 +32,7 @@ public final class Items { /** * All recipe parts. */ - private static final Map REGISTRY = new HashMap<>(); + private static final Map REGISTRY = new ConcurrentHashMap<>(); /** * Register a new recipe part. @@ -111,7 +114,7 @@ public final class Items { /* Legacy id:amount format - This has been superceded by id amount + This has been superseded by id amount */ if (part == null) { Material material = Material.getMaterial(split[0].toUpperCase()); @@ -127,7 +130,7 @@ public final class Items { /* Legacy namespace:id:amount format - This has been superceded by namespace:id amount + This has been superseded by namespace:id amount */ if (split.length == 3) { CustomItem part = REGISTRY.get(NamespacedKeyUtils.create(split[0], split[1])); @@ -152,44 +155,80 @@ public final class Items { return new EmptyTestableItem(); } - String[] enchantArgs = Arrays.copyOfRange(args, usingNewStackFormat ? 2 : 1, args.length); + ItemStack example = item.getItem(); + ItemMeta meta = example.getItemMeta(); + assert meta != null; + String[] modifierArgs = Arrays.copyOfRange(args, usingNewStackFormat ? 2 : 1, args.length); + + boolean hasModifiers = false; Map requiredEnchantments = new HashMap<>(); + String skullTexture = null; - for (String enchantArg : enchantArgs) { + // Handle skull texture + for (String arg : modifierArgs) { + String[] argSplit = arg.split(":"); + if (!argSplit[0].equalsIgnoreCase("texture")) { + continue; + } + + if (argSplit.length < 2) { + continue; + } + + skullTexture = argSplit[1]; + hasModifiers = true; + } + + if (meta instanceof SkullMeta skullMeta && skullTexture != null) { + SkullUtils.setSkullTexture(skullMeta, skullTexture); + } + + // Handle enchantment modifiers + for (String enchantArg : modifierArgs) { String[] enchantArgSplit = enchantArg.split(":"); Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(enchantArgSplit[0].toLowerCase())); + if (enchantment == null) { + continue; + } + + if (enchantArgSplit.length < 2) { + continue; + } + int level = Integer.parseInt(enchantArgSplit[1]); requiredEnchantments.put(enchantment, level); + hasModifiers = true; } - ItemStack example = item.getItem(); - - if (example.getItemMeta() instanceof EnchantmentStorageMeta storageMeta) { + if (meta instanceof EnchantmentStorageMeta storageMeta) { requiredEnchantments.forEach((enchantment, integer) -> storageMeta.addStoredEnchant(enchantment, integer, true)); - example.setItemMeta(storageMeta); } else { - ItemMeta meta = example.getItemMeta(); - assert meta != null; requiredEnchantments.forEach((enchantment, integer) -> meta.addEnchant(enchantment, integer, true)); - example.setItemMeta(meta); } - if (!requiredEnchantments.isEmpty()) { + /* + The modifiers are then applied. + */ + + example.setItemMeta(meta); + + String finalSkullTexture = skullTexture; // I hate this, java. + if (hasModifiers) { item = new ModifiedTestableItem( item, - itemStack -> { - if (!itemStack.hasItemMeta()) { + test -> { + if (!test.hasItemMeta()) { return false; } - ItemMeta meta = itemStack.getItemMeta(); + ItemMeta testMeta = test.getItemMeta(); - assert meta != null; + assert testMeta != null; - if (meta instanceof EnchantmentStorageMeta storageMeta) { + if (testMeta instanceof EnchantmentStorageMeta storageMeta) { for (Map.Entry entry : requiredEnchantments.entrySet()) { if (!storageMeta.hasStoredEnchant(entry.getKey())) { return false; @@ -200,15 +239,21 @@ public final class Items { } } else { for (Map.Entry entry : requiredEnchantments.entrySet()) { - if (!meta.hasEnchant(entry.getKey())) { + if (!testMeta.hasEnchant(entry.getKey())) { return false; } - if (meta.getEnchantLevel(entry.getKey()) < entry.getValue()) { + if (testMeta.getEnchantLevel(entry.getKey()) < entry.getValue()) { return false; } } } + if (testMeta instanceof SkullMeta skullMeta && finalSkullTexture != null) { + if (!finalSkullTexture.equalsIgnoreCase(SkullUtils.getSkullTexture(skullMeta))) { + return false; + } + } + return true; }, example diff --git a/eco-api/src/main/java/com/willfp/eco/util/SkullUtils.java b/eco-api/src/main/java/com/willfp/eco/util/SkullUtils.java index 262e2e62..552ec621 100644 --- a/eco-api/src/main/java/com/willfp/eco/util/SkullUtils.java +++ b/eco-api/src/main/java/com/willfp/eco/util/SkullUtils.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import java.util.function.BiConsumer; +import java.util.function.Function; /** * Utilities / API methods for player heads. @@ -23,6 +24,11 @@ public class SkullUtils { */ private BiConsumer metaSetConsumer = null; + /** + * The meta get function. + */ + private Function metaGetConsumer = null; + /** * Set the texture of a skull from base64. * @@ -37,16 +43,32 @@ public class SkullUtils { metaSetConsumer.accept(meta, base64); } + /** + * Get the texture of a skull - in base64. + * + * @param meta The meta to modify. + * @return The texture. + */ + public String getSkullTexture(@NotNull final SkullMeta meta) { + Validate.isTrue(initialized, "Must be initialized!"); + Validate.notNull(metaGetConsumer, "Must be initialized!"); + + return metaGetConsumer.apply(meta); + } + /** * Initialize the skull texture function. * - * @param function The function. + * @param function The function. + * @param function2 Get function. */ @ApiStatus.Internal - public void initialize(@NotNull final BiConsumer function) { + public void initialize(@NotNull final BiConsumer function, + @NotNull final Function function2) { Validate.isTrue(!initialized, "Already initialized!"); metaSetConsumer = function; + metaGetConsumer = function2; initialized = true; } } diff --git a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/proxy/v1_16_R3/Skull.kt b/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/proxy/v1_16_R3/Skull.kt index 6f9a1823..c59c27f7 100644 --- a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/proxy/v1_16_R3/Skull.kt +++ b/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/proxy/v1_16_R3/Skull.kt @@ -1,32 +1,43 @@ package com.willfp.eco.proxy.v1_16_R3 + import com.mojang.authlib.GameProfile import com.mojang.authlib.properties.Property -import org.bukkit.inventory.meta.SkullMeta import com.willfp.eco.proxy.SkullProxy +import org.bukkit.inventory.meta.SkullMeta +import java.lang.reflect.Field import java.lang.reflect.Method import java.util.* class Skull : SkullProxy { private lateinit var setProfile: Method + private lateinit var profile: Field override fun setSkullTexture( meta: SkullMeta, base64: String ) { - try { - if (!this::setProfile.isInitialized) { - setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java) - setProfile.isAccessible = true - } - val uuid = UUID( - base64.substring(base64.length - 20).hashCode().toLong(), - base64.substring(base64.length - 10).hashCode().toLong() - ) - val profile = GameProfile(uuid, "eco") - profile.properties.put("textures", Property("textures", base64)) - setProfile.invoke(meta, profile) - } catch (e: ReflectiveOperationException) { - e.printStackTrace() + if (!this::setProfile.isInitialized) { + setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java) + setProfile.isAccessible = true } + val uuid = UUID( + base64.substring(base64.length - 20).hashCode().toLong(), + base64.substring(base64.length - 10).hashCode().toLong() + ) + val profile = GameProfile(uuid, "eco") + profile.properties.put("textures", Property("textures", base64)) + setProfile.invoke(meta, profile) + } + + override fun getSkullTexture( + meta: SkullMeta + ): String? { + if (!this::profile.isInitialized) { + profile = meta.javaClass.getDeclaredField("profile") + profile.isAccessible = true + } + val profile = profile[meta] as GameProfile? + val property = profile?.properties?.get("textures") as Property? + return property?.value } } \ No newline at end of file diff --git a/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/proxy/v1_17_R1/Skull.kt b/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/proxy/v1_17_R1/Skull.kt index a4edcfd6..529ca6b7 100644 --- a/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/proxy/v1_17_R1/Skull.kt +++ b/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/proxy/v1_17_R1/Skull.kt @@ -4,30 +4,40 @@ import com.mojang.authlib.GameProfile import com.mojang.authlib.properties.Property import com.willfp.eco.proxy.SkullProxy import org.bukkit.inventory.meta.SkullMeta +import java.lang.reflect.Field import java.lang.reflect.Method import java.util.* class Skull : SkullProxy { private lateinit var setProfile: Method + private lateinit var profile: Field override fun setSkullTexture( meta: SkullMeta, base64: String ) { - try { - if (!this::setProfile.isInitialized) { - setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java) - setProfile.isAccessible = true - } - val uuid = UUID( - base64.substring(base64.length - 20).hashCode().toLong(), - base64.substring(base64.length - 10).hashCode().toLong() - ) - val profile = GameProfile(uuid, "eco") - profile.properties.put("textures", Property("textures", base64)) - setProfile.invoke(meta, profile) - } catch (e: ReflectiveOperationException) { - e.printStackTrace() + if (!this::setProfile.isInitialized) { + setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java) + setProfile.isAccessible = true } + val uuid = UUID( + base64.substring(base64.length - 20).hashCode().toLong(), + base64.substring(base64.length - 10).hashCode().toLong() + ) + val profile = GameProfile(uuid, "eco") + profile.properties.put("textures", Property("textures", base64)) + setProfile.invoke(meta, profile) + } + + override fun getSkullTexture( + meta: SkullMeta + ): String? { + if (!this::profile.isInitialized) { + profile = meta.javaClass.getDeclaredField("profile") + profile.isAccessible = true + } + val profile = profile[meta] as GameProfile? + val property = profile?.properties?.get("textures") as Property? + return property?.value } } \ No newline at end of file diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/spigot/EcoSpigotPlugin.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/spigot/EcoSpigotPlugin.kt index b96ec6ff..552c88e0 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/spigot/EcoSpigotPlugin.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/spigot/EcoSpigotPlugin.kt @@ -46,7 +46,10 @@ abstract class EcoSpigotPlugin : EcoPlugin( Display.setFinalizeKey(namespacedKeyFactory.create("finalized")) val skullProxy = getProxy(SkullProxy::class.java) - SkullUtils.initialize { meta: SkullMeta, base64: String -> skullProxy.setSkullTexture(meta, base64) } + SkullUtils.initialize( + { meta: SkullMeta, base64: String -> skullProxy.setSkullTexture(meta, base64) }, + { meta: SkullMeta -> skullProxy.getSkullTexture(meta) } + ) val blockBreakProxy = getProxy(BlockBreakProxy::class.java) BlockUtils.initialize { player: Player, block: Block -> blockBreakProxy.breakBlock(player, block) } diff --git a/eco-core/core-proxy/src/main/kotlin/com/willfp/eco/proxy/SkullProxy.kt b/eco-core/core-proxy/src/main/kotlin/com/willfp/eco/proxy/SkullProxy.kt index 1190f081..c02d5241 100644 --- a/eco-core/core-proxy/src/main/kotlin/com/willfp/eco/proxy/SkullProxy.kt +++ b/eco-core/core-proxy/src/main/kotlin/com/willfp/eco/proxy/SkullProxy.kt @@ -8,4 +8,8 @@ interface SkullProxy : AbstractProxy { meta: SkullMeta, base64: String ) + + fun getSkullTexture( + meta: SkullMeta + ): String? } \ No newline at end of file