diff --git a/config/checkstyle/suppression.xml b/config/checkstyle/suppression.xml index afd1b233..343b3f35 100644 --- a/config/checkstyle/suppression.xml +++ b/config/checkstyle/suppression.xml @@ -5,6 +5,10 @@ "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd"> + + + + diff --git a/eco-api/src/main/java/com/willfp/eco/internal/fast/AbstractFastItemStackHandler.java b/eco-api/src/main/java/com/willfp/eco/internal/fast/AbstractFastItemStackHandler.java new file mode 100644 index 00000000..434baf7a --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/internal/fast/AbstractFastItemStackHandler.java @@ -0,0 +1,40 @@ +package com.willfp.eco.internal.fast; + +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public interface AbstractFastItemStackHandler { + Map getEnchantments(); + + int getEnchantmentLevel(@NotNull Enchantment enchantment); + + List getLore(); + + void setLore(@NotNull List lore); + + Set getItemFlags(); + + void setItemFlags(@NotNull Set flags); + + void writePersistentKey(@NotNull NamespacedKey key, + @NotNull PersistentDataType type, + @NotNull Z value); + + Z readPersistentKey(@NotNull NamespacedKey key, + @NotNull PersistentDataType type); + + Set getPersistentKeys(); + + String getDisplayName(); + + void setDisplayName(@NotNull String name); + + void apply(); +} diff --git a/eco-api/src/main/java/com/willfp/eco/internal/fast/FastItemStackHandlerFactory.java b/eco-api/src/main/java/com/willfp/eco/internal/fast/FastItemStackHandlerFactory.java new file mode 100644 index 00000000..503cc362 --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/internal/fast/FastItemStackHandlerFactory.java @@ -0,0 +1,14 @@ +package com.willfp.eco.internal.fast; + +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +public interface FastItemStackHandlerFactory { + /** + * Create new FastItemStackHandler. + * + * @param itemStack The ItemStack to handle. + * @return The handler. + */ + AbstractFastItemStackHandler create(@NotNull ItemStack itemStack); +} diff --git a/eco-api/src/main/java/com/willfp/eco/util/fast/FastItemStack.java b/eco-api/src/main/java/com/willfp/eco/util/fast/FastItemStack.java new file mode 100644 index 00000000..4a0101c9 --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/util/fast/FastItemStack.java @@ -0,0 +1,164 @@ +package com.willfp.eco.util.fast; + +import com.willfp.eco.internal.fast.AbstractFastItemStackHandler; +import com.willfp.eco.internal.fast.FastItemStackHandlerFactory; +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class FastItemStack { + /** + * The ItemStack handler. + */ + private static FastItemStackHandlerFactory factory; + + /** + * The ItemStack to interface with. + */ + private final AbstractFastItemStackHandler handle; + + /** + * Create a new fast ItemStack. + * + * @param itemStack The ItemStack. + */ + public FastItemStack(@NotNull final ItemStack itemStack) { + this.handle = factory.create(itemStack); + } + + /** + * Get the enchantments on the item. + * + * @return The enchantments. + */ + public Map getEnchantments() { + return handle.getEnchantments(); + } + + /** + * Get the level of a specific enchantment. + * + * @param enchantment The enchantments. + * @return The level, or 0 if not found. + */ + public int getEnchantmentLevel(@NotNull final Enchantment enchantment) { + return handle.getEnchantmentLevel(enchantment); + } + + /** + * Get the lore of an item. + * + * @return The lore. + */ + public List getLore() { + return handle.getLore(); + } + + /** + * Set the lore of an item. + * + * @param lore The lore. + */ + public void setLore(@NotNull final List lore) { + handle.setLore(lore); + } + + /** + * Get the item flags on an item. + * + * @return The item flags. + */ + public Set getItemFlags() { + return handle.getItemFlags(); + } + + /** + * Set the item flags on an item. + * + * @param flags The flags. + */ + public void setItemFlags(@NotNull final Set flags) { + handle.setItemFlags(flags); + } + + /** + * Write a key in persistent meta. + * + * @param key The key. + * @param type The type. + * @param value The value. + * @param The type. + * @param The type. + */ + public void writePersistentKey(@NotNull final NamespacedKey key, + @NotNull final PersistentDataType type, + @NotNull final Z value) { + handle.writePersistentKey(key, type, value); + } + + /** + * Read a key from persistent meta. + * + * @param key The key. + * @param type The type. + * @param The type. + * @param The type. + * @return The value. + */ + public Z readPersistentKey(@NotNull final NamespacedKey key, + @NotNull final PersistentDataType type) { + return handle.readPersistentKey(key, type); + } + + /** + * Get persistent meta keys. + * + * @return The keys. + */ + public Set getPersistentKeys() { + return handle.getPersistentKeys(); + } + + /** + * Get the display name + * + * @return The display name. + */ + public String getDisplayName() { + return handle.getDisplayName(); + } + + /** + * Set the display name. + * + * @param name The name. + */ + public void setDisplayName(@NotNull final String name) { + handle.setDisplayName(name); + } + + /** + * Apply changes. + */ + public void apply() { + handle.apply(); + } + + /** + * Initialize the ItemStack handler factory. + * + * @param handlerFactory The handler factory. + */ + @ApiStatus.Internal + public static void initialize(@NotNull final FastItemStackHandlerFactory handlerFactory) { + factory = handlerFactory; + } +} diff --git a/eco-core/core-nms/v1_16_R3/src/main/java/com/willfp/eco/proxy/v1_16_R3/FastItemStackHandlerFactory.java b/eco-core/core-nms/v1_16_R3/src/main/java/com/willfp/eco/proxy/v1_16_R3/FastItemStackHandlerFactory.java new file mode 100644 index 00000000..94b7a5c6 --- /dev/null +++ b/eco-core/core-nms/v1_16_R3/src/main/java/com/willfp/eco/proxy/v1_16_R3/FastItemStackHandlerFactory.java @@ -0,0 +1,49 @@ +package com.willfp.eco.proxy.v1_16_R3; + +import com.willfp.eco.internal.fast.AbstractFastItemStackHandler; +import com.willfp.eco.proxy.proxies.FastItemStackHandlerFactoryProxy; +import com.willfp.eco.proxy.v1_16_R3.fast.FastItemStackHandler; +import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Field; + +public class FastItemStackHandlerFactory implements FastItemStackHandlerFactoryProxy { + /** + * The field to get the handle without a copy. + */ + private static final Field HANDLE_FIELD; + + @Override + public AbstractFastItemStackHandler create(@NotNull final ItemStack itemStack) { + return new FastItemStackHandler(get(itemStack)); + } + + /** + * Get from field. + * + * @param itemStack The ItemStack. + * @return The NMS ItemStack. + */ + public net.minecraft.server.v1_16_R3.ItemStack get(@NotNull final ItemStack itemStack) { + try { + return (net.minecraft.server.v1_16_R3.ItemStack) HANDLE_FIELD.get(itemStack); + } catch (ReflectiveOperationException e) { + e.printStackTrace(); + } + + return null; + } + + static { + Field handle = null; + try { + handle = CraftItemStack.class.getDeclaredField("handle"); + handle.setAccessible(true); + } catch (ReflectiveOperationException e) { + e.printStackTrace(); + } + HANDLE_FIELD = handle; + } +} diff --git a/eco-core/core-nms/v1_16_R3/src/main/java/com/willfp/eco/proxy/v1_16_R3/fast/FastItemStackHandler.java b/eco-core/core-nms/v1_16_R3/src/main/java/com/willfp/eco/proxy/v1_16_R3/fast/FastItemStackHandler.java new file mode 100644 index 00000000..f9988386 --- /dev/null +++ b/eco-core/core-nms/v1_16_R3/src/main/java/com/willfp/eco/proxy/v1_16_R3/fast/FastItemStackHandler.java @@ -0,0 +1,163 @@ +package com.willfp.eco.proxy.v1_16_R3.fast; + +import com.willfp.eco.internal.fast.AbstractFastItemStackHandler; +import net.minecraft.server.v1_16_R3.NBTBase; +import net.minecraft.server.v1_16_R3.NBTTagCompound; +import net.minecraft.server.v1_16_R3.NBTTagList; +import net.minecraft.server.v1_16_R3.NBTTagString; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.v1_16_R3.util.CraftChatMessage; +import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.v1_16_R3.util.CraftNamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class FastItemStackHandler implements AbstractFastItemStackHandler { + /** + * The ItemStack. + */ + private final net.minecraft.server.v1_16_R3.ItemStack itemStack; + + /** + * The nbt tag. + */ + private final NBTTagCompound tag; + + /** + * Create new FastItemStack handler. + * + * @param itemStack The ItemStack. + */ + public FastItemStackHandler(@NotNull final net.minecraft.server.v1_16_R3.ItemStack itemStack) { + this.itemStack = itemStack; + + this.tag = itemStack.getOrCreateTag(); + } + + + @Override + public Map getEnchantments() { + NBTTagList enchantmentNBT = itemStack.getEnchantments(); + HashMap foundEnchantments = new HashMap<>(); + + for (NBTBase base : enchantmentNBT) { + NBTTagCompound compound = (NBTTagCompound) base; + String key = compound.getString("id"); + int level = '\uffff' & compound.getShort("lvl"); + + Enchantment found = Enchantment.getByKey(CraftNamespacedKey.fromStringOrNull(key)); + if (found != null) { + foundEnchantments.put(found, level); + } + } + + return foundEnchantments; + } + + @Override + public int getEnchantmentLevel(@NotNull final Enchantment enchantment) { + NBTTagList enchantmentNBT = itemStack.getEnchantments(); + + for (NBTBase base : enchantmentNBT) { + NBTTagCompound compound = (NBTTagCompound) base; + String key = compound.getString("id"); + if (!key.equals(enchantment.getKey().toString())) { + continue; + } + + return '\uffff' & compound.getShort("lvl"); + } + return 0; + } + + @Override + public List getLore() { + if (tag.hasKey("Lore")) { + NBTTagList list = tag.getList("Lore", CraftMagicNumbers.NBT.TAG_STRING); + List lore = new ArrayList<>(list.size()); + + for (int index = 0; index < list.size(); index++) { + String line = list.getString(index); + lore.add(CraftChatMessage.fromJSONComponent(line)); + } + + return lore; + } else { + return new ArrayList<>(); + } + } + + @Override + public void setLore(@NotNull final List lore) { + NBTTagList tagList = new NBTTagList(); + for (String value : lore) { + tagList.add(NBTTagString.a(CraftChatMessage.fromJSONComponent(value))); + } + + setDisplayTag("Lore", tagList); + } + + @Override + public Set getItemFlags() { + return null; + } + + @Override + public void setItemFlags(@NotNull final Set flags) { + + } + + @Override + public void writePersistentKey(@NotNull final NamespacedKey key, + @NotNull final PersistentDataType type, + @NotNull final Z value) { + + } + + @Override + public Z readPersistentKey(@NotNull final NamespacedKey key, + @NotNull final PersistentDataType type) { + return null; + } + + @Override + public Set getPersistentKeys() { + return null; + } + + @Override + public String getDisplayName() { + return CraftChatMessage.fromComponent(itemStack.getName()); + } + + @Override + public void setDisplayName(@NotNull final String name) { + itemStack.a(CraftChatMessage.fromStringOrNull(name)); + } + + @Override + public void apply() { + itemStack.setTag(tag); + } + + private NBTTagCompound getDisplayTag(@NotNull final NBTTagCompound base) { + return base.getCompound("display"); + } + + private void setDisplayTag(@NotNull final String key, + @NotNull final NBTBase value) { + final NBTTagCompound display = tag.getCompound("display"); + + display.set(key, value); + + tag.set("display", display); + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/eco/spigot/EcoPlugin.java b/eco-core/core-plugin/src/main/java/com/willfp/eco/spigot/EcoPlugin.java index d190d990..a57ea5ba 100644 --- a/eco-core/core-plugin/src/main/java/com/willfp/eco/spigot/EcoPlugin.java +++ b/eco-core/core-plugin/src/main/java/com/willfp/eco/spigot/EcoPlugin.java @@ -2,6 +2,7 @@ package com.willfp.eco.spigot; import com.willfp.eco.proxy.proxies.BlockBreakProxy; import com.willfp.eco.proxy.proxies.CooldownProxy; +import com.willfp.eco.proxy.proxies.FastItemStackHandlerFactoryProxy; import com.willfp.eco.proxy.proxies.SkullProxy; import com.willfp.eco.proxy.proxies.TridentStackProxy; import com.willfp.eco.spigot.display.PacketAutoRecipe; @@ -11,6 +12,8 @@ import com.willfp.eco.spigot.display.PacketSetCreativeSlot; import com.willfp.eco.spigot.display.PacketSetSlot; import com.willfp.eco.spigot.display.PacketWindowItems; import com.willfp.eco.spigot.drops.CollatedRunnable; +import com.willfp.eco.spigot.eventlisteners.ArmorListener; +import com.willfp.eco.spigot.eventlisteners.DispenserArmorListener; import com.willfp.eco.spigot.eventlisteners.EntityDeathByEntityListeners; import com.willfp.eco.spigot.eventlisteners.NaturalExpGainListeners; import com.willfp.eco.spigot.integrations.anticheat.AnticheatAAC; @@ -33,8 +36,7 @@ import com.willfp.eco.util.TridentUtils; import com.willfp.eco.util.command.AbstractCommand; import com.willfp.eco.util.display.Display; import com.willfp.eco.util.display.DisplayModule; -import com.willfp.eco.spigot.eventlisteners.ArmorListener; -import com.willfp.eco.spigot.eventlisteners.DispenserArmorListener; +import com.willfp.eco.util.fast.FastItemStack; import com.willfp.eco.util.integrations.IntegrationLoader; import com.willfp.eco.util.integrations.anticheat.AnticheatManager; import com.willfp.eco.util.integrations.antigrief.AntigriefManager; @@ -66,6 +68,7 @@ public class EcoPlugin extends com.willfp.eco.util.plugin.EcoPlugin { BlockUtils.initialize(((player, block) -> InternalProxyUtils.getProxy(BlockBreakProxy.class).breakBlock(player, block))); PlayerUtils.initialize(((player) -> InternalProxyUtils.getProxy(CooldownProxy.class).getAttackCooldown(player))); TridentUtils.initialize(((trident) -> InternalProxyUtils.getProxy(TridentStackProxy.class).getTridentStack(trident))); + FastItemStack.initialize(InternalProxyUtils.getProxy(FastItemStackHandlerFactoryProxy.class)); } @Override diff --git a/eco-core/core-proxy/src/main/java/com/willfp/eco/proxy/proxies/FastItemStackHandlerFactoryProxy.java b/eco-core/core-proxy/src/main/java/com/willfp/eco/proxy/proxies/FastItemStackHandlerFactoryProxy.java new file mode 100644 index 00000000..39c49855 --- /dev/null +++ b/eco-core/core-proxy/src/main/java/com/willfp/eco/proxy/proxies/FastItemStackHandlerFactoryProxy.java @@ -0,0 +1,7 @@ +package com.willfp.eco.proxy.proxies; + +import com.willfp.eco.internal.fast.FastItemStackHandlerFactory; +import com.willfp.eco.util.proxy.AbstractProxy; + +public interface FastItemStackHandlerFactoryProxy extends AbstractProxy, FastItemStackHandlerFactory { +}