1.0.0.3 - new modules

Added utility, menu, thirdparty and exposed modules
A few little fixes
This commit is contained in:
redtea committed 2024-03-28 10:12:38 +03:00
1 parent e5a7e08e56
commit 9655d10025
63 files changed
+5334 -12

No files matched your search

@@ -0,0 +1,64 @@
package tech.carcadex.kotlinbukkitkit.exposed
import kotlinx.serialization.Serializable
import java.io.File
import java.sql.SQLException
public interface DatabaseTypeConfigHeader {
public val type: String
public val hostname: String
public val port: Short
public val database: String
public val user: String
public val password: String
}
@Serializable
public data class DatabaseTypeConfig(
override var type: String = "H2",
override var hostname: String = "localhost",
override var port: Short = 3306,
override var database: String = "kbapi_database",
override var user: String = "root",
override var password: String = "12345",
) : DatabaseTypeConfigHeader
public fun databaseTypeFrom(dataFolder: File, config: DatabaseTypeConfig): DatabaseType {
val type = DatabaseType.byName(config.type)
if (type != null) {
return when (type) {
DatabaseType.H2::class -> DatabaseType.H2(
dataFolder,
config.database,
)
DatabaseType.SQLite::class -> DatabaseType.SQLite(
dataFolder,
config.database,
)
DatabaseType.MySQL::class -> DatabaseType.MySQL(
config.hostname,
config.port,
config.database,
config.user,
config.password,
)
DatabaseType.PostgreSQL::class -> DatabaseType.PostgreSQL(
config.hostname,
config.port,
config.database,
config.user,
config.password,
)
DatabaseType.SQLServer::class -> DatabaseType.SQLServer(
config.hostname,
config.port,
config.database,
config.user,
config.password,
)
else -> throw SQLException("SQL type not finded or supported.")
}
} else {
throw SQLException("SQL type not finded or supported.")
}
}
@@ -0,0 +1,232 @@
package tech.carcadex.kotlinbukkitkit.exposed
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.net.URL
import java.net.URLClassLoader
import java.sql.SQLException
import kotlin.reflect.KClass
private const val KEY_FILE = "{file}"
public sealed class DatabaseType(
public val name: String,
public val jdbc: String,
public val driverClass: String,
public val driverLink: String,
) {
public companion object {
public val fileDatabases: Map<String, KClass<out DatabaseType>> =
mapOf("h2" to H2::class, "sqlite" to SQLite::class)
public val remoteDatabases: Map<String, KClass<out DatabaseType>> =
mapOf("mysql" to MySQL::class, "postgresql" to PostgreSQL::class, "sqlserver" to SQLServer::class)
public val databases: Map<String, KClass<out DatabaseType>> = fileDatabases + remoteDatabases
public fun byName(name: String): KClass<out DatabaseType>? = databases[name.toLowerCase()]
}
public abstract fun dataSource(): HikariDataSource
public abstract fun config(): HikariConfig
public abstract class FileDatabaseType(
name: String,
jdbc: String,
driverClass: String,
driverLink: String,
public val dataFolder: File,
public val file: String,
public val databaseExtension: String,
public val needFileCreation: Boolean,
) : DatabaseType(name, jdbc, driverClass, driverLink) {
private val realFile = File(dataFolder, "$file.$databaseExtension")
override fun dataSource(): HikariDataSource {
if (needFileCreation && !realFile.exists()) realFile.createNewFile()
loadDependency()
return HikariDataSource(config())
}
override fun config(): HikariConfig = HikariConfig().apply {
driverClassName = driverClass
jdbcUrl = jdbc.replace(KEY_FILE, realFile.path)
}
}
public abstract class RemoteDatabaseType(
name: String,
jdbc: String,
driverClass: String,
driverLink: String,
public val hostname: String,
public val port: Short,
public val database: String,
public val username: String,
public val password: String,
) : DatabaseType(name, jdbc, driverClass, driverLink) {
override fun dataSource(): HikariDataSource {
loadDependency()
return HikariDataSource(config())
}
override fun config(): HikariConfig = HikariConfig().apply {
driverClassName = driverClass
jdbcUrl = jdbc
username = this@RemoteDatabaseType.username
password = this@RemoteDatabaseType.password
}
}
public class H2(
dataFolder: File,
file: String,
) : FileDatabaseType(
"H2",
"jdbc:h2:file:./$KEY_FILE",
"org.h2.Driver",
"https://repo1.maven.org/maven2/com/h2database/h2/1.4.199/h2-1.4.199.jar",
dataFolder,
file,
"h2.db",
false,
)
public class SQLite(
dataFolder: File,
file: String,
) : FileDatabaseType(
"SQLite",
"jdbc:sqlite:./$KEY_FILE",
"org.sqlite.JDBC",
"https://bitbucket.org/xerial/sqlite-jdbc/downloads/sqlite-jdbc-3.23.1.jar",
dataFolder,
file,
"sqlite.db",
true,
) {
// https://github.com/brettwooldridge/HikariCP/issues/393#issuecomment-135580191
override fun config(): HikariConfig {
return super.config().apply {
connectionTestQuery = "SELECT 1"
}
}
}
public class MySQL(
hostname: String,
port: Short,
database: String,
username: String,
password: String,
) : RemoteDatabaseType(
"MySQL",
"jdbc:mysql://$hostname:$port/$database",
"com.mysql.jdbc.Driver",
"https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.11/mysql-connector-java-8.0.11.jar",
hostname, port, database,
username, password,
)
public class PostgreSQL(
hostname: String,
port: Short,
database: String,
username: String,
password: String,
) : RemoteDatabaseType(
"PostgreSQL",
"jdbc:postgresql://$hostname:$port/$database",
"org.postgresql.Driver",
"https://jdbc.postgresql.org/download/postgresql-42.2.2.jre7.jar",
hostname, port, database,
username, password,
)
public class SQLServer(
hostname: String,
port: Short,
database: String,
username: String,
password: String,
) : RemoteDatabaseType(
"SQLServer",
"jdbc:sqlserver://$hostname:$port;databaseName=$database",
"com.microsoft.sqlserver.jdbc.SQLServerDriver",
"https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/6.4.0.jre8/mssql-jdbc-6.4.0.jre8.jar",
hostname, port, database,
username, password,
)
private val libsFolder = File("klibs").apply { mkdirs() }
private val jarFile = File(libsFolder, "$name-Driver.jar")
protected fun loadDependency() {
try {
Class.forName(driverClass)
} catch (e: ClassNotFoundException) {
if (jarFile.exists()) {
loadDriver()
} else {
try {
downloadDriver()
} catch (e: Exception) {
throw SQLException("Cant download the driver dependencie of $name")
}
try {
loadDriver()
Class.forName(driverClass)
} catch (e: Exception) {
jarFile.delete()
throw SQLException("Cant load the driver dependencies of $name")
}
}
}
}
private fun loadDriver() {
val url = jarFile.toURI().toURL()
val classLoader = DatabaseType::class.java.classLoader as URLClassLoader
val method = URLClassLoader::class.java.getDeclaredMethod("addURL", URL::class.java)
method.isAccessible = true
method.invoke(classLoader, url)
}
private fun downloadDriver() {
val input = URL(driverLink).openStream()
if (jarFile.exists()) {
if (jarFile.isDirectory) {
throw IOException("File '" + jarFile.name + "' is a directory")
}
if (!jarFile.canWrite()) {
throw IOException("File '" + jarFile.name + "' cannot be written")
}
} else {
val parent = jarFile.parentFile
if (parent != null && !parent.exists() && !parent.mkdirs()) {
throw IOException("File '" + jarFile.name + "' could not be created")
}
}
val output = FileOutputStream(jarFile)
val buffer = ByteArray(4096)
var n = input.read(buffer)
while (-1 != n) {
output.write(buffer, 0, n)
n = input.read(buffer)
}
input.close()
output.close()
}
}
@@ -0,0 +1,162 @@
package tech.carcadex.kotlinbukkitkit.exposed.delegate
import org.bukkit.Bukkit
import org.bukkit.block.Block
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.sql.Column
import kotlin.reflect.KProperty
public fun Entity<*>.block(column: Column<String>): ExposedDelegate<Block> = BlockExposedDelegate(column)
@JvmName("blockNullable")
public fun Entity<*>.block(column: Column<String?>): ExposedDelegate<Block?> = BlockExposedDelegateNullable(column)
public fun Entity<*>.block(
worldColumn: Column<String>,
xColumn: Column<Int>,
yColumn: Column<Int>,
zColumn: Column<Int>,
): ExposedDelegate<Block> = BlockMultiColumnExposedDelegate(worldColumn, xColumn, yColumn, zColumn)
@JvmName("blockNullable")
public fun Entity<*>.nullableBlock(
worldColumn: Column<String?>,
xColumn: Column<Int?>,
yColumn: Column<Int?>,
zColumn: Column<Int?>,
): ExposedDelegate<Block?> = BlockMultiColumnExposedDelegateNullable(worldColumn, xColumn, yColumn, zColumn)
public class BlockExposedDelegate(
public val column: Column<String>,
) : ExposedDelegate<Block> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): Block {
val data = entity.run { column.getValue(this, desc) }
val slices = data.split(";")
val worldName = slices[0]
val world = requireNotNull(Bukkit.getWorld(worldName)) { "World '$worldName' retrieving from database unavailable." }
return world.getBlockAt(
slices[1].toInt(),
slices[2].toInt(),
slices[3].toInt(),
)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: Block,
) {
val parsed = value.run { "${world.name};$x;$y;$z" }
entity.apply { column.setValue(this, desc, parsed) }
}
}
public class BlockExposedDelegateNullable(
public val column: Column<String?>,
) : ExposedDelegate<Block?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): Block? {
val data = entity.run { column.getValue(this, desc) }
val slices = data?.split(";")
return slices?.let {
val worldName = it[0]
val world = requireNotNull(Bukkit.getWorld(worldName)) { "World '$worldName' retrieving from database unavailable." }
world.getBlockAt(
it[1].toInt(),
it[2].toInt(),
it[3].toInt(),
)
}
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: Block?,
) {
val parsed = value?.run { "${world.name};$x;$y;$z" }
entity.apply { column.setValue(this, desc, parsed) }
}
}
public class BlockMultiColumnExposedDelegate(
public val worldColumn: Column<String>,
public val xColumn: Column<Int>,
public val yColumn: Column<Int>,
public val zColumn: Column<Int>,
) : ExposedDelegate<Block> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): Block {
val worldName = entity.run { worldColumn.getValue(this, desc) }
val x = entity.run { xColumn.getValue(this, desc) }
val y = entity.run { yColumn.getValue(this, desc) }
val z = entity.run { zColumn.getValue(this, desc) }
val world = requireNotNull(Bukkit.getWorld(worldName)) { "World '$worldName' retrieving from database unavailable." }
return world.getBlockAt(x, y, z)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: Block,
) {
entity.apply {
value.apply {
worldColumn.setValue(entity, desc, world.name)
xColumn.setValue(entity, desc, x)
yColumn.setValue(entity, desc, y)
zColumn.setValue(entity, desc, z)
}
}
}
}
public class BlockMultiColumnExposedDelegateNullable(
public val worldColumn: Column<String?>,
public val xColumn: Column<Int?>,
public val yColumn: Column<Int?>,
public val zColumn: Column<Int?>,
) : ExposedDelegate<Block?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): Block? {
val worldName = entity.run { worldColumn.getValue(this, desc) }
val x = entity.run { xColumn.getValue(this, desc) }
val y = entity.run { yColumn.getValue(this, desc) }
val z = entity.run { zColumn.getValue(this, desc) }
return if (
worldName != null &&
x != null && y != null && z != null
) {
val world = requireNotNull(Bukkit.getWorld(worldName)) { "World '$worldName' retrieving from database unavailable." }
world.getBlockAt(x, y, z)
} else {
null
}
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: Block?,
) {
entity.apply {
worldColumn.setValue(entity, desc, value?.world?.name)
xColumn.setValue(entity, desc, value?.x)
yColumn.setValue(entity, desc, value?.y)
zColumn.setValue(entity, desc, value?.z)
}
}
}
@@ -0,0 +1,148 @@
package tech.carcadex.kotlinbukkitkit.exposed.delegate
import tech.carcadex.kotlinbukkitkit.utility.types.BlockPos
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.sql.Column
import kotlin.reflect.KProperty
public fun Entity<*>.blockPos(column: Column<String>): ExposedDelegate<BlockPos> = BlockPosExposedDelegate(column)
@JvmName("blockPosNullable")
public fun Entity<*>.blockPos(column: Column<String?>): ExposedDelegate<BlockPos?> = BlockPosExposedDelegateNullable(column)
public fun Entity<*>.blockPos(
xColumn: Column<Int>,
yColumn: Column<Int>,
zColumn: Column<Int>,
): ExposedDelegate<BlockPos> = BlockPosMultiColumnExposedDelegate(xColumn, yColumn, zColumn)
@JvmName("blockPosNullable")
public fun Entity<*>.nullableBlockPos(
xColumn: Column<Int?>,
yColumn: Column<Int?>,
zColumn: Column<Int?>,
): ExposedDelegate<BlockPos?> = BlockPosMultiColumnExposedDelegateNullable(xColumn, yColumn, zColumn)
public class BlockPosExposedDelegate(
public val column: Column<String>,
) : ExposedDelegate<BlockPos> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): BlockPos {
val data = entity.run { column.getValue(this, desc) }
val slices = data.split(";")
return BlockPos(
slices[0].toInt(),
slices[1].toInt(),
slices[2].toInt(),
)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: BlockPos,
) {
val parsed = value.run { "$x;$y;$z" }
entity.apply { column.setValue(this, desc, parsed) }
}
}
public class BlockPosExposedDelegateNullable(
public val column: Column<String?>,
) : ExposedDelegate<BlockPos?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): BlockPos? {
val data = entity.run { column.getValue(this, desc) }
val slices = data?.split(";")
return slices?.let {
BlockPos(
it[0].toInt(),
it[1].toInt(),
it[2].toInt(),
)
}
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: BlockPos?,
) {
val parsed = value?.run { "$x;$y;$z" }
entity.apply { column.setValue(this, desc, parsed) }
}
}
public class BlockPosMultiColumnExposedDelegate(
public val xColumn: Column<Int>,
public val yColumn: Column<Int>,
public val zColumn: Column<Int>,
) : ExposedDelegate<BlockPos> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): BlockPos {
val x = entity.run { xColumn.getValue(this, desc) }
val y = entity.run { yColumn.getValue(this, desc) }
val z = entity.run { zColumn.getValue(this, desc) }
return BlockPos(x, y, z)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: BlockPos,
) {
entity.apply {
value.apply {
xColumn.setValue(entity, desc, x)
yColumn.setValue(entity, desc, y)
zColumn.setValue(entity, desc, z)
}
}
}
}
public class BlockPosMultiColumnExposedDelegateNullable(
public val xColumn: Column<Int?>,
public val yColumn: Column<Int?>,
public val zColumn: Column<Int?>,
) : ExposedDelegate<BlockPos?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): BlockPos? {
val x = entity.run { xColumn.getValue(this, desc) }
val y = entity.run { yColumn.getValue(this, desc) }
val z = entity.run { zColumn.getValue(this, desc) }
return if (
x != null && y != null && z != null
) {
BlockPos(
x,
y,
z,
)
} else {
null
}
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: BlockPos?,
) {
entity.apply {
xColumn.setValue(entity, desc, value?.x)
yColumn.setValue(entity, desc, value?.y)
zColumn.setValue(entity, desc, value?.z)
}
}
}
@@ -0,0 +1,35 @@
package tech.carcadex.kotlinbukkitkit.exposed.delegate
import org.jetbrains.exposed.dao.Entity
import kotlin.reflect.KProperty
public fun <T> ExposedDelegate<T>.cached(): ExposedDelegate<T> = CachedExposedDelegate(this)
public class CachedExposedDelegate<T>(
private val delegate: ExposedDelegate<T>,
) : ExposedDelegate<T> {
private var cache: T? = null
private var isCached: Boolean = false
override fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): T {
if (!isCached) {
cache = delegate.getValue(entity, desc)
isCached = true
}
return cache!!
}
override fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: T,
) {
delegate.setValue(entity, desc, value)
cache = value
isCached = true
}
}
@@ -0,0 +1,152 @@
package tech.carcadex.kotlinbukkitkit.exposed.delegate
import org.bukkit.Bukkit
import org.bukkit.Chunk
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.sql.Column
import kotlin.reflect.KProperty
public fun Entity<*>.chunk(column: Column<String>): ExposedDelegate<Chunk> = ChunkExposedDelegate(column)
@JvmName("chunkNullable")
public fun Entity<*>.chunk(column: Column<String?>): ExposedDelegate<Chunk?> = ChunkExposedDelegateNullable(column)
public fun Entity<*>.chunk(
worldColumn: Column<String>,
xColumn: Column<Int>,
zColumn: Column<Int>,
): ExposedDelegate<Chunk> = ChunkMultiColumnExposedDelegate(worldColumn, xColumn, zColumn)
@JvmName("chunkNullable")
public fun Entity<*>.chunk(
worldColumn: Column<String?>,
xColumn: Column<Int?>,
zColumn: Column<Int?>,
): ExposedDelegate<Chunk?> = ChunkMultiColumnExposedDelegateNullable(worldColumn, xColumn, zColumn)
public class ChunkExposedDelegate(
public val column: Column<String>,
) : ExposedDelegate<Chunk> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): Chunk {
val data = entity.run { column.getValue(this, desc) }
val slices = data.split(";")
val worldName = slices[0]
val world = requireNotNull(Bukkit.getWorld(worldName)) { "World '$worldName' retrieving from database unavailable." }
return world.getChunkAt(
slices[1].toInt(),
slices[2].toInt(),
)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: Chunk,
) {
val parsed = value.run { "${world.name};$x;$z" }
entity.apply { column.setValue(this, desc, parsed) }
}
}
public class ChunkExposedDelegateNullable(
public val column: Column<String?>,
) : ExposedDelegate<Chunk?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): Chunk? {
val data = entity.run { column.getValue(this, desc) }
val slices = data?.split(";")
return slices?.let {
val worldName = it[0]
val world = requireNotNull(Bukkit.getWorld(worldName)) { "World '$worldName' retrieving from database unavailable." }
world.getChunkAt(
it[1].toInt(),
it[2].toInt(),
)
}
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: Chunk?,
) {
val parsed = value?.run { "${world.name};$x;$z" }
entity.apply { column.setValue(this, desc, parsed) }
}
}
public class ChunkMultiColumnExposedDelegate(
public val worldColumn: Column<String>,
public val xColumn: Column<Int>,
public val zColumn: Column<Int>,
) : ExposedDelegate<Chunk> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): Chunk {
val worldName = entity.run { worldColumn.getValue(this, desc) }
val x = entity.run { xColumn.getValue(this, desc) }
val z = entity.run { zColumn.getValue(this, desc) }
val world = requireNotNull(Bukkit.getWorld(worldName)) { "World '$worldName' retrieving from database unavailable." }
return world.getChunkAt(x, z)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: Chunk,
) {
entity.apply {
value.apply {
worldColumn.setValue(entity, desc, world.name)
xColumn.setValue(entity, desc, x)
zColumn.setValue(entity, desc, z)
}
}
}
}
public class ChunkMultiColumnExposedDelegateNullable(
public val worldColumn: Column<String?>,
public val xColumn: Column<Int?>,
public val zColumn: Column<Int?>,
) : ExposedDelegate<Chunk?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): Chunk? {
val worldName = entity.run { worldColumn.getValue(this, desc) }
val x = entity.run { xColumn.getValue(this, desc) }
val z = entity.run { zColumn.getValue(this, desc) }
return if (
worldName != null &&
x != null && z != null
) {
val world = requireNotNull(Bukkit.getWorld(worldName)) { "World '$worldName' retrieving from database unavailable." }
world.getChunkAt(x, z)
} else {
null
}
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: Chunk?,
) {
entity.apply {
worldColumn.setValue(entity, desc, value?.world?.name)
xColumn.setValue(entity, desc, value?.x)
zColumn.setValue(entity, desc, value?.z)
}
}
}
@@ -0,0 +1,137 @@
package tech.carcadex.kotlinbukkitkit.exposed.delegate
import tech.carcadex.kotlinbukkitkit.utility.types.ChunkPos
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.sql.Column
import kotlin.reflect.KProperty
public fun Entity<*>.chunkPos(column: Column<String>): ExposedDelegate<ChunkPos> = ChunkPosExposedDelegate(column)
@JvmName("chunkPosNullable")
public fun Entity<*>.chunkPos(column: Column<String?>): ExposedDelegate<ChunkPos?> = ChunkPosExposedDelegateNullable(column)
public fun Entity<*>.chunkPos(
xColumn: Column<Int>,
zColumn: Column<Int>,
): ExposedDelegate<ChunkPos> = ChunkPosMultiColumnExposedDelegate(xColumn, zColumn)
@JvmName("chunkPosNullable")
public fun Entity<*>.chunkPos(
xColumn: Column<Int?>,
zColumn: Column<Int?>,
): ExposedDelegate<ChunkPos?> = ChunkPosMultiColumnExposedDelegateNullable(xColumn, zColumn)
public class ChunkPosExposedDelegate(
public val column: Column<String>,
) : ExposedDelegate<ChunkPos> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): ChunkPos {
val data = entity.run { column.getValue(this, desc) }
val slices = data.split(";")
return ChunkPos(
slices[0].toInt(),
slices[1].toInt(),
)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: ChunkPos,
) {
val parsed = value.run { "$x;$z" }
entity.apply { column.setValue(this, desc, parsed) }
}
}
public class ChunkPosExposedDelegateNullable(
public val column: Column<String?>,
) : ExposedDelegate<ChunkPos?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): ChunkPos? {
val data = entity.run { column.getValue(this, desc) }
val slices = data?.split(";")
return slices?.let {
ChunkPos(
it[0].toInt(),
it[1].toInt(),
)
}
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: ChunkPos?,
) {
val parsed = value?.run { "$x;$z" }
entity.apply { column.setValue(this, desc, parsed) }
}
}
public class ChunkPosMultiColumnExposedDelegate(
public val xColumn: Column<Int>,
public val zColumn: Column<Int>,
) : ExposedDelegate<ChunkPos> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): ChunkPos {
val x = entity.run { xColumn.getValue(this, desc) }
val z = entity.run { zColumn.getValue(this, desc) }
return ChunkPos(x, z)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: ChunkPos,
) {
entity.apply {
value.apply {
xColumn.setValue(entity, desc, x)
zColumn.setValue(entity, desc, z)
}
}
}
}
public class ChunkPosMultiColumnExposedDelegateNullable(
public val xColumn: Column<Int?>,
public val zColumn: Column<Int?>,
) : ExposedDelegate<ChunkPos?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): ChunkPos? {
val x = entity.run { xColumn.getValue(this, desc) }
val z = entity.run { zColumn.getValue(this, desc) }
return if (
x != null && z != null
) {
ChunkPos(
x,
z,
)
} else {
null
}
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: ChunkPos?,
) {
entity.apply {
xColumn.setValue(entity, desc, value?.x)
zColumn.setValue(entity, desc, value?.z)
}
}
}
@@ -0,0 +1,18 @@
package tech.carcadex.kotlinbukkitkit.exposed.delegate
import org.jetbrains.exposed.dao.Entity
import kotlin.reflect.KProperty
public interface ExposedDelegate<T> {
public operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): T
public operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: T,
)
}
@@ -0,0 +1,82 @@
package tech.carcadex.kotlinbukkitkit.exposed.delegate
import org.bukkit.inventory.ItemStack
import org.bukkit.util.io.BukkitObjectInputStream
import org.bukkit.util.io.BukkitObjectOutputStream
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.statements.api.ExposedBlob
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import kotlin.reflect.KProperty
/**
* NOTE: This not save NBT and could break version to version, if you pretend
* to upgrade your server and this keep the same, I can't guarantee that.
*/
public fun Entity<*>.itemStack(column: Column<ExposedBlob>): ExposedDelegate<ItemStack> = ItemStackExposedDelegate(column)
@JvmName("itemStackNullable")
public fun Entity<*>.itemStack(column: Column<ExposedBlob?>): ExposedDelegate<ItemStack?> = ItemStackExposedDelegateNullable(column)
public class ItemStackExposedDelegate(
public val column: Column<ExposedBlob>,
) : ExposedDelegate<ItemStack> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): ItemStack {
val blob = entity.run { column.getValue(this, desc) }
return toItemStack(blob.bytes)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: ItemStack,
) {
val byteArray = toByteArray(value)
val blob = ExposedBlob(byteArray)
entity.apply { column.setValue(this, desc, blob) }
}
}
public class ItemStackExposedDelegateNullable(
public val column: Column<ExposedBlob?>,
) : ExposedDelegate<ItemStack?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): ItemStack? {
val blob = entity.run { column.getValue(this, desc) }
return blob?.bytes?.let { toItemStack(it) }
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: ItemStack?,
) {
val byteArray = value?.let { toByteArray(it) }
val blob = byteArray?.let { ExposedBlob(it) }
entity.apply { column.setValue(this, desc, blob) }
}
}
private fun toByteArray(item: ItemStack): ByteArray {
val outputStream = ByteArrayOutputStream()
BukkitObjectOutputStream(outputStream).use {
it.writeObject(item)
}
return outputStream.toByteArray()
}
private fun toItemStack(byteArray: ByteArray): ItemStack {
return ByteArrayInputStream(byteArray).use {
BukkitObjectInputStream(it).use {
it.readObject() as ItemStack
}
}
}
@@ -0,0 +1,190 @@
package tech.carcadex.kotlinbukkitkit.exposed.delegate
import tech.carcadex.kotlinbukkitkit.extensions.world
import org.bukkit.Bukkit
import org.bukkit.Location
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.sql.Column
import kotlin.reflect.KProperty
public fun Entity<*>.location(column: Column<String>): ExposedDelegate<Location> = LocationExposedDelegate(column)
@JvmName("locationNullable")
public fun Entity<*>.location(column: Column<String?>): ExposedDelegate<Location?> = LocationExposedDelegateNullable(column)
public fun Entity<*>.location(
worldColumn: Column<String>,
xColumn: Column<Double>,
yColumn: Column<Double>,
zColumn: Column<Double>,
yawColumn: Column<Float>,
pitchColumn: Column<Float>,
): ExposedDelegate<Location> = LocationMultiColumnExposedDelegate(worldColumn, xColumn, yColumn, zColumn, yawColumn, pitchColumn)
@JvmName("locationNullable")
public fun Entity<*>.location(
worldColumn: Column<String?>,
xColumn: Column<Double?>,
yColumn: Column<Double?>,
zColumn: Column<Double?>,
yawColumn: Column<Float?>,
pitchColumn: Column<Float?>,
): ExposedDelegate<Location?> = LocationMultiColumnExposedDelegateNullable(worldColumn, xColumn, yColumn, zColumn, yawColumn, pitchColumn)
public class LocationExposedDelegate(
public val column: Column<String>,
) : ExposedDelegate<Location> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): Location {
val data = entity.run { column.getValue(this, desc) }
val slices = data.split(";")
return Location(
Bukkit.getWorld(slices[0]),
slices[1].toDouble(),
slices[2].toDouble(),
slices[3].toDouble(),
slices[4].toFloat(),
slices[5].toFloat(),
)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: Location,
) {
val world = requireNotNull(value.world) { "Location with nullable world can't be stored in database" }
val parsed = value.run { "${world.name};$x;$y;$z;$yaw;$pitch" }
entity.apply { column.setValue(this, desc, parsed) }
}
}
public class LocationExposedDelegateNullable(
public val column: Column<String?>,
) : ExposedDelegate<Location?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): Location? {
val data = entity.run { column.getValue(this, desc) }
val slices = data?.split(";")
return slices?.let {
Location(
Bukkit.getWorld(it[0]),
it[1].toDouble(),
it[2].toDouble(),
it[3].toDouble(),
it[4].toFloat(),
it[5].toFloat(),
)
}
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: Location?,
) {
val parsed = value?.run {
val world = requireNotNull(world) { "Location with nullable world can't be stored in database" }
"${world.name};$x;$y;$z;$yaw;$pitch"
}
entity.apply { column.setValue(this, desc, parsed) }
}
}
public class LocationMultiColumnExposedDelegate(
public val worldColumn: Column<String>,
public val xColumn: Column<Double>,
public val yColumn: Column<Double>,
public val zColumn: Column<Double>,
public val yawColumn: Column<Float>,
public val pitchColumn: Column<Float>,
) : ExposedDelegate<Location> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): Location {
val worldName = entity.run { worldColumn.getValue(this, desc) }
val x = entity.run { xColumn.getValue(this, desc) }
val y = entity.run { yColumn.getValue(this, desc) }
val z = entity.run { zColumn.getValue(this, desc) }
val yaw = entity.run { yawColumn.getValue(this, desc) }
val pitch = entity.run { pitchColumn.getValue(this, desc) }
return Location(
Bukkit.getWorld(worldName),
x,
y,
z,
yaw,
pitch,
)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: Location,
) {
entity.apply {
value.apply {
val world = requireNotNull(world) { "Location with nullable world can't be stored in database" }
worldColumn.setValue(entity, desc, world.name)
xColumn.setValue(entity, desc, x)
yColumn.setValue(entity, desc, y)
zColumn.setValue(entity, desc, z)
yawColumn.setValue(entity, desc, yaw)
pitchColumn.setValue(entity, desc, pitch)
}
}
}
}
public class LocationMultiColumnExposedDelegateNullable(
public val worldColumn: Column<String?>,
public val xColumn: Column<Double?>,
public val yColumn: Column<Double?>,
public val zColumn: Column<Double?>,
public val yawColumn: Column<Float?>,
public val pitchColumn: Column<Float?>,
) : ExposedDelegate<Location?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): Location? {
val worldName = entity.run { worldColumn.getValue(this, desc) }
val x = entity.run { xColumn.getValue(this, desc) }
val y = entity.run { yColumn.getValue(this, desc) }
val z = entity.run { zColumn.getValue(this, desc) }
val yaw = entity.run { yawColumn.getValue(this, desc) }
val pitch = entity.run { pitchColumn.getValue(this, desc) }
return if (
worldName != null &&
x != null && y != null && z != null &&
yaw != null && pitch != null
) {
Location(Bukkit.getWorld(worldName), x, y, z, yaw, pitch)
} else {
null
}
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: Location?,
) {
entity.apply {
worldColumn.setValue(entity, desc, value?.world?.name)
xColumn.setValue(entity, desc, value?.x)
yColumn.setValue(entity, desc, value?.y)
zColumn.setValue(entity, desc, value?.z)
yawColumn.setValue(entity, desc, value?.yaw)
pitchColumn.setValue(entity, desc, value?.pitch)
}
}
}
@@ -0,0 +1,177 @@
package tech.carcadex.kotlinbukkitkit.exposed.delegate
import tech.carcadex.kotlinbukkitkit.utility.types.LocationPos
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.sql.Column
import kotlin.reflect.KProperty
public fun Entity<*>.locationPos(column: Column<String>): ExposedDelegate<LocationPos> = LocationPosExposedDelegate(column)
@JvmName("locationPosNullable")
public fun Entity<*>.locationPos(column: Column<String?>): ExposedDelegate<LocationPos?> = LocationPosExposedDelegateNullable(column)
public fun Entity<*>.locationPos(
xColumn: Column<Double>,
yColumn: Column<Double>,
zColumn: Column<Double>,
yawColumn: Column<Float>,
pitchColumn: Column<Float>,
): ExposedDelegate<LocationPos> = LocationPosMultiColumnExposedDelegate(xColumn, yColumn, zColumn, yawColumn, pitchColumn)
@JvmName("locationPosNullable")
public fun Entity<*>.locationPos(
xColumn: Column<Double?>,
yColumn: Column<Double?>,
zColumn: Column<Double?>,
yawColumn: Column<Float?>,
pitchColumn: Column<Float?>,
): ExposedDelegate<LocationPos?> = LocationPosMultiColumnExposedDelegateNullable(xColumn, yColumn, zColumn, yawColumn, pitchColumn)
public class LocationPosExposedDelegate(
public val column: Column<String>,
) : ExposedDelegate<LocationPos> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): LocationPos {
val data = entity.run { column.getValue(this, desc) }
val slices = data.split(";")
return LocationPos(
slices[0].toDouble(),
slices[1].toDouble(),
slices[2].toDouble(),
slices[3].toFloat(),
slices[4].toFloat(),
)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: LocationPos,
) {
val parsed = value.run { "$x;$y;$z;$yaw;$pitch" }
entity.apply { column.setValue(this, desc, parsed) }
}
}
public class LocationPosExposedDelegateNullable(
public val column: Column<String?>,
) : ExposedDelegate<LocationPos?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): LocationPos? {
val data = entity.run { column.getValue(this, desc) }
val slices = data?.split(";")
return slices?.let {
LocationPos(
it[0].toDouble(),
it[1].toDouble(),
it[2].toDouble(),
it[3].toFloat(),
it[4].toFloat(),
)
}
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: LocationPos?,
) {
val parsed = value?.run { "$x;$y;$z;$yaw;$pitch" }
entity.apply { column.setValue(this, desc, parsed) }
}
}
public class LocationPosMultiColumnExposedDelegate(
public val xColumn: Column<Double>,
public val yColumn: Column<Double>,
public val zColumn: Column<Double>,
public val yawColumn: Column<Float>,
public val pitchColumn: Column<Float>,
) : ExposedDelegate<LocationPos> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): LocationPos {
val x = entity.run { xColumn.getValue(this, desc) }
val y = entity.run { yColumn.getValue(this, desc) }
val z = entity.run { zColumn.getValue(this, desc) }
val yaw = entity.run { yawColumn.getValue(this, desc) }
val pitch = entity.run { pitchColumn.getValue(this, desc) }
return LocationPos(
x,
y,
z,
yaw,
pitch,
)
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: LocationPos,
) {
entity.apply {
value.apply {
xColumn.setValue(entity, desc, x)
yColumn.setValue(entity, desc, y)
zColumn.setValue(entity, desc, z)
yawColumn.setValue(entity, desc, yaw)
pitchColumn.setValue(entity, desc, pitch)
}
}
}
}
public class LocationPosMultiColumnExposedDelegateNullable(
public val xColumn: Column<Double?>,
public val yColumn: Column<Double?>,
public val zColumn: Column<Double?>,
public val yawColumn: Column<Float?>,
public val pitchColumn: Column<Float?>,
) : ExposedDelegate<LocationPos?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): LocationPos? {
val x = entity.run { xColumn.getValue(this, desc) }
val y = entity.run { yColumn.getValue(this, desc) }
val z = entity.run { zColumn.getValue(this, desc) }
val yaw = entity.run { yawColumn.getValue(this, desc) }
val pitch = entity.run { pitchColumn.getValue(this, desc) }
return if (
x != null && y != null && z != null &&
yaw != null && pitch != null
) {
LocationPos(
x,
y,
z,
yaw,
pitch,
)
} else {
null
}
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: LocationPos?,
) {
entity.apply {
xColumn.setValue(entity, desc, value?.x)
yColumn.setValue(entity, desc, value?.y)
zColumn.setValue(entity, desc, value?.z)
yawColumn.setValue(entity, desc, value?.yaw)
pitchColumn.setValue(entity, desc, value?.pitch)
}
}
}
@@ -0,0 +1,47 @@
package tech.carcadex.kotlinbukkitkit.exposed.delegate
import tech.carcadex.kotlinbukkitkit.extensions.offlinePlayer
import org.bukkit.OfflinePlayer
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.sql.Column
import java.util.*
import kotlin.reflect.KProperty
public fun Entity<*>.offlinePlayer(column: Column<UUID>): ExposedDelegate<OfflinePlayer> = OfflinePlayerExposedDelegate(column)
@JvmName("offlinePlayerNullable")
public fun Entity<*>.offlinePlayer(column: Column<UUID?>): ExposedDelegate<OfflinePlayer?> = OfflinePlayerExposedDelegateNullable(column)
public class OfflinePlayerExposedDelegate(
public val column: Column<UUID>,
) : ExposedDelegate<OfflinePlayer> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): OfflinePlayer {
val uuid = entity.run { column.getValue(this, desc) }
return offlinePlayer(uuid)
}
override operator fun <ID : Comparable<ID>> setValue(entity: Entity<ID>, desc: KProperty<*>, value: OfflinePlayer) {
entity.apply { column.setValue(this, desc, value.uniqueId) }
}
}
public class OfflinePlayerExposedDelegateNullable(
public val column: Column<UUID?>,
) : ExposedDelegate<OfflinePlayer?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): OfflinePlayer? {
val uuid = entity.run { column.getValue(this, desc) }
return uuid?.let { offlinePlayer(it) }
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: OfflinePlayer?,
) {
entity.apply { column.setValue(this, desc, value?.uniqueId) }
}
}
@@ -0,0 +1,52 @@
package tech.carcadex.kotlinbukkitkit.exposed.delegate
import org.bukkit.Bukkit
import org.bukkit.World
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.sql.Column
import kotlin.reflect.KProperty
public fun Entity<*>.world(column: Column<String>): ExposedDelegate<World> = WorldExposedDelegate(column)
@JvmName("worldNullable")
public fun Entity<*>.world(column: Column<String?>): ExposedDelegate<World?> = WorldExposedDelegateNullable(column)
public class WorldExposedDelegate(
public val column: Column<String>,
) : ExposedDelegate<World> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): World {
val data = entity.run { column.getValue(this, desc) }
return requireNotNull(Bukkit.getWorld(data)) { "World '$data' retrieving from database not loaded at server." }
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: World,
) {
entity.apply { column.setValue(this, desc, value.name) }
}
}
public class WorldExposedDelegateNullable(
public val column: Column<String?>,
) : ExposedDelegate<World?> {
override operator fun <ID : Comparable<ID>> getValue(
entity: Entity<ID>,
desc: KProperty<*>,
): World? {
val data = entity.run { column.getValue(this, desc) }
return data?.let { Bukkit.getWorld(it) }
}
override operator fun <ID : Comparable<ID>> setValue(
entity: Entity<ID>,
desc: KProperty<*>,
value: World?,
) {
entity.apply { column.setValue(this, desc, value?.name) }
}
}