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..171098ba 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; /** @@ -27,6 +29,11 @@ public class PersistentDataKey { */ private final PersistentDataKeyType type; + /** + * If the key is for server data. + */ + private final boolean isServerKey; + /** * Create a new Persistent Data Key. * @@ -37,9 +44,25 @@ public class PersistentDataKey { public PersistentDataKey(@NotNull final NamespacedKey key, @NotNull final PersistentDataKeyType type, @NotNull final T defaultValue) { + this(key, type, defaultValue, false); + } + + /** + * Create a new Persistent Data Key. + * + * @param key The key. + * @param type The data type. + * @param defaultValue The default value. + * @param isServerKey If the key is for server data. + */ + public PersistentDataKey(@NotNull final NamespacedKey key, + @NotNull final PersistentDataKeyType type, + @NotNull final T defaultValue, + final boolean isServerKey) { this.key = key; this.defaultValue = defaultValue; this.type = type; + this.isServerKey = isServerKey; Eco.getHandler().getKeyRegistry().registerKey(this); } @@ -80,6 +103,15 @@ public class PersistentDataKey { return this.type; } + /** + * Get if the key is for server data. + * + * @return If server key. + */ + public boolean isServerKey() { + return isServerKey; + } + /** * Get all persistent data keys. * @@ -88,4 +120,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-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..5db4d328 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 @@ -43,7 +43,7 @@ class EcoHandler : EcoSpigotPlugin(), Handler { @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/data/EcoKeyRegistry.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/data/EcoKeyRegistry.kt index 05c76fcc..ed856251 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,12 +4,9 @@ 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>() override fun registerKey(key: PersistentDataKey<*>) { 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..3fd15f60 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 @@ -2,10 +2,12 @@ package com.willfp.eco.internal.spigot.data.storage 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.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.serverProfileUUID import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import org.apache.logging.log4j.Level @@ -31,8 +33,64 @@ import java.util.concurrent.Executors @Suppress("UNCHECKED_CAST") class MySQLDataHandler( plugin: EcoSpigotPlugin, - private val handler: EcoProfileHandler + handler: EcoProfileHandler ) : DataHandler { + private val playerHandler = ImplementedMySQLHandler( + handler, + UUIDTable("eco_players"), + plugin + ) { !it.isServerKey } + + private val serverHandler = ImplementedMySQLHandler( + handler, + UUIDTable("eco_server"), + plugin + ) { it.isServerKey } + + 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) { + applyFor(uuid) { + it.write(uuid, key, value) + } + } + + override fun saveKeysForPlayer(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) + } + } + + override fun updateKeys() { + playerHandler.updateKeys() + serverHandler.updateKeys() + } + + private inline fun applyFor(uuid: UUID, function: (ImplementedMySQLHandler) -> R): R { + return if (uuid == serverProfileUUID) { + function(serverHandler) + } else { + function(playerHandler) + } + } +} + +@Suppress("UNCHECKED_CAST") +private class ImplementedMySQLHandler( + private val handler: EcoProfileHandler, + private val table: UUIDTable, + plugin: EcoPlugin, + private val validator: (PersistentDataKey<*>) -> Boolean +) { 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) @@ -52,7 +110,7 @@ class MySQLDataHandler( transaction { - SchemaUtils.create(Players) + SchemaUtils.create(table) } // Get Exposed to shut the hell up @@ -67,18 +125,20 @@ class MySQLDataHandler( } } - override fun updateKeys() { + fun updateKeys() { transaction { for (key in Eco.getHandler().keyRegistry.registeredKeys) { - registerColumn(key, Players) + if (validator(key)) { + registerColumn(key, table) + } } - SchemaUtils.createMissingTablesAndColumns(Players, withLogs = false) + SchemaUtils.createMissingTablesAndColumns(table, withLogs = false) } } - override fun write(uuid: UUID, key: NamespacedKey, value: T) { - getPlayer(uuid) + fun write(uuid: UUID, key: NamespacedKey, value: T) { + getRow(uuid) writeAsserted(uuid, key, value) } @@ -87,42 +147,44 @@ class MySQLDataHandler( 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) + getRow(uuid) for (key in keys) { - writeAsserted(uuid, key.key, profile.read(key)) + if (validator(key)) { + writeAsserted(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) + val player = getRow(uuid) value = player[getColumn(key.toString())] as T? } @@ -136,8 +198,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() }) { @@ -165,22 +225,22 @@ class MySQLDataHandler( return cached } - columns[name] = Players.columns.stream().filter { it.name == name }.findFirst().get() + columns[name] = table.columns.stream().filter { it.name == name }.findFirst().get() return getColumn(name) } - private fun getPlayer(uuid: UUID): ResultRow { + private fun getRow(uuid: UUID): ResultRow { val player = transaction { - Players.select { Players.id eq uuid }.limit(1).singleOrNull() + table.select { table.id eq uuid }.limit(1).singleOrNull() } return if (player != null) { player } else { transaction { - Players.insert { it[id] = uuid } + table.insert { it[id] = uuid } } - getPlayer(uuid) + getRow(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..f43a1993 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 @@ -51,4 +51,4 @@ class YamlDataHandler( false, ConfigType.YAML ) -} \ No newline at end of file +}