mirror of
				https://github.com/GayPizzaSpecifications/foundation.git
				synced 2025-11-03 19:29:38 +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