Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13772002e8 | ||
|
|
c9b84889e7 | ||
|
|
1513578266 | ||
|
|
89d6f2f867 | ||
|
|
8e6d98c997 | ||
|
|
5bc2cb31a4 | ||
|
|
041575a103 | ||
|
|
c88dac56b7 | ||
|
|
00da717f6d | ||
|
|
cc557378cc | ||
|
|
b5c49c79b8 | ||
|
|
28018430e7 | ||
|
|
7b6c8d68a8 | ||
|
|
ad3cb3a620 | ||
|
|
511a7e4830 | ||
|
|
5aeeafc041 | ||
|
|
9a51fb8358 | ||
|
|
eeefb9f40e | ||
|
|
aa1ce34cbc | ||
|
|
47772c3ff7 | ||
|
|
dfcac5d527 | ||
|
|
40f88f0b59 | ||
|
|
105355d967 | ||
|
|
3cddff22b8 | ||
|
|
f8e930d29e | ||
|
|
9dbe088e66 | ||
|
|
6361c0e8e9 | ||
|
|
1135672241 | ||
|
|
80891e4a81 | ||
|
|
3e0be3a629 | ||
|
|
17819de2ea | ||
|
|
209cdd6b0d | ||
|
|
fbf6b2edd9 | ||
|
|
8b9e8589a0 |
@@ -10,7 +10,7 @@ buildscript {
|
||||
|
||||
plugins {
|
||||
id("java-library")
|
||||
id("com.github.johnrengelman.shadow") version "7.1.0"
|
||||
id("com.github.johnrengelman.shadow") version "7.1.2"
|
||||
id("maven-publish")
|
||||
id("java")
|
||||
kotlin("jvm") version "1.6.10"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.willfp.eco.internal.entities
|
||||
|
||||
import com.willfp.eco.core.entities.args.EntityArgParseResult
|
||||
import com.willfp.eco.core.entities.args.EntityArgParser
|
||||
import org.bukkit.entity.Animals
|
||||
import org.bukkit.entity.Ageable
|
||||
|
||||
class EntityArgParserAdult : EntityArgParser {
|
||||
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
|
||||
@@ -20,14 +20,14 @@ class EntityArgParserAdult : EntityArgParser {
|
||||
|
||||
return EntityArgParseResult(
|
||||
{
|
||||
if (it !is Animals) {
|
||||
if (it !is Ageable) {
|
||||
return@EntityArgParseResult false
|
||||
}
|
||||
|
||||
it.isAdult
|
||||
},
|
||||
{
|
||||
(it as? Animals)?.setAdult()
|
||||
(it as? Ageable)?.setAdult()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.willfp.eco.internal.entities
|
||||
|
||||
import com.willfp.eco.core.entities.args.EntityArgParseResult
|
||||
import com.willfp.eco.core.entities.args.EntityArgParser
|
||||
import org.bukkit.entity.Animals
|
||||
import org.bukkit.entity.Ageable
|
||||
|
||||
class EntityArgParserBaby : EntityArgParser {
|
||||
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
|
||||
@@ -20,14 +20,14 @@ class EntityArgParserBaby : EntityArgParser {
|
||||
|
||||
return EntityArgParseResult(
|
||||
{
|
||||
if (it !is Animals) {
|
||||
if (it !is Ageable) {
|
||||
return@EntityArgParseResult false
|
||||
}
|
||||
|
||||
!it.isAdult
|
||||
},
|
||||
{
|
||||
(it as? Animals)?.setBaby()
|
||||
(it as? Ageable)?.setBaby()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.willfp.eco.internal.entities
|
||||
|
||||
import com.willfp.eco.core.entities.args.EntityArgParseResult
|
||||
import com.willfp.eco.core.entities.args.EntityArgParser
|
||||
import com.willfp.eco.core.items.Items
|
||||
import com.willfp.eco.core.items.TestableItem
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.inventory.EquipmentSlot
|
||||
|
||||
class EntityArgParserEquipment : EntityArgParser {
|
||||
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
|
||||
val equipment = mutableMapOf<EquipmentSlot, TestableItem>()
|
||||
|
||||
for (arg in args) {
|
||||
val argSplit = arg.split(":")
|
||||
for (slot in EquipmentSlot.values()) {
|
||||
if (!argSplit[0].equals(slot.name, ignoreCase = true)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (argSplit.size < 2) {
|
||||
continue
|
||||
}
|
||||
|
||||
equipment[slot] = Items.lookup(argSplit[1])
|
||||
}
|
||||
}
|
||||
|
||||
if (equipment.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return EntityArgParseResult(
|
||||
{
|
||||
if (it !is LivingEntity) {
|
||||
return@EntityArgParseResult false
|
||||
}
|
||||
|
||||
val entityEquipment = it.equipment ?: return@EntityArgParseResult false
|
||||
|
||||
for ((slot, item) in equipment) {
|
||||
if (!item.matches(entityEquipment.getItem(slot))) {
|
||||
return@EntityArgParseResult false
|
||||
}
|
||||
}
|
||||
|
||||
return@EntityArgParseResult true
|
||||
},
|
||||
{
|
||||
if (it !is LivingEntity) {
|
||||
return@EntityArgParseResult
|
||||
}
|
||||
|
||||
val entityEquipment = it.equipment ?: return@EntityArgParseResult
|
||||
|
||||
for ((slot, item) in equipment) {
|
||||
entityEquipment.setItem(slot, item.item, false)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.willfp.eco.internal.spigot
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.PluginProps
|
||||
import com.willfp.eco.core.Handler
|
||||
import com.willfp.eco.core.PluginProps
|
||||
import com.willfp.eco.core.fast.FastItemStack
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration
|
||||
import com.willfp.eco.internal.EcoCleaner
|
||||
@@ -24,10 +24,9 @@ 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.data.storage.MySQLDataHandler
|
||||
import com.willfp.eco.internal.spigot.data.storage.YamlDataHandler
|
||||
import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler
|
||||
import com.willfp.eco.internal.spigot.proxy.DummyEntityProxy
|
||||
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
|
||||
@@ -40,16 +39,15 @@ 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 playerProfileHandler = EcoProfileHandler(
|
||||
if (this.configYml.getBool("mysql.enabled"))
|
||||
MySQLDataHandler(this) else YamlDataHandler(this)
|
||||
)
|
||||
private val keyRegistry = EcoKeyRegistry()
|
||||
private val playerProfileHandler = EcoProfileHandler(this.configYml.getBool("mysql.enabled"), this)
|
||||
|
||||
@Suppress("RedundantNullableReturnType")
|
||||
private val keyFactory: InternalNamespacedKeyFactory? =
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.willfp.eco.internal.entities.EntityArgParserAttackDamage
|
||||
import com.willfp.eco.internal.entities.EntityArgParserAttackSpeed
|
||||
import com.willfp.eco.internal.entities.EntityArgParserBaby
|
||||
import com.willfp.eco.internal.entities.EntityArgParserCharged
|
||||
import com.willfp.eco.internal.entities.EntityArgParserEquipment
|
||||
import com.willfp.eco.internal.entities.EntityArgParserExplosionRadius
|
||||
import com.willfp.eco.internal.entities.EntityArgParserFlySpeed
|
||||
import com.willfp.eco.internal.entities.EntityArgParserFollowRange
|
||||
@@ -46,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
|
||||
@@ -121,6 +124,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())
|
||||
@@ -148,6 +153,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
Entities.registerArgParser(EntityArgParserCharged())
|
||||
Entities.registerArgParser(EntityArgParserExplosionRadius())
|
||||
Entities.registerArgParser(EntityArgParserSilent())
|
||||
Entities.registerArgParser(EntityArgParserEquipment())
|
||||
|
||||
ShapedRecipeListener.registerListener(ComplexInComplex())
|
||||
ShapedRecipeListener.registerListener(ComplexInEco())
|
||||
@@ -181,10 +187,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() {
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,4 +65,4 @@ class EcoServerProfile(
|
||||
override fun toString(): String {
|
||||
return "EcoServerProfile"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,17 +5,23 @@ import com.willfp.eco.core.data.Profile
|
||||
import com.willfp.eco.core.data.ProfileHandler
|
||||
import com.willfp.eco.core.data.ServerProfile
|
||||
import com.willfp.eco.core.data.keys.PersistentDataKey
|
||||
import com.willfp.eco.internal.spigot.EcoSpigotPlugin
|
||||
import com.willfp.eco.internal.spigot.data.storage.DataHandler
|
||||
import com.willfp.eco.internal.spigot.data.storage.MySQLDataHandler
|
||||
import com.willfp.eco.internal.spigot.data.storage.YamlDataHandler
|
||||
import java.util.UUID
|
||||
|
||||
val serverProfileUUID = UUID(0, 0)
|
||||
|
||||
class EcoProfileHandler(
|
||||
private val handler: DataHandler
|
||||
useSql: Boolean,
|
||||
plugin: EcoSpigotPlugin
|
||||
) : ProfileHandler {
|
||||
private val loaded = mutableMapOf<UUID, Profile>()
|
||||
val handler: DataHandler = if (useSql) MySQLDataHandler(plugin, this) else
|
||||
YamlDataHandler(plugin, this)
|
||||
|
||||
private fun loadGenericProfile(uuid: UUID): Profile {
|
||||
fun loadGenericProfile(uuid: UUID): Profile {
|
||||
val found = loaded[uuid]
|
||||
if (found != null) {
|
||||
return found
|
||||
@@ -58,7 +64,7 @@ class EcoProfileHandler(
|
||||
handler.save()
|
||||
}
|
||||
|
||||
fun updateKeys() {
|
||||
handler.updateKeys()
|
||||
fun initialize() {
|
||||
handler.initialize()
|
||||
}
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
}
|
||||
@@ -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?
|
||||
}
|
||||
@@ -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.data.PlayerProfile
|
||||
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,15 +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 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()
|
||||
@@ -49,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 }
|
||||
@@ -64,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()
|
||||
.expireAfterAccess(5, TimeUnit.SECONDS)
|
||||
.build<String, Column<*>>()
|
||||
|
||||
private val rows = Caffeine.newBuilder()
|
||||
.expireAfterAccess(5, 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<*>>) {
|
||||
val profile = PlayerProfile.load(uuid)
|
||||
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 {
|
||||
@@ -135,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() }) {
|
||||
@@ -158,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
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.PlayerProfile
|
||||
import com.willfp.eco.core.data.keys.PersistentDataKey
|
||||
import com.willfp.eco.internal.spigot.EcoSpigotPlugin
|
||||
import com.willfp.eco.internal.spigot.data.EcoProfileHandler
|
||||
import org.bukkit.NamespacedKey
|
||||
import java.util.UUID
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class YamlDataHandler(
|
||||
plugin: EcoSpigotPlugin
|
||||
plugin: EcoSpigotPlugin,
|
||||
private val handler: EcoProfileHandler
|
||||
) : DataHandler {
|
||||
private val dataYml = DataYml(plugin)
|
||||
private val dataYml = plugin.dataYml
|
||||
|
||||
override fun save() {
|
||||
dataYml.save()
|
||||
@@ -26,8 +25,8 @@ class YamlDataHandler(
|
||||
save()
|
||||
}
|
||||
|
||||
override fun saveKeysForPlayer(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
||||
val profile = PlayerProfile.load(uuid)
|
||||
override fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
||||
val profile = handler.loadGenericProfile(uuid)
|
||||
|
||||
for (key in keys) {
|
||||
write(uuid, key.key, profile.read(key))
|
||||
@@ -41,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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,4 +135,4 @@ class ShapedRecipeListener : Listener {
|
||||
listeners.add(listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;'
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version = 6.24.0
|
||||
version = 6.25.1
|
||||
plugin-name = eco
|
||||
kotlin.code.style = official
|
||||
Reference in New Issue
Block a user