diff --git a/README.md b/README.md index 086fb8cb..3114415f 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ and many more. # For server owners - Requires ProtocolLib to be installed: get the latest version [here](https://www.spigotmc.org/resources/protocollib.1997/) -- Supports 1.16.5+ +- Supports 1.17+ ## Downloads diff --git a/build.gradle.kts b/build.gradle.kts index 26fd2a24..61da86a5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,7 +21,6 @@ dependencies { implementation(project(":eco-core:core-plugin")) implementation(project(":eco-core:core-proxy")) implementation(project(":eco-core:core-backend")) - implementation(project(":eco-core:core-nms:v1_16_R3")) implementation(project(path = ":eco-core:core-nms:v1_17_R1", configuration = "reobf")) implementation(project(path = ":eco-core:core-nms:v1_18_R1", configuration = "reobf")) } diff --git a/eco-api/src/main/java/com/willfp/eco/core/Prerequisite.java b/eco-api/src/main/java/com/willfp/eco/core/Prerequisite.java index 223bc1d0..1006138a 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/Prerequisite.java +++ b/eco-api/src/main/java/com/willfp/eco/core/Prerequisite.java @@ -51,7 +51,10 @@ public class Prerequisite { /** * Requires the server to be running 1.17. + * + * @deprecated eco no longer supports versions before 1.17. */ + @Deprecated(since = "6.25.2") public static final Prerequisite HAS_1_17 = new Prerequisite( () -> ProxyConstants.NMS_VERSION.contains("17") || HAS_1_18.isMet(), "Requires server to be running 1.17+" diff --git a/eco-api/src/main/java/com/willfp/eco/core/data/keys/KeyRegistry.java b/eco-api/src/main/java/com/willfp/eco/core/data/keys/KeyRegistry.java index 3827eab1..f1ed8713 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/data/keys/KeyRegistry.java +++ b/eco-api/src/main/java/com/willfp/eco/core/data/keys/KeyRegistry.java @@ -1,12 +1,18 @@ package com.willfp.eco.core.data.keys; +import com.willfp.eco.core.Eco; +import org.bukkit.NamespacedKey; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Set; /** * API to register persistent data keys. */ +@ApiStatus.Internal +@Eco.HandlerComponent public interface KeyRegistry { /** * Register a persistent data key to be stored. @@ -21,4 +27,37 @@ public interface KeyRegistry { * @return The keys. */ Set> getRegisteredKeys(); + + /** + * Mark key as category. + * + * @param key The key. + * @param category The category. + */ + void markKeyAs(@NotNull PersistentDataKey key, + @NotNull KeyRegistry.KeyCategory category); + + /** + * Get persistent data key from namespaced key. + * + * @param namespacedKey The key. + * @return The key, or null if not found. + */ + @Nullable + PersistentDataKey getKeyFrom(@NotNull NamespacedKey namespacedKey); + + /** + * Locations for key categorization. + */ + enum KeyCategory { + /** + * Player keys. + */ + PLAYER, + + /** + * Server keys. + */ + SERVER + } } diff --git a/eco-api/src/main/java/com/willfp/eco/core/data/keys/PersistentDataKey.java b/eco-api/src/main/java/com/willfp/eco/core/data/keys/PersistentDataKey.java index fd1a5f01..35f26e95 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/data/keys/PersistentDataKey.java +++ b/eco-api/src/main/java/com/willfp/eco/core/data/keys/PersistentDataKey.java @@ -3,7 +3,9 @@ package com.willfp.eco.core.data.keys; import com.willfp.eco.core.Eco; import org.bukkit.NamespacedKey; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.Objects; import java.util.Set; /** @@ -11,7 +13,7 @@ import java.util.Set; * * @param The type of the data. */ -public class PersistentDataKey { +public final class PersistentDataKey { /** * The key of the persistent data value. */ @@ -80,6 +82,32 @@ public class PersistentDataKey { return this.type; } + /** + * Categorize key as a server key, will register new column to MySQL + * database immediately rather than waiting for auto-categorization. + *

