mirror of
				https://github.com/GayPizzaSpecifications/foundation.git
				synced 2025-11-04 11:39:39 +00:00 
			
		
		
		
	Remove heimdall and tool project.
This commit is contained in:
		@ -1,21 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall
 | 
			
		||||
 | 
			
		||||
fun String.sqlSplitStatements(): List<String> {
 | 
			
		||||
  val statements = mutableListOf<String>()
 | 
			
		||||
  val buffer = StringBuilder()
 | 
			
		||||
  fun flush() {
 | 
			
		||||
    val trimmed = buffer.toString().trim()
 | 
			
		||||
    if (trimmed.isNotEmpty()) {
 | 
			
		||||
      statements.add(trimmed)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  for (line in lines()) {
 | 
			
		||||
    if (line.trim() == "--") {
 | 
			
		||||
      flush()
 | 
			
		||||
    } else {
 | 
			
		||||
      buffer.append(line).append("\n")
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  flush()
 | 
			
		||||
  return statements
 | 
			
		||||
}
 | 
			
		||||
@ -1,183 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall
 | 
			
		||||
 | 
			
		||||
import com.charleskorn.kaml.Yaml
 | 
			
		||||
import com.zaxxer.hikari.HikariConfig
 | 
			
		||||
import com.zaxxer.hikari.HikariDataSource
 | 
			
		||||
import gay.pizza.foundation.core.FoundationCorePlugin
 | 
			
		||||
import gay.pizza.foundation.core.Util
 | 
			
		||||
import gay.pizza.foundation.heimdall.buffer.BufferFlushThread
 | 
			
		||||
import gay.pizza.foundation.heimdall.buffer.EventBuffer
 | 
			
		||||
import gay.pizza.foundation.heimdall.event.BlockBreak
 | 
			
		||||
import gay.pizza.foundation.heimdall.event.BlockPlace
 | 
			
		||||
import gay.pizza.foundation.heimdall.event.EntityKill
 | 
			
		||||
import gay.pizza.foundation.heimdall.event.PlayerAdvancement
 | 
			
		||||
import gay.pizza.foundation.heimdall.event.PlayerDeath
 | 
			
		||||
import gay.pizza.foundation.heimdall.event.PlayerPosition
 | 
			
		||||
import gay.pizza.foundation.heimdall.event.PlayerSession
 | 
			
		||||
import gay.pizza.foundation.heimdall.event.WorldChange
 | 
			
		||||
import gay.pizza.foundation.heimdall.export.ExportChunksCommand
 | 
			
		||||
import gay.pizza.foundation.heimdall.model.HeimdallConfig
 | 
			
		||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
 | 
			
		||||
import org.bukkit.event.EventHandler
 | 
			
		||||
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.entity.PlayerDeathEvent
 | 
			
		||||
import org.bukkit.event.player.PlayerAdvancementDoneEvent
 | 
			
		||||
import org.bukkit.event.player.PlayerChangedWorldEvent
 | 
			
		||||
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.time.Duration
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.util.UUID
 | 
			
		||||
import java.util.concurrent.ConcurrentHashMap
 | 
			
		||||
import kotlin.io.path.inputStream
 | 
			
		||||
 | 
			
		||||
class FoundationHeimdallPlugin : JavaPlugin(), Listener {
 | 
			
		||||
  private lateinit var config: HeimdallConfig
 | 
			
		||||
  private lateinit var pool: HikariDataSource
 | 
			
		||||
  internal var db: Database? = null
 | 
			
		||||
 | 
			
		||||
  private val buffer = EventBuffer()
 | 
			
		||||
  private val bufferFlushThread = BufferFlushThread(this, buffer)
 | 
			
		||||
 | 
			
		||||
  private val playerJoinTimes = ConcurrentHashMap<UUID, Instant>()
 | 
			
		||||
 | 
			
		||||
  private val legacyComponentSerializer = LegacyComponentSerializer.builder().build()
 | 
			
		||||
 | 
			
		||||
  override fun onEnable() {
 | 
			
		||||
    val exportChunksCommand = getCommand("export_all_chunks") ?: throw Exception("Failed to get export_all_chunks command")
 | 
			
		||||
    exportChunksCommand.setExecutor(ExportChunksCommand(this))
 | 
			
		||||
 | 
			
		||||
    val foundation = server.pluginManager.getPlugin("Foundation") as FoundationCorePlugin
 | 
			
		||||
 | 
			
		||||
    val configPath = Util.copyDefaultConfig<FoundationHeimdallPlugin>(
 | 
			
		||||
      slF4JLogger,
 | 
			
		||||
      foundation.pluginDataPath,
 | 
			
		||||
      "heimdall.yaml"
 | 
			
		||||
    )
 | 
			
		||||
    config = Yaml.default.decodeFromStream(HeimdallConfig.serializer(), configPath.inputStream())
 | 
			
		||||
    if (!config.enabled) {
 | 
			
		||||
      slF4JLogger.info("Heimdall is not enabled.")
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    slF4JLogger.info("Heimdall is enabled.")
 | 
			
		||||
    if (!Driver.isRegistered()) {
 | 
			
		||||
      Driver.register()
 | 
			
		||||
    }
 | 
			
		||||
    pool = HikariDataSource(HikariConfig().apply {
 | 
			
		||||
      jdbcUrl = config.db.url
 | 
			
		||||
      username = config.db.username
 | 
			
		||||
      password = config.db.password
 | 
			
		||||
      schema = "heimdall"
 | 
			
		||||
      maximumPoolSize = 10
 | 
			
		||||
      idleTimeout = Duration.ofMinutes(5).toMillis()
 | 
			
		||||
      maxLifetime = Duration.ofMinutes(10).toMillis()
 | 
			
		||||
    })
 | 
			
		||||
    val initMigrationContent = FoundationHeimdallPlugin::class.java.getResourceAsStream(
 | 
			
		||||
      "/init.sql"
 | 
			
		||||
    )?.readAllBytes()?.decodeToString() ?: throw RuntimeException("Unable to find Heimdall init.sql")
 | 
			
		||||
 | 
			
		||||
    val statements = initMigrationContent.sqlSplitStatements()
 | 
			
		||||
 | 
			
		||||
    pool.connection.use { conn ->
 | 
			
		||||
      conn.autoCommit = false
 | 
			
		||||
      try {
 | 
			
		||||
        for (statementAsString in statements) {
 | 
			
		||||
          conn.prepareStatement(statementAsString).use {
 | 
			
		||||
            it.execute()
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        conn.commit()
 | 
			
		||||
      } catch (e: Exception) {
 | 
			
		||||
        conn.rollback()
 | 
			
		||||
        throw e
 | 
			
		||||
      } finally {
 | 
			
		||||
        conn.autoCommit = true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    db = Database.connect(pool)
 | 
			
		||||
    server.pluginManager.registerEvents(this, this)
 | 
			
		||||
    bufferFlushThread.start()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @EventHandler
 | 
			
		||||
  fun onPlayerMove(event: PlayerMoveEvent) = buffer.push(PlayerPosition(event))
 | 
			
		||||
 | 
			
		||||
  @EventHandler
 | 
			
		||||
  fun onBlockBroken(event: BlockPlaceEvent) = buffer.push(BlockPlace(event))
 | 
			
		||||
 | 
			
		||||
  @EventHandler
 | 
			
		||||
  fun onBlockBroken(event: BlockBreakEvent) = buffer.push(BlockBreak(event))
 | 
			
		||||
 | 
			
		||||
  @EventHandler
 | 
			
		||||
  fun onPlayerJoin(event: PlayerJoinEvent) {
 | 
			
		||||
    playerJoinTimes[event.player.uniqueId] = Instant.now()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @EventHandler
 | 
			
		||||
  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))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @EventHandler
 | 
			
		||||
  fun onPlayerDeath(event: PlayerDeathEvent) {
 | 
			
		||||
    val deathMessage = event.deathMessage()
 | 
			
		||||
    val deathMessageString = if (deathMessage != null) {
 | 
			
		||||
      legacyComponentSerializer.serialize(deathMessage)
 | 
			
		||||
    } else {
 | 
			
		||||
      null
 | 
			
		||||
    }
 | 
			
		||||
    buffer.push(PlayerDeath(event, deathMessageString))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @EventHandler
 | 
			
		||||
  fun onPlayerAdvancementDone(event: PlayerAdvancementDoneEvent) = buffer.push(PlayerAdvancement(event))
 | 
			
		||||
 | 
			
		||||
  @EventHandler
 | 
			
		||||
  fun onWorldLoad(event: PlayerChangedWorldEvent) = buffer.push(
 | 
			
		||||
    WorldChange(
 | 
			
		||||
      event.player.uniqueId,
 | 
			
		||||
      event.from.uid,
 | 
			
		||||
      event.from.name,
 | 
			
		||||
      event.player.world.uid,
 | 
			
		||||
      event.player.world.name
 | 
			
		||||
    )
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  @EventHandler
 | 
			
		||||
  fun onEntityDeath(event: EntityDeathEvent) {
 | 
			
		||||
    val killer = event.entity.killer ?: return
 | 
			
		||||
    buffer.push(
 | 
			
		||||
      EntityKill(
 | 
			
		||||
        killer.uniqueId,
 | 
			
		||||
        killer.location,
 | 
			
		||||
        event.entity.uniqueId,
 | 
			
		||||
        event.entityType.key.toString()
 | 
			
		||||
      )
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,49 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.buffer
 | 
			
		||||
 | 
			
		||||
import gay.pizza.foundation.heimdall.FoundationHeimdallPlugin
 | 
			
		||||
import org.jetbrains.exposed.sql.transactions.transaction
 | 
			
		||||
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 {
 | 
			
		||||
      val db = plugin.db
 | 
			
		||||
      if (db == null) {
 | 
			
		||||
        buffer.clear()
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
      transaction(plugin.db) {
 | 
			
		||||
        val count = buffer.flush(this)
 | 
			
		||||
        if (count > 0) {
 | 
			
		||||
          plugin.slF4JLogger.debug("Flushed $count Events")
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } catch (e: Exception) {
 | 
			
		||||
      plugin.slF4JLogger.warn("Failed to flush buffer.", e)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,28 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.buffer
 | 
			
		||||
 | 
			
		||||
import gay.pizza.foundation.heimdall.event.HeimdallEvent
 | 
			
		||||
import org.jetbrains.exposed.sql.Transaction
 | 
			
		||||
 | 
			
		||||
class EventBuffer {
 | 
			
		||||
  private var events = mutableListOf<HeimdallEvent>()
 | 
			
		||||
 | 
			
		||||
  fun flush(transaction: Transaction): Long {
 | 
			
		||||
    val referenceOfEvents = events
 | 
			
		||||
    this.events = mutableListOf()
 | 
			
		||||
    var count = 0L
 | 
			
		||||
    while (referenceOfEvents.isNotEmpty()) {
 | 
			
		||||
      val event = referenceOfEvents.removeAt(0)
 | 
			
		||||
      event.store(transaction)
 | 
			
		||||
      count++
 | 
			
		||||
    }
 | 
			
		||||
    return count
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fun push(event: HeimdallEvent) {
 | 
			
		||||
    events.add(event)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fun clear() {
 | 
			
		||||
    events = mutableListOf()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.event
 | 
			
		||||
 | 
			
		||||
import gay.pizza.foundation.heimdall.table.BlockBreakTable
 | 
			
		||||
import org.bukkit.Location
 | 
			
		||||
import org.bukkit.Material
 | 
			
		||||
import org.bukkit.event.block.BlockBreakEvent
 | 
			
		||||
import org.jetbrains.exposed.sql.Transaction
 | 
			
		||||
import org.jetbrains.exposed.sql.insert
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.util.UUID
 | 
			
		||||
 | 
			
		||||
class BlockBreak(
 | 
			
		||||
  val playerUniqueIdentity: UUID,
 | 
			
		||||
  val location: Location,
 | 
			
		||||
  val material: Material,
 | 
			
		||||
  val timestamp: Instant = Instant.now()
 | 
			
		||||
) : HeimdallEvent() {
 | 
			
		||||
  constructor(event: BlockBreakEvent) : this(event.player.uniqueId, event.block.location, event.block.type)
 | 
			
		||||
 | 
			
		||||
  override fun store(transaction: Transaction) {
 | 
			
		||||
    transaction.apply {
 | 
			
		||||
      BlockBreakTable.insert {
 | 
			
		||||
        it[time] = timestamp
 | 
			
		||||
        it[player] = playerUniqueIdentity
 | 
			
		||||
        it[world] = location.world.uid
 | 
			
		||||
        it[x] = location.x
 | 
			
		||||
        it[y] = location.y
 | 
			
		||||
        it[z] = location.z
 | 
			
		||||
        it[pitch] = location.pitch.toDouble()
 | 
			
		||||
        it[yaw] = location.yaw.toDouble()
 | 
			
		||||
        it[block] = material.key.toString()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.event
 | 
			
		||||
 | 
			
		||||
import gay.pizza.foundation.heimdall.table.BlockPlaceTable
 | 
			
		||||
import org.bukkit.Location
 | 
			
		||||
import org.bukkit.Material
 | 
			
		||||
import org.bukkit.event.block.BlockPlaceEvent
 | 
			
		||||
import org.jetbrains.exposed.sql.Transaction
 | 
			
		||||
import org.jetbrains.exposed.sql.insert
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.util.UUID
 | 
			
		||||
 | 
			
		||||
class BlockPlace(
 | 
			
		||||
  val playerUniqueIdentity: UUID,
 | 
			
		||||
  val location: Location,
 | 
			
		||||
  val material: Material,
 | 
			
		||||
  val timestamp: Instant = Instant.now()
 | 
			
		||||
) : HeimdallEvent() {
 | 
			
		||||
  constructor(event: BlockPlaceEvent) : this(event.player.uniqueId, event.block.location, event.block.type)
 | 
			
		||||
 | 
			
		||||
  override fun store(transaction: Transaction) {
 | 
			
		||||
    transaction.apply {
 | 
			
		||||
      BlockPlaceTable.insert {
 | 
			
		||||
        it[time] = timestamp
 | 
			
		||||
        it[player] = playerUniqueIdentity
 | 
			
		||||
        it[world] = location.world.uid
 | 
			
		||||
        it[x] = location.x
 | 
			
		||||
        it[y] = location.y
 | 
			
		||||
        it[z] = location.z
 | 
			
		||||
        it[pitch] = location.pitch.toDouble()
 | 
			
		||||
        it[yaw] = location.yaw.toDouble()
 | 
			
		||||
        it[block] = material.key.toString()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,33 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.event
 | 
			
		||||
 | 
			
		||||
import gay.pizza.foundation.heimdall.table.EntityKillTable
 | 
			
		||||
import org.bukkit.Location
 | 
			
		||||
import org.jetbrains.exposed.sql.Transaction
 | 
			
		||||
import org.jetbrains.exposed.sql.insert
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.util.UUID
 | 
			
		||||
 | 
			
		||||
class EntityKill(
 | 
			
		||||
  val playerUniqueIdentity: UUID,
 | 
			
		||||
  val location: Location,
 | 
			
		||||
  val entityUniqueIdentity: UUID,
 | 
			
		||||
  val entityTypeName: String,
 | 
			
		||||
  val timestamp: Instant = Instant.now()
 | 
			
		||||
) : HeimdallEvent() {
 | 
			
		||||
  override fun store(transaction: Transaction) {
 | 
			
		||||
    transaction.apply {
 | 
			
		||||
      EntityKillTable.insert {
 | 
			
		||||
        it[time] = timestamp
 | 
			
		||||
        it[player] = playerUniqueIdentity
 | 
			
		||||
        it[world] = location.world.uid
 | 
			
		||||
        it[x] = location.x
 | 
			
		||||
        it[y] = location.y
 | 
			
		||||
        it[z] = location.z
 | 
			
		||||
        it[pitch] = location.pitch.toDouble()
 | 
			
		||||
        it[yaw] = location.yaw.toDouble()
 | 
			
		||||
        it[entity] = entityUniqueIdentity
 | 
			
		||||
        it[entityType] = entityTypeName
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.event
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.exposed.sql.Transaction
 | 
			
		||||
 | 
			
		||||
abstract class HeimdallEvent {
 | 
			
		||||
  abstract fun store(transaction: Transaction)
 | 
			
		||||
}
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.event
 | 
			
		||||
 | 
			
		||||
import gay.pizza.foundation.heimdall.table.PlayerAdvancementTable
 | 
			
		||||
import org.bukkit.Location
 | 
			
		||||
import org.bukkit.advancement.Advancement
 | 
			
		||||
import org.bukkit.event.player.PlayerAdvancementDoneEvent
 | 
			
		||||
import org.jetbrains.exposed.sql.Transaction
 | 
			
		||||
import org.jetbrains.exposed.sql.insert
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.util.UUID
 | 
			
		||||
 | 
			
		||||
class PlayerAdvancement(
 | 
			
		||||
  val playerUniqueIdentity: UUID,
 | 
			
		||||
  val location: Location,
 | 
			
		||||
  val advancement: Advancement,
 | 
			
		||||
  val timestamp: Instant = Instant.now()
 | 
			
		||||
) : HeimdallEvent() {
 | 
			
		||||
  constructor(event: PlayerAdvancementDoneEvent) : this(event.player.uniqueId, event.player.location, event.advancement)
 | 
			
		||||
 | 
			
		||||
  override fun store(transaction: Transaction) {
 | 
			
		||||
    transaction.apply {
 | 
			
		||||
      PlayerAdvancementTable.insert {
 | 
			
		||||
        it[time] = timestamp
 | 
			
		||||
        it[player] = playerUniqueIdentity
 | 
			
		||||
        it[world] = location.world.uid
 | 
			
		||||
        it[x] = location.x
 | 
			
		||||
        it[y] = location.y
 | 
			
		||||
        it[z] = location.z
 | 
			
		||||
        it[pitch] = location.pitch.toDouble()
 | 
			
		||||
        it[yaw] = location.yaw.toDouble()
 | 
			
		||||
        it[advancement] = this@PlayerAdvancement.advancement.key.toString()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,41 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.event
 | 
			
		||||
 | 
			
		||||
import gay.pizza.foundation.heimdall.table.PlayerDeathTable
 | 
			
		||||
import org.bukkit.Location
 | 
			
		||||
import org.bukkit.event.entity.PlayerDeathEvent
 | 
			
		||||
import org.jetbrains.exposed.sql.Transaction
 | 
			
		||||
import org.jetbrains.exposed.sql.insert
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.util.UUID
 | 
			
		||||
 | 
			
		||||
class PlayerDeath(
 | 
			
		||||
  val playerUniqueIdentity: UUID,
 | 
			
		||||
  val location: Location,
 | 
			
		||||
  val experienceLevel: Float,
 | 
			
		||||
  val deathMessage: String?,
 | 
			
		||||
  val timestamp: Instant = Instant.now()
 | 
			
		||||
) : HeimdallEvent() {
 | 
			
		||||
  constructor(event: PlayerDeathEvent, deathMessage: String? = null) : this(
 | 
			
		||||
    event.player.uniqueId,
 | 
			
		||||
    event.player.location,
 | 
			
		||||
    event.player.exp,
 | 
			
		||||
    deathMessage
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  override fun store(transaction: Transaction) {
 | 
			
		||||
    transaction.apply {
 | 
			
		||||
      PlayerDeathTable.insert {
 | 
			
		||||
        it[time] = timestamp
 | 
			
		||||
        it[player] = playerUniqueIdentity
 | 
			
		||||
        it[world] = location.world.uid
 | 
			
		||||
        it[x] = location.x
 | 
			
		||||
        it[y] = location.y
 | 
			
		||||
        it[z] = location.z
 | 
			
		||||
        it[pitch] = location.pitch.toDouble()
 | 
			
		||||
        it[yaw] = location.yaw.toDouble()
 | 
			
		||||
        it[experience] = experienceLevel.toDouble()
 | 
			
		||||
        it[message] = deathMessage
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,32 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.event
 | 
			
		||||
 | 
			
		||||
import gay.pizza.foundation.heimdall.table.PlayerPositionTable
 | 
			
		||||
import org.bukkit.Location
 | 
			
		||||
import org.bukkit.event.player.PlayerMoveEvent
 | 
			
		||||
import org.jetbrains.exposed.sql.Transaction
 | 
			
		||||
import org.jetbrains.exposed.sql.insert
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.util.UUID
 | 
			
		||||
 | 
			
		||||
class PlayerPosition(
 | 
			
		||||
  val playerUniqueIdentity: UUID,
 | 
			
		||||
  val location: Location,
 | 
			
		||||
  val timestamp: Instant = Instant.now()
 | 
			
		||||
) : HeimdallEvent() {
 | 
			
		||||
  constructor(event: PlayerMoveEvent) : this(event.player.uniqueId, event.to)
 | 
			
		||||
 | 
			
		||||
  override fun store(transaction: Transaction) {
 | 
			
		||||
    transaction.apply {
 | 
			
		||||
      PlayerPositionTable.insert {
 | 
			
		||||
        it[time] = timestamp
 | 
			
		||||
        it[player] = playerUniqueIdentity
 | 
			
		||||
        it[world] = location.world.uid
 | 
			
		||||
        it[x] = location.x
 | 
			
		||||
        it[y] = location.y
 | 
			
		||||
        it[z] = location.z
 | 
			
		||||
        it[pitch] = location.pitch.toDouble()
 | 
			
		||||
        it[yaw] = location.yaw.toDouble()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,26 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.event
 | 
			
		||||
 | 
			
		||||
import gay.pizza.foundation.heimdall.table.PlayerSessionTable
 | 
			
		||||
import org.jetbrains.exposed.sql.Transaction
 | 
			
		||||
import org.jetbrains.exposed.sql.insert
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.util.UUID
 | 
			
		||||
 | 
			
		||||
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[id] = UUID.randomUUID()
 | 
			
		||||
        it[player] = playerUniqueIdentity
 | 
			
		||||
        it[name] = playerName
 | 
			
		||||
        it[startTime] = startTimeInstant
 | 
			
		||||
        it[endTime] = endTimeInstant
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,29 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.event
 | 
			
		||||
 | 
			
		||||
import gay.pizza.foundation.heimdall.table.WorldChangeTable
 | 
			
		||||
import org.jetbrains.exposed.sql.Transaction
 | 
			
		||||
import org.jetbrains.exposed.sql.insert
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.util.UUID
 | 
			
		||||
 | 
			
		||||
class WorldChange(
 | 
			
		||||
  val playerUniqueIdentity: UUID,
 | 
			
		||||
  val fromWorldId: UUID,
 | 
			
		||||
  val fromWorldActualName: String,
 | 
			
		||||
  val toWorldId: UUID,
 | 
			
		||||
  val toWorldActualName: String,
 | 
			
		||||
  val timestamp: Instant = Instant.now()
 | 
			
		||||
) : HeimdallEvent() {
 | 
			
		||||
  override fun store(transaction: Transaction) {
 | 
			
		||||
    transaction.apply {
 | 
			
		||||
      WorldChangeTable.insert {
 | 
			
		||||
        it[time] = timestamp
 | 
			
		||||
        it[player] = playerUniqueIdentity
 | 
			
		||||
        it[fromWorld] = fromWorldId
 | 
			
		||||
        it[fromWorldName] = fromWorldActualName
 | 
			
		||||
        it[toWorld] = toWorldId
 | 
			
		||||
        it[toWorldName] = toWorldActualName
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,68 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.export
 | 
			
		||||
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import kotlinx.serialization.json.encodeToStream
 | 
			
		||||
import org.bukkit.Chunk
 | 
			
		||||
import org.bukkit.ChunkSnapshot
 | 
			
		||||
import org.bukkit.Server
 | 
			
		||||
import org.bukkit.World
 | 
			
		||||
import org.bukkit.plugin.Plugin
 | 
			
		||||
import java.io.File
 | 
			
		||||
import java.util.zip.GZIPOutputStream
 | 
			
		||||
 | 
			
		||||
class ChunkExporter(private val plugin: Plugin, private val server: Server, val world: World) {
 | 
			
		||||
  private val json = Json {
 | 
			
		||||
    ignoreUnknownKeys = true
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fun exportLoadedChunksAsync() {
 | 
			
		||||
    exportChunkListAsync(world.loadedChunks.toList())
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private fun exportChunkListAsync(chunks: List<Chunk>) {
 | 
			
		||||
    plugin.slF4JLogger.info("Exporting ${chunks.size} Chunks")
 | 
			
		||||
    val snapshots = chunks.map { it.chunkSnapshot }
 | 
			
		||||
    Thread {
 | 
			
		||||
      for (snapshot in snapshots) {
 | 
			
		||||
        exportChunkSnapshot(snapshot)
 | 
			
		||||
      }
 | 
			
		||||
      plugin.slF4JLogger.info("Exported ${chunks.size} Chunks")
 | 
			
		||||
    }.start()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private fun exportChunkSnapshot(snapshot: ChunkSnapshot) {
 | 
			
		||||
    val sections = mutableListOf<ExportedChunkSection>()
 | 
			
		||||
    val yRange = world.minHeight until world.maxHeight
 | 
			
		||||
    val chunkRange = 0..15
 | 
			
		||||
    for (x in chunkRange) {
 | 
			
		||||
      for (z in chunkRange) {
 | 
			
		||||
        sections.add(exportChunkSection(snapshot, yRange, x, z))
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val exported = ExportedChunk(snapshot.x, snapshot.z, sections)
 | 
			
		||||
    saveChunkSnapshot(snapshot, exported)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private fun saveChunkSnapshot(snapshot: ChunkSnapshot, chunk: ExportedChunk) {
 | 
			
		||||
    val file = File("exported_chunks/${snapshot.worldName}_chunk_${snapshot.x}_${snapshot.z}.json.gz")
 | 
			
		||||
    if (!file.parentFile.exists()) {
 | 
			
		||||
      file.parentFile.mkdirs()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val fileOutputStream = file.outputStream()
 | 
			
		||||
    val gzipOutputStream = GZIPOutputStream(fileOutputStream)
 | 
			
		||||
    json.encodeToStream(ExportedChunk.serializer(), chunk, gzipOutputStream)
 | 
			
		||||
    gzipOutputStream.close()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private fun exportChunkSection(snapshot: ChunkSnapshot, yRange: IntRange, x: Int, z: Int): ExportedChunkSection {
 | 
			
		||||
    val blocks = mutableListOf<ExportedBlock>()
 | 
			
		||||
    for (y in yRange) {
 | 
			
		||||
      val blockData = snapshot.getBlockData(x, y, z)
 | 
			
		||||
      val block = ExportedBlock(blockData.material.key.toString())
 | 
			
		||||
      blocks.add(block)
 | 
			
		||||
    }
 | 
			
		||||
    return ExportedChunkSection(x, z, blocks)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.export
 | 
			
		||||
 | 
			
		||||
import org.bukkit.command.Command
 | 
			
		||||
import org.bukkit.command.CommandExecutor
 | 
			
		||||
import org.bukkit.command.CommandSender
 | 
			
		||||
import org.bukkit.plugin.Plugin
 | 
			
		||||
 | 
			
		||||
class ExportChunksCommand(private val plugin: Plugin) : CommandExecutor {
 | 
			
		||||
  override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
 | 
			
		||||
    plugin.slF4JLogger.info("Exporting All Chunks")
 | 
			
		||||
    for (world in sender.server.worlds) {
 | 
			
		||||
      val export = ChunkExporter(plugin, sender.server, world)
 | 
			
		||||
      export.exportLoadedChunksAsync()
 | 
			
		||||
    }
 | 
			
		||||
    return true
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.export
 | 
			
		||||
 | 
			
		||||
import kotlinx.serialization.Serializable
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class ExportedBlock(
 | 
			
		||||
  val type: String
 | 
			
		||||
)
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.export
 | 
			
		||||
 | 
			
		||||
import kotlinx.serialization.Serializable
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class ExportedChunk(
 | 
			
		||||
  val x: Int,
 | 
			
		||||
  val z: Int,
 | 
			
		||||
  val sections: List<ExportedChunkSection>
 | 
			
		||||
)
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.export
 | 
			
		||||
 | 
			
		||||
import kotlinx.serialization.Serializable
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class ExportedChunkSection(
 | 
			
		||||
  val x: Int,
 | 
			
		||||
  val z: Int,
 | 
			
		||||
  val blocks: List<ExportedBlock>
 | 
			
		||||
)
 | 
			
		||||
@ -1,16 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.model
 | 
			
		||||
 | 
			
		||||
import kotlinx.serialization.Serializable
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class HeimdallConfig(
 | 
			
		||||
  val enabled: Boolean = false,
 | 
			
		||||
  val db: DbConfig
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class DbConfig(
 | 
			
		||||
  val url: String,
 | 
			
		||||
  val username: String,
 | 
			
		||||
  val password: String
 | 
			
		||||
)
 | 
			
		||||
@ -1,16 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.table
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.exposed.sql.Table
 | 
			
		||||
import org.jetbrains.exposed.sql.javatime.timestamp
 | 
			
		||||
 | 
			
		||||
object BlockBreakTable : Table("block_breaks") {
 | 
			
		||||
  val time = timestamp("time")
 | 
			
		||||
  val player = uuid("player")
 | 
			
		||||
  val world = uuid("world")
 | 
			
		||||
  val x = double("x")
 | 
			
		||||
  val y = double("y")
 | 
			
		||||
  val z = double("z")
 | 
			
		||||
  val pitch = double("pitch")
 | 
			
		||||
  val yaw = double("yaw")
 | 
			
		||||
  val block = text("block")
 | 
			
		||||
}
 | 
			
		||||
@ -1,16 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.table
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.exposed.sql.Table
 | 
			
		||||
import org.jetbrains.exposed.sql.javatime.timestamp
 | 
			
		||||
 | 
			
		||||
object BlockPlaceTable : Table("block_places") {
 | 
			
		||||
  val time = timestamp("time")
 | 
			
		||||
  val player = uuid("player")
 | 
			
		||||
  val world = uuid("world")
 | 
			
		||||
  val x = double("x")
 | 
			
		||||
  val y = double("y")
 | 
			
		||||
  val z = double("z")
 | 
			
		||||
  val pitch = double("pitch")
 | 
			
		||||
  val yaw = double("yaw")
 | 
			
		||||
  val block = text("block")
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.table
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.exposed.sql.Table
 | 
			
		||||
import org.jetbrains.exposed.sql.javatime.timestamp
 | 
			
		||||
 | 
			
		||||
object EntityKillTable : Table("entity_kills") {
 | 
			
		||||
  val time = timestamp("time")
 | 
			
		||||
  val player = uuid("player")
 | 
			
		||||
  val entity = uuid("entity")
 | 
			
		||||
  val world = uuid("world")
 | 
			
		||||
  val x = double("x")
 | 
			
		||||
  val y = double("y")
 | 
			
		||||
  val z = double("z")
 | 
			
		||||
  val pitch = double("pitch")
 | 
			
		||||
  val yaw = double("yaw")
 | 
			
		||||
  val entityType = text("entity_type")
 | 
			
		||||
}
 | 
			
		||||
@ -1,16 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.table
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.exposed.sql.Table
 | 
			
		||||
import org.jetbrains.exposed.sql.javatime.timestamp
 | 
			
		||||
 | 
			
		||||
object PlayerAdvancementTable : Table("player_advancements") {
 | 
			
		||||
  val time = timestamp("time")
 | 
			
		||||
  val player = uuid("player")
 | 
			
		||||
  val world = uuid("world")
 | 
			
		||||
  val x = double("x")
 | 
			
		||||
  val y = double("y")
 | 
			
		||||
  val z = double("z")
 | 
			
		||||
  val pitch = double("pitch")
 | 
			
		||||
  val yaw = double("yaw")
 | 
			
		||||
  val advancement = text("advancement")
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.table
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.exposed.sql.Table
 | 
			
		||||
import org.jetbrains.exposed.sql.javatime.timestamp
 | 
			
		||||
 | 
			
		||||
object PlayerDeathTable : Table("player_deaths") {
 | 
			
		||||
  val time = timestamp("time")
 | 
			
		||||
  val world = uuid("world")
 | 
			
		||||
  val player = uuid("player")
 | 
			
		||||
  val x = double("x")
 | 
			
		||||
  val y = double("y")
 | 
			
		||||
  val z = double("z")
 | 
			
		||||
  val pitch = double("pitch")
 | 
			
		||||
  val yaw = double("yaw")
 | 
			
		||||
  val experience = double("experience")
 | 
			
		||||
  val message = text("message").nullable()
 | 
			
		||||
}
 | 
			
		||||
@ -1,15 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.table
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.exposed.sql.Table
 | 
			
		||||
import org.jetbrains.exposed.sql.javatime.timestamp
 | 
			
		||||
 | 
			
		||||
object PlayerPositionTable : Table("player_positions") {
 | 
			
		||||
  val time = timestamp("time")
 | 
			
		||||
  val player = uuid("player")
 | 
			
		||||
  val world = uuid("world")
 | 
			
		||||
  val x = double("x")
 | 
			
		||||
  val y = double("y")
 | 
			
		||||
  val z = double("z")
 | 
			
		||||
  val pitch = double("pitch")
 | 
			
		||||
  val yaw = double("yaw")
 | 
			
		||||
}
 | 
			
		||||
@ -1,12 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.table
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.exposed.sql.Table
 | 
			
		||||
import org.jetbrains.exposed.sql.javatime.timestamp
 | 
			
		||||
 | 
			
		||||
object PlayerSessionTable : Table("player_sessions") {
 | 
			
		||||
  val id = uuid("id")
 | 
			
		||||
  val player = uuid("player")
 | 
			
		||||
  val name = text("name")
 | 
			
		||||
  val startTime = timestamp("start")
 | 
			
		||||
  val endTime = timestamp("end")
 | 
			
		||||
}
 | 
			
		||||
@ -1,13 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.table
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.exposed.sql.Table
 | 
			
		||||
import org.jetbrains.exposed.sql.javatime.timestamp
 | 
			
		||||
 | 
			
		||||
object WorldChangeTable : Table("world_changes") {
 | 
			
		||||
  val time = timestamp("time")
 | 
			
		||||
  val player = uuid("player")
 | 
			
		||||
  val fromWorld = uuid("from_world")
 | 
			
		||||
  val toWorld = uuid("to_world")
 | 
			
		||||
  val fromWorldName = text("from_world_name")
 | 
			
		||||
  val toWorldName = text("to_world_name")
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +0,0 @@
 | 
			
		||||
package gay.pizza.foundation.heimdall.view
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.exposed.sql.Table
 | 
			
		||||
import org.jetbrains.exposed.sql.javatime.timestamp
 | 
			
		||||
 | 
			
		||||
object BlockChangeView : Table("block_changes") {
 | 
			
		||||
  val isBreak = bool("break")
 | 
			
		||||
  val time = timestamp("time")
 | 
			
		||||
  val player = uuid("player")
 | 
			
		||||
  val world = uuid("world")
 | 
			
		||||
  val x = double("x")
 | 
			
		||||
  val y = double("y")
 | 
			
		||||
  val z = double("z")
 | 
			
		||||
  val pitch = double("pitch")
 | 
			
		||||
  val yaw = double("yaw")
 | 
			
		||||
  val block = text("block")
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
# Whether Heimdall should be enabled for tracking events.
 | 
			
		||||
enabled: false
 | 
			
		||||
 | 
			
		||||
# Database connection information.
 | 
			
		||||
db:
 | 
			
		||||
  # JDBC URL
 | 
			
		||||
  url: "jdbc:postgresql://localhost/foundation"
 | 
			
		||||
  # JDBC Username
 | 
			
		||||
  username: "foundation"
 | 
			
		||||
  # JDBC Password
 | 
			
		||||
  password: "foundation"
 | 
			
		||||
@ -1,147 +0,0 @@
 | 
			
		||||
create extension if not exists "uuid-ossp";
 | 
			
		||||
--
 | 
			
		||||
create extension if not exists timescaledb;
 | 
			
		||||
--
 | 
			
		||||
create schema if not exists heimdall;
 | 
			
		||||
--
 | 
			
		||||
create table if not exists heimdall.player_positions (
 | 
			
		||||
    time timestamp not null,
 | 
			
		||||
    player uuid not null,
 | 
			
		||||
    world uuid not null,
 | 
			
		||||
    x double precision not null,
 | 
			
		||||
    y double precision not null,
 | 
			
		||||
    z double precision not null,
 | 
			
		||||
    pitch double precision not null,
 | 
			
		||||
    yaw double precision not null,
 | 
			
		||||
    PRIMARY KEY (time, player, world)
 | 
			
		||||
);
 | 
			
		||||
--
 | 
			
		||||
select create_hypertable('heimdall.player_positions', 'time', 'player', 4,  if_not_exists => TRUE);
 | 
			
		||||
--
 | 
			
		||||
alter table heimdall.player_positions set (
 | 
			
		||||
    timescaledb.compress,
 | 
			
		||||
    timescaledb.compress_segmentby = 'player,world',
 | 
			
		||||
    timescaledb.compress_orderby = 'time'
 | 
			
		||||
);
 | 
			
		||||
--
 | 
			
		||||
select add_compression_policy('heimdall.player_positions', interval '3 days', if_not_exists => true);
 | 
			
		||||
--
 | 
			
		||||
create table if not exists heimdall.block_breaks (
 | 
			
		||||
    time timestamp not null,
 | 
			
		||||
    player uuid not null,
 | 
			
		||||
    world uuid not null,
 | 
			
		||||
    x double precision not null,
 | 
			
		||||
    y double precision not null,
 | 
			
		||||
    z double precision not null,
 | 
			
		||||
    pitch double precision not null,
 | 
			
		||||
    yaw double precision not null,
 | 
			
		||||
    block text not null,
 | 
			
		||||
    PRIMARY KEY (time, player, world)
 | 
			
		||||
);
 | 
			
		||||
--
 | 
			
		||||
select create_hypertable('heimdall.block_breaks', 'time', 'player', 4,  if_not_exists => TRUE);
 | 
			
		||||
--
 | 
			
		||||
create table if not exists heimdall.block_places (
 | 
			
		||||
    time timestamp not null,
 | 
			
		||||
    player uuid not null,
 | 
			
		||||
    world uuid not null,
 | 
			
		||||
    x double precision not null,
 | 
			
		||||
    y double precision not null,
 | 
			
		||||
    z double precision not null,
 | 
			
		||||
    pitch double precision not null,
 | 
			
		||||
    yaw double precision not null,
 | 
			
		||||
    block text not null,
 | 
			
		||||
    PRIMARY KEY (time, player, world)
 | 
			
		||||
);
 | 
			
		||||
--
 | 
			
		||||
select create_hypertable('heimdall.block_places', 'time', 'player', 4,  if_not_exists => TRUE);
 | 
			
		||||
--
 | 
			
		||||
create table if not exists heimdall.player_sessions (
 | 
			
		||||
    id uuid not null,
 | 
			
		||||
    player uuid not null,
 | 
			
		||||
    name text not null,
 | 
			
		||||
    "start" timestamp not null,
 | 
			
		||||
    "end" timestamp not null,
 | 
			
		||||
    primary key (id, player, start)
 | 
			
		||||
);
 | 
			
		||||
--
 | 
			
		||||
select create_hypertable('heimdall.player_sessions', 'start', 'player', 4,  if_not_exists => TRUE);
 | 
			
		||||
--
 | 
			
		||||
create table if not exists heimdall.world_changes (
 | 
			
		||||
    time timestamp not null,
 | 
			
		||||
    player uuid not null,
 | 
			
		||||
    from_world uuid not null,
 | 
			
		||||
    from_world_name text not null,
 | 
			
		||||
    to_world uuid not null,
 | 
			
		||||
    to_world_name text not null,
 | 
			
		||||
    primary key (time, player)
 | 
			
		||||
);
 | 
			
		||||
--
 | 
			
		||||
select create_hypertable('heimdall.world_changes', 'time', 'player', 4,  if_not_exists => TRUE);
 | 
			
		||||
--
 | 
			
		||||
create table if not exists heimdall.player_deaths (
 | 
			
		||||
    time timestamp not null,
 | 
			
		||||
    player uuid not null,
 | 
			
		||||
    world uuid not null,
 | 
			
		||||
    x double precision not null,
 | 
			
		||||
    y double precision not null,
 | 
			
		||||
    z double precision not null,
 | 
			
		||||
    pitch double precision not null,
 | 
			
		||||
    yaw double precision not null,
 | 
			
		||||
    experience double precision not null,
 | 
			
		||||
    message text null,
 | 
			
		||||
    primary key (time, player)
 | 
			
		||||
);
 | 
			
		||||
--
 | 
			
		||||
select create_hypertable('heimdall.player_deaths', 'time', 'player', 4,  if_not_exists => TRUE);
 | 
			
		||||
--
 | 
			
		||||
create table if not exists heimdall.player_advancements (
 | 
			
		||||
    time timestamp not null,
 | 
			
		||||
    player uuid not null,
 | 
			
		||||
    world uuid not null,
 | 
			
		||||
    x double precision not null,
 | 
			
		||||
    y double precision not null,
 | 
			
		||||
    z double precision not null,
 | 
			
		||||
    pitch double precision not null,
 | 
			
		||||
    yaw double precision not null,
 | 
			
		||||
    advancement text not null,
 | 
			
		||||
    primary key (time, player, advancement)
 | 
			
		||||
);
 | 
			
		||||
--
 | 
			
		||||
select create_hypertable('heimdall.player_advancements', 'time', 'player', 4,  if_not_exists => TRUE);
 | 
			
		||||
--
 | 
			
		||||
create table if not exists heimdall.entity_kills (
 | 
			
		||||
    time timestamp not null,
 | 
			
		||||
    player uuid not null,
 | 
			
		||||
    entity uuid not null,
 | 
			
		||||
    world uuid not null,
 | 
			
		||||
    x double precision not null,
 | 
			
		||||
    y double precision not null,
 | 
			
		||||
    z double precision not null,
 | 
			
		||||
    pitch double precision not null,
 | 
			
		||||
    yaw double precision not null,
 | 
			
		||||
    entity_type text not null,
 | 
			
		||||
    primary key (time, entity, player)
 | 
			
		||||
);
 | 
			
		||||
--
 | 
			
		||||
select create_hypertable('heimdall.entity_kills', 'time', 'player', 4,  if_not_exists => TRUE);
 | 
			
		||||
--
 | 
			
		||||
create or replace view heimdall.block_changes as
 | 
			
		||||
    select true as break, *
 | 
			
		||||
    from heimdall.block_breaks
 | 
			
		||||
    union all
 | 
			
		||||
    select false as break, * from heimdall.block_places;
 | 
			
		||||
--
 | 
			
		||||
create or replace view heimdall.player_names as
 | 
			
		||||
    with unique_player_ids as (
 | 
			
		||||
        select distinct player
 | 
			
		||||
        from heimdall.player_sessions
 | 
			
		||||
    )
 | 
			
		||||
    select player, (
 | 
			
		||||
        select name
 | 
			
		||||
        from heimdall.player_sessions
 | 
			
		||||
        where player = unique_player_ids.player
 | 
			
		||||
        order by "end" desc
 | 
			
		||||
        limit 1
 | 
			
		||||
    ) as name
 | 
			
		||||
    from unique_player_ids;
 | 
			
		||||
@ -1,15 +0,0 @@
 | 
			
		||||
name: Foundation-Heimdall
 | 
			
		||||
version: '${version}'
 | 
			
		||||
main: gay.pizza.foundation.heimdall.FoundationHeimdallPlugin
 | 
			
		||||
api-version: 1.18
 | 
			
		||||
prefix: Foundation-Heimdall
 | 
			
		||||
load: STARTUP
 | 
			
		||||
depend:
 | 
			
		||||
  - Foundation
 | 
			
		||||
authors:
 | 
			
		||||
  - kubelet
 | 
			
		||||
commands:
 | 
			
		||||
  export_all_chunks:
 | 
			
		||||
    description: Export All Chunks
 | 
			
		||||
    usage: /export_all_chunks
 | 
			
		||||
    permission: foundation.heimdall.command.export_all_chunks
 | 
			
		||||
		Reference in New Issue
	
	Block a user