mirror of
				https://github.com/GayPizzaSpecifications/foundation.git
				synced 2025-11-04 03:39:37 +00:00 
			
		
		
		
	Heimdall: Player Session Tracking
This commit is contained in:
		@ -7,20 +7,25 @@ import cloud.kubelet.foundation.heimdall.buffer.EventBuffer
 | 
			
		||||
import cloud.kubelet.foundation.heimdall.event.BlockBreak
 | 
			
		||||
import cloud.kubelet.foundation.heimdall.event.BlockPlace
 | 
			
		||||
import cloud.kubelet.foundation.heimdall.event.PlayerPosition
 | 
			
		||||
import cloud.kubelet.foundation.heimdall.event.PlayerSession
 | 
			
		||||
import cloud.kubelet.foundation.heimdall.model.HeimdallConfig
 | 
			
		||||
import com.charleskorn.kaml.Yaml
 | 
			
		||||
import com.zaxxer.hikari.HikariConfig
 | 
			
		||||
import com.zaxxer.hikari.HikariDataSource
 | 
			
		||||
import org.bukkit.event.EventHandler
 | 
			
		||||
import org.bukkit.event.EventPriority
 | 
			
		||||
import org.bukkit.event.Listener
 | 
			
		||||
import org.bukkit.event.block.BlockBreakEvent
 | 
			
		||||
import org.bukkit.event.block.BlockPlaceEvent
 | 
			
		||||
import org.bukkit.event.entity.EntityDeathEvent
 | 
			
		||||
import org.bukkit.event.player.PlayerJoinEvent
 | 
			
		||||
import org.bukkit.event.player.PlayerMoveEvent
 | 
			
		||||
import org.bukkit.event.player.PlayerQuitEvent
 | 
			
		||||
import org.bukkit.plugin.java.JavaPlugin
 | 
			
		||||
import org.jetbrains.exposed.sql.Database
 | 
			
		||||
import org.postgresql.Driver
 | 
			
		||||
import java.lang.Exception
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.concurrent.ConcurrentHashMap
 | 
			
		||||
import kotlin.io.path.inputStream
 | 
			
		||||
 | 
			
		||||
class FoundationHeimdallPlugin : JavaPlugin(), Listener {
 | 
			