+ * This will improve performance. + * + * @return The key. + */ + public PersistentDataKey server() { + Eco.getHandler().getKeyRegistry().markKeyAs(this, KeyRegistry.KeyCategory.SERVER); + return this; + } + + /** + * Categorize key as a player key, will register new column to MySQL + * database immediately rather than waiting for auto-categorization. + *

+ * This will improve performance. + * + * @return The key. + */ + public PersistentDataKey player() { + Eco.getHandler().getKeyRegistry().markKeyAs(this, KeyRegistry.KeyCategory.PLAYER); + return this; + } + /** * Get all persistent data keys. * @@ -88,4 +116,20 @@ public class PersistentDataKey { public static Set> values() { return Eco.getHandler().getKeyRegistry().getRegisteredKeys(); } + + @Override + public boolean equals(@Nullable final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof PersistentDataKey that)) { + return false; + } + return Objects.equals(this.getKey(), that.getKey()); + } + + @Override + public int hashCode() { + return Objects.hash(this.getKey()); + } } diff --git a/eco-api/src/main/java/com/willfp/eco/util/TeamUtils.java b/eco-api/src/main/java/com/willfp/eco/util/TeamUtils.java index c40c2458..49b85e71 100644 --- a/eco-api/src/main/java/com/willfp/eco/util/TeamUtils.java +++ b/eco-api/src/main/java/com/willfp/eco/util/TeamUtils.java @@ -2,7 +2,6 @@ package com.willfp.eco.util; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; -import com.willfp.eco.core.Prerequisite; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -91,17 +90,15 @@ public final class TeamUtils { MATERIAL_COLORS.put(Material.EMERALD_ORE, ChatColor.GREEN); MATERIAL_COLORS.put(Material.ANCIENT_DEBRIS, ChatColor.DARK_RED); - if (Prerequisite.HAS_1_17.isMet()) { - MATERIAL_COLORS.put(Material.COPPER_ORE, ChatColor.GOLD); - MATERIAL_COLORS.put(Material.DEEPSLATE_COPPER_ORE, ChatColor.GOLD); - MATERIAL_COLORS.put(Material.DEEPSLATE_COAL_ORE, ChatColor.BLACK); - MATERIAL_COLORS.put(Material.DEEPSLATE_IRON_ORE, ChatColor.GRAY); - MATERIAL_COLORS.put(Material.DEEPSLATE_GOLD_ORE, ChatColor.YELLOW); - MATERIAL_COLORS.put(Material.DEEPSLATE_LAPIS_ORE, ChatColor.BLUE); - MATERIAL_COLORS.put(Material.DEEPSLATE_REDSTONE_ORE, ChatColor.RED); - MATERIAL_COLORS.put(Material.DEEPSLATE_DIAMOND_ORE, ChatColor.AQUA); - MATERIAL_COLORS.put(Material.DEEPSLATE_EMERALD_ORE, ChatColor.GREEN); - } + MATERIAL_COLORS.put(Material.COPPER_ORE, ChatColor.GOLD); + MATERIAL_COLORS.put(Material.DEEPSLATE_COPPER_ORE, ChatColor.GOLD); + MATERIAL_COLORS.put(Material.DEEPSLATE_COAL_ORE, ChatColor.BLACK); + MATERIAL_COLORS.put(Material.DEEPSLATE_IRON_ORE, ChatColor.GRAY); + MATERIAL_COLORS.put(Material.DEEPSLATE_GOLD_ORE, ChatColor.YELLOW); + MATERIAL_COLORS.put(Material.DEEPSLATE_LAPIS_ORE, ChatColor.BLUE); + MATERIAL_COLORS.put(Material.DEEPSLATE_REDSTONE_ORE, ChatColor.RED); + MATERIAL_COLORS.put(Material.DEEPSLATE_DIAMOND_ORE, ChatColor.AQUA); + MATERIAL_COLORS.put(Material.DEEPSLATE_EMERALD_ORE, ChatColor.GREEN); } private TeamUtils() { diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/proxy/EcoProxyFactory.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/proxy/EcoProxyFactory.kt index fc8cbc7f..4b7c296c 100644 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/proxy/EcoProxyFactory.kt +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/proxy/EcoProxyFactory.kt @@ -77,7 +77,6 @@ class EcoProxyFactory( companion object { val SUPPORTED_VERSIONS = listOf( - "v1_16_R3", "v1_17_R1", "v1_18_R1" ) diff --git a/eco-core/core-nms/v1_16_R3/build.gradle b/eco-core/core-nms/v1_16_R3/build.gradle deleted file mode 100644 index aa9e602b..00000000 --- a/eco-core/core-nms/v1_16_R3/build.gradle +++ /dev/null @@ -1,6 +0,0 @@ -group 'com.willfp' -version rootProject.version - -dependencies { - compileOnly 'org.spigotmc:spigot:1.16.5-R0.1-SNAPSHOT' -} \ No newline at end of file diff --git a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/AutoCraft.kt b/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/AutoCraft.kt deleted file mode 100644 index 8168a246..00000000 --- a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/AutoCraft.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.willfp.eco.internal.spigot.proxy.v1_16_R3 -import com.willfp.eco.internal.spigot.proxy.AutoCraftProxy -import net.minecraft.server.v1_16_R3.MinecraftKey -import net.minecraft.server.v1_16_R3.PacketPlayOutAutoRecipe - -class AutoCraft : AutoCraftProxy { - override fun modifyPacket(packet: Any) { - val recipePacket = packet as PacketPlayOutAutoRecipe - val fKey = recipePacket.javaClass.getDeclaredField("b") - fKey.isAccessible = true - val key = fKey[recipePacket] as MinecraftKey - fKey[recipePacket] = MinecraftKey(key.namespace, key.key + "_displayed") - } -} \ No newline at end of file diff --git a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/BlockBreak.kt b/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/BlockBreak.kt deleted file mode 100644 index 32825338..00000000 --- a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/BlockBreak.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.willfp.eco.internal.spigot.proxy.v1_16_R3 -import com.willfp.eco.internal.spigot.proxy.BlockBreakProxy -import net.minecraft.server.v1_16_R3.BlockPosition -import org.bukkit.block.Block -import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer -import org.bukkit.entity.Player - -class BlockBreak : BlockBreakProxy { - override fun breakBlock( - player: Player, - block: Block - ) { - if (player !is CraftPlayer) { - return - } - player.handle.playerInteractManager.breakBlock(BlockPosition(block.x, block.y, block.z)) - } -} \ No newline at end of file diff --git a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/ChatComponent.kt b/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/ChatComponent.kt deleted file mode 100644 index 04625e0d..00000000 --- a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/ChatComponent.kt +++ /dev/null @@ -1,93 +0,0 @@ -package com.willfp.eco.internal.spigot.proxy.v1_16_R3 - -import com.willfp.eco.core.display.Display -import com.willfp.eco.internal.spigot.proxy.ChatComponentProxy -import net.kyori.adventure.nbt.api.BinaryTagHolder -import net.kyori.adventure.text.BuildableComponent -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.TranslatableComponent -import net.kyori.adventure.text.event.HoverEvent -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer -import net.minecraft.server.v1_16_R3.IChatBaseComponent -import net.minecraft.server.v1_16_R3.MojangsonParser -import org.bukkit.Material -import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack -import org.bukkit.entity.Player - -@Suppress("UNCHECKED_CAST") -class ChatComponent : ChatComponentProxy { - private val gsonComponentSerializer = GsonComponentSerializer.gson() - - override fun modifyComponent(obj: Any, player: Player): Any { - if (obj !is IChatBaseComponent) { - return obj - } - - val component = gsonComponentSerializer.deserialize( - IChatBaseComponent.ChatSerializer.a( - obj - ) - ).asComponent() as BuildableComponent<*, *> - - val newComponent = modifyBaseComponent(component, player) - - return IChatBaseComponent.ChatSerializer.a( - gsonComponentSerializer.serialize(newComponent.asComponent()) - ) ?: obj - } - - private fun modifyBaseComponent(baseComponent: Component, player: Player): Component { - var component = baseComponent - - if (component is TranslatableComponent) { - val args = mutableListOf() - for (arg in component.args()) { - args.add(modifyBaseComponent(arg, player)) - } - component = component.args(args) - } - - val children = mutableListOf() - for (child in component.children()) { - children.add(modifyBaseComponent(child, player)) - } - component = component.children(children) - - val hoverEvent: HoverEvent = component.style().hoverEvent() as HoverEvent? ?: return component - - val showItem = hoverEvent.value() - - if (showItem !is HoverEvent.ShowItem) { - return component - } - - val newShowItem = showItem.nbt( - BinaryTagHolder.of( - CraftItemStack.asNMSCopy( - Display.display( - CraftItemStack.asBukkitCopy( - CraftItemStack.asNMSCopy( - org.bukkit.inventory.ItemStack( - Material.matchMaterial( - showItem.item() - .toString() - ) ?: return component, - showItem.count() - ) - ).apply { - this.tag = MojangsonParser.parse( - showItem.nbt()?.string() ?: return component - ) ?: return component - } - ), - player - ) - ).orCreateTag.toString() - ) - ) - - val newHover = hoverEvent.value(newShowItem) - val style = component.style().hoverEvent(newHover) - return component.style(style) - } -} \ No newline at end of file diff --git a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/DummyEntity.kt b/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/DummyEntity.kt deleted file mode 100644 index 3ba96fe7..00000000 --- a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/DummyEntity.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.willfp.eco.internal.spigot.proxy.v1_16_R3 - -import com.willfp.eco.internal.spigot.proxy.DummyEntityProxy -import org.bukkit.Location -import org.bukkit.craftbukkit.v1_16_R3.CraftWorld -import org.bukkit.entity.Entity -import org.bukkit.entity.EntityType - -class DummyEntity : DummyEntityProxy { - override fun createDummyEntity(location: Location): Entity { - val world = location.world as CraftWorld - @Suppress("UsePropertyAccessSyntax") - return world.createEntity(location, EntityType.ZOMBIE.entityClass).getBukkitEntity() - } -} \ No newline at end of file diff --git a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/FastItemStackFactory.kt b/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/FastItemStackFactory.kt deleted file mode 100644 index 453ca91d..00000000 --- a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/FastItemStackFactory.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.willfp.eco.internal.spigot.proxy.v1_16_R3 -import com.willfp.eco.core.fast.FastItemStack -import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy -import com.willfp.eco.internal.spigot.proxy.v1_16_R3.fast.NMSFastItemStack -import org.bukkit.inventory.ItemStack - -class FastItemStackFactory : FastItemStackFactoryProxy { - override fun create(itemStack: ItemStack): FastItemStack { - return NMSFastItemStack(itemStack) - } -} \ No newline at end of file diff --git a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/Skull.kt b/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/Skull.kt deleted file mode 100644 index 093e16f0..00000000 --- a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/Skull.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.willfp.eco.internal.spigot.proxy.v1_16_R3 - -import com.mojang.authlib.GameProfile -import com.mojang.authlib.properties.Property -import com.willfp.eco.internal.spigot.proxy.SkullProxy -import org.bukkit.inventory.meta.SkullMeta -import java.lang.reflect.Field -import java.lang.reflect.Method -import java.util.UUID - -class Skull : SkullProxy { - private lateinit var setProfile: Method - private lateinit var profile: Field - - override fun setSkullTexture( - meta: SkullMeta, - base64: String - ) { - 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? ?: return null - val properties = profile.properties ?: return null - val prop = properties["textures"] ?: return null - return prop.toMutableList().firstOrNull()?.name - } -} \ No newline at end of file diff --git a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/TPS.kt b/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/TPS.kt deleted file mode 100644 index 2229fd82..00000000 --- a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/TPS.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.willfp.eco.internal.spigot.proxy.v1_16_R3 - -import com.willfp.eco.internal.spigot.proxy.TPSProxy -import org.bukkit.Bukkit -import org.bukkit.craftbukkit.v1_16_R3.CraftServer - -class TPS : TPSProxy { - override fun getTPS(): Double { - return (Bukkit.getServer() as CraftServer).handle.server.recentTps[0] - } -} \ No newline at end of file diff --git a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/VillagerTrade.kt b/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/VillagerTrade.kt deleted file mode 100644 index c96e1f86..00000000 --- a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/VillagerTrade.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.willfp.eco.internal.spigot.proxy.v1_16_R3 - -import com.willfp.eco.core.display.Display -import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy -import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftMerchantRecipe -import org.bukkit.entity.Player -import org.bukkit.inventory.MerchantRecipe -import java.lang.reflect.Field - -class VillagerTrade : VillagerTradeProxy { - private val handle: Field = CraftMerchantRecipe::class.java.getDeclaredField("handle") - - override fun displayTrade( - recipe: MerchantRecipe, - player: Player - ): MerchantRecipe { - val oldRecipe = recipe as CraftMerchantRecipe - val newRecipe = CraftMerchantRecipe( - Display.display(recipe.getResult().clone(), player), - recipe.getUses(), - recipe.getMaxUses(), - recipe.hasExperienceReward(), - recipe.getVillagerExperience(), - recipe.getPriceMultiplier() - ) - for (ingredient in recipe.getIngredients()) { - newRecipe.addIngredient(Display.display(ingredient.clone(), player)) - } - getHandle(newRecipe).specialPrice = getHandle(oldRecipe).specialPrice - return newRecipe - } - - private fun getHandle(recipe: CraftMerchantRecipe): net.minecraft.server.v1_16_R3.MerchantRecipe { - return handle[recipe] as net.minecraft.server.v1_16_R3.MerchantRecipe - } - - init { - handle.isAccessible = true - } -} \ No newline at end of file diff --git a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/fast/FastItemStackUtils.kt b/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/fast/FastItemStackUtils.kt deleted file mode 100644 index 76058373..00000000 --- a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/fast/FastItemStackUtils.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.willfp.eco.internal.spigot.proxy.v1_16_R3.fast - -import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack -import org.bukkit.inventory.ItemStack -import java.lang.reflect.Field - -private val field: Field = CraftItemStack::class.java.getDeclaredField("handle").apply { - isAccessible = true -} - -fun ItemStack.getNMSStack(): net.minecraft.server.v1_16_R3.ItemStack { - return if (this !is CraftItemStack) { - CraftItemStack.asNMSCopy(this) - } else { - field[this] as net.minecraft.server.v1_16_R3.ItemStack? ?: CraftItemStack.asNMSCopy(this) - } -} \ No newline at end of file diff --git a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/fast/NMSFastItemStack.kt b/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/fast/NMSFastItemStack.kt deleted file mode 100644 index 736e71f5..00000000 --- a/eco-core/core-nms/v1_16_R3/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_16_R3/fast/NMSFastItemStack.kt +++ /dev/null @@ -1,176 +0,0 @@ -package com.willfp.eco.internal.spigot.proxy.v1_16_R3.fast - -import com.willfp.eco.internal.fast.EcoFastItemStack -import com.willfp.eco.util.NamespacedKeyUtils -import com.willfp.eco.util.StringUtils -import net.minecraft.server.v1_16_R3.Item -import net.minecraft.server.v1_16_R3.ItemEnchantedBook -import net.minecraft.server.v1_16_R3.ItemStack -import net.minecraft.server.v1_16_R3.Items -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.craftbukkit.v1_16_R3.inventory.CraftItemStack -import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers -import org.bukkit.enchantments.Enchantment -import org.bukkit.inventory.ItemFlag -import kotlin.experimental.and - -class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemStack( - itemStack.getNMSStack(), itemStack -) { - private var loreCache: List? = null - override fun getEnchants(checkStored: Boolean): Map { - val enchantmentNBT = if (checkStored && handle.item === Items.ENCHANTED_BOOK) ItemEnchantedBook.d( - handle - ) else handle.enchantments - val foundEnchantments: MutableMap = HashMap() - for (base in enchantmentNBT) { - val compound = base as NBTTagCompound - val key = compound.getString("id") - val level: Int = ('\uffff'.code.toShort() and compound.getShort("lvl")).toInt() - val found = Enchantment.getByKey(NamespacedKeyUtils.fromStringOrNull(key)) - if (found != null) { - foundEnchantments[found] = level - } - } - return foundEnchantments - } - - override fun getLevelOnItem( - enchantment: Enchantment, - checkStored: Boolean - ): Int { - val enchantmentNBT = if (checkStored && handle.item === Items.ENCHANTED_BOOK) ItemEnchantedBook.d( - handle - ) else handle.enchantments - for (base in enchantmentNBT) { - val compound = base as NBTTagCompound - val key = compound.getString("id") - if (key != enchantment.key.toString()) { - continue - } - return ('\uffff'.code.toShort() and compound.getShort("lvl")).toInt() - } - return 0 - } - - override fun setLore(lore: List?) { - loreCache = null - val jsonLore: MutableList = ArrayList() - if (lore != null) { - for (s in lore) { - jsonLore.add(StringUtils.legacyToJson(s)) - } - } - val displayTag = handle.a("display") - if (!displayTag.hasKey("Lore")) { - displayTag["Lore"] = NBTTagList() - } - val loreTag = displayTag.getList("Lore", CraftMagicNumbers.NBT.TAG_STRING) - loreTag.clear() - for (s in jsonLore) { - loreTag.add(NBTTagString.a(s)) - } - apply() - } - - override fun getLore(): List { - if (loreCache != null) { - return loreCache as List - } - val lore: MutableList = ArrayList() - for (s in getLoreJSON()) { - lore.add(StringUtils.jsonToLegacy(s)) - } - loreCache = lore - return lore - } - - private fun getLoreJSON(): List { - val displayTag = handle.b("display") ?: return emptyList() - return if (displayTag.hasKey("Lore")) { - val loreTag = displayTag.getList("Lore", CraftMagicNumbers.NBT.TAG_STRING) - val lore: MutableList = ArrayList(loreTag.size) - for (i in loreTag.indices) { - lore.add(loreTag.getString(i)) - } - lore - } else { - emptyList() - } - } - - override fun addItemFlags(vararg hideFlags: ItemFlag) { - for (flag in hideFlags) { - this.flagBits = this.flagBits or getBitModifier(flag) - } - - apply() - } - - override fun removeItemFlags(vararg hideFlags: ItemFlag) { - for (flag in hideFlags) { - this.flagBits = this.flagBits and getBitModifier(flag) - } - - apply() - } - - override fun getItemFlags(): MutableSet { - val flags = mutableSetOf() - - var flagArr: Array - val size = ItemFlag.values().also { flagArr = it }.size - - for (i in 0 until size) { - val flag = flagArr[i] - if (this.hasItemFlag(flag)) { - flags.add(flag) - } - } - - return flags - } - - override fun hasItemFlag(flag: ItemFlag): Boolean { - val bitModifier = getBitModifier(flag) - return this.flagBits and bitModifier == bitModifier - } - - private var flagBits: Int - get() = - if (handle.hasTag() && handle.tag!!.hasKeyOfType( - "HideFlags", - 99 - ) - ) handle.tag!!.getInt("HideFlags") else 0 - set(value) = - handle.orCreateTag.setInt("HideFlags", value) - - override fun getRepairCost(): Int { - return handle.repairCost - } - - override fun setRepairCost(cost: Int) { - handle.repairCost = cost - } - - override fun equals(other: Any?): Boolean { - if (other !is NMSFastItemStack) { - return false - } - - return other.hashCode() == this.hashCode() - } - - override fun hashCode(): Int { - return handle.tag?.hashCode() ?: (0b00010101 * 31 + Item.getId(handle.item)) - } - - private fun apply() { - if (bukkit !is CraftItemStack) { - bukkit.itemMeta = CraftItemStack.asCraftMirror(handle).itemMeta - } - } -} \ No newline at end of file diff --git a/eco-core/core-plugin/build.gradle b/eco-core/core-plugin/build.gradle index f6813a57..808a3df8 100644 --- a/eco-core/core-plugin/build.gradle +++ b/eco-core/core-plugin/build.gradle @@ -30,9 +30,9 @@ dependencies { compileOnly 'com.github.brcdev-minecraft:shopgui-api:2.2.0' compileOnly 'com.github.LoneDev6:API-ItemsAdder:2.4.7' compileOnly 'com.arcaniax:HeadDatabase-API:1.3.0' - compileOnly 'org.jetbrains.exposed:exposed-core:0.36.2' - compileOnly 'org.jetbrains.exposed:exposed-dao:0.36.2' - compileOnly 'org.jetbrains.exposed:exposed-jdbc:0.36.2' + compileOnly 'org.jetbrains.exposed:exposed-core:0.37.3' + compileOnly 'org.jetbrains.exposed:exposed-dao:0.37.3' + compileOnly 'org.jetbrains.exposed:exposed-jdbc:0.37.3' compileOnly 'mysql:mysql-connector-java:8.0.25' compileOnly 'com.zaxxer:HikariCP:5.0.0' compileOnly 'com.gmail.filoghost.holographicdisplays:holographicdisplays-api:2.4.0' diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoHandler.kt index a05c95fa..2c23705e 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoHandler.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoHandler.kt @@ -24,6 +24,7 @@ import com.willfp.eco.internal.integrations.PlaceholderIntegrationPAPI import com.willfp.eco.internal.logging.EcoLogger import com.willfp.eco.internal.proxy.EcoProxyFactory import com.willfp.eco.internal.scheduling.EcoScheduler +import com.willfp.eco.internal.spigot.data.DataYml import com.willfp.eco.internal.spigot.data.EcoKeyRegistry import com.willfp.eco.internal.spigot.data.EcoProfileHandler import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler @@ -38,12 +39,14 @@ import java.util.logging.Logger @Suppress("UNUSED") class EcoHandler : EcoSpigotPlugin(), Handler { + override val dataYml = DataYml(this) + private val cleaner = EcoCleaner() @Suppress("DEPRECATION") private val requirementFactory = com.willfp.eco.internal.requirement.EcoRequirementFactory() private var adventure: BukkitAudiences? = null - private val keyRegistry = EcoKeyRegistry(this) + private val keyRegistry = EcoKeyRegistry() private val playerProfileHandler = EcoProfileHandler(this.configYml.getBool("mysql.enabled"), this) @Suppress("RedundantNullableReturnType") diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt index 01e9354a..1d62f705 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt @@ -47,6 +47,8 @@ import com.willfp.eco.internal.items.ArgParserTexture import com.willfp.eco.internal.items.ArgParserUnbreakable import com.willfp.eco.internal.spigot.arrows.ArrowDataListener import com.willfp.eco.internal.spigot.data.DataListener +import com.willfp.eco.internal.spigot.data.DataYml +import com.willfp.eco.internal.spigot.data.EcoProfileHandler import com.willfp.eco.internal.spigot.data.PlayerBlockListener import com.willfp.eco.internal.spigot.data.storage.ProfileSaver import com.willfp.eco.internal.spigot.display.PacketAutoRecipe @@ -123,6 +125,8 @@ import org.bukkit.event.Listener import org.bukkit.inventory.ItemStack abstract class EcoSpigotPlugin : EcoPlugin() { + abstract val dataYml: DataYml + init { Items.registerArgParser(ArgParserEnchantment()) Items.registerArgParser(ArgParserColor()) @@ -184,10 +188,11 @@ abstract class EcoSpigotPlugin : EcoPlugin() { (Eco.getHandler() as EcoHandler).setAdventure(BukkitAudiences.create(this)) } - this.logger.info("Ignore messages about deprecated events!") - // Init FIS this.getProxy(FastItemStackFactoryProxy::class.java).create(ItemStack(Material.AIR)).unwrap() + + // Preload categorized persistent data keys + (Eco.getHandler().profileHandler as EcoProfileHandler).initialize() } override fun handleDisable() { diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/DataYml.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/DataYml.kt new file mode 100644 index 00000000..89c57f56 --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/DataYml.kt @@ -0,0 +1,14 @@ +package com.willfp.eco.internal.spigot.data + +import com.willfp.eco.core.config.BaseConfig +import com.willfp.eco.core.config.ConfigType +import com.willfp.eco.internal.spigot.EcoSpigotPlugin + +class DataYml( + plugin: EcoSpigotPlugin +) : BaseConfig( + "data", + plugin, + false, + ConfigType.YAML +) diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoKeyRegistry.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoKeyRegistry.kt index 05c76fcc..efbc4c50 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoKeyRegistry.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoKeyRegistry.kt @@ -4,13 +4,11 @@ import com.willfp.eco.core.Eco import com.willfp.eco.core.data.keys.KeyRegistry import com.willfp.eco.core.data.keys.PersistentDataKey import com.willfp.eco.core.data.keys.PersistentDataKeyType -import com.willfp.eco.internal.spigot.EcoSpigotPlugin import org.bukkit.NamespacedKey -class EcoKeyRegistry( - private val plugin: EcoSpigotPlugin -) : KeyRegistry { +class EcoKeyRegistry : KeyRegistry { private val registry = mutableMapOf>() + private val categories = mutableMapOf() override fun registerKey(key: PersistentDataKey<*>) { if (this.registry.containsKey(key.key)) { @@ -20,8 +18,6 @@ class EcoKeyRegistry( validateKey(key) this.registry[key.key] = key - - (Eco.getHandler().profileHandler as EcoProfileHandler).updateKeys() } override fun getRegisteredKeys(): MutableSet> { @@ -46,4 +42,13 @@ class EcoKeyRegistry( else -> throw NullPointerException("Null value found!") } } -} \ No newline at end of file + + override fun markKeyAs(key: PersistentDataKey<*>, category: KeyRegistry.KeyCategory) { + categories[key.key] = category + (Eco.getHandler().profileHandler as EcoProfileHandler).handler.categorize(key, category) // ew + } + + override fun getKeyFrom(namespacedKey: NamespacedKey): PersistentDataKey<*>? { + return registry[namespacedKey] + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoProfile.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoProfile.kt index daba4d9e..fef4e092 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoProfile.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoProfile.kt @@ -65,4 +65,4 @@ class EcoServerProfile( override fun toString(): String { return "EcoServerProfile" } -} \ No newline at end of file +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoProfileHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoProfileHandler.kt index 4655e5a1..83064da0 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoProfileHandler.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoProfileHandler.kt @@ -18,7 +18,7 @@ class EcoProfileHandler( plugin: EcoSpigotPlugin ) : ProfileHandler { private val loaded = mutableMapOf() - private val handler: DataHandler = if (useSql) MySQLDataHandler(plugin, this) else + val handler: DataHandler = if (useSql) MySQLDataHandler(plugin, this) else YamlDataHandler(plugin, this) fun loadGenericProfile(uuid: UUID): Profile { @@ -64,7 +64,7 @@ class EcoProfileHandler( handler.save() } - fun updateKeys() { - handler.updateKeys() + fun initialize() { + handler.initialize() } } \ No newline at end of file diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/KeyHelpers.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/KeyHelpers.kt new file mode 100644 index 00000000..2240ec9b --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/KeyHelpers.kt @@ -0,0 +1,46 @@ +package com.willfp.eco.internal.spigot.data + +import com.willfp.eco.core.data.keys.PersistentDataKey +import com.willfp.eco.core.data.keys.PersistentDataKeyType +import com.willfp.eco.util.NamespacedKeyUtils + +@Suppress("UNCHECKED_CAST") +object KeyHelpers { + fun deserializeFromString(serialized: String): PersistentDataKey<*>? { + val split = serialized.split(";").toTypedArray() + + if (split.size < 2) { + return null + } + + val key = NamespacedKeyUtils.fromStringOrNull(split[0]) ?: return null + val type = PersistentDataKeyType.valueOf(split[1]) ?: return null + return when (type) { + PersistentDataKeyType.STRING -> PersistentDataKey( + key, + type as PersistentDataKeyType, + if (split.size >= 3) split.toList().subList(2, split.size).joinToString("") else "" + ) + PersistentDataKeyType.INT -> PersistentDataKey( + key, + type as PersistentDataKeyType, + split[2].toInt() + ) + PersistentDataKeyType.DOUBLE -> PersistentDataKey( + key, + type as PersistentDataKeyType, + split[2].toDouble() + ) + PersistentDataKeyType.BOOLEAN -> PersistentDataKey( + key, + type as PersistentDataKeyType, + java.lang.Boolean.parseBoolean(split[2]) + ) + else -> null + } + } + + fun serializeToString(key: PersistentDataKey<*>): String { + return "${key.key};${key.type.name()};${key.defaultValue}" + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/DataHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/DataHandler.kt index 309c1a52..72310c8f 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/DataHandler.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/DataHandler.kt @@ -1,25 +1,27 @@ package com.willfp.eco.internal.spigot.data.storage +import com.willfp.eco.core.data.keys.KeyRegistry import com.willfp.eco.core.data.keys.PersistentDataKey import org.bukkit.NamespacedKey import java.util.UUID interface DataHandler { - fun save() { + fun save() + fun saveAll(uuids: Iterable) + + fun categorize(key: PersistentDataKey<*>, category: KeyRegistry.KeyCategory) { } - fun saveAll(uuids: Iterable) - - fun updateKeys() { + fun initialize() { } fun savePlayer(uuid: UUID) { - saveKeysForPlayer(uuid, PersistentDataKey.values()) + saveKeysFor(uuid, PersistentDataKey.values()) } fun write(uuid: UUID, key: NamespacedKey, value: T) - fun saveKeysForPlayer(uuid: UUID, keys: Set>) + fun saveKeysFor(uuid: UUID, keys: Set>) fun read(uuid: UUID, key: NamespacedKey): T? } \ No newline at end of file diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/MySQLDataHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/MySQLDataHandler.kt index 00b6aba5..0c82ab93 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/MySQLDataHandler.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/MySQLDataHandler.kt @@ -1,11 +1,16 @@ package com.willfp.eco.internal.spigot.data.storage +import com.github.benmanes.caffeine.cache.Caffeine import com.google.common.util.concurrent.ThreadFactoryBuilder import com.willfp.eco.core.Eco +import com.willfp.eco.core.EcoPlugin +import com.willfp.eco.core.data.keys.KeyRegistry import com.willfp.eco.core.data.keys.PersistentDataKey import com.willfp.eco.core.data.keys.PersistentDataKeyType import com.willfp.eco.internal.spigot.EcoSpigotPlugin import com.willfp.eco.internal.spigot.data.EcoProfileHandler +import com.willfp.eco.internal.spigot.data.KeyHelpers +import com.willfp.eco.internal.spigot.data.serverProfileUUID import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import org.apache.logging.log4j.Level @@ -26,16 +31,18 @@ import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.update import java.util.UUID import java.util.concurrent.Callable +import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.Executors +import java.util.concurrent.Future +import java.util.concurrent.TimeUnit @Suppress("UNCHECKED_CAST") class MySQLDataHandler( - plugin: EcoSpigotPlugin, - private val handler: EcoProfileHandler + private val plugin: EcoSpigotPlugin, + handler: EcoProfileHandler ) : DataHandler { - private val columns = mutableMapOf>() - private val threadFactory = ThreadFactoryBuilder().setNameFormat("eco-mysql-thread-%d").build() - private val executor = Executors.newFixedThreadPool(plugin.configYml.getInt("mysql.threads"), threadFactory) + private val playerHandler: ImplementedMySQLHandler + private val serverHandler: ImplementedMySQLHandler init { val config = HikariConfig() @@ -50,11 +57,6 @@ class MySQLDataHandler( Database.connect(HikariDataSource(config)) - - transaction { - SchemaUtils.create(Players) - } - // Get Exposed to shut the hell up runCatching { exposedLogger::class.java.getDeclaredField("logger").apply { isAccessible = true } @@ -65,70 +67,205 @@ class MySQLDataHandler( } } } + + playerHandler = ImplementedMySQLHandler( + handler, + UUIDTable("eco_players"), + plugin, + plugin.dataYml.getStrings("categorized-keys.player") + .mapNotNull { KeyHelpers.deserializeFromString(it) } + ) + + serverHandler = ImplementedMySQLHandler( + handler, + UUIDTable("eco_server"), + plugin, + plugin.dataYml.getStrings("categorized-keys.server") + .mapNotNull { KeyHelpers.deserializeFromString(it) } + ) } - override fun updateKeys() { - transaction { - for (key in Eco.getHandler().keyRegistry.registeredKeys) { - registerColumn(key, Players) - } - - SchemaUtils.createMissingTablesAndColumns(Players, withLogs = false) - } + override fun saveAll(uuids: Iterable) { + serverHandler.saveAll(uuids.filter { it == serverProfileUUID }) + playerHandler.saveAll(uuids.filter { it != serverProfileUUID }) } override fun write(uuid: UUID, key: NamespacedKey, value: T) { - getPlayer(uuid) - writeAsserted(uuid, key, value) + applyFor(uuid) { + it.write(uuid, key, value) + } } - private fun writeAsserted(uuid: UUID, key: NamespacedKey, value: T) { - val column: Column = getColumn(key.toString()) as Column + override fun saveKeysFor(uuid: UUID, keys: Set>) { + applyFor(uuid) { + it.saveKeysForRow(uuid, keys) + } + } + + override fun read(uuid: UUID, key: NamespacedKey): T? { + return applyFor(uuid) { + it.read(uuid, key) + } + } + + private inline fun applyFor(uuid: UUID, function: (ImplementedMySQLHandler) -> R): R { + return if (uuid == serverProfileUUID) { + function(serverHandler) + } else { + function(playerHandler) + } + } + + override fun categorize(key: PersistentDataKey<*>, category: KeyRegistry.KeyCategory) { + if (category == KeyRegistry.KeyCategory.SERVER) { + serverHandler.ensureKeyRegistration(key.key) + } else { + playerHandler.ensureKeyRegistration(key.key) + } + } + + override fun save() { + plugin.dataYml.set( + "categorized-keys.player", + playerHandler.registeredKeys.values + .map { KeyHelpers.serializeToString(it) } + ) + plugin.dataYml.set( + "categorized-keys.server", + serverHandler.registeredKeys.values + .map { KeyHelpers.serializeToString(it) } + ) + plugin.dataYml.save() + } + + override fun initialize() { + playerHandler.initialize() + serverHandler.initialize() + } +} + +@Suppress("UNCHECKED_CAST") +private class ImplementedMySQLHandler( + private val handler: EcoProfileHandler, + private val table: UUIDTable, + private val plugin: EcoPlugin, + private val knownKeys: Collection> +) { + private val columns = Caffeine.newBuilder() + .expireAfterWrite(3, TimeUnit.SECONDS) + .build>() + + private val rows = Caffeine.newBuilder() + .expireAfterWrite(3, TimeUnit.SECONDS) + .build() + + private val threadFactory = ThreadFactoryBuilder().setNameFormat("eco-mysql-thread-%d").build() + private val executor = Executors.newFixedThreadPool(plugin.configYml.getInt("mysql.threads"), threadFactory) + val registeredKeys = ConcurrentHashMap>() + private val currentlyProcessingRegistration = ConcurrentHashMap>() + + init { + transaction { + SchemaUtils.create(table) + } + } + + fun initialize() { + transaction { + for (key in knownKeys) { + registerColumn(key, table) + } + + SchemaUtils.createMissingTablesAndColumns(table, withLogs = false) + for (key in knownKeys) { + registeredKeys[key.key] = key + } + } + } + + fun ensureKeyRegistration(key: NamespacedKey) { + if (registeredKeys.contains(key)) { + return + } + + val persistentKey = Eco.getHandler().keyRegistry.getKeyFrom(key) ?: return + + if (table.columns.any { it.name == key.toString() }) { + registeredKeys[key] = persistentKey + return + } + + val future = currentlyProcessingRegistration[key] + + if (future != null) { + future.get() + return + } + + currentlyProcessingRegistration[key] = executor.submit { + transaction { + registerColumn(persistentKey, table) + SchemaUtils.createMissingTablesAndColumns(table, withLogs = false) + } + registeredKeys[key] = persistentKey + currentlyProcessingRegistration.remove(key) + } + } + + fun write(uuid: UUID, key: NamespacedKey, value: T) { + getOrCreateRow(uuid) + doWrite(uuid, key, value) + } + + private fun doWrite(uuid: UUID, key: NamespacedKey, value: T) { + val column: Column = getColumn(key) as Column executor.submit { transaction { - Players.update({ Players.id eq uuid }) { + table.update({ table.id eq uuid }) { it[column] = value } } } } - override fun saveKeysForPlayer(uuid: UUID, keys: Set>) { - savePlayer(uuid, keys) + fun saveKeysForRow(uuid: UUID, keys: Set>) { + saveRow(uuid, keys) } - override fun saveAll(uuids: Iterable) { + fun saveAll(uuids: Iterable) { for (uuid in uuids) { - savePlayer(uuid) + saveRow(uuid, PersistentDataKey.values()) } } - private fun savePlayer(uuid: UUID, keys: Set>) { + private fun saveRow(uuid: UUID, keys: Set>) { val profile = handler.loadGenericProfile(uuid) executor.submit { transaction { - getPlayer(uuid) + getOrCreateRow(uuid) for (key in keys) { - writeAsserted(uuid, key.key, profile.read(key)) + doWrite(uuid, key.key, profile.read(key)) } } } } - override fun read(uuid: UUID, key: NamespacedKey): T? { + fun read(uuid: UUID, key: NamespacedKey): T? { val doRead = Callable { var value: T? = null transaction { - val player = getPlayer(uuid) - value = player[getColumn(key.toString())] as T? + val row = getOrCreateRow(uuid) + value = row[getColumn(key)] as T? } return@Callable value } + ensureKeyRegistration(key) // DON'T DELETE THIS LINE! I know it's covered in getColumn, but I need to do it here as well. + return if (Eco.getHandler().ecoPlugin.configYml.getBool("mysql.async-reads")) { executor.submit(doRead).get() } else { @@ -136,8 +273,6 @@ class MySQLDataHandler( } } - object Players : UUIDTable("eco_players") - private fun registerColumn(key: PersistentDataKey, table: UUIDTable) { table.apply { if (this.columns.stream().anyMatch { it.name == key.key.toString() }) { @@ -159,28 +294,34 @@ class MySQLDataHandler( } } - private fun getColumn(name: String): Column<*> { - val cached = columns[name] - if (cached != null) { - return cached - } + private fun getColumn(key: NamespacedKey): Column<*> { + ensureKeyRegistration(key) - columns[name] = Players.columns.stream().filter { it.name == name }.findFirst().get() - return getColumn(name) + val name = key.toString() + + return columns.get(name) { + table.columns.first { it.name == name } + } } - private fun getPlayer(uuid: UUID): ResultRow { - val player = transaction { - Players.select { Players.id eq uuid }.limit(1).singleOrNull() - } - - return if (player != null) { - player - } else { - transaction { - Players.insert { it[id] = uuid } + private fun getOrCreateRow(uuid: UUID): ResultRow { + fun select(uuid: UUID): ResultRow? { + return transaction { + table.select { table.id eq uuid }.limit(1).singleOrNull() + } + } + + return rows.get(uuid) { + val row = select(uuid) + + return@get if (row != null) { + row + } else { + transaction { + table.insert { it[id] = uuid } + } + select(uuid) } - getPlayer(uuid) } } -} \ No newline at end of file +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/YamlDataHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/YamlDataHandler.kt index dbd6f08b..bd470c30 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/YamlDataHandler.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/storage/YamlDataHandler.kt @@ -1,7 +1,5 @@ package com.willfp.eco.internal.spigot.data.storage -import com.willfp.eco.core.config.BaseConfig -import com.willfp.eco.core.config.ConfigType import com.willfp.eco.core.data.keys.PersistentDataKey import com.willfp.eco.internal.spigot.EcoSpigotPlugin import com.willfp.eco.internal.spigot.data.EcoProfileHandler @@ -13,7 +11,7 @@ class YamlDataHandler( plugin: EcoSpigotPlugin, private val handler: EcoProfileHandler ) : DataHandler { - private val dataYml = DataYml(plugin) + private val dataYml = plugin.dataYml override fun save() { dataYml.save() @@ -27,7 +25,7 @@ class YamlDataHandler( save() } - override fun saveKeysForPlayer(uuid: UUID, keys: Set>) { + override fun saveKeysFor(uuid: UUID, keys: Set>) { val profile = handler.loadGenericProfile(uuid) for (key in keys) { @@ -42,13 +40,4 @@ class YamlDataHandler( override fun read(uuid: UUID, key: NamespacedKey): T? { return dataYml.get("player.$uuid.$key") as T? } - - class DataYml( - plugin: EcoSpigotPlugin - ) : BaseConfig( - "data", - plugin, - false, - ConfigType.YAML - ) -} \ No newline at end of file +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/display/PacketHeldWindowItems.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/display/PacketHeldWindowItems.kt index 4b9f79e2..1797188a 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/display/PacketHeldWindowItems.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/display/PacketHeldWindowItems.kt @@ -5,21 +5,17 @@ import com.comphenix.protocol.events.PacketContainer import com.comphenix.protocol.events.PacketEvent import com.willfp.eco.core.AbstractPacketAdapter import com.willfp.eco.core.EcoPlugin -import com.willfp.eco.core.Prerequisite import com.willfp.eco.core.display.Display import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack -class PacketHeldWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, PacketType.Play.Server.WINDOW_ITEMS, false) { +class PacketHeldWindowItems(plugin: EcoPlugin) : + AbstractPacketAdapter(plugin, PacketType.Play.Server.WINDOW_ITEMS, false) { override fun onSend( packet: PacketContainer, player: Player, event: PacketEvent ) { - if (!Prerequisite.HAS_1_17.isMet) { - return - } - packet.itemModifier.modify(0) { item: ItemStack? -> Display.display( item!!, player diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/recipes/ShapedRecipeListener.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/recipes/ShapedRecipeListener.kt index 4b77582f..7c2bf477 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/recipes/ShapedRecipeListener.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/recipes/ShapedRecipeListener.kt @@ -49,15 +49,13 @@ class ShapedRecipeListener : Listener { } isStackedRecipe = true } else if (inMatrix != null) { - val max = Math.floorDiv(inMatrix.amount, inRecipe.item.amount) + val max = inMatrix.amount if (max < upperBound) { upperBound = max } - isStackedRecipe = true } } - if (!isStackedRecipe) { return } @@ -68,10 +66,8 @@ class ShapedRecipeListener : Listener { upperBound-- } - val newMatrix = matrix; - for (i in 0..8) { - val inMatrix = matrix[i] + val inMatrix = event.inventory.matrix[i] val inRecipe = matched.parts[i] if (inRecipe is TestableStack) { @@ -80,35 +76,13 @@ class ShapedRecipeListener : Listener { for (j in 0..upperBound) { amount -= inRecipe.amount } - inMatrix.amount = amount; - newMatrix[i] = inMatrix - + inMatrix.amount = amount } else { inMatrix.amount = inMatrix.amount - (inRecipe.amount - 1) - newMatrix[i] = inMatrix - } - } else { - @Suppress("SENSELESS_COMPARISON") - if (inMatrix == null) { - continue - } - - if (event.isShiftClick) { - var amount = inMatrix.amount + 1 - for (j in 0..upperBound) { - amount -= inRecipe.item.amount - } - inMatrix.amount = amount; - newMatrix[i] = inMatrix - } else { - inMatrix.amount = inMatrix.amount - (inRecipe.item.amount - 1) - newMatrix[i] = inMatrix } } } - event.inventory.matrix = newMatrix; - if (event.isShiftClick) { val result = event.inventory.result ?: return @@ -161,4 +135,4 @@ class ShapedRecipeListener : Listener { listeners.add(listener) } } -} \ No newline at end of file +} diff --git a/eco-core/core-plugin/src/main/resources/data.yml b/eco-core/core-plugin/src/main/resources/data.yml index 80ad14ee..3209391d 100644 --- a/eco-core/core-plugin/src/main/resources/data.yml +++ b/eco-core/core-plugin/src/main/resources/data.yml @@ -1 +1,71 @@ -# For internal storage use only, do not modify. \ No newline at end of file +# For internal storage use only, do not modify. + +categorized-keys: + # Preloading known keys (as of the release of 6.25.0) for optimal performance. + # This is only used when MySQL is enabled as the columns must be added each time a new key is registered. + player: + - ecoskills:crit_damage;INT;0 + - ecoskills:strong_impact;INT;0 + - ecoskills:shamanism;INT;0 + - ecoskills:reimbursement;INT;0 + - ecoskills:armory_xp;DOUBLE;0.0 + - ecoskills:bravery;INT;0 + - ecoskills:seamless_movement;INT;0 + - ecoskills:fishing;INT;0 + - ecoskills:armory;INT;0 + - ecoskills:accelerated_escape;INT;0 + - ecoskills:alchemy_xp;DOUBLE;0.0 + - boosters:2sell_multiplier;INT;0 + - ecoskills:second_chance;INT;0 + - ecoskills:health;INT;0 + - ecoskills:spelunking;INT;0 + - eco:player_name;STRING;Unknown Player + - ecoskills:strength;INT;0 + - ecoskills:woodcutting_xp;DOUBLE;0.0 + - ecoskills:versatile_tools;INT;0 + - boosters:skill_xp;INT;0 + - ecoskills:infernal_resistance;INT;0 + - ecoskills:wisdom;INT;0 + - ecoskills:master_lumberjack;INT;0 + - ecoskills:defense;INT;0 + - ecoskills:mystic_resilience;INT;0 + - ecoskills:gainsound;BOOLEAN;true + - ecoskills:golden_yield;INT;0 + - ecoskills:dazzle;INT;0 + - ecoskills:dodging;INT;0 + - ecoskills:efficient_brewing;INT;0 + - ecoskills:bountiful_harvest;INT;0 + - ecoskills:actionbar_enabled;BOOLEAN;true + - ecoskills:enchanting_xp;DOUBLE;0.0 + - ecoskills:overcompensation;INT;0 + - ecoskills:alchemy;INT;0 + - ecoskills:woodcutting;INT;0 + - ecoskills:mining;INT;0 + - ecoskills:magnetic_rod;INT;0 + - ecoskills:fishing_xp;DOUBLE;0.0 + - ecoskills:farming_xp;DOUBLE;0.0 + - ecoskills:speed;INT;0 + - ecoskills:potionmaster;INT;0 + - ecoskills:combat_xp;DOUBLE;0.0 + - ecoskills:eye_of_the_depths;INT;0 + - ecoskills:ferocity;INT;0 + - ecoskills:combat;INT;0 + - ecoskills:mining_xp;DOUBLE;0.0 + - ecoskills:satiation;INT;0 + - ecoskills:craftsmanship;INT;0 + - ecoskills:crit_chance;INT;0 + - ecoskills:dynamic_mining;INT;0 + - ecoskills:exploration;INT;0 + - boosters:1_5sell_multiplier;INT;0 + - ecoskills:enchanting;INT;0 + - ecoskills:endangering;INT;0 + - ecoskills:serrated_strikes;INT;0 + - ecoskills:exploration_xp;DOUBLE;0.0 + - ecoskills:farming;INT;0 + server: + - 'talismans:known_points;STRING;' + - 'ecoarmor:known_points;STRING;' + - 'ecoenchants:known_points;STRING;' + - 'ecoitems:known_points;STRING;' + - 'boosters:known_points;STRING;' + - 'reforges:known_points;STRING;' diff --git a/eco-core/core-plugin/src/main/resources/plugin.yml b/eco-core/core-plugin/src/main/resources/plugin.yml index ba8270f5..94ada954 100644 --- a/eco-core/core-plugin/src/main/resources/plugin.yml +++ b/eco-core/core-plugin/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: eco version: ${projectVersion} main: com.willfp.eco.internal.spigot.EcoHandler -api-version: 1.16 +api-version: 1.17 authors: [ Auxilor ] website: willfp.com load: STARTUP @@ -51,9 +51,9 @@ libraries: - 'net.kyori:adventure-api:4.9.3' - 'net.kyori:adventure-text-serializer-gson:4.9.3' - 'net.kyori:adventure-text-serializer-legacy:4.9.3' - - 'org.jetbrains.exposed:exposed-core:0.36.2' - - 'org.jetbrains.exposed:exposed-dao:0.36.2' - - 'org.jetbrains.exposed:exposed-jdbc:0.36.2' + - 'org.jetbrains.exposed:exposed-core:0.37.3' + - 'org.jetbrains.exposed:exposed-dao:0.37.3' + - 'org.jetbrains.exposed:exposed-jdbc:0.37.3' - 'mysql:mysql-connector-java:8.0.25' - 'com.google.guava:guava:31.0.1-jre' - 'com.zaxxer:HikariCP:5.0.0' diff --git a/gradle.properties b/gradle.properties index 2377fa38..aab2c291 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -version = 6.24.3 +version = 6.25.2 plugin-name = eco kotlin.code.style = official \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 234a096f..66c08b24 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -11,7 +11,6 @@ rootProject.name = "eco" include(":eco-api") include(":eco-core") include(":eco-core:core-nms") -include(":eco-core:core-nms:v1_16_R3") include(":eco-core:core-nms:v1_17_R1") include(":eco-core:core-nms:v1_18_R1") include(":eco-core:core-proxy")