From 53f68e973e799de3e1866b57d98fdbbb33b4d9b8 Mon Sep 17 00:00:00 2001 From: Hare Date: Sat, 21 Sep 2024 14:48:13 +0900 Subject: [PATCH] feat: database connection and data serialization --- .../kotlin/net/hareworks/simplymcdb/App.kt | 31 ++- .../net/hareworks/simplymcdb/Command.kt | 178 +++++++++++------- .../kotlin/net/hareworks/simplymcdb/Config.kt | 39 +++- .../kotlin/net/hareworks/simplymcdb/Event.kt | 39 +++- .../net/hareworks/simplymcdb/PlayerData.kt | 49 ++++- .../hareworks/simplymcdb/PlayerSerializer.kt | 31 +++ .../hareworks/simplymcdb/database/Database.kt | 42 +++-- src/main/resources/config.yml | 10 + 8 files changed, 301 insertions(+), 118 deletions(-) create mode 100644 src/main/kotlin/net/hareworks/simplymcdb/PlayerSerializer.kt diff --git a/src/main/kotlin/net/hareworks/simplymcdb/App.kt b/src/main/kotlin/net/hareworks/simplymcdb/App.kt index 7a91a71..7809345 100644 --- a/src/main/kotlin/net/hareworks/simplymcdb/App.kt +++ b/src/main/kotlin/net/hareworks/simplymcdb/App.kt @@ -1,14 +1,23 @@ package net.hareworks.simplymcdb -import net.hareworks.simplymcdb.config.init as initConfig +import net.hareworks.simplymcdb.Config import net.hareworks.simplymcdb.database.Database import net.hareworks.simplymcdb.command.smcdb import net.hareworks.kommandlib.KommandLib import org.bukkit.plugin.java.JavaPlugin +enum class State { + ACTIVE, + DISCONNECTED, + DISABLED +} + public class App : JavaPlugin() { - public var enabled: Boolean = false - private set + public var enabled: State = State.DISABLED + private set(value) { + field = value + Config.config.set("enabled", !value.equals(State.DISABLED)) + } companion object { lateinit var instance: App private set @@ -19,25 +28,29 @@ public class App : JavaPlugin() { instance = this logger.info("simplymcdb enabled.") - initConfig() - Database.connect() + Config.init() command = KommandLib(this, "smcdb" to smcdb) } override fun onDisable() { - enabled = false + enabled = State.DISABLED Database.disconnect() command.unregister() logger.info("simplymcdb disabled.") } public fun enable() { - enabled = true + Database.connect() + if (Database.instance == null) { + enabled = State.DISCONNECTED + return + } logger.info("simplymcdb enabled.") + enabled = State.ACTIVE } public fun disable() { - enabled = false - logger.info("simplymcdb disabled.") Database.disconnect() + logger.info("simplymcdb disabled.") + enabled = State.DISABLED } } \ No newline at end of file diff --git a/src/main/kotlin/net/hareworks/simplymcdb/Command.kt b/src/main/kotlin/net/hareworks/simplymcdb/Command.kt index 0651c37..0cae784 100644 --- a/src/main/kotlin/net/hareworks/simplymcdb/Command.kt +++ b/src/main/kotlin/net/hareworks/simplymcdb/Command.kt @@ -2,80 +2,118 @@ package net.hareworks.simplymcdb.command import net.hareworks.kommandlib.* import net.hareworks.simplymcdb.App +import net.hareworks.simplymcdb.State import net.hareworks.simplymcdb.config.reload as reloadConfig +import net.hareworks.simplymcdb.database.Database import net.kyori.adventure.text.minimessage.MiniMessage -import org.bukkit.entity.Player public val smcdb: Route = - Route( - "config" to - Route( - "reload" to - Route { sender, _ -> - sender.sendMessage("reloading config...") - reloadConfig() - sender.sendMessage("reloaded.") - } - .apply { - permission = - "simplydb.command.config.reload" - }, - "fetch" to - Route { sender, _ -> - sender.sendMessage("fetching config...") - } - .apply { - permission = - "simplydb.command.config.fetch" - }, - "upload" to - Route { sender, _ -> - sender.sendMessage("uploading config...") - } - .apply { - permission = - "simplydb.command.config.upload" - }, - "help" to - Route { sender, _ -> - var help = - MiniMessage.miniMessage() - .deserialize( - """simplymcdb config help -reload: reload the config from config.yml -fetch: fetch the config from the database -upload: upload the current config to the database -""" - ) - sender.sendMessage(help) - } - .apply { - permission = - "simplydb.command.config" + Route( + "config" to + Route( + "reload" to + Route { sender, _ -> + sender.sendMessage("reloading config...") + reloadConfig() + sender.sendMessage("reloaded.") + } + .apply { + permission = + "simplydb.command.config.reload" + }, + "fetch" to + Route { sender, _ -> + sender.sendMessage("fetching config...") + } + .apply { + permission = + "simplydb.command.config.fetch" + }, + "upload" to + Route { sender, _ -> + sender.sendMessage("uploading config...") + } + .apply { + permission = + "simplydb.command.config.upload" + }, + "help" to + Route { sender, _ -> + var help = + MiniMessage.miniMessage() + .deserialize( + "simplymcdb config helpreload: reload the config from config.ymlfetch: fetch the config from the databaseupload: upload the current config to the database" + ) + sender.sendMessage(help) + } + .apply { + permission = + "simplydb.command.config" + }, + "on" to + Route { sender, _ -> + if (App.instance.enabled == State.ACTIVE + ) { + sender.sendMessage( + "simplymcdb is already enabled." + ) + return@Route + } + App.instance.enable() + sender.sendMessage("simplymcdb enabled.") + } + .apply { + permission = "simplydb.command.config.on" + }, + "off" to + Route { sender, _ -> + if (App.instance.enabled != State.ACTIVE + ) { + sender.sendMessage( + "simplymcdb is already disabled." + ) + return@Route + } + App.instance.disable() + sender.sendMessage("simplymcdb disabled.") + } + .apply { + permission = + "simplydb.command.config.off" + }, + ) { sender, _ -> + (sender as ).performCommand("smcdb config help") } - ) { sender, _ -> - (sender as Player).performCommand("smcdb config help") - } - .apply { permission = "simplydb.command.config" }, - "on" to - Route { sender, _ -> - if (App.instance.enabled) { - sender.sendMessage("simplymcdb is already enabled.") - return@Route + .apply { permission = "simplydb.command.config" }, + "help" to Route { sender, _ -> + var help = + MiniMessage.miniMessage() + .deserialize( + "simplymcdb helpconfig: configre the pluginactivate: when the plugin is disabled, activate itdeactivate: when the plugin is enabled, deactivate it" + ) + sender.sendMessage(help) } - App.instance.enable() - sender.sendMessage("simplymcdb enabled.") - } - .apply { permission = "simplydb.command.on" }, - "off" to - Route { sender, _ -> - if (!App.instance.enabled) { - sender.sendMessage("simplymcdb is already disabled.") - return@Route + .apply { permission = "simplydb.command" }, + "activate" to Route { sender, _ -> + if (App.instance.enabled == State.ACTIVE + ) { + sender.sendMessage( + "simplymcdb is already enabled." + ) + return@Route + } + App.instance.enable() + sender.sendMessage("simplymcdb enabled.") } - App.instance.disable() - sender.sendMessage("simplymcdb disabled.") - } - .apply { permission = "simplydb.command.off" }, - ) { sender, _ -> sender.sendMessage("simplymcdb command") } - .apply { permission = "simplydb.command" } + .apply { permission = "simplydb.command.activate" }, + "initialize" to Route { sender, _ -> + sender.sendMessage("database initializing...") + Database.initialize() + } + .apply { permission = "simplydb.command.setup" }, + "confirm" to Route { sender, _ -> + + } + .apply { permission = "simplydb.command.confirm" }, + ) { sender, _ -> sender.sendMessage("simplymcdb command") } + .apply { name = "simplymcdb" } diff --git a/src/main/kotlin/net/hareworks/simplymcdb/Config.kt b/src/main/kotlin/net/hareworks/simplymcdb/Config.kt index 37cd3ab..bf6794b 100644 --- a/src/main/kotlin/net/hareworks/simplymcdb/Config.kt +++ b/src/main/kotlin/net/hareworks/simplymcdb/Config.kt @@ -1,16 +1,37 @@ -package net.hareworks.simplymcdb.config +package net.hareworks.simplymcdb -import net.hareworks.simplymcdb.App import org.bukkit.configuration.file.YamlConfiguration +import org.jetbrains.exposed.sql.Table -public val config: YamlConfiguration = YamlConfiguration() -public fun init() { - App.instance.saveDefaultConfig() - config.load(App.instance.dataFolder.resolve("config.yml")) +object ConfigTable : Table() { + val uuid = varchar("uuid", 36) + val name = varchar("name", 16) + val lastLogin = long("last_login") + val lastLogout = long("last_logout") + val playTime = long("play_time") + val firstLogin = long("first_login") + val lastIp = varchar("last_ip", 15) + val lastServer = varchar("last_server", 255) + + override val primaryKey = PrimaryKey(uuid) } -public fun reload() { - config.load(App.instance.dataFolder.resolve("config.yml")) - App.instance.logger.info("config reloaded.") +public object Config { + public val config: YamlConfiguration = YamlConfiguration() + + public fun init() { + App.instance.saveDefaultConfig() + config.load(App.instance.dataFolder.resolve("config.yml")) + } + + public fun reload() { + config.load(App.instance.dataFolder.resolve("config.yml")) + App.instance.logger.info("config reloaded.") + } + + public fun save() { + config.save(App.instance.dataFolder.resolve("config.yml")) + App.instance.logger.info("config saved.") + } } diff --git a/src/main/kotlin/net/hareworks/simplymcdb/Event.kt b/src/main/kotlin/net/hareworks/simplymcdb/Event.kt index b8c8a53..5b99687 100644 --- a/src/main/kotlin/net/hareworks/simplymcdb/Event.kt +++ b/src/main/kotlin/net/hareworks/simplymcdb/Event.kt @@ -1,17 +1,42 @@ package net.hareworks.simplymcdb.event import net.hareworks.simplymcdb.App -import org.bukkit.event.Listener -import org.bukkit.event.EventHandler -import org.bukkit.event.player.PlayerJoinEvent +import net.hareworks.simplymcdb.State +import net.hareworks.simplymcdb.database.Database import net.kyori.adventure.text.minimessage.MiniMessage +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.event.player.PlayerJoinEvent +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.transaction public object EventListener : Listener { @EventHandler fun onJoin(event: PlayerJoinEvent) { - if (event.player.hasPermission("simplymcdb.admin") || !App.instance.enabled) { - val mm = MiniMessage.miniMessage().deserialize("simplymcdb is disabled.") - event.player.sendMessage(mm) + if (event.player.hasPermission("simplymcdb.admin")) { + when (App.instance.enabled) { + State.DISABLED -> { + val mm = MiniMessage.miniMessage().deserialize("simplymcdb is disabled.") + event.player.sendMessage(mm) + } + State.DISCONNECTED -> { + val mm = MiniMessage.miniMessage().deserialize("simplymcdb is enabled but disconnected.
Check the database connection and try /smcdb on.") + event.player.sendMessage(mm) + } + else -> { + val mm = MiniMessage.miniMessage().deserialize("simplymcdb is enabled.") + event.player.sendMessage(mm) + } + } + } + if (App.instance.enabled == State.ACTIVE) { + val player = event.player + // if player has already registered in the database, load the data + Database.instance?.let { + transaction(it) { + + } + } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/net/hareworks/simplymcdb/PlayerData.kt b/src/main/kotlin/net/hareworks/simplymcdb/PlayerData.kt index 0a78bea..367ec8b 100644 --- a/src/main/kotlin/net/hareworks/simplymcdb/PlayerData.kt +++ b/src/main/kotlin/net/hareworks/simplymcdb/PlayerData.kt @@ -1,8 +1,49 @@ package net.hareworks.simplymcdb.playerdata -public class PlayerData { - override fun toString() : String { - return "PlayerData" +import net.hareworks.simplymcdb.App +import net.hareworks.simplymcdb.database.Database +import org.bukkit.entity.Player as BukkitPlayer +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.transactions.transaction + +public object Player : Table() { + val uuid = varchar("uuid", 36) + val name = varchar("name", 16) + val lastLogin = long("last_login") + val lastLogout = long("last_logout") + val playTime = long("play_time") + val firstLogin = long("first_login") + val lastIp = varchar("last_ip", 15) + + val data = text("data").nullable() + + override val primaryKey = PrimaryKey(uuid) +} + +public fun register(player: BukkitPlayer) { + App.instance.logger.info("Registering player data for ${player.name}") + Database.instance?.let { + transaction { + Player.insert { + it[uuid] = player.uniqueId.toString() + it[name] = player.name + it[lastLogin] = System.currentTimeMillis() + it[firstLogin] = System.currentTimeMillis() + it[lastIp] = player.address?.address?.hostAddress ?: "unknown" + } + } } } - + +public fun push(player: BukkitPlayer) { + App.instance.logger.info("Creating player data for ${player.name}") + Database.instance?.let { + transaction { + Player.update({ Player.uuid eq player.uniqueId.toString() }) { + it[lastLogin] = System.currentTimeMillis() + it[lastIp] = player.address?.address?.hostAddress ?: "unknown" + + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/hareworks/simplymcdb/PlayerSerializer.kt b/src/main/kotlin/net/hareworks/simplymcdb/PlayerSerializer.kt new file mode 100644 index 0000000..09543ed --- /dev/null +++ b/src/main/kotlin/net/hareworks/simplymcdb/PlayerSerializer.kt @@ -0,0 +1,31 @@ +package net.hareworks.simplymcdb + +import org.bukkit.entity.Player as BukkitPlayer +import org.bukkit.inventory.ItemStack + +class PlayerInventory( + val contents: Array, + val armor: Array, +) + +object PlayerSerializer { + fun serialize(player: BukkitPlayer): String { + val inv = player.inventory.storageContents + val armor = player.inventory.armorContents + val enderChest = player.enderChest + + return "" // base64 encoded string + } + + fun deserialize(data: String): Map { + return mapOf() + } +} + +fun ItemStacksToBase64(item: Array): String { + return "" +} + +fun fromBase64(data: String): ByteArray { + return byteArrayOf() +} \ No newline at end of file diff --git a/src/main/kotlin/net/hareworks/simplymcdb/database/Database.kt b/src/main/kotlin/net/hareworks/simplymcdb/database/Database.kt index 64d7a1e..aa3acfc 100644 --- a/src/main/kotlin/net/hareworks/simplymcdb/database/Database.kt +++ b/src/main/kotlin/net/hareworks/simplymcdb/database/Database.kt @@ -2,24 +2,11 @@ package net.hareworks.simplymcdb.database import net.hareworks.simplymcdb.App import net.hareworks.simplymcdb.config.config +import net.hareworks.simplymcdb.playerdata.Player import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.Database -import org.jetbrains.exposed.sql.Table import org.jetbrains.exposed.sql.transactions.transaction -object Players : Table() { - val uuid = varchar("uuid", 36) - val name = varchar("name", 16) - val lastLogin = long("last_login") - val lastLogout = long("last_logout") - val playTime = long("play_time") - val firstLogin = long("first_login") - val lastIp = varchar("last_ip", 15) - val lastServer = varchar("last_server", 255) - - override val primaryKey = PrimaryKey(uuid) -} - public object Database { public var instance: Database? = null private set @@ -62,11 +49,10 @@ public object Database { } if (instance == null) return App.instance.logger.info("Database connected: $host:$port/$database") - transaction { addLogger(StdOutSqlLogger) - SchemaUtils.create(Players) - Players.selectAll().forEach { - App.instance.logger.info(it[Players.name]) - } + if (!ping()) { + App.instance.logger.warning("Database ping failed") + } else { + App.instance.logger.info("Database ping successful") } } public fun disconnect() { @@ -78,4 +64,22 @@ public object Database { } App.instance.logger.warning("Database is not connected") } + + public fun ping(): Boolean { + return try { + transaction { + addLogger(StdOutSqlLogger) + exec("SELECT 1") + } + true + } catch (e: Exception) { + false + } + } + + public fun initialize() { + transaction { + SchemaUtils.create(Player) + } + } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index aa660cc..ca15183 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -6,3 +6,13 @@ database: database: smcdb user: smcdb password: SaN1m_wk2eh9 +playerdata: + health: true + hunger: true + experience: true + status: true + inventory: true + enderchest: true + # achievements: true + # recipebook: true + gamemode: true \ No newline at end of file