feat: database connection and data serialization

This commit is contained in:
Keisuke Hirata 2024-09-21 14:48:13 +09:00
parent 21702d6997
commit 53f68e973e
8 changed files with 301 additions and 118 deletions

View File

@ -1,14 +1,23 @@
package net.hareworks.simplymcdb 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.database.Database
import net.hareworks.simplymcdb.command.smcdb import net.hareworks.simplymcdb.command.smcdb
import net.hareworks.kommandlib.KommandLib import net.hareworks.kommandlib.KommandLib
import org.bukkit.plugin.java.JavaPlugin import org.bukkit.plugin.java.JavaPlugin
enum class State {
ACTIVE,
DISCONNECTED,
DISABLED
}
public class App : JavaPlugin() { public class App : JavaPlugin() {
public var enabled: Boolean = false public var enabled: State = State.DISABLED
private set private set(value) {
field = value
Config.config.set("enabled", !value.equals(State.DISABLED))
}
companion object { companion object {
lateinit var instance: App lateinit var instance: App
private set private set
@ -19,25 +28,29 @@ public class App : JavaPlugin() {
instance = this instance = this
logger.info("simplymcdb enabled.") logger.info("simplymcdb enabled.")
initConfig() Config.init()
Database.connect()
command = KommandLib(this, "smcdb" to smcdb) command = KommandLib(this, "smcdb" to smcdb)
} }
override fun onDisable() { override fun onDisable() {
enabled = false enabled = State.DISABLED
Database.disconnect() Database.disconnect()
command.unregister() command.unregister()
logger.info("simplymcdb disabled.") logger.info("simplymcdb disabled.")
} }
public fun enable() { public fun enable() {
enabled = true Database.connect()
if (Database.instance == null) {
enabled = State.DISCONNECTED
return
}
logger.info("simplymcdb enabled.") logger.info("simplymcdb enabled.")
enabled = State.ACTIVE
} }
public fun disable() { public fun disable() {
enabled = false
logger.info("simplymcdb disabled.")
Database.disconnect() Database.disconnect()
logger.info("simplymcdb disabled.")
enabled = State.DISABLED
} }
} }

View File

@ -2,9 +2,10 @@ package net.hareworks.simplymcdb.command
import net.hareworks.kommandlib.* import net.hareworks.kommandlib.*
import net.hareworks.simplymcdb.App import net.hareworks.simplymcdb.App
import net.hareworks.simplymcdb.State
import net.hareworks.simplymcdb.config.reload as reloadConfig import net.hareworks.simplymcdb.config.reload as reloadConfig
import net.hareworks.simplymcdb.database.Database
import net.kyori.adventure.text.minimessage.MiniMessage import net.kyori.adventure.text.minimessage.MiniMessage
import org.bukkit.entity.Player
public val smcdb: Route = public val smcdb: Route =
Route( Route(
@ -41,41 +42,78 @@ public val smcdb: Route =
var help = var help =
MiniMessage.miniMessage() MiniMessage.miniMessage()
.deserialize( .deserialize(
"""<red>simplymcdb config help "<red>simplymcdb config help<newline><gray>reload: <green>reload the config from config.yml<newline><gray>fetch: <green>fetch the config from the database<newline><gray>upload: <green>upload the current config to the database"
<gray>reload: <green>reload the config from config.yml
<gray>fetch: <green>fetch the config from the database
<gray>upload: <green>upload the current config to the database
"""
) )
sender.sendMessage(help) sender.sendMessage(help)
} }
.apply { .apply {
permission = permission =
"simplydb.command.config" "simplydb.command.config"
} },
) { sender, _ ->
(sender as Player).performCommand("smcdb config help")
}
.apply { permission = "simplydb.command.config" },
"on" to "on" to
Route { sender, _ -> Route { sender, _ ->
if (App.instance.enabled) { if (App.instance.enabled == State.ACTIVE
sender.sendMessage("simplymcdb is already enabled.") ) {
sender.sendMessage(
"simplymcdb is already enabled."
)
return@Route return@Route
} }
App.instance.enable() App.instance.enable()
sender.sendMessage("simplymcdb enabled.") sender.sendMessage("simplymcdb enabled.")
} }
.apply { permission = "simplydb.command.on" }, .apply {
permission = "simplydb.command.config.on"
},
"off" to "off" to
Route { sender, _ -> Route { sender, _ ->
if (!App.instance.enabled) { if (App.instance.enabled != State.ACTIVE
sender.sendMessage("simplymcdb is already disabled.") ) {
sender.sendMessage(
"simplymcdb is already disabled."
)
return@Route return@Route
} }
App.instance.disable() App.instance.disable()
sender.sendMessage("simplymcdb disabled.") sender.sendMessage("simplymcdb disabled.")
} }
.apply { permission = "simplydb.command.off" }, .apply {
permission =
"simplydb.command.config.off"
},
) { sender, _ ->
(sender as ).performCommand("smcdb config help")
}
.apply { permission = "simplydb.command.config" },
"help" to Route { sender, _ ->
var help =
MiniMessage.miniMessage()
.deserialize(
"<red>simplymcdb help<newline><gray>config: <green>configre the plugin<newline><gray>activate: <green>when the plugin is disabled, activate it<newline><gray>deactivate: <green>when the plugin is enabled, deactivate it"
)
sender.sendMessage(help)
}
.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.")
}
.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") } ) { sender, _ -> sender.sendMessage("simplymcdb command") }
.apply { permission = "simplydb.command" } .apply { name = "simplymcdb" }

