Merge branch 'Auxilor:master' into master

This commit is contained in:
0ft3n
2022-02-23 11:43:39 +03:00
committed by GitHub
35 changed files with 475 additions and 595 deletions

View File

@@ -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

View File

@@ -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"))
}

View File

@@ -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+"

View File

@@ -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<PersistentDataKey<?>> 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
}
}

View File

@@ -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 <T> The type of the data.
*/
public class PersistentDataKey<T> {
public final class PersistentDataKey<T> {
/**
* The key of the persistent data value.
*/
@@ -80,6 +82,32 @@ public class PersistentDataKey<T> {
return this.type;
}
/**
* Categorize key as a server key, will register new column to MySQL
* database immediately rather than waiting for auto-categorization.
* <p>
* This will improve performance.
*
* @return The key.
*/
public PersistentDataKey<T> 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.
* <p>
* This will improve performance.
*
* @return The key.
*/
public PersistentDataKey<T> player() {
Eco.getHandler().getKeyRegistry().markKeyAs(this, KeyRegistry.KeyCategory.PLAYER);
return this;
}
/**
* Get all persistent data keys.
*
@@ -88,4 +116,20 @@ public class PersistentDataKey<T> {
public static Set<PersistentDataKey<?>> 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());
}
}

View File

@@ -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() {

View File

@@ -77,7 +77,6 @@ class EcoProxyFactory(
companion object {
val SUPPORTED_VERSIONS = listOf(
"v1_16_R3",
"v1_17_R1",
"v1_18_R1"
)

View File

@@ -1,6 +0,0 @@
group 'com.willfp'
version rootProject.version
dependencies {
compileOnly 'org.spigotmc:spigot:1.16.5-R0.1-SNAPSHOT'
}

View File

@@ -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")
}
}

View File

@@ -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))
}
}

View File

@@ -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<Component>()
for (arg in component.args()) {
args.add(modifyBaseComponent(arg, player))
}
component = component.args(args)
}
val children = mutableListOf<Component>()
for (child in component.children()) {
children.add(modifyBaseComponent(child, player))
}
component = component.children(children)
val hoverEvent: HoverEvent<Any> = component.style().hoverEvent() as HoverEvent<Any>? ?: 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)
}
}

View File

@@ -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()
}
}

View File

@@ -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)
}
}

View File

@@ -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
}
}

View File

@@ -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]
}
}

View File

@@ -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
}
}

View File

@@ -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)
}
}

View File

@@ -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>(
itemStack.getNMSStack(), itemStack
) {
private var loreCache: List<String>? = null
override fun getEnchants(checkStored: Boolean): Map<Enchantment, Int> {
val enchantmentNBT = if (checkStored && handle.item === Items.ENCHANTED_BOOK) ItemEnchantedBook.d(
handle
) else handle.enchantments
val foundEnchantments: MutableMap<Enchantment, Int> = 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<String>?) {
loreCache = null
val jsonLore: MutableList<String> = 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<String> {
if (loreCache != null) {
return loreCache as List<String>
}
val lore: MutableList<String> = ArrayList()
for (s in getLoreJSON()) {
lore.add(StringUtils.jsonToLegacy(s))
}
loreCache = lore
return lore
}
private fun getLoreJSON(): List<String> {
val displayTag = handle.b("display") ?: return emptyList()
return if (displayTag.hasKey("Lore")) {
val loreTag = displayTag.getList("Lore", CraftMagicNumbers.NBT.TAG_STRING)
val lore: MutableList<String> = 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<ItemFlag> {
val flags = mutableSetOf<ItemFlag>()
var flagArr: Array<ItemFlag>
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
}
}
}

View File

@@ -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'

View File

@@ -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")

View File

@@ -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() {

View File

@@ -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
)

View File

@@ -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<NamespacedKey, PersistentDataKey<*>>()
private val categories = mutableMapOf<NamespacedKey, KeyRegistry.KeyCategory>()
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<PersistentDataKey<*>> {
@@ -46,4 +42,13 @@ class EcoKeyRegistry(
else -> throw NullPointerException("Null value found!")
}
}
}
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]
}
}

View File

@@ -65,4 +65,4 @@ class EcoServerProfile(
override fun toString(): String {
return "EcoServerProfile"
}
}
}

View File

@@ -18,7 +18,7 @@ class EcoProfileHandler(
plugin: EcoSpigotPlugin
) : ProfileHandler {
private val loaded = mutableMapOf<UUID, Profile>()
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()
}
}

View File

@@ -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<String>,
if (split.size >= 3) split.toList().subList(2, split.size).joinToString("") else ""
)
PersistentDataKeyType.INT -> PersistentDataKey(
key,
type as PersistentDataKeyType<Int>,
split[2].toInt()
)
PersistentDataKeyType.DOUBLE -> PersistentDataKey(
key,
type as PersistentDataKeyType<Double>,
split[2].toDouble()
)
PersistentDataKeyType.BOOLEAN -> PersistentDataKey(
key,
type as PersistentDataKeyType<Boolean>,
java.lang.Boolean.parseBoolean(split[2])
)
else -> null
}
}
fun serializeToString(key: PersistentDataKey<*>): String {
return "${key.key};${key.type.name()};${key.defaultValue}"
}
}

View File

@@ -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<UUID>)
fun categorize(key: PersistentDataKey<*>, category: KeyRegistry.KeyCategory) {
}
fun saveAll(uuids: Iterable<UUID>)
fun updateKeys() {
fun initialize() {
}
fun savePlayer(uuid: UUID) {
saveKeysForPlayer(uuid, PersistentDataKey.values())
saveKeysFor(uuid, PersistentDataKey.values())
}
fun <T> write(uuid: UUID, key: NamespacedKey, value: T)
fun saveKeysForPlayer(uuid: UUID, keys: Set<PersistentDataKey<*>>)
fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>)
fun <T> read(uuid: UUID, key: NamespacedKey): T?
}

View File

@@ -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<String, Column<*>>()
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<UUID>) {
serverHandler.saveAll(uuids.filter { it == serverProfileUUID })
playerHandler.saveAll(uuids.filter { it != serverProfileUUID })
}
override fun <T> write(uuid: UUID, key: NamespacedKey, value: T) {
getPlayer(uuid)
writeAsserted(uuid, key, value)
applyFor(uuid) {
it.write(uuid, key, value)
}
}
private fun <T> writeAsserted(uuid: UUID, key: NamespacedKey, value: T) {
val column: Column<T> = getColumn(key.toString()) as Column<T>
override fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
applyFor(uuid) {
it.saveKeysForRow(uuid, keys)
}
}
override fun <T> read(uuid: UUID, key: NamespacedKey): T? {
return applyFor(uuid) {
it.read(uuid, key)
}
}
private inline fun <R> 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<PersistentDataKey<*>>
) {
private val columns = Caffeine.newBuilder()
.expireAfterWrite(3, TimeUnit.SECONDS)
.build<String, Column<*>>()
private val rows = Caffeine.newBuilder()
.expireAfterWrite(3, TimeUnit.SECONDS)
.build<UUID, ResultRow>()
private val threadFactory = ThreadFactoryBuilder().setNameFormat("eco-mysql-thread-%d").build()
private val executor = Executors.newFixedThreadPool(plugin.configYml.getInt("mysql.threads"), threadFactory)
val registeredKeys = ConcurrentHashMap<NamespacedKey, PersistentDataKey<*>>()
private val currentlyProcessingRegistration = ConcurrentHashMap<NamespacedKey, Future<*>>()
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 <T> write(uuid: UUID, key: NamespacedKey, value: T) {
getOrCreateRow(uuid)
doWrite(uuid, key, value)
}
private fun <T> doWrite(uuid: UUID, key: NamespacedKey, value: T) {
val column: Column<T> = getColumn(key) as Column<T>
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<PersistentDataKey<*>>) {
savePlayer(uuid, keys)
fun saveKeysForRow(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
saveRow(uuid, keys)
}
override fun saveAll(uuids: Iterable<UUID>) {
fun saveAll(uuids: Iterable<UUID>) {
for (uuid in uuids) {
savePlayer(uuid)
saveRow(uuid, PersistentDataKey.values())
}
}
private fun savePlayer(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
private fun saveRow(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
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 <T> read(uuid: UUID, key: NamespacedKey): T? {
fun <T> read(uuid: UUID, key: NamespacedKey): T? {
val doRead = Callable<T?> {
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 <T> registerColumn(key: PersistentDataKey<T>, 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)
}
}
}
}

View File

@@ -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<PersistentDataKey<*>>) {
override fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
val profile = handler.loadGenericProfile(uuid)
for (key in keys) {
@@ -42,13 +40,4 @@ class YamlDataHandler(
override fun <T> read(uuid: UUID, key: NamespacedKey): T? {
return dataYml.get("player.$uuid.$key") as T?
}
class DataYml(
plugin: EcoSpigotPlugin
) : BaseConfig(
"data",
plugin,
false,
ConfigType.YAML
)
}
}

View File

@@ -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

View File

@@ -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)
}
}
}
}

View File

@@ -1 +1,71 @@
# For internal storage use only, do not modify.
# 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;'

View File

@@ -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'

View File

@@ -1,3 +1,3 @@
version = 6.24.3
version = 6.25.2
plugin-name = eco
kotlin.code.style = official

View File

@@ -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")