mirror of
https://github.com/GayPizzaSpecifications/foundation.git
synced 2025-08-03 05:30:55 +00:00
heimdall: implement precise block change collector
This commit is contained in:
@ -4,4 +4,5 @@ object BlockChangeTable : PlayerTimedLocalEventTable("block_changes") {
|
|||||||
val block = text("block")
|
val block = text("block")
|
||||||
val data = text("data")
|
val data = text("data")
|
||||||
val cause = text("cause")
|
val cause = text("cause")
|
||||||
|
val inc = integer("inc")
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ class FoundationHeimdallPlugin : JavaPlugin(), Listener {
|
|||||||
private val buffer = EventBuffer()
|
private val buffer = EventBuffer()
|
||||||
private val bufferFlushThread = BufferFlushThread(this, buffer)
|
private val bufferFlushThread = BufferFlushThread(this, buffer)
|
||||||
|
|
||||||
private val collectors = mutableListOf<EventCollector<*>>()
|
val collectors = mutableListOf<EventCollector<*>>()
|
||||||
|
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
val exportChunksCommand = getCommand("export_all_chunks") ?:
|
val exportChunksCommand = getCommand("export_all_chunks") ?:
|
||||||
@ -48,10 +48,10 @@ class FoundationHeimdallPlugin : JavaPlugin(), Listener {
|
|||||||
)
|
)
|
||||||
config = Yaml.default.decodeFromStream(HeimdallConfig.serializer(), configPath.inputStream())
|
config = Yaml.default.decodeFromStream(HeimdallConfig.serializer(), configPath.inputStream())
|
||||||
if (!config.enabled) {
|
if (!config.enabled) {
|
||||||
slF4JLogger.info("Heimdall is not enabled.")
|
slF4JLogger.info("Heimdall tracking is not enabled.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
slF4JLogger.info("Heimdall is enabled.")
|
slF4JLogger.info("Heimdall tracking is enabled.")
|
||||||
if (!Driver.isRegistered()) {
|
if (!Driver.isRegistered()) {
|
||||||
Driver.register()
|
Driver.register()
|
||||||
}
|
}
|
||||||
@ -91,7 +91,7 @@ class FoundationHeimdallPlugin : JavaPlugin(), Listener {
|
|||||||
bufferFlushThread.start()
|
bufferFlushThread.start()
|
||||||
|
|
||||||
for (collectorProvider in EventCollectorProviders.all) {
|
for (collectorProvider in EventCollectorProviders.all) {
|
||||||
val collector = collectorProvider.collector(buffer)
|
val collector = collectorProvider.collector(config, buffer)
|
||||||
server.pluginManager.registerEvents(collector, this)
|
server.pluginManager.registerEvents(collector, this)
|
||||||
collectors.add(collector)
|
collectors.add(collector)
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,12 @@ class BufferFlushThread(val plugin: FoundationHeimdallPlugin, val buffer: EventB
|
|||||||
fun start() {
|
fun start() {
|
||||||
running.set(true)
|
running.set(true)
|
||||||
val thread = Thread {
|
val thread = Thread {
|
||||||
plugin.slF4JLogger.info("Buffer Flusher Started")
|
plugin.slF4JLogger.info("Buffer flusher started.")
|
||||||
while (running.get()) {
|
while (running.get()) {
|
||||||
flush()
|
flush()
|
||||||
Thread.sleep(5000)
|
Thread.sleep(5000)
|
||||||
}
|
}
|
||||||
plugin.slF4JLogger.info("Buffer Flusher Stopped")
|
plugin.slF4JLogger.info("Buffer flusher stopped.")
|
||||||
}
|
}
|
||||||
thread.name = "Heimdall Buffer Flush"
|
thread.name = "Heimdall Buffer Flush"
|
||||||
thread.isDaemon = false
|
thread.isDaemon = false
|
||||||
@ -31,6 +31,10 @@ class BufferFlushThread(val plugin: FoundationHeimdallPlugin, val buffer: EventB
|
|||||||
|
|
||||||
fun flush() {
|
fun flush() {
|
||||||
try {
|
try {
|
||||||
|
for (collector in plugin.collectors) {
|
||||||
|
collector.beforeBufferFlush()
|
||||||
|
}
|
||||||
|
|
||||||
val db = plugin.db
|
val db = plugin.db
|
||||||
if (db == null) {
|
if (db == null) {
|
||||||
buffer.clear()
|
buffer.clear()
|
||||||
@ -39,7 +43,7 @@ class BufferFlushThread(val plugin: FoundationHeimdallPlugin, val buffer: EventB
|
|||||||
transaction(plugin.db) {
|
transaction(plugin.db) {
|
||||||
val count = buffer.flush(this)
|
val count = buffer.flush(this)
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
plugin.slF4JLogger.debug("Flushed $count Events")
|
plugin.slF4JLogger.debug("Flushed $count events.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -12,7 +12,7 @@ class EventBuffer : IEventBuffer {
|
|||||||
var count = 0L
|
var count = 0L
|
||||||
while (referenceOfEvents.isNotEmpty()) {
|
while (referenceOfEvents.isNotEmpty()) {
|
||||||
val event = referenceOfEvents.removeAt(0)
|
val event = referenceOfEvents.removeAt(0)
|
||||||
event.store(transaction)
|
event.store(transaction, count.toInt())
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
return count
|
return count
|
||||||
@ -22,6 +22,10 @@ class EventBuffer : IEventBuffer {
|
|||||||
events.add(event)
|
events.add(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun pushAll(events: List<HeimdallEvent>) {
|
||||||
|
this.events.addAll(events)
|
||||||
|
}
|
||||||
|
|
||||||
fun clear() {
|
fun clear() {
|
||||||
events = mutableListOf()
|
events = mutableListOf()
|
||||||
}
|
}
|
||||||
|
@ -4,4 +4,5 @@ import gay.pizza.foundation.heimdall.plugin.event.HeimdallEvent
|
|||||||
|
|
||||||
interface IEventBuffer {
|
interface IEventBuffer {
|
||||||
fun push(event: HeimdallEvent)
|
fun push(event: HeimdallEvent)
|
||||||
|
fun pushAll(events: List<HeimdallEvent>)
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
|
}
|
@ -1,26 +1,14 @@
|
|||||||
package gay.pizza.foundation.heimdall.plugin.event
|
package gay.pizza.foundation.heimdall.plugin.event
|
||||||
|
|
||||||
import gay.pizza.foundation.heimdall.plugin.buffer.EventBuffer
|
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 gay.pizza.foundation.heimdall.table.BlockChangeTable
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.block.Block
|
import org.bukkit.block.Block
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.block.BlockState
|
||||||
import org.bukkit.event.EventPriority
|
import org.bukkit.block.data.BlockData
|
||||||
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.event.block.BlockEvent
|
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.Transaction
|
||||||
import org.jetbrains.exposed.sql.insert
|
import org.jetbrains.exposed.sql.insert
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@ -39,19 +27,25 @@ class BlockChange(
|
|||||||
isBreak: Boolean = false,
|
isBreak: Boolean = false,
|
||||||
cause: String,
|
cause: String,
|
||||||
event: BlockEvent,
|
event: BlockEvent,
|
||||||
block: Block = event.block
|
block: Block = event.block,
|
||||||
|
state: BlockState = block.state,
|
||||||
|
data: BlockData = state.blockData
|
||||||
) : this(
|
) : this(
|
||||||
playerUniqueIdentity = playerUniqueIdentity,
|
playerUniqueIdentity = playerUniqueIdentity,
|
||||||
cause = cause,
|
cause = cause,
|
||||||
location = block.location,
|
location = block.location.clone(),
|
||||||
material = if (isBreak) Material.AIR else block.type,
|
material = if (isBreak) Material.AIR else data.material,
|
||||||
blockData = if (isBreak) Material.AIR.createBlockData().asString
|
blockData =
|
||||||
else block.blockData.asString
|
if (isBreak)
|
||||||
|
Material.AIR.createBlockData().asString
|
||||||
|
else
|
||||||
|
data.asString
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun store(transaction: Transaction) {
|
override fun store(transaction: Transaction, index: Int) {
|
||||||
transaction.apply {
|
transaction.apply {
|
||||||
BlockChangeTable.insert {
|
BlockChangeTable.insert {
|
||||||
|
it[inc] = index
|
||||||
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
|
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
|
||||||
it[block] = material.key.toString()
|
it[block] = material.key.toString()
|
||||||
it[data] = this@BlockChange.blockData
|
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> {
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
)
|
||||||
|
}
|
@ -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.EventBuffer
|
||||||
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
|
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
|
||||||
|
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
|
||||||
import gay.pizza.foundation.heimdall.table.EntityKillTable
|
import gay.pizza.foundation.heimdall.table.EntityKillTable
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
@ -18,7 +19,7 @@ class EntityKill(
|
|||||||
val entityTypeName: String,
|
val entityTypeName: String,
|
||||||
val timestamp: Instant = Instant.now()
|
val timestamp: Instant = Instant.now()
|
||||||
) : HeimdallEvent() {
|
) : HeimdallEvent() {
|
||||||
override fun store(transaction: Transaction) {
|
override fun store(transaction: Transaction, index: Int) {
|
||||||
transaction.apply {
|
transaction.apply {
|
||||||
EntityKillTable.insert {
|
EntityKillTable.insert {
|
||||||
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
|
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
|
||||||
@ -35,7 +36,7 @@ class EntityKill(
|
|||||||
buffer.push(
|
buffer.push(
|
||||||
EntityKill(
|
EntityKill(
|
||||||
killer.uniqueId,
|
killer.uniqueId,
|
||||||
killer.location,
|
killer.location.clone(),
|
||||||
event.entity.uniqueId,
|
event.entity.uniqueId,
|
||||||
event.entityType.key.toString()
|
event.entityType.key.toString()
|
||||||
)
|
)
|
||||||
@ -44,6 +45,6 @@ class EntityKill(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object : EventCollectorProvider<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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,5 +4,6 @@ import org.bukkit.Server
|
|||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.Listener
|
||||||
|
|
||||||
interface EventCollector<T : HeimdallEvent> : Listener {
|
interface EventCollector<T : HeimdallEvent> : Listener {
|
||||||
|
fun beforeBufferFlush() {}
|
||||||
fun onPluginDisable(server: Server) {}
|
fun onPluginDisable(server: Server) {}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package gay.pizza.foundation.heimdall.plugin.event
|
package gay.pizza.foundation.heimdall.plugin.event
|
||||||
|
|
||||||
import gay.pizza.foundation.heimdall.plugin.buffer.EventBuffer
|
import gay.pizza.foundation.heimdall.plugin.buffer.EventBuffer
|
||||||
|
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
|
||||||
|
|
||||||
interface EventCollectorProvider<T : HeimdallEvent> {
|
interface EventCollectorProvider<T : HeimdallEvent> {
|
||||||
fun collector(buffer: EventBuffer): EventCollector<T>
|
fun collector(config: HeimdallConfig, buffer: EventBuffer): EventCollector<T>
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,5 @@ package gay.pizza.foundation.heimdall.plugin.event
|
|||||||
import org.jetbrains.exposed.sql.Transaction
|
import org.jetbrains.exposed.sql.Transaction
|
||||||
|
|
||||||
abstract class HeimdallEvent {
|
abstract class HeimdallEvent {
|
||||||
abstract fun store(transaction: Transaction)
|
abstract fun store(transaction: Transaction, index: Int)
|
||||||
}
|
}
|
||||||
|
@ -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.EventBuffer
|
||||||
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
|
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
|
||||||
|
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
|
||||||
import gay.pizza.foundation.heimdall.table.PlayerAdvancementTable
|
import gay.pizza.foundation.heimdall.table.PlayerAdvancementTable
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.advancement.Advancement
|
import org.bukkit.advancement.Advancement
|
||||||
@ -20,11 +21,11 @@ class PlayerAdvancement(
|
|||||||
) : HeimdallEvent() {
|
) : HeimdallEvent() {
|
||||||
constructor(event: PlayerAdvancementDoneEvent) : this(
|
constructor(event: PlayerAdvancementDoneEvent) : this(
|
||||||
event.player.uniqueId,
|
event.player.uniqueId,
|
||||||
event.player.location,
|
event.player.location.clone(),
|
||||||
event.advancement
|
event.advancement
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun store(transaction: Transaction) {
|
override fun store(transaction: Transaction, index: Int) {
|
||||||
transaction.apply {
|
transaction.apply {
|
||||||
PlayerAdvancementTable.insert {
|
PlayerAdvancementTable.insert {
|
||||||
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
|
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
|
||||||
@ -39,6 +40,6 @@ class PlayerAdvancement(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object : EventCollectorProvider<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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.EventBuffer
|
||||||
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
|
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
|
||||||
|
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
|
||||||
import gay.pizza.foundation.heimdall.table.PlayerDeathTable
|
import gay.pizza.foundation.heimdall.table.PlayerDeathTable
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
@ -21,12 +22,12 @@ class PlayerDeath(
|
|||||||
) : HeimdallEvent() {
|
) : HeimdallEvent() {
|
||||||
constructor(event: PlayerDeathEvent, deathMessage: String? = null) : this(
|
constructor(event: PlayerDeathEvent, deathMessage: String? = null) : this(
|
||||||
event.player.uniqueId,
|
event.player.uniqueId,
|
||||||
event.player.location,
|
event.player.location.clone(),
|
||||||
event.player.exp,
|
event.player.exp,
|
||||||
deathMessage
|
deathMessage
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun store(transaction: Transaction) {
|
override fun store(transaction: Transaction, index: Int) {
|
||||||
transaction.apply {
|
transaction.apply {
|
||||||
PlayerDeathTable.insert {
|
PlayerDeathTable.insert {
|
||||||
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
|
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
|
||||||
@ -52,6 +53,6 @@ class PlayerDeath(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object : EventCollectorProvider<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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.EventBuffer
|
||||||
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
|
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
|
||||||
|
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
|
||||||
import gay.pizza.foundation.heimdall.table.PlayerPositionTable
|
import gay.pizza.foundation.heimdall.table.PlayerPositionTable
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
@ -18,10 +19,10 @@ class PlayerPosition(
|
|||||||
) : HeimdallEvent() {
|
) : HeimdallEvent() {
|
||||||
constructor(event: PlayerMoveEvent) : this(
|
constructor(event: PlayerMoveEvent) : this(
|
||||||
event.player.uniqueId,
|
event.player.uniqueId,
|
||||||
event.to
|
event.to.clone()
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun store(transaction: Transaction) {
|
override fun store(transaction: Transaction, index: Int) {
|
||||||
transaction.apply {
|
transaction.apply {
|
||||||
PlayerPositionTable.insert {
|
PlayerPositionTable.insert {
|
||||||
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
|
putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
|
||||||
@ -35,6 +36,6 @@ class PlayerPosition(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object : EventCollectorProvider<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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.EventBuffer
|
||||||
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
|
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
|
||||||
|
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
|
||||||
import gay.pizza.foundation.heimdall.table.PlayerSessionTable
|
import gay.pizza.foundation.heimdall.table.PlayerSessionTable
|
||||||
import org.bukkit.Server
|
import org.bukkit.Server
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
@ -19,7 +20,7 @@ class PlayerSession(
|
|||||||
val startTimeInstant: Instant,
|
val startTimeInstant: Instant,
|
||||||
val endTimeInstant: Instant
|
val endTimeInstant: Instant
|
||||||
) : HeimdallEvent() {
|
) : HeimdallEvent() {
|
||||||
override fun store(transaction: Transaction) {
|
override fun store(transaction: Transaction, index: Int) {
|
||||||
transaction.apply {
|
transaction.apply {
|
||||||
PlayerSessionTable.insert {
|
PlayerSessionTable.insert {
|
||||||
it[id] = UUID.randomUUID()
|
it[id] = UUID.randomUUID()
|
||||||
@ -61,6 +62,6 @@ class PlayerSession(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object : EventCollectorProvider<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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -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.EventBuffer
|
||||||
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
|
import gay.pizza.foundation.heimdall.plugin.buffer.IEventBuffer
|
||||||
|
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
|
||||||
import gay.pizza.foundation.heimdall.table.WorldChangeTable
|
import gay.pizza.foundation.heimdall.table.WorldChangeTable
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
import org.bukkit.event.player.PlayerChangedWorldEvent
|
import org.bukkit.event.player.PlayerChangedWorldEvent
|
||||||
@ -18,7 +19,7 @@ class WorldChange(
|
|||||||
val toWorldActualName: String,
|
val toWorldActualName: String,
|
||||||
val timestamp: Instant = Instant.now()
|
val timestamp: Instant = Instant.now()
|
||||||
) : HeimdallEvent() {
|
) : HeimdallEvent() {
|
||||||
override fun store(transaction: Transaction) {
|
override fun store(transaction: Transaction, index: Int) {
|
||||||
transaction.apply {
|
transaction.apply {
|
||||||
WorldChangeTable.insert {
|
WorldChangeTable.insert {
|
||||||
putTimedEvent(it, timestamp)
|
putTimedEvent(it, timestamp)
|
||||||
@ -45,6 +46,6 @@ class WorldChange(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object : EventCollectorProvider<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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,9 @@ import kotlinx.serialization.Serializable
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class HeimdallConfig(
|
data class HeimdallConfig(
|
||||||
val enabled: Boolean = false,
|
val enabled: Boolean = false,
|
||||||
val db: DbConfig
|
val db: DbConfig,
|
||||||
|
val blockChangePrecise: Boolean = false,
|
||||||
|
val blockChangePreciseImmediate: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
# Whether Heimdall should be enabled for tracking events.
|
# Whether Heimdall should be enabled for tracking events.
|
||||||
enabled: false
|
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.
|
# Database connection information.
|
||||||
db:
|
db:
|
||||||
# JDBC URL
|
# JDBC URL
|
||||||
|
@ -28,6 +28,7 @@ select add_compression_policy('player_positions', interval '3 days', if_not_exis
|
|||||||
--
|
--
|
||||||
create table if not exists block_changes (
|
create table if not exists block_changes (
|
||||||
time timestamp not null,
|
time timestamp not null,
|
||||||
|
inc int not null,
|
||||||
player uuid null,
|
player uuid null,
|
||||||
world uuid not null,
|
world uuid not null,
|
||||||
x double precision not null,
|
x double precision not null,
|
||||||
@ -38,10 +39,10 @@ create table if not exists block_changes (
|
|||||||
block text not null,
|
block text not null,
|
||||||
data text not null,
|
data text not null,
|
||||||
cause 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 (
|
create table if not exists player_sessions (
|
||||||
id uuid not null,
|
id uuid not null,
|
||||||
|
Reference in New Issue
Block a user