View File

@ -1,8 +1,23 @@
package net.hareworks.simplymcdb.config package net.hareworks.simplymcdb
import net.hareworks.simplymcdb.App
import org.bukkit.configuration.file.YamlConfiguration import org.bukkit.configuration.file.YamlConfiguration
import org.jetbrains.exposed.sql.Table
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 object Config {
public val config: YamlConfiguration = YamlConfiguration() public val config: YamlConfiguration = YamlConfiguration()
public fun init() { public fun init() {
@ -14,3 +29,9 @@ public fun reload() {
config.load(App.instance.dataFolder.resolve("config.yml")) config.load(App.instance.dataFolder.resolve("config.yml"))
App.instance.logger.info("config reloaded.") App.instance.logger.info("config reloaded.")
} }
public fun save() {
config.save(App.instance.dataFolder.resolve("config.yml"))
App.instance.logger.info("config saved.")
}
}

View File

@ -1,17 +1,42 @@
package net.hareworks.simplymcdb.event package net.hareworks.simplymcdb.event
import net.hareworks.simplymcdb.App import net.hareworks.simplymcdb.App
import org.bukkit.event.Listener import net.hareworks.simplymcdb.State
import org.bukkit.event.EventHandler import net.hareworks.simplymcdb.database.Database
import org.bukkit.event.player.PlayerJoinEvent
import net.kyori.adventure.text.minimessage.MiniMessage 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 { public object EventListener : Listener {
@EventHandler @EventHandler
fun onJoin(event: PlayerJoinEvent) { fun onJoin(event: PlayerJoinEvent) {
if (event.player.hasPermission("simplymcdb.admin") || !App.instance.enabled) { if (event.player.hasPermission("simplymcdb.admin")) {
when (App.instance.enabled) {
State.DISABLED -> {
val mm = MiniMessage.miniMessage().deserialize("<red>simplymcdb is disabled.") val mm = MiniMessage.miniMessage().deserialize("<red>simplymcdb is disabled.")
event.player.sendMessage(mm) event.player.sendMessage(mm)
} }
State.DISCONNECTED -> {
val mm = MiniMessage.miniMessage().deserialize("<red>simplymcdb is enabled but disconnected.<br><gray>Check the database connection and try /smcdb on.")
event.player.sendMessage(mm)
}
else -> {
val mm = MiniMessage.miniMessage().deserialize("<green>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) {
}
}
}
} }
} }

View File

@ -1,8 +1,49 @@
package net.hareworks.simplymcdb.playerdata package net.hareworks.simplymcdb.playerdata
public class PlayerData { import net.hareworks.simplymcdb.App
override fun toString() : String { import net.hareworks.simplymcdb.database.Database
return "PlayerData" 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"
}
}
}
}

View File

@ -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<ItemStack>,
val armor: Array<ItemStack>,
)
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<String, Any> {
return mapOf()
}
}
fun ItemStacksToBase64(item: Array<ItemStack>): String {
return ""
}
fun fromBase64(data: String): ByteArray {
return byteArrayOf()
}

View File

@ -2,24 +2,11 @@ package net.hareworks.simplymcdb.database
import net.hareworks.simplymcdb.App import net.hareworks.simplymcdb.App
import net.hareworks.simplymcdb.config.config import net.hareworks.simplymcdb.config.config
import net.hareworks.simplymcdb.playerdata.Player
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.transactions.transaction 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 object Database {
public var instance: Database? = null public var instance: Database? = null
private set private set
@ -62,11 +49,10 @@ public object Database {
} }
if (instance == null) return if (instance == null) return
App.instance.logger.info("Database connected: $host:$port/$database") App.instance.logger.info("Database connected: $host:$port/$database")
transaction { addLogger(StdOutSqlLogger) if (!ping()) {
SchemaUtils.create(Players) App.instance.logger.warning("Database ping failed")
Players.selectAll().forEach { } else {
App.instance.logger.info(it[Players.name]) App.instance.logger.info("Database ping successful")
}
} }
} }
public fun disconnect() { public fun disconnect() {
@ -78,4 +64,22 @@ public object Database {
} }
App.instance.logger.warning("Database is not connected") 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)
}
}
} }

View File

@ -6,3 +6,13 @@ database:
database: smcdb database: smcdb
user: smcdb user: smcdb
password: SaN1m_wk2eh9 password: SaN1m_wk2eh9
playerdata:
health: true
hunger: true
experience: true
status: true
inventory: true
enderchest: true
# achievements: true
# recipebook: true
gamemode: true