mirror of
				https://github.com/GayPizzaSpecifications/foundation.git
				synced 2025-11-04 11:39:39 +00:00 
			
		
		
		
	Heimdall: Keep track of block data.
This commit is contained in:
		@ -4,5 +4,6 @@ import kotlinx.serialization.Serializable
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
data class ExportedBlock(
 | 
					data class ExportedBlock(
 | 
				
			||||||
  val type: String
 | 
					  val type: String,
 | 
				
			||||||
 | 
					  val data: String? = null
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
				
			|||||||
@ -2,4 +2,5 @@ package gay.pizza.foundation.heimdall.table
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
object BlockBreakTable : PlayerTimedLocalEventTable("block_breaks") {
 | 
					object BlockBreakTable : PlayerTimedLocalEventTable("block_breaks") {
 | 
				
			||||||
  val block = text("block")
 | 
					  val block = text("block")
 | 
				
			||||||
 | 
					  val blockData = text("block_data").nullable()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,4 +2,5 @@ package gay.pizza.foundation.heimdall.table
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
object BlockPlaceTable : PlayerTimedLocalEventTable("block_places") {
 | 
					object BlockPlaceTable : PlayerTimedLocalEventTable("block_places") {
 | 
				
			||||||
  val block = text("block")
 | 
					  val block = text("block")
 | 
				
			||||||
 | 
					  val blockData = text("block_data").nullable()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,4 +5,5 @@ import gay.pizza.foundation.heimdall.table.PlayerTimedLocalEventTable
 | 
				
			|||||||
object BlockChangeView : PlayerTimedLocalEventTable("block_changes") {
 | 
					object BlockChangeView : PlayerTimedLocalEventTable("block_changes") {
 | 
				
			||||||
  val isBreak = bool("break")
 | 
					  val isBreak = bool("break")
 | 
				
			||||||
  val block = text("block")
 | 
					  val block = text("block")
 | 
				
			||||||
 | 
					  val blockData = text("block_data").nullable()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -16,12 +16,14 @@ class BlockBreak(
 | 
				
			|||||||
  val playerUniqueIdentity: UUID,
 | 
					  val playerUniqueIdentity: UUID,
 | 
				
			||||||
  val location: Location,
 | 
					  val location: Location,
 | 
				
			||||||
  val material: Material,
 | 
					  val material: Material,
 | 
				
			||||||
 | 
					  val blockData: String? = null,
 | 
				
			||||||
  val timestamp: Instant = Instant.now()
 | 
					  val timestamp: Instant = Instant.now()
 | 
				
			||||||
) : HeimdallEvent() {
 | 
					) : HeimdallEvent() {
 | 
				
			||||||
  constructor(event: BlockBreakEvent) : this(
 | 
					  constructor(event: BlockBreakEvent) : this(
 | 
				
			||||||
    event.player.uniqueId,
 | 
					    event.player.uniqueId,
 | 
				
			||||||
    event.block.location,
 | 
					    event.block.location,
 | 
				
			||||||
    event.block.type
 | 
					    event.block.type,
 | 
				
			||||||
 | 
					    event.block.blockData.asString
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun store(transaction: Transaction) {
 | 
					  override fun store(transaction: Transaction) {
 | 
				
			||||||
@ -29,6 +31,7 @@ class BlockBreak(
 | 
				
			|||||||
      BlockBreakTable.insert {
 | 
					      BlockBreakTable.insert {
 | 
				
			||||||
        putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
 | 
					        putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
 | 
				
			||||||
        it[block] = material.key.toString()
 | 
					        it[block] = material.key.toString()
 | 
				
			||||||
 | 
					        it[blockData] = this@BlockBreak.blockData
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -16,12 +16,14 @@ class BlockPlace(
 | 
				
			|||||||
  val playerUniqueIdentity: UUID,
 | 
					  val playerUniqueIdentity: UUID,
 | 
				
			||||||
  val location: Location,
 | 
					  val location: Location,
 | 
				
			||||||
  val material: Material,
 | 
					  val material: Material,
 | 
				
			||||||
 | 
					  val blockData: String? = null,
 | 
				
			||||||
  val timestamp: Instant = Instant.now()
 | 
					  val timestamp: Instant = Instant.now()
 | 
				
			||||||
) : HeimdallEvent() {
 | 
					) : HeimdallEvent() {
 | 
				
			||||||
  constructor(event: BlockPlaceEvent) : this(
 | 
					  constructor(event: BlockPlaceEvent) : this(
 | 
				
			||||||
    event.player.uniqueId,
 | 
					    event.player.uniqueId,
 | 
				
			||||||
    event.block.location,
 | 
					    event.block.location,
 | 
				
			||||||
    event.block.type
 | 
					    event.block.type,
 | 
				
			||||||
 | 
					    event.block.blockData.asString
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun store(transaction: Transaction) {
 | 
					  override fun store(transaction: Transaction) {
 | 
				
			||||||
@ -29,6 +31,7 @@ class BlockPlace(
 | 
				
			|||||||
      BlockPlaceTable.insert {
 | 
					      BlockPlaceTable.insert {
 | 
				
			||||||
        putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
 | 
					        putPlayerTimedLocalEvent(it, timestamp, location, playerUniqueIdentity)
 | 
				
			||||||
        it[block] = material.key.toString()
 | 
					        it[block] = material.key.toString()
 | 
				
			||||||
 | 
					        it[blockData] = this@BlockPlace.blockData
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
package gay.pizza.foundation.heimdall.plugin.load
 | 
					package gay.pizza.foundation.heimdall.plugin.load
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import gay.pizza.foundation.heimdall.export.ExportedBlock
 | 
				
			||||||
import gay.pizza.foundation.heimdall.load.WorldLoadFormat
 | 
					import gay.pizza.foundation.heimdall.load.WorldLoadFormat
 | 
				
			||||||
import gay.pizza.foundation.heimdall.load.WorldLoadWorld
 | 
					import gay.pizza.foundation.heimdall.load.WorldLoadWorld
 | 
				
			||||||
import org.bukkit.Location
 | 
					import org.bukkit.Location
 | 
				
			||||||
@ -24,7 +25,7 @@ class WorldReassembler(val plugin: Plugin, val server: Server, val format: World
 | 
				
			|||||||
          continue
 | 
					          continue
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val blocksToMake = mutableListOf<Pair<Location, Material>>()
 | 
					        val blocksToMake = mutableListOf<Pair<Location, ExportedBlock>>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for ((x, zBlocks) in load.blocks) {
 | 
					        for ((x, zBlocks) in load.blocks) {
 | 
				
			||||||
          for ((z, yBlocks) in zBlocks) {
 | 
					          for ((z, yBlocks) in zBlocks) {
 | 
				
			||||||
@ -36,7 +37,7 @@ class WorldReassembler(val plugin: Plugin, val server: Server, val format: World
 | 
				
			|||||||
                continue
 | 
					                continue
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              blocksToMake.add(Location(world, x.toDouble(), y.toDouble(), z.toDouble()) to material)
 | 
					              blocksToMake.add(Location(world, x.toDouble(), y.toDouble(), z.toDouble()) to block)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -50,9 +51,15 @@ class WorldReassembler(val plugin: Plugin, val server: Server, val format: World
 | 
				
			|||||||
          val copy = section.toList()
 | 
					          val copy = section.toList()
 | 
				
			||||||
          val runnable = object : BukkitRunnable() {
 | 
					          val runnable = object : BukkitRunnable() {
 | 
				
			||||||
            override fun run() {
 | 
					            override fun run() {
 | 
				
			||||||
              for ((location, material) in copy) {
 | 
					              for ((location, blk) in copy) {
 | 
				
			||||||
                val block = world.getBlockAt(location)
 | 
					                val block = world.getBlockAt(location)
 | 
				
			||||||
 | 
					                val blockData = if (blk.data != null) server.createBlockData(blk.data!!) else null
 | 
				
			||||||
 | 
					                if (blockData != null) {
 | 
				
			||||||
 | 
					                  block.blockData = blockData
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                  val material = Material.matchMaterial(blk.type)!!
 | 
				
			||||||
                  block.type = material
 | 
					                  block.type = material
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                count.incrementAndGet()
 | 
					                count.incrementAndGet()
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              feedback("Placed ${count.get()} blocks in ${world.name}")
 | 
					              feedback("Placed ${count.get()} blocks in ${world.name}")
 | 
				
			||||||
 | 
				
			|||||||
@ -126,12 +126,6 @@ create table if not exists entity_kills (
 | 
				
			|||||||
--
 | 
					--
 | 
				
			||||||
select create_hypertable('entity_kills', 'time', 'player', 4,  if_not_exists => TRUE);
 | 
					select create_hypertable('entity_kills', 'time', 'player', 4,  if_not_exists => TRUE);
 | 
				
			||||||
--
 | 
					--
 | 
				
			||||||
create or replace view block_changes as
 | 
					 | 
				
			||||||
    select true as break, *
 | 
					 | 
				
			||||||
    from block_breaks
 | 
					 | 
				
			||||||
    union all
 | 
					 | 
				
			||||||
    select false as break, * from block_places;
 | 
					 | 
				
			||||||
--
 | 
					 | 
				
			||||||
create or replace view player_names as
 | 
					create or replace view player_names as
 | 
				
			||||||
    with unique_player_ids as (
 | 
					    with unique_player_ids as (
 | 
				
			||||||
        select distinct player
 | 
					        select distinct player
 | 
				
			||||||
@ -145,3 +139,14 @@ create or replace view player_names as
 | 
				
			|||||||
        limit 1
 | 
					        limit 1
 | 
				
			||||||
    ) as name
 | 
					    ) as name
 | 
				
			||||||
    from unique_player_ids;
 | 
					    from unique_player_ids;
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					alter table block_places add column if not exists block_data text null;
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					alter table block_breaks add column if not exists block_data text null;
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
					create or replace view block_changes as
 | 
				
			||||||
 | 
					    select true as break, *
 | 
				
			||||||
 | 
					    from block_breaks
 | 
				
			||||||
 | 
					    union all
 | 
				
			||||||
 | 
					    select false as break, * from block_places;
 | 
				
			||||||
 | 
					--
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,7 @@ class GenerateWorldLoadFile : CliktCommand(name = "generate-world-load", help =
 | 
				
			|||||||
    for ((id, changelog) in worldChangelogs) {
 | 
					    for ((id, changelog) in worldChangelogs) {
 | 
				
			||||||
      val tracker = BlockLogTracker()
 | 
					      val tracker = BlockLogTracker()
 | 
				
			||||||
      tracker.replay(changelog)
 | 
					      tracker.replay(changelog)
 | 
				
			||||||
      val sparse = tracker.buildBlockMap { ExportedBlock(it.type) }
 | 
					      val sparse = tracker.buildBlockMap { ExportedBlock(it.type, it.data) }
 | 
				
			||||||
      val blocks = sparse.blocks
 | 
					      val blocks = sparse.blocks
 | 
				
			||||||
      worlds[id.toString().lowercase()] = WorldLoadWorld(
 | 
					      worlds[id.toString().lowercase()] = WorldLoadWorld(
 | 
				
			||||||
        worldNames[id] ?: "unknown_$id",
 | 
					        worldNames[id] ?: "unknown_$id",
 | 
				
			||||||
 | 
				
			|||||||
@ -47,7 +47,7 @@ class ChunkExportLoader(
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val coordinate = BlockCoordinate(x.toLong(), y.toLong(), z.toLong())
 | 
					        val coordinate = BlockCoordinate(x.toLong(), y.toLong(), z.toLong())
 | 
				
			||||||
        val state = BlockState.cached(block.type)
 | 
					        val state = BlockState(block.type, block.data)
 | 
				
			||||||
        map?.put(coordinate, state)
 | 
					        map?.put(coordinate, state)
 | 
				
			||||||
        if (allBlocks != null) {
 | 
					        if (allBlocks != null) {
 | 
				
			||||||
          allBlocks[coordinate] = state
 | 
					          allBlocks[coordinate] = state
 | 
				
			||||||
 | 
				
			|||||||
@ -68,10 +68,11 @@ class BlockChangelog(
 | 
				
			|||||||
        val y = row[BlockChangeView.y]
 | 
					        val y = row[BlockChangeView.y]
 | 
				
			||||||
        val z = row[BlockChangeView.z]
 | 
					        val z = row[BlockChangeView.z]
 | 
				
			||||||
        val block = row[BlockChangeView.block]
 | 
					        val block = row[BlockChangeView.block]
 | 
				
			||||||
 | 
					        val blockData = row[BlockChangeView.blockData]
 | 
				
			||||||
        val location = BlockCoordinate(x.toLong(), y.toLong(), z.toLong())
 | 
					        val location = BlockCoordinate(x.toLong(), y.toLong(), z.toLong())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val fromBlock = if (changeIsBreak) {
 | 
					        val fromBlock = if (changeIsBreak) {
 | 
				
			||||||
          BlockState.cached(block)
 | 
					          BlockState(block, blockData)
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          BlockState.AirBlock
 | 
					          BlockState.AirBlock
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -79,7 +80,7 @@ class BlockChangelog(
 | 
				
			|||||||
        val toBlock = if (changeIsBreak) {
 | 
					        val toBlock = if (changeIsBreak) {
 | 
				
			||||||
          BlockState.AirBlock
 | 
					          BlockState.AirBlock
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          BlockState.cached(block)
 | 
					          BlockState(block, blockData)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        BlockChange(
 | 
					        BlockChange(
 | 
				
			||||||
 | 
				
			|||||||
@ -1,15 +1,13 @@
 | 
				
			|||||||
package gay.pizza.foundation.heimdall.tool.state
 | 
					package gay.pizza.foundation.heimdall.tool.state
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.concurrent.ConcurrentHashMap
 | 
					 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Serializable(BlockStateSerializer::class)
 | 
					@Serializable
 | 
				
			||||||
data class BlockState(val type: String) {
 | 
					data class BlockState(
 | 
				
			||||||
 | 
					  val type: String,
 | 
				
			||||||
 | 
					  val data: String? = null
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
  companion object {
 | 
					  companion object {
 | 
				
			||||||
    private val cache = ConcurrentHashMap<String, BlockState>()
 | 
					    val AirBlock: BlockState = BlockState("minecraft:air")
 | 
				
			||||||
 | 
					 | 
				
			||||||
    val AirBlock: BlockState = cached("minecraft:air")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun cached(type: String): BlockState = cache.computeIfAbsent(type) { BlockState(type) }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,20 +0,0 @@
 | 
				
			|||||||
package gay.pizza.foundation.heimdall.tool.state
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import kotlinx.serialization.KSerializer
 | 
					 | 
				
			||||||
import kotlinx.serialization.builtins.serializer
 | 
					 | 
				
			||||||
import kotlinx.serialization.descriptors.SerialDescriptor
 | 
					 | 
				
			||||||
import kotlinx.serialization.encoding.Decoder
 | 
					 | 
				
			||||||
import kotlinx.serialization.encoding.Encoder
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class BlockStateSerializer : KSerializer<BlockState> {
 | 
					 | 
				
			||||||
  override val descriptor: SerialDescriptor
 | 
					 | 
				
			||||||
    get() = String.serializer().descriptor
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun deserialize(decoder: Decoder): BlockState {
 | 
					 | 
				
			||||||
    return BlockState.cached(decoder.decodeString())
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override fun serialize(encoder: Encoder, value: BlockState) {
 | 
					 | 
				
			||||||
    encoder.encodeString(value.type)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user