		||||
@ -31,6 +36,8 @@ class FoundationHeimdallPlugin : JavaPlugin(), Listener {
 | 
			
		||||
  private val buffer = EventBuffer()
 | 
			
		||||
  private val bufferFlushThread = BufferFlushThread(this, buffer)
 | 
			
		||||
 | 
			
		||||
  private val playerJoinTimes = ConcurrentHashMap<UUID, Instant>()
 | 
			
		||||
 | 
			
		||||
  override fun onEnable() {
 | 
			
		||||
    val foundation = server.pluginManager.getPlugin("Foundation") as FoundationCorePlugin
 | 
			
		||||
 | 
			
		||||
@ -91,7 +98,25 @@ class FoundationHeimdallPlugin : JavaPlugin(), Listener {
 | 
			
		||||
  @EventHandler
 | 
			
		||||
  fun onBlockBroken(event: BlockBreakEvent) = buffer.push(BlockBreak(event))
 | 
			
		||||
 | 
			
		||||
  @EventHandler
 | 
			
		||||
  fun onPlayerJoin(event: PlayerJoinEvent) {
 | 
			
		||||
    playerJoinTimes[event.player.uniqueId] = Instant.now()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @EventHandler(priority = EventPriority.HIGHEST)
 | 
			
		||||
  fun onPlayerQuit(event: PlayerQuitEvent) {
 | 
			
		||||
    val startTime = playerJoinTimes.remove(event.player.uniqueId) ?: return
 | 
			
		||||
    val endTime = Instant.now()
 | 
			
		||||
    buffer.push(PlayerSession(event.player.uniqueId, event.player.name, startTime, endTime))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  override fun onDisable() {
 | 
			
		||||
    bufferFlushThread.stop()
 | 
			
		||||
    val endTime = Instant.now()
 | 
			
		||||
    for (playerId in playerJoinTimes.keys().toList()) {
 | 
			
		||||
      val startTime = playerJoinTimes.remove(playerId) ?: continue
 | 
			
		||||
      buffer.push(PlayerSession(playerId, server.getPlayer(playerId)?.name ?: "__unknown__", startTime, endTime))
 | 
			
		||||
    }
 | 
			
		||||
    bufferFlushThread.flush()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6,12 +6,30 @@ import java.util.concurrent.atomic.AtomicBoolean
 | 
			
		||||
 | 
			
		||||
class BufferFlushThread(val plugin: FoundationHeimdallPlugin, val buffer: EventBuffer) {
 | 
			
		||||
  private val running = AtomicBoolean(false)
 | 
			
		||||
  private var thread: Thread? = null
 | 
			
		||||
 | 
			
		||||
  fun start() {
 | 
			
		||||
    running.set(true)
 | 
			
		||||
    val thread = Thread {
 | 
			
		||||
      plugin.slF4JLogger.info("Buffer Flusher Started")
 | 
			
		||||
      while (running.get()) {
 | 
			
		||||
        flush()
 | 
			
		||||
        Thread.sleep(5000)
 | 
			
		||||
      }
 | 
			
		||||
      plugin.slF4JLogger.info("Buffer Flusher Stopped")
 | 
			
		||||
    }
 | 
			
		||||
    thread.name = "Heimdall Buffer Flush"
 | 
			
		||||
    thread.isDaemon = false
 | 
			
		||||
    thread.start()
 | 
			
		||||
    this.thread = thread
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fun stop() {
 | 
			
		||||
    running.set(false)
 | 
			
		||||
    thread?.join()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fun flush() {
 | 
			
		||||
    try {
 | 
			
		||||
      transaction(plugin.db) {
 | 
			
		||||
        val count = buffer.flush(this)
 | 
			
		||||
@ -22,16 +40,5 @@ class BufferFlushThread(val plugin: FoundationHeimdallPlugin, val buffer: EventB
 | 
			
		||||
    } catch (e: Exception) {
 | 
			
		||||
      plugin.slF4JLogger.warn("Failed to flush buffer.", e)
 | 
			
		||||
    }
 | 
			
		||||
        Thread.sleep(5000)
 | 
			
		||||
      }
 | 
			
		||||
      plugin.slF4JLogger.info("Buffer Flusher Stopped")
 | 
			
		||||
    }
 | 
			
		||||
    thread.name = "Heimdall Buffer Flush"
 | 
			
		||||
    thread.isDaemon = false
 | 
			
		||||
    thread.start()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fun stop() {
 | 
			
		||||
    running.set(false)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,25 @@
 | 
			
		||||
package cloud.kubelet.foundation.heimdall.event
 | 
			
		||||
 | 
			
		||||
import cloud.kubelet.foundation.heimdall.table.PlayerSessionTable
 | 
			
		||||
import org.jetbrains.exposed.sql.Transaction
 | 
			
		||||
import org.jetbrains.exposed.sql.insert
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
class PlayerSession(
 | 
			
		||||
  val playerUniqueIdentity: UUID,
 | 
			
		||||
  val playerName: String,
 | 
			
		||||
  val startTimeInstant: Instant,
 | 
			
		||||
  val endTimeInstant: Instant
 | 
			
		||||
) : HeimdallEvent() {
 | 
			
		||||
  override fun store(transaction: Transaction) {
 | 
			
		||||
    transaction.apply {
 | 
			
		||||
      PlayerSessionTable.insert {
 | 
			
		||||
        it[player] = playerUniqueIdentity
 | 
			
		||||
        it[name] = playerName
 | 
			
		||||
        it[startTime] = startTimeInstant
 | 
			
		||||
        it[endTime] = endTimeInstant
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,11 @@
 | 
			
		||||
package cloud.kubelet.foundation.heimdall.table
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.exposed.sql.*
 | 
			
		||||
import org.jetbrains.exposed.sql.javatime.timestamp
 | 
			
		||||
 | 
			
		||||
object PlayerSessionTable : Table("player_sessions") {
 | 
			
		||||
  val player = uuid("player")
 | 
			
		||||
  val name = text("name")
 | 
			
		||||
  val startTime = timestamp("start")
 | 
			
		||||
  val endTime = timestamp("end")
 | 
			
		||||
}
 | 
			
		||||
@ -44,3 +44,13 @@ create table if not exists heimdall.block_places (
 | 
			
		||||
);
 | 
			
		||||
--
 | 
			
		||||
select create_hypertable('heimdall.block_places', 'time', 'player', 4,  if_not_exists => TRUE);
 | 
			
		||||
--
 | 
			
		||||
create table if not exists heimdall.player_sessions (
 | 
			
		||||
    player uuid not null,
 | 
			
		||||
    name text not null,
 | 
			
		||||
    "start" timestamp not null,
 | 
			
		||||
    "end" timestamp not null,
 | 
			
		||||
    PRIMARY KEY (player, start)
 | 
			
		||||
);
 | 
			
		||||
--
 | 
			
		||||
select create_hypertable('heimdall.player_sessions', 'start', 'player', 4,  if_not_exists => TRUE);
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user