heimdall: implement precise block change collector

This commit is contained in:
Alex Zenla 2023-02-09 03:44:43 -05:00
parent eaa3888821
commit ef822f9217
Signed by: alex
GPG Key ID: C0780728420EBFE5
21 changed files with 326 additions and 167 deletions

View File

@ -4,4 +4,5 @@ object BlockChangeTable : PlayerTimedLocalEventTable("block_changes") {
val block = text("block")
val data = text("data")
val cause = text("cause")
val inc = integer("inc")
}

View File

@ -29,7 +29,7 @@ class FoundationHeimdallPlugin : JavaPlugin(), Listener {
private val buffer = EventBuffer()
private val bufferFlushThread = BufferFlushThread(this, buffer)
private val collectors = mutableListOf<EventCollector<*>>()
val collectors = mutableListOf<EventCollector<*>>()
override fun onEnable() {
val exportChunksCommand = getCommand("export_all_chunks") ?:
@ -48,10 +48,10 @@ class FoundationHeimdallPlugin : JavaPlugin(), Listener {
)
config = Yaml.default.decodeFromStream(HeimdallConfig.serializer(), configPath.inputStream())
if (!config.enabled) {
slF4JLogger.info("Heimdall is not enabled.")
slF4JLogger.info("Heimdall tracking is not enabled.")
return
}
slF4JLogger.info("Heimdall is enabled.")
slF4JLogger.info("Heimdall tracking is enabled.")
if (!Driver.isRegistered()) {
Driver.register()
}
@ -91,7 +91,7 @@ class FoundationHeimdallPlugin : JavaPlugin(), Listener {
bufferFlushThread.start()
for (collectorProvider in EventCollectorProviders.all) {
val collector = collectorProvider.collector(buffer)
val collector = collectorProvider.collector(config, buffer)
server.pluginManager.registerEvents(collector, this)
collectors.add(collector)
}

View File

@ -11,12 +11,12 @@ class BufferFlushThread(val plugin: FoundationHeimdallPlugin, val buffer: EventB
fun start() {
running.set(true)
val thread = Thread {
plugin.slF4JLogger.info("Buffer Flusher Started")
plugin.slF4JLogger.info("Buffer flusher started.")
while (running.get()) {
flush()
Thread.sleep(5000)
}
plugin.slF4JLogger.info("Buffer Flusher Stopped")
plugin.slF4JLogger.info("Buffer flusher stopped.")
}
thread.name = "Heimdall Buffer Flush"
thread.isDaemon = false
@ -31,6 +31,10 @@ class BufferFlushThread(val plugin: FoundationHeimdallPlugin, val buffer: EventB
fun flush() {
try {
for (collector in plugin.collectors) {
collector.beforeBufferFlush()
}
val db = plugin.db
if (db == null) {
buffer.clear()
@ -39,7 +43,7 @@ class BufferFlushThread(val plugin: FoundationHeimdallPlugin, val buffer: EventB
transaction(plugin.db) {
val count = buffer.flush(this)
if (count > 0) {
plugin.slF4JLogger.debug("Flushed $count Events")
plugin.slF4JLogger.debug("Flushed $count events.")
}
}
} catch (e: Exception) {

View File

@ -12,7 +12,7 @@ class EventBuffer : IEventBuffer {
var count = 0L
while (referenceOfEvents.isNotEmpty()) {
val event = referenceOfEvents.removeAt(0)
event.store(transaction)
event.store(transaction, count.toInt())
count++
}
return count
@ -22,6 +22,10 @@ class EventBuffer : IEventBuffer {
events.add(event)
}
override fun pushAll(events: List<HeimdallEvent>) {
this.events.addAll(events)
}
fun clear() {
events = mutableListOf()
}

View File

@ -4,4 +4,5 @@ import gay.pizza.foundation.heimdall.plugin.event.HeimdallEvent
interface IEventBuffer {
fun push(event: HeimdallEvent)
fun pushAll(events: List<HeimdallEvent>)
}

View File

@ -0,0 +1,68 @@
package gay.pizza.foundation.heimdall.plugin.event
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.block.*
class AccurateBlockChangeCollector(val buffer: IEventBuffer) : EventCollector<BlockChange> {
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockPlaced(event: BlockPlaceEvent) =
buffer.push(BlockChangeConversions.blockPlace(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockBreak(event: BlockBreakEvent) =
buffer.push(BlockChangeConversions.blockBreak(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockExplode(event: BlockExplodeEvent) =
buffer.pushAll(BlockChangeConversions.blockExplode(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockBurn(event: BlockBurnEvent) =
buffer.push(BlockChangeConversions.blockBurn(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockDamage(event: BlockDamageEvent) =
buffer.push(BlockChangeConversions.blockDamage(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockForm(event: BlockFormEvent) =
buffer.push(BlockChangeConversions.blockForm(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockGrow(event: BlockGrowEvent) =
buffer.push(BlockChangeConversions.blockGrow(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockFade(event: BlockFadeEvent) =
buffer.push(BlockChangeConversions.blockFade(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockIgnite(event: BlockIgniteEvent) =
buffer.push(BlockChangeConversions.blockIgnite(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockSpread(event: BlockSpreadEvent) =
buffer.push(BlockChangeConversions.blockSpread(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onFluidLevelChange(event: FluidLevelChangeEvent) =
buffer.push(BlockChangeConversions.fluidLevelChange(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onSpongeAbsorb(event: SpongeAbsorbEvent) =
buffer.pushAll(BlockChangeConversions.spongeAbsorb(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onSignChange(event: SignChangeEvent) =
buffer.push(BlockChangeConversions.signChange(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onMoistureChange(event: MoistureChangeEvent) =
buffer.push(BlockChangeConversions.moistureChange(event))
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockCook(event: BlockCookEvent) =
buffer.push(BlockChangeConversions.blockCook(event))
}

View File

@ -1,26 +1,14 @@
package gay.pizza.foundation.heimdall.plugin.event
import gay.pizza.foundation.heimdall.plugin.buffer.EventBuffer
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
import gay.pizza.foundation.heimdall.table.BlockChangeTable
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.block.Block
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.block.BlockBreakEvent
import org.bukkit.event.block.BlockBurnEvent
import org.bukkit.event.block.BlockDamageEvent
import org.bukkit.event.block.BlockDispenseEvent
import org.bukkit.block.BlockState
import org.bukkit.block.data.BlockData
import org.bukkit.event.block.BlockEvent
import org.bukkit.event.block.BlockExplodeEvent
import org.bukkit.event.block.BlockFadeEvent
import org.bukkit.event.block.BlockFormEvent
import org.bukkit.event.block.BlockGrowEvent
import org.bukkit.event.block.BlockIgniteEvent
import org.bukkit.event.block.BlockPlaceEvent
import org.bukkit.event.block.BlockSpreadEvent
import org.bukkit.event.block.FluidLevelChangeEvent
import org.jetbrains.exposed.sql.Transaction
import org.jetbrains.exposed.sql.insert
import java.time.Instant
@ -39,19 +27,25 @@ class BlockChange(
isBreak: Boolean = false,
cause: String,
event: BlockEvent,
block: Block = event.block
block: Block = event.block,
state: BlockState = block.state,
data: BlockData = state.blockData
) : this(
playerUniqueIdentity = playerUniqueIdentity,
cause = cause,
location = block.location,
material = if (isBreak) Material.AIR else block.type,
blockData = if (isBreak) Material.AIR.createBlockData().asString
else block.blockData.asString
location = block.location.clone(),
material = if (isBreak) Material.AIR else data.material,
blockData =
if (isBreak)
Material.AIR.createBlockData().asString
else
data.asString
)
override fun store(transaction: Transaction) {
override fun store(transaction: Transaction, index: Int) {
transaction.apply {
BlockChangeTable.insert {
it[inc] = index
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
it[block] = material.key.toString()
it[data] = this@BlockChange.blockData
@ -60,123 +54,12 @@ class BlockChange(
}
}
class Collector(val buffer: IEventBuffer) : EventCollector<BlockChange> {
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockPlaced(event: BlockPlaceEvent) = buffer.push(
BlockChange(
playerUniqueIdentity = event.player.uniqueId,
event = event,
cause = "place",
isBreak = false
)
)
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockBreak(event: BlockBreakEvent) = buffer.push(
BlockChange(
playerUniqueIdentity = event.player.uniqueId,
event = event,
cause = "break",
isBreak = true
)
)
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockExplode(event: BlockExplodeEvent) = event.blockList().forEach { block ->
buffer.push(
BlockChange(
event = event,
cause = "explode",
isBreak = true,
block = block
)
)
}
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockBurn(event: BlockBurnEvent) = buffer.push(
BlockChange(
playerUniqueIdentity = null,
event = event,
cause = "burn",
isBreak = true
)
)
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockDamage(event: BlockDamageEvent) = buffer.push(
BlockChange(
playerUniqueIdentity = null,
event = event,
cause = "damage"
)
)
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockForm(event: BlockFormEvent) = buffer.push(
BlockChange(
playerUniqueIdentity = null,
event = event,
cause = "form"
)
)
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockGrow(event: BlockGrowEvent) = buffer.push(
BlockChange(
playerUniqueIdentity = null,
event = event,
cause = "grow"
)
)
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockFade(event: BlockFadeEvent) = buffer.push(
BlockChange(
playerUniqueIdentity = null,
event = event,
cause = "fade"
)
)
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockIgnite(event: BlockIgniteEvent) = buffer.push(
BlockChange(
playerUniqueIdentity = null,
event = event,
cause = "ignite"
)
)
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockDispense(event: BlockDispenseEvent) = buffer.push(
BlockChange(
playerUniqueIdentity = null,
event = event,
cause = "dispense"
)
)
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockSpread(event: BlockSpreadEvent) = buffer.push(
BlockChange(
playerUniqueIdentity = null,
event = event,
cause = "spread"
)
)
@EventHandler(priority = EventPriority.MONITOR)
fun onFluidLevelChange(event: FluidLevelChangeEvent) = buffer.push(
BlockChange(
playerUniqueIdentity = null,
event = event,
cause = "fluid-level-change"
)
)
}
companion object : EventCollectorProvider<BlockChange> {
override fun collector(buffer: EventBuffer): EventCollector<BlockChange> = Collector(buffer)
override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector<BlockChange> =
if (config.blockChangePrecise) {
PreciseBlockChangeCollector(config, buffer)
} else {
AccurateBlockChangeCollector(buffer)
}
}
}

View File

@ -0,0 +1,143 @@
package gay.pizza.foundation.heimdall.plugin.event
import org.bukkit.event.block.*
object BlockChangeConversions {
fun blockPlace(event: BlockPlaceEvent): BlockChange =
BlockChange(
playerUniqueIdentity = event.player.uniqueId,
isBreak = false,
cause = "place",
event = event
)
fun blockBreak(event: BlockBreakEvent): BlockChange =
BlockChange(
playerUniqueIdentity = event.player.uniqueId,
isBreak = true,
cause = "break",
event = event
)
fun blockExplode(event: BlockExplodeEvent): List<BlockChange> =
mutableListOf<BlockChange>().apply {
addAll(event.blockList().map { block ->
BlockChange(
cause = "explode",
event = event,
block = block,
isBreak = true
)
})
add(BlockChange(
cause = "exploded",
event = event,
block = event.block,
isBreak = true
))
}
fun blockBurn(event: BlockBurnEvent): BlockChange =
BlockChange(
playerUniqueIdentity = null,
isBreak = true,
cause = "burn",
event = event
)
fun blockDamage(event: BlockDamageEvent): BlockChange =
BlockChange(
playerUniqueIdentity = null,
cause = "damage",
event = event
)
fun blockForm(event: BlockFormEvent): BlockChange =
BlockChange(
playerUniqueIdentity = null,
cause = "form",
event = event,
state = event.newState
)
fun blockGrow(event: BlockGrowEvent): BlockChange =
BlockChange(
playerUniqueIdentity = null,
cause = "grow",
event = event,
state = event.newState
)
fun blockFade(event: BlockFadeEvent): BlockChange =
BlockChange(
playerUniqueIdentity = null,
cause = "fade",
event = event,
state = event.newState
)
fun blockIgnite(event: BlockIgniteEvent): BlockChange =
BlockChange(
playerUniqueIdentity = event.player?.uniqueId,
cause = "ignite",
event = event
)
fun blockSpread(event: BlockSpreadEvent): BlockChange =
BlockChange(
playerUniqueIdentity = null,
cause = "spread",
event = event,
state = event.newState
)
fun fluidLevelChange(event: FluidLevelChangeEvent): BlockChange =
BlockChange(
playerUniqueIdentity = null,
cause = "fluid-level-change",
event = event,
data = event.newData
)
fun signChange(event: SignChangeEvent): BlockChange =
BlockChange(
playerUniqueIdentity = event.player.uniqueId,
cause = "sign-change",
event = event
)
fun spongeAbsorb(event: SpongeAbsorbEvent): List<BlockChange> =
event.blocks.map { block ->
BlockChange(
playerUniqueIdentity = null,
event = event,
cause = "sponge-absorb",
block = block.block,
state = block
)
}
fun moistureChange(event: MoistureChangeEvent): BlockChange =
BlockChange(
playerUniqueIdentity = null,
event = event,
cause = "moisture-change",
state = event.newState
)
fun blockCook(event: BlockCookEvent): BlockChange =
BlockChange(
playerUniqueIdentity = null,
event = event,
cause = "cook"
)
fun physics(event: BlockPhysicsEvent): BlockChange =
BlockChange(
playerUniqueIdentity = null,
event = event,
data = event.changedBlockData,
cause = "physics"
)
}

View File

@ -2,6 +2,7 @@ package gay.pizza.foundation.heimdall.plugin.event
import gay.pizza.foundation.heimdall.plugin.buffer.EventBuffer
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
import gay.pizza.foundation.heimdall.table.EntityKillTable
import org.bukkit.Location
import org.bukkit.event.EventHandler
@ -18,7 +19,7 @@ class EntityKill(
val entityTypeName: String,
val timestamp: Instant = Instant.now()
) : HeimdallEvent() {
override fun store(transaction: Transaction) {
override fun store(transaction: Transaction, index: Int) {
transaction.apply {
EntityKillTable.insert {
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
@ -35,7 +36,7 @@ class EntityKill(
buffer.push(
EntityKill(
killer.uniqueId,
killer.location,
killer.location.clone(),
event.entity.uniqueId,
event.entityType.key.toString()
)
@ -44,6 +45,6 @@ class EntityKill(
}
companion object : EventCollectorProvider<EntityKill> {
override fun collector(buffer: EventBuffer): EventCollector<EntityKill> = Collector(buffer)
override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector<EntityKill> = Collector(buffer)
}
}

View File

@ -4,5 +4,6 @@ import org.bukkit.Server
import org.bukkit.event.Listener
interface EventCollector<T : HeimdallEvent> : Listener {
fun beforeBufferFlush() {}
fun onPluginDisable(server: Server) {}
}

View File

@ -1,7 +1,8 @@
package gay.pizza.foundation.heimdall.plugin.event
import gay.pizza.foundation.heimdall.plugin.buffer.EventBuffer
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
interface EventCollectorProvider<T : HeimdallEvent> {
fun collector(buffer: EventBuffer): EventCollector<T>
fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector<T>
}

View File

@ -3,5 +3,5 @@ package gay.pizza.foundation.heimdall.plugin.event
import org.jetbrains.exposed.sql.Transaction
abstract class HeimdallEvent {
abstract fun store(transaction: Transaction)
abstract fun store(transaction: Transaction, index: Int)
}

View File

@ -2,6 +2,7 @@ package gay.pizza.foundation.heimdall.plugin.event
import gay.pizza.foundation.heimdall.plugin.buffer.EventBuffer
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
import gay.pizza.foundation.heimdall.table.PlayerAdvancementTable
import org.bukkit.Location
import org.bukkit.advancement.Advancement
@ -20,11 +21,11 @@ class PlayerAdvancement(
) : HeimdallEvent() {
constructor(event: PlayerAdvancementDoneEvent) : this(
event.player.uniqueId,
event.player.location,
event.player.location.clone(),
event.advancement
)
override fun store(transaction: Transaction) {
override fun store(transaction: Transaction, index: Int) {
transaction.apply {
PlayerAdvancementTable.insert {
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
@ -39,6 +40,6 @@ class PlayerAdvancement(
}
companion object : EventCollectorProvider<PlayerAdvancement> {
override fun collector(buffer: EventBuffer): EventCollector<PlayerAdvancement> = Collector(buffer)
override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector<PlayerAdvancement> = Collector(buffer)
}
}

View File

@ -2,6 +2,7 @@ package gay.pizza.foundation.heimdall.plugin.event
import gay.pizza.foundation.heimdall.plugin.buffer.EventBuffer
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
import gay.pizza.foundation.heimdall.table.PlayerDeathTable
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
import org.bukkit.Location
@ -21,12 +22,12 @@ class PlayerDeath(
) : HeimdallEvent() {
constructor(event: PlayerDeathEvent, deathMessage: String? = null) : this(
event.player.uniqueId,
event.player.location,
event.player.location.clone(),
event.player.exp,
deathMessage
)
override fun store(transaction: Transaction) {
override fun store(transaction: Transaction, index: Int) {
transaction.apply {
PlayerDeathTable.insert {
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
@ -52,6 +53,6 @@ class PlayerDeath(
}
companion object : EventCollectorProvider<PlayerDeath> {
override fun collector(buffer: EventBuffer): EventCollector<PlayerDeath> = Collector(buffer)
override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector<PlayerDeath> = Collector(buffer)
}
}

View File

@ -2,6 +2,7 @@ package gay.pizza.foundation.heimdall.plugin.event
import gay.pizza.foundation.heimdall.plugin.buffer.EventBuffer
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
import gay.pizza.foundation.heimdall.table.PlayerPositionTable
import org.bukkit.Location
import org.bukkit.event.EventHandler
@ -18,10 +19,10 @@ class PlayerPosition(
) : HeimdallEvent() {
constructor(event: PlayerMoveEvent) : this(
event.player.uniqueId,
event.to
event.to.clone()
)
override fun store(transaction: Transaction) {
override fun store(transaction: Transaction, index: Int) {
transaction.apply {
PlayerPositionTable.insert {
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
@ -35,6 +36,6 @@ class PlayerPosition(
}
companion object : EventCollectorProvider<PlayerPosition> {
override fun collector(buffer: EventBuffer): EventCollector<PlayerPosition> = Collector(buffer)
override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector<PlayerPosition> = Collector(buffer)
}
}

View File

@ -2,6 +2,7 @@ package gay.pizza.foundation.heimdall.plugin.event
import gay.pizza.foundation.heimdall.plugin.buffer.EventBuffer
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
import gay.pizza.foundation.heimdall.table.PlayerSessionTable
import org.bukkit.Server
import org.bukkit.event.EventHandler
@ -19,7 +20,7 @@ class PlayerSession(
val startTimeInstant: Instant,
val endTimeInstant: Instant
) : HeimdallEvent() {
override fun store(transaction: Transaction) {
override fun store(transaction: Transaction, index: Int) {
transaction.apply {
PlayerSessionTable.insert {
it[id] = UUID.randomUUID()
@ -61,6 +62,6 @@ class PlayerSession(
}
companion object : EventCollectorProvider<PlayerSession> {
override fun collector(buffer: EventBuffer): EventCollector<PlayerSession> = Collector(buffer)
override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector<PlayerSession> = Collector(buffer)
}
}

View File

@ -0,0 +1,34 @@
package gay.pizza.foundation.heimdall.plugin.event
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.block.BlockPhysicsEvent
class PreciseBlockChangeCollector(val config: HeimdallConfig, val buffer: IEventBuffer) : EventCollector<BlockChange> {
private var changes = mutableMapOf<String, BlockChange>()
override fun beforeBufferFlush() {
if (config.blockChangePreciseImmediate) {
return
}
val changesToInsert = changes
changes = mutableMapOf()
buffer.pushAll(changesToInsert.values.toList())
}
@EventHandler(priority = EventPriority.MONITOR)
fun onBlockPhysics(event: BlockPhysicsEvent) {
val change = BlockChangeConversions.physics(event)
if (config.blockChangePreciseImmediate) {
buffer.push(change)
return
}
changes[(event.sourceBlock.location.world.name to listOf(
event.sourceBlock.location.x.toLong(),
event.sourceBlock.location.y.toLong(),
event.sourceBlock.location.z.toLong()
)).toString()] = change
}
}

View File

@ -2,6 +2,7 @@ package gay.pizza.foundation.heimdall.plugin.event
import gay.pizza.foundation.heimdall.plugin.buffer.EventBuffer
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
import gay.pizza.foundation.heimdall.table.WorldChangeTable
import org.bukkit.event.EventHandler
import org.bukkit.event.player.PlayerChangedWorldEvent
@ -18,7 +19,7 @@ class WorldChange(
val toWorldActualName: String,
val timestamp: Instant = Instant.now()
) : HeimdallEvent() {
override fun store(transaction: Transaction) {
override fun store(transaction: Transaction, index: Int) {
transaction.apply {
WorldChangeTable.insert {
putTimedEvent(it, timestamp)
@ -45,6 +46,6 @@ class WorldChange(
}
companion object : EventCollectorProvider<WorldChange> {
override fun collector(buffer: EventBuffer): EventCollector<WorldChange> = Collector(buffer)
override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector<WorldChange> = Collector(buffer)
}
}

View File

@ -5,7 +5,9 @@ import kotlinx.serialization.Serializable
@Serializable
data class HeimdallConfig(
val enabled: Boolean = false,
val db: DbConfig
val db: DbConfig,
val blockChangePrecise: Boolean = false,
val blockChangePreciseImmediate: Boolean = false
)
@Serializable

View File

@ -1,6 +1,16 @@
# Whether Heimdall should be enabled for tracking events.
enabled: false
# Whether the block change events should be precise.
# Detail of the cause will be lost but all block updates
# will be captured utilizing physics recording.
blockChangePrecise: false
# Whether the precise block change collector should
# immediately insert changes to the buffer. This is not
# recommended as this may cause large insert operations.
blockChangePreciseImmediate: false
# Database connection information.
db:
# JDBC URL

View File

@ -28,6 +28,7 @@ select add_compression_policy('player_positions', interval '3 days', if_not_exis
--
create table if not exists block_changes (
time timestamp not null,
inc int not null,
player uuid null,
world uuid not null,
x double precision not null,
@ -38,10 +39,10 @@ create table if not exists block_changes (
block text not null,
data text not null,
cause text not null,
PRIMARY KEY (time, world, x, y, z)
PRIMARY KEY (time, inc)
);
--
select create_hypertable('block_changes', 'time', 'x', 4, if_not_exists => TRUE);
select create_hypertable('block_changes', 'time', 'inc', 4, if_not_exists => TRUE);
--
create table if not exists player_sessions (
id uuid not null,