Compare commits

..

34 Commits

Author SHA1 Message Date
Auxilor
13772002e8 Updated to 6.25.1 2022-02-17 17:03:16 +00:00
Auxilor
c9b84889e7 Fixed recursive caching bug 2022-02-17 17:03:10 +00:00
Auxilor
1513578266 Fixed recursive caching bug 2022-02-17 17:01:42 +00:00
Auxilor
89d6f2f867 Fixed initialization order 2022-02-17 12:53:54 +00:00
Auxilor
8e6d98c997 More MySQL Changes 2022-02-17 12:51:43 +00:00
Auxilor
5bc2cb31a4 Switched expiry from write to access (MySQL) 2022-02-17 12:47:59 +00:00
Auxilor
041575a103 Cached rows and columns with Caffeine 2022-02-17 12:47:32 +00:00
Auxilor
c88dac56b7 Added ability to manually categorize keys to improve performance 2022-02-17 12:21:26 +00:00
Auxilor
00da717f6d Changed key serialization 2022-02-17 11:49:26 +00:00
Auxilor
cc557378cc Preloaded known data keys 2022-02-16 18:16:09 +00:00
Auxilor
b5c49c79b8 Improvements to key saving 2022-02-16 18:13:04 +00:00
Auxilor
28018430e7 Categorized keys are now saved completely serialized 2022-02-16 18:01:41 +00:00
Auxilor
7b6c8d68a8 Key registration changes 2022-02-16 17:38:07 +00:00
Auxilor
ad3cb3a620 Fixed postInit 2022-02-16 16:48:40 +00:00
Auxilor
511a7e4830 Added optimisations to lazy column creation 2022-02-16 16:42:47 +00:00
Auxilor
5aeeafc041 MySQL Data Changes: Keys are now registered on first read/write 2022-02-16 16:32:38 +00:00
Auxilor
9a51fb8358 Updated to 6.25.0 2022-02-16 16:11:31 +00:00
Auxilor
eeefb9f40e Server persistence changes 2022-02-16 16:01:55 +00:00
Auxilor
aa1ce34cbc Updated to 6.24.4 2022-02-16 14:21:49 +00:00
Auxilor
47772c3ff7 Reverted Shaped Recipe changes 2022-02-16 14:21:03 +00:00
Auxilor
dfcac5d527 PR Changes 2022-02-14 13:28:37 +00:00
Auxilor
40f88f0b59 Revert "refactor(nms): Change checking if value is initialized to a lazy val"
This reverts commit 6361c0e8e9.
2022-02-14 13:28:25 +00:00
Auxilor
105355d967 Updated to 6.24.3 2022-02-14 13:15:55 +00:00
Will FP
3cddff22b8 Merge pull request #73
Bump com.github.johnrengelman.shadow from 7.1.0 to 7.1.2
2022-02-14 13:15:39 +00:00
Will FP
f8e930d29e Merge pull request #91
Update ShapedRecipeListener.kt
2022-02-14 13:15:28 +00:00
Will FP
9dbe088e66 Merge pull request #92
refactor(nms): Change checking if value is initialized to a lazy val
2022-02-14 13:15:17 +00:00
Racci
6361c0e8e9 refactor(nms): Change checking if value is initialized to a lazy val 2022-02-14 17:32:12 +11:00
casper
1135672241 Update ShapedRecipeListener.kt
| ShapedRecipeListener.kt Modified to change matrix at the end of the crafting to prevent duplication of items
2022-02-13 12:55:05 -05:00
Auxilor
80891e4a81 Fixed profile saveAll not working 2022-02-11 10:14:33 +00:00
Auxilor
3e0be3a629 Updated to 6.24.2 2022-02-09 15:20:30 +00:00
Auxilor
17819de2ea Fixed adult/baby parsers 2022-02-09 15:20:21 +00:00
Auxilor
209cdd6b0d Updated to 6.24.1 2022-02-05 17:05:29 +00:00
Auxilor
fbf6b2edd9 Added equipment arg parser 2022-02-05 17:05:18 +00:00
dependabot[bot]
8b9e8589a0 Bump com.github.johnrengelman.shadow from 7.1.0 to 7.1.2
Bumps com.github.johnrengelman.shadow from 7.1.0 to 7.1.2.

---
updated-dependencies:
- dependency-name: com.github.johnrengelman.shadow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-03 18:54:34 +00:00
19 changed files with 536 additions and 111 deletions

View File

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

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

View File

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

View File

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

View File

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

View File

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

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

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

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

View File

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

View File

@@ -135,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,3 +1,3 @@
version = 6.24.0
version = 6.25.1
plugin-name = eco
kotlin.code.style = official