Rewrite Heimdall block handling to support more event types and non-player block changes.

This commit is contained in:
2023-02-07 23:41:22 -05:00
parent 688106a6e6
commit e0823f7b15
19 changed files with 228 additions and 218 deletions

View File

@ -8,11 +8,11 @@ import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.options.required
import com.github.ajalt.clikt.parameters.types.enum
import com.github.ajalt.clikt.parameters.types.int
import gay.pizza.foundation.heimdall.table.BlockChangeTable
import gay.pizza.foundation.heimdall.table.WorldChangeTable
import gay.pizza.foundation.heimdall.tool.render.*
import gay.pizza.foundation.heimdall.tool.state.*
import gay.pizza.foundation.heimdall.tool.util.compose
import gay.pizza.foundation.heimdall.view.BlockChangeView
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greaterEq
@ -49,8 +49,6 @@ class BlockChangeTimelapseCommand : CliktCommand("Block Change Timelapse", name
.enum<ImageFormatType> { it.id }
.default(ImageFormatType.Png)
private val considerAirBlocks by option("--consider-air-blocks", help = "Enable Air Block Consideration").flag()
private val fromCoordinate by option("--trim-from", help = "Trim From Coordinate")
private val toCoordinate by option("--trim-to", help = "Trim To Coordinate")
@ -100,11 +98,11 @@ class BlockChangeTimelapseCommand : CliktCommand("Block Change Timelapse", name
val filter = compose(
combine = { a, b -> a and b },
{ trim?.first?.x != null } to { BlockChangeView.x greaterEq trim!!.first.x.toDouble() },
{ trim?.first?.z != null } to { BlockChangeView.z greaterEq trim!!.first.z.toDouble() },
{ trim?.second?.x != null } to { BlockChangeView.x lessEq trim!!.second.x.toDouble() },
{ trim?.second?.z != null } to { BlockChangeView.z lessEq trim!!.second.z.toDouble() },
{ true } to { BlockChangeView.world eq world }
{ trim?.first?.x != null } to { BlockChangeTable.x greaterEq trim!!.first.x.toDouble() },
{ trim?.first?.z != null } to { BlockChangeTable.z greaterEq trim!!.first.z.toDouble() },
{ trim?.second?.x != null } to { BlockChangeTable.x lessEq trim!!.second.x.toDouble() },
{ trim?.second?.z != null } to { BlockChangeTable.z lessEq trim!!.second.z.toDouble() },
{ true } to { BlockChangeTable.world eq world }
)
val changelog = BlockChangelog.query(db, filter)
@ -131,7 +129,6 @@ class BlockChangeTimelapseCommand : CliktCommand("Block Change Timelapse", name
val pool = BlockMapRenderPool(
changelog = changelog,
blockTrackMode = if (considerAirBlocks) BlockTrackMode.AirOnDelete else BlockTrackMode.RemoveOnDelete,
delegate = timelapse,
createRendererFunction = { expanse -> render.createNewRenderer(expanse, db) },
threadPoolExecutor = threadPoolExecutor

View File

@ -36,9 +36,9 @@ class PlayerLocationShareRenderer(
val player = it[PlayerPositionTable.player]
playerSparseMap.createOrModify(
coordinate,
create = { mutableListOf(player) },
modify = { players -> players.add(player) })
allPlayerIds.add(player)
create = { mutableListOf(player!!) },
modify = { players -> players.add(player!!) })
allPlayerIds.add(player!!)
}
}

View File

@ -1,9 +0,0 @@
package gay.pizza.foundation.heimdall.tool.state
import kotlinx.serialization.Serializable
@Serializable
enum class BlockChangeType {
Place,
Break
}

View File

@ -1,6 +1,6 @@
package gay.pizza.foundation.heimdall.tool.state
import gay.pizza.foundation.heimdall.view.BlockChangeView
import gay.pizza.foundation.heimdall.table.BlockChangeTable
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.Op
import org.jetbrains.exposed.sql.select
@ -10,7 +10,7 @@ import java.time.Instant
import java.util.stream.Stream
class BlockChangelog(
val changes: List<BlockChange>
val changes: List<RecordedBlockChange>
) {
fun slice(slice: ChangelogSlice): BlockChangelog = BlockChangelog(changes.filter {
slice.isTimeWithinFullRange(it.time)
@ -60,43 +60,30 @@ class BlockChangelog(
companion object {
fun query(db: Database, filter: Op<Boolean> = Op.TRUE): BlockChangelog = transaction(db) {
BlockChangelog(BlockChangeView.select(filter).orderBy(BlockChangeView.time).map { row ->
val time = row[BlockChangeView.time]
val changeIsBreak = row[BlockChangeView.isBreak]
val world = row[BlockChangeView.world]
val x = row[BlockChangeView.x]
val y = row[BlockChangeView.y]
val z = row[BlockChangeView.z]
val block = row[BlockChangeView.block]
val blockData = row[BlockChangeView.blockData]
BlockChangelog(BlockChangeTable.select(filter).orderBy(BlockChangeTable.time).map { row ->
val time = row[BlockChangeTable.time]
val world = row[BlockChangeTable.world]
val x = row[BlockChangeTable.x]
val y = row[BlockChangeTable.y]
val z = row[BlockChangeTable.z]
val blockMaterial = row[BlockChangeTable.block]
val blockData = row[BlockChangeTable.data]
val location = BlockCoordinate(x.toLong(), y.toLong(), z.toLong())
val fromBlock = if (changeIsBreak) {
BlockState(block, blockData)
} else {
BlockState.AirBlock
}
val block = BlockState(blockMaterial, blockData)
val toBlock = if (changeIsBreak) {
BlockState.AirBlock
} else {
BlockState(block, blockData)
}
BlockChange(
RecordedBlockChange(
time,
world,
if (changeIsBreak) BlockChangeType.Break else BlockChangeType.Place,
location,
fromBlock,
toBlock
block
)
})
}
}
fun <T> splitBy(key: (BlockChange) -> T): Map<T, BlockChangelog> {
val logs = mutableMapOf<T, MutableList<BlockChange>>()
fun <T> splitBy(key: (RecordedBlockChange) -> T): Map<T, BlockChangelog> {
val logs = mutableMapOf<T, MutableList<RecordedBlockChange>>()
for (change in changes) {
val k = key(change)
var log = logs[k]

View File

@ -5,7 +5,7 @@ import gay.pizza.foundation.heimdall.tool.util.minOfAll
import java.util.concurrent.ConcurrentHashMap
import kotlin.math.absoluteValue
class BlockLogTracker(private val mode: BlockTrackMode = BlockTrackMode.RemoveOnDelete, isConcurrent: Boolean = false) {
class BlockLogTracker(isConcurrent: Boolean = false) {
internal val blocks: MutableMap<BlockCoordinate, BlockState> = if (isConcurrent) ConcurrentHashMap() else mutableMapOf()
fun place(position: BlockCoordinate, state: BlockState) {
@ -16,14 +16,6 @@ class BlockLogTracker(private val mode: BlockTrackMode = BlockTrackMode.RemoveOn
blocks.putAll(map)
}
fun delete(position: BlockCoordinate) {
if (mode == BlockTrackMode.AirOnDelete) {
blocks[position] = BlockState.AirBlock
} else {
blocks.remove(position)
}
}
fun calculateZeroBlockOffset(): BlockCoordinate {
val (x, y, z) = blocks.keys.minOfAll(3) { listOf(it.x, it.y, it.z) }
val xOffset = if (x < 0) x.absoluteValue else 0
@ -60,11 +52,7 @@ class BlockLogTracker(private val mode: BlockTrackMode = BlockTrackMode.RemoveOn
}
fun replay(changelog: BlockChangelog) = changelog.changes.forEach { change ->
if (change.type == BlockChangeType.Break) {
delete(change.location)
} else {
place(change.location, change.to)
}
place(change.location, change.state)
}
fun get(position: BlockCoordinate): BlockState? = blocks[position]

View File

@ -8,7 +8,6 @@ import java.util.concurrent.ThreadPoolExecutor
class BlockMapRenderPool<T>(
val changelog: BlockChangelog,
val blockTrackMode: BlockTrackMode,
val createRendererFunction: (BlockExpanse) -> BlockMapRenderer<T>,
val delegate: BlockMapRenderPoolDelegate<T>,
val threadPoolExecutor: ThreadPoolExecutor,
@ -64,7 +63,7 @@ class BlockMapRenderPool<T>(
private fun runPlaybackSlice(id: String, slice: ChangelogSlice) {
val start = System.currentTimeMillis()
val sliced = changelog.slice(slice)
val tracker = BlockLogTracker(blockTrackMode)
val tracker = BlockLogTracker()
tracker.replay(sliced)
if (tracker.isNotEmpty()) {
trackers[slice] = tracker

View File

@ -21,7 +21,7 @@ class PlayerPositionChangelog(
val pitch = row[PlayerPositionTable.z]
val yaw = row[PlayerPositionTable.z]
PlayerPositionChange(time, player, world, x, y, z, pitch, yaw)
PlayerPositionChange(time, player!!, world, x, y, z, pitch, yaw)
})
}
}

View File

@ -3,11 +3,9 @@ package gay.pizza.foundation.heimdall.tool.state
import java.time.Instant
import java.util.UUID
data class BlockChange(
data class RecordedBlockChange(
val time: Instant,
val world: UUID,
val type: BlockChangeType,
val location: BlockCoordinate,
val from: BlockState,
val to: BlockState
val state: BlockState
)