Server persistence changes

This commit is contained in:
Auxilor
2022-02-16 16:01:55 +00:00
parent aa1ce34cbc
commit eeefb9f40e
5 changed files with 136 additions and 31 deletions

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;
/**
@@ -27,6 +29,11 @@ public class PersistentDataKey<T> {
*/
private final PersistentDataKeyType<T> 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<T> {
public PersistentDataKey(@NotNull final NamespacedKey key,
@NotNull final PersistentDataKeyType<T> 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<T> 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<T> {
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<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

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

View File

@@ -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<NamespacedKey, PersistentDataKey<*>>()
override fun registerKey(key: PersistentDataKey<*>) {

View File

@@ -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<UUID>) {
serverHandler.saveAll(uuids.filter { it == serverProfileUUID })
playerHandler.saveAll(uuids.filter { it != serverProfileUUID })
}
override fun <T> write(uuid: UUID, key: NamespacedKey, value: T) {
applyFor(uuid) {
it.write(uuid, key, value)
}
}
override fun saveKeysForPlayer(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)
}
}
override fun updateKeys() {
playerHandler.updateKeys()
serverHandler.updateKeys()
}
private inline fun <R> 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<String, Column<*>>()
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 <T> write(uuid: UUID, key: NamespacedKey, value: T) {
getPlayer(uuid)
fun <T> 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<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)
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 <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)
val player = getRow(uuid)
value = player[getColumn(key.toString())] as T?
}
@@ -136,8 +198,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() }) {
@@ -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)
}
}
}
}

View File

@@ -51,4 +51,4 @@ class YamlDataHandler(
false,
ConfigType.YAML
)
}
}