mirror of
https://github.com/GayPizzaSpecifications/foundation.git
synced 2025-08-02 13:10:55 +00:00
Merge branch 'store' into 'main'
Basic Persistent Store using Xodus See merge request lgorence/foundation!2
This commit is contained in:
commit
1791a4ccd4
@ -85,6 +85,10 @@ subprojects {
|
||||
implementation("com.charleskorn.kaml:kaml:0.38.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1")
|
||||
|
||||
// Persistence
|
||||
implementation("org.jetbrains.xodus:xodus-openAPI:1.3.232")
|
||||
implementation("org.jetbrains.xodus:xodus-entity-store:1.3.232")
|
||||
|
||||
// Paper API
|
||||
compileOnly("io.papermc.paper:paper-api:1.18.1-R0.1-SNAPSHOT")
|
||||
}
|
||||
|
@ -1,17 +1,22 @@
|
||||
package cloud.kubelet.foundation.core
|
||||
|
||||
import cloud.kubelet.foundation.core.command.BackupCommand
|
||||
import cloud.kubelet.foundation.core.command.GamemodeCommand
|
||||
import cloud.kubelet.foundation.core.command.LeaderboardCommand
|
||||
import cloud.kubelet.foundation.core.command.UpdateCommand
|
||||
import cloud.kubelet.foundation.core.command.*
|
||||
import cloud.kubelet.foundation.core.persist.PersistentStore
|
||||
import cloud.kubelet.foundation.core.persist.setAllProperties
|
||||
import io.papermc.paper.event.player.AsyncChatEvent
|
||||
import net.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.text.TextComponent
|
||||
import org.bukkit.GameMode
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
import java.nio.file.Path
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class FoundationCorePlugin : JavaPlugin(), Listener {
|
||||
internal val persistentStores = ConcurrentHashMap<String, PersistentStore>()
|
||||
private lateinit var _pluginDataPath: Path
|
||||
|
||||
var pluginDataPath: Path
|
||||
@ -29,6 +34,13 @@ class FoundationCorePlugin : JavaPlugin(), Listener {
|
||||
_pluginDataPath = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a persistent store by name. Make sure the name is path-safe, descriptive and consistent across server runs.
|
||||
*/
|
||||
fun getPersistentStore(name: String) = persistentStores.getOrPut(name) { PersistentStore(this, name) }
|
||||
|
||||
private lateinit var chatLogStore: PersistentStore
|
||||
|
||||
override fun onEnable() {
|
||||
pluginDataPath = dataFolder.toPath()
|
||||
val backupPath = pluginDataPath.resolve(BACKUPS_DIRECTORY)
|
||||
@ -48,10 +60,12 @@ class FoundationCorePlugin : JavaPlugin(), Listener {
|
||||
registerCommandExecutor(listOf("adventure", "a"), GamemodeCommand(GameMode.ADVENTURE))
|
||||
registerCommandExecutor(listOf("spectator", "sp"), GamemodeCommand(GameMode.SPECTATOR))
|
||||
registerCommandExecutor(listOf("leaderboard", "lb"), LeaderboardCommand())
|
||||
registerCommandExecutor(listOf("pstorestats"), StoreStatsCommand(this))
|
||||
|
||||
val log = slF4JLogger
|
||||
log.info("Features:")
|
||||
Util.printFeatureStatus(log, "Backup", BACKUP_ENABLED)
|
||||
chatLogStore = getPersistentStore("chat-logs")
|
||||
}
|
||||
|
||||
private fun registerCommandExecutor(name: String, executor: CommandExecutor) {
|
||||
@ -81,6 +95,26 @@ class FoundationCorePlugin : JavaPlugin(), Listener {
|
||||
server.sendMessage(component)
|
||||
}*/
|
||||
|
||||
@EventHandler
|
||||
private fun logOnChatMessage(e: AsyncChatEvent) {
|
||||
val player = e.player
|
||||
val message = e.message()
|
||||
|
||||
if (message !is TextComponent) {
|
||||
return
|
||||
}
|
||||
|
||||
val content = message.content()
|
||||
chatLogStore.create("ChatMessageEvent") {
|
||||
setAllProperties(
|
||||
"timestamp" to Instant.now().toEpochMilli(),
|
||||
"player.id" to player.identity().uuid().toString(),
|
||||
"player.name" to player.name,
|
||||
"message.content" to content
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val BACKUPS_DIRECTORY = "backups"
|
||||
|
||||
|
@ -0,0 +1,19 @@
|
||||
package cloud.kubelet.foundation.core.command
|
||||
|
||||
import cloud.kubelet.foundation.core.FoundationCorePlugin
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
class StoreStatsCommand(private val plugin: FoundationCorePlugin) : CommandExecutor {
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
plugin.persistentStores.forEach { (name, store) ->
|
||||
store.transact { tx ->
|
||||
val types = tx.entityTypes
|
||||
val counts = types.associateWith { type -> tx.getAll(type).size() }.toSortedMap()
|
||||
sender.sendMessage("Store $name ->", *counts.map { " ${it.key} -> ${it.value} entries" }.toTypedArray())
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package cloud.kubelet.foundation.core.persist
|
||||
|
||||
import cloud.kubelet.foundation.core.FoundationCorePlugin
|
||||
import jetbrains.exodus.entitystore.Entity
|
||||
import jetbrains.exodus.entitystore.PersistentEntityStores
|
||||
import jetbrains.exodus.entitystore.StoreTransaction
|
||||
|
||||
class PersistentStore(corePlugin: FoundationCorePlugin, fileStoreName: String) : AutoCloseable {
|
||||
private val fileStorePath = corePlugin.pluginDataPath.resolve("persistence/${fileStoreName}")
|
||||
internal val entityStore = PersistentEntityStores.newInstance(fileStorePath.toFile())
|
||||
|
||||
fun transact(block: (StoreTransaction) -> Unit) = entityStore.executeInTransaction(block)
|
||||
|
||||
fun create(entityTypeName: String, populate: Entity.() -> Unit) = transact { tx ->
|
||||
val entity = tx.newEntity(entityTypeName)
|
||||
populate(entity)
|
||||
}
|
||||
|
||||
fun <T> find(entityTypeName: String, propertyName: String, value: Comparable<T>) =
|
||||
transact { tx -> tx.find(entityTypeName, propertyName, value) }
|
||||
|
||||
override fun close() {
|
||||
entityStore.close()
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package cloud.kubelet.foundation.core.persist
|
||||
|
||||
import jetbrains.exodus.entitystore.Entity
|
||||
|
||||
fun <T : Comparable<*>> Entity.setAllProperties(vararg entries: Pair<String, T>) = entries.forEach { entry ->
|
||||
setProperty(entry.first, entry.second)
|
||||
}
|
@ -45,3 +45,7 @@ commands:
|
||||
aliases:
|
||||
- lb
|
||||
permission: foundation.command.leaderboard
|
||||
pstorestats:
|
||||
description: Persistent Store Stats
|
||||
usage: /pstorestats
|
||||
permission: foundation.command.pstorestats
|
||||
|
Loading…
Reference in New Issue
Block a user