From ef822f921799ed5d47b79914127f9ff2ea0e15a0 Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Thu, 9 Feb 2023 03:44:43 -0500 Subject: [PATCH] heimdall: implement precise block change collector --- .../heimdall/table/BlockChangeTable.kt | 1 + .../plugin/FoundationHeimdallPlugin.kt | 8 +- .../plugin/buffer/BufferFlushThread.kt | 10 +- .../heimdall/plugin/buffer/EventBuffer.kt | 6 +- .../heimdall/plugin/buffer/IEventBuffer.kt | 1 + .../event/AccurateBlockChangeCollector.kt | 68 ++++++++ .../heimdall/plugin/event/BlockChange.kt | 159 +++--------------- .../plugin/event/BlockChangeConversions.kt | 143 ++++++++++++++++ .../heimdall/plugin/event/EntityKill.kt | 7 +- .../heimdall/plugin/event/EventCollector.kt | 1 + .../plugin/event/EventCollectorProvider.kt | 3 +- .../heimdall/plugin/event/HeimdallEvent.kt | 2 +- .../plugin/event/PlayerAdvancement.kt | 7 +- .../heimdall/plugin/event/PlayerDeath.kt | 7 +- .../heimdall/plugin/event/PlayerPosition.kt | 7 +- .../heimdall/plugin/event/PlayerSession.kt | 5 +- .../event/PreciseBlockChangeCollector.kt | 34 ++++ .../heimdall/plugin/event/WorldChange.kt | 5 +- .../heimdall/plugin/model/HeimdallConfig.kt | 4 +- .../src/main/resources/heimdall.yaml | 10 ++ .../src/main/resources/init.sql | 5 +- 21 files changed, 326 insertions(+), 167 deletions(-) create mode 100644 foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/AccurateBlockChangeCollector.kt create mode 100644 foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/BlockChangeConversions.kt create mode 100644 foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PreciseBlockChangeCollector.kt diff --git a/common-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/table/BlockChangeTable.kt b/common-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/table/BlockChangeTable.kt index d65ad03..ae76748 100644 --- a/common-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/table/BlockChangeTable.kt +++ b/common-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/table/BlockChangeTable.kt @@ -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") } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/FoundationHeimdallPlugin.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/FoundationHeimdallPlugin.kt index 1b8c05a..79c1777 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/FoundationHeimdallPlugin.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/FoundationHeimdallPlugin.kt @@ -29,7 +29,7 @@ class FoundationHeimdallPlugin : JavaPlugin(), Listener { private val buffer = EventBuffer() private val bufferFlushThread = BufferFlushThread(this, buffer) - private val collectors = mutableListOf>() + val collectors = mutableListOf>() 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) } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/buffer/BufferFlushThread.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/buffer/BufferFlushThread.kt index d9d0947..f7a5a13 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/buffer/BufferFlushThread.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/buffer/BufferFlushThread.kt @@ -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) { diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/buffer/EventBuffer.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/buffer/EventBuffer.kt index 2be0b2b..b9f5f19 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/buffer/EventBuffer.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/buffer/EventBuffer.kt @@ -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) { + this.events.addAll(events) + } + fun clear() { events = mutableListOf() } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/buffer/IEventBuffer.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/buffer/IEventBuffer.kt index 5eb72a3..9d5a2fd 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/buffer/IEventBuffer.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/buffer/IEventBuffer.kt @@ -4,4 +4,5 @@ import gay.pizza.foundation.heimdall.plugin.event.HeimdallEvent interface IEventBuffer { fun push(event: HeimdallEvent) + fun pushAll(events: List) } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/AccurateBlockChangeCollector.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/AccurateBlockChangeCollector.kt new file mode 100644 index 0000000..c5c70b7 --- /dev/null +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/AccurateBlockChangeCollector.kt @@ -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 { + @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)) +} diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/BlockChange.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/BlockChange.kt index 678ebde..44843d7 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/BlockChange.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/BlockChange.kt @@ -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 { - @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 { - override fun collector(buffer: EventBuffer): EventCollector = Collector(buffer) + override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector = + if (config.blockChangePrecise) { + PreciseBlockChangeCollector(config, buffer) + } else { + AccurateBlockChangeCollector(buffer) + } } } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/BlockChangeConversions.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/BlockChangeConversions.kt new file mode 100644 index 0000000..5485460 --- /dev/null +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/BlockChangeConversions.kt @@ -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 = + mutableListOf().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 = + 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" + ) +} diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/EntityKill.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/EntityKill.kt index 4f4ca6e..9ca2017 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/EntityKill.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/EntityKill.kt @@ -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 { - override fun collector(buffer: EventBuffer): EventCollector = Collector(buffer) + override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector = Collector(buffer) } } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/EventCollector.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/EventCollector.kt index 30167ed..4c34086 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/EventCollector.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/EventCollector.kt @@ -4,5 +4,6 @@ import org.bukkit.Server import org.bukkit.event.Listener interface EventCollector : Listener { + fun beforeBufferFlush() {} fun onPluginDisable(server: Server) {} } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/EventCollectorProvider.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/EventCollectorProvider.kt index bbe4eeb..5eb91a1 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/EventCollectorProvider.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/EventCollectorProvider.kt @@ -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 { - fun collector(buffer: EventBuffer): EventCollector + fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/HeimdallEvent.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/HeimdallEvent.kt index 0bdf203..d113a83 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/HeimdallEvent.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/HeimdallEvent.kt @@ -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) } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerAdvancement.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerAdvancement.kt index c428405..051a5ee 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerAdvancement.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerAdvancement.kt @@ -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 { - override fun collector(buffer: EventBuffer): EventCollector = Collector(buffer) + override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector = Collector(buffer) } } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerDeath.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerDeath.kt index 26041b8..10dbd4b 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerDeath.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerDeath.kt @@ -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 { - override fun collector(buffer: EventBuffer): EventCollector = Collector(buffer) + override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector = Collector(buffer) } } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerPosition.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerPosition.kt index 5434d1a..8732387 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerPosition.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerPosition.kt @@ -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 { - override fun collector(buffer: EventBuffer): EventCollector = Collector(buffer) + override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector = Collector(buffer) } } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerSession.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerSession.kt index b0e2aa5..723f279 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerSession.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PlayerSession.kt @@ -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 { - override fun collector(buffer: EventBuffer): EventCollector = Collector(buffer) + override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector = Collector(buffer) } } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PreciseBlockChangeCollector.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PreciseBlockChangeCollector.kt new file mode 100644 index 0000000..c9d4fdf --- /dev/null +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/PreciseBlockChangeCollector.kt @@ -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 { + private var changes = mutableMapOf() + + 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 + } +} diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/WorldChange.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/WorldChange.kt index 9d123c1..7773d45 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/WorldChange.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/event/WorldChange.kt @@ -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 { - override fun collector(buffer: EventBuffer): EventCollector = Collector(buffer) + override fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector = Collector(buffer) } } diff --git a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/model/HeimdallConfig.kt b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/model/HeimdallConfig.kt index 74ccb62..45b019f 100644 --- a/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/model/HeimdallConfig.kt +++ b/foundation-heimdall/src/main/kotlin/gay/pizza/foundation/heimdall/plugin/model/HeimdallConfig.kt @@ -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 diff --git a/foundation-heimdall/src/main/resources/heimdall.yaml b/foundation-heimdall/src/main/resources/heimdall.yaml index 6e76f0b..0d6614c 100644 --- a/foundation-heimdall/src/main/resources/heimdall.yaml +++ b/foundation-heimdall/src/main/resources/heimdall.yaml @@ -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 diff --git a/foundation-heimdall/src/main/resources/init.sql b/foundation-heimdall/src/main/resources/init.sql index 0f4c3f3..735c761 100644 --- a/foundation-heimdall/src/main/resources/init.sql +++ b/foundation-heimdall/src/main/resources/init.sql @@ -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,