mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-08 23:13:10 -04:00
wip: improved chunk storing format
This commit is contained in:
parent
db88f83f72
commit
86155c8f3f
@ -24,5 +24,5 @@ abstract class BlockEntity(
|
||||
|
||||
open fun updateNBT(nbt: Map<String, Any>) = Unit
|
||||
|
||||
open fun realTick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) = Unit
|
||||
open fun tick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) = Unit
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ class CampfireBlockEntity(connection: PlayConnection) : BlockEntity(connection)
|
||||
}
|
||||
|
||||
|
||||
override fun realTick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) {
|
||||
override fun tick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) {
|
||||
if (blockState.properties[BlockProperties.LIT] != true) {
|
||||
return
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ class MobSpawnerBlockEntity(connection: PlayConnection) : BlockEntity(connection
|
||||
// ToDo: {MaxNearbyEntities: 6s, RequiredPlayerRange: 16s, SpawnCount: 4s, x: -80, y: 4, SpawnData: {id: "minecraft:zombie"}, z: 212, id: "minecraft:mob_spawner", MaxSpawnDelay: 800s, SpawnRange: 4s, Delay: 0s, MinSpawnDelay: 200s}
|
||||
}
|
||||
|
||||
override fun realTick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) {
|
||||
override fun tick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) {
|
||||
spawnParticles(blockPosition)
|
||||
}
|
||||
|
||||
|
@ -50,8 +50,8 @@ class NoteBlockBlockEntity(connection: PlayConnection) : BlockEntity(connection)
|
||||
// ToDo: Play sound?
|
||||
}
|
||||
|
||||
override fun realTick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) {
|
||||
super.realTick(connection, blockState, blockPosition)
|
||||
override fun tick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) {
|
||||
super.tick(connection, blockState, blockPosition)
|
||||
if (!showParticleNextTick) {
|
||||
return
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ data class DimensionProperties(
|
||||
} else {
|
||||
height / ProtocolDefinition.SECTION_HEIGHT_Y
|
||||
}
|
||||
val sections = highestSection - lowestSection
|
||||
|
||||
val lightLevels = FloatArray(16)
|
||||
|
||||
init {
|
||||
|
@ -18,12 +18,7 @@ import de.bixilon.minosoft.data.entities.entities.animal.horse.*
|
||||
import de.bixilon.minosoft.data.entities.entities.monster.*
|
||||
import de.bixilon.minosoft.data.entities.entities.vehicle.*
|
||||
import de.bixilon.minosoft.data.entities.meta.EntityMetaData
|
||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
import de.bixilon.minosoft.data.world.ChunkSection
|
||||
import de.bixilon.minosoft.data.world.ChunkSection.Companion.indexPosition
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
object VersionTweaker {
|
||||
// some data was packed in mata data in early versions (1.8). This function converts it to the real resource location
|
||||
@ -87,40 +82,4 @@ object VersionTweaker {
|
||||
}
|
||||
return fakeClass
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun transformSections(sections: Map<Int, ChunkSection>, versionId: Int) {
|
||||
// some blocks need to be tweaked. eg. Grass with a snow block on top becomes snowy grass block
|
||||
if (versionId >= ProtocolDefinition.FLATTING_VERSION_ID) {
|
||||
return
|
||||
}
|
||||
for ((sectionHeight, section) in sections) {
|
||||
for ((index, blockState) in section.blocks.withIndex()) {
|
||||
if (blockState == null) {
|
||||
continue
|
||||
}
|
||||
val location = index.indexPosition
|
||||
val newBlock = transformBlock(blockState, sections, location, sectionHeight)
|
||||
if (newBlock === blockState) {
|
||||
continue
|
||||
}
|
||||
if (newBlock == null) {
|
||||
section.setBlockState(location, null)
|
||||
continue
|
||||
}
|
||||
section.setBlockState(location, newBlock)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@JvmStatic
|
||||
fun transformBlock(originalBlock: BlockState?, sections: Map<Int, ChunkSection>, inChunkSectionPositions: Vec3i, sectionHeight: Int): BlockState? {
|
||||
// ToDo: Broken
|
||||
return originalBlock
|
||||
}
|
||||
|
||||
private fun getBlockAbove(sections: Map<Int, ChunkSection>, inChunkSectionPositions: Vec3i, sectionHeight: Int): BlockState? {
|
||||
return sections[sectionHeight]?.getBlockState(inChunkSectionPositions)
|
||||
}
|
||||
}
|
||||
|
@ -16,102 +16,113 @@ import de.bixilon.minosoft.data.entities.block.BlockEntity
|
||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
import de.bixilon.minosoft.data.world.biome.source.BiomeSource
|
||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkSectionPosition
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import glm_.vec2.Vec2i
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
/**
|
||||
* Collection of chunks sections (allocated in y)
|
||||
* Collection of chunks sections (from the lowest section to the highest section in y axis)
|
||||
*/
|
||||
class Chunk(
|
||||
var sections: MutableMap<Int, ChunkSection>? = null,
|
||||
private val connection: PlayConnection,
|
||||
private var sections: Array<ChunkSection?>? = null,
|
||||
var biomeSource: BiomeSource? = null,
|
||||
var lightAccessor: LightAccessor? = null,
|
||||
) {
|
||||
private val lock = Object()
|
||||
) : Iterable<ChunkSection?> {
|
||||
val lowestSection = connection.world.dimension!!.lowestSection
|
||||
|
||||
val blocksInitialized: Boolean
|
||||
get() = sections != null
|
||||
val biomesInitialized
|
||||
get() = biomeSource != null
|
||||
val lightInitialized
|
||||
get() = lightAccessor != null
|
||||
|
||||
val isFullyLoaded: Boolean
|
||||
get() {
|
||||
return sections != null && biomeSource != null && lightAccessor != null
|
||||
}
|
||||
get() = blocksInitialized && biomesInitialized && lightInitialized
|
||||
|
||||
operator fun get(inChunkPosition: Vec3i): BlockState? {
|
||||
return sections?.get(inChunkPosition.sectionHeight)?.getBlockState(inChunkPosition.inChunkSectionPosition)
|
||||
operator fun get(sectionHeight: Int): ChunkSection? = sections?.getOrNull(sectionHeight - lowestSection)
|
||||
|
||||
fun get(x: Int, y: Int, z: Int): BlockState? {
|
||||
return this[y.sectionHeight]?.blocks?.get(x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z)
|
||||
}
|
||||
|
||||
operator fun get(x: Int, y: Int, z: Int): BlockState? {
|
||||
return get(Vec3i(x, y, z))
|
||||
operator fun get(position: Vec3i): BlockState? = get(position.x, position.y, position.z)
|
||||
|
||||
fun set(x: Int, y: Int, z: Int, blockState: BlockState?, blockEntity: BlockEntity? = null) {
|
||||
val section = getOrPut(y.sectionHeight)
|
||||
section.blocks[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z] = blockState
|
||||
section.blockEntities[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z] = blockEntity // ToDo
|
||||
}
|
||||
|
||||
operator fun set(position: Vec3i, blockState: BlockState?) = set(position.x, position.y, position.z, blockState)
|
||||
|
||||
fun setBlocks(blocks: Map<Vec3i, BlockState?>) {
|
||||
for ((location, blockInfo) in blocks) {
|
||||
set(location, blockInfo)
|
||||
for ((location, blockState) in blocks) {
|
||||
set(location, blockState)
|
||||
}
|
||||
}
|
||||
|
||||
fun getBlockEntity(x: Int, y: Int, z: Int): BlockEntity? {
|
||||
return this[y.sectionHeight]?.blockEntities?.get(x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z)
|
||||
}
|
||||
|
||||
fun getBlockEntity(position: Vec3i): BlockEntity? = getBlockEntity(position.x, position.y, position.z)
|
||||
|
||||
fun setBlockEntity(x: Int, y: Int, z: Int, blockEntity: BlockEntity?) {
|
||||
getOrPut(y.sectionHeight).blockEntities[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z] = blockEntity
|
||||
}
|
||||
|
||||
fun setBlockEntity(position: Vec3i, blockEntity: BlockEntity?) = setBlockEntity(position.x, position.y, position.z, blockEntity)
|
||||
|
||||
fun setData(data: ChunkData, merge: Boolean = false) {
|
||||
synchronized(lock) {
|
||||
data.blocks?.let {
|
||||
if (sections == null) {
|
||||
sections = mutableMapOf()
|
||||
}
|
||||
if (!merge) {
|
||||
sections?.clear()
|
||||
}
|
||||
// replace all chunk sections
|
||||
for ((sectionHeight, chunkSection) in it) {
|
||||
getOrPut(sectionHeight).setData(chunkSection)
|
||||
}
|
||||
data.blocks?.let {
|
||||
var sections = this.sections
|
||||
if (sections == null || !merge) {
|
||||
sections = arrayOfNulls(connection.world.dimension!!.sections)
|
||||
this.sections = sections
|
||||
}
|
||||
data.biomeSource?.let {
|
||||
this.biomeSource = it
|
||||
}
|
||||
data.lightAccessor?.let {
|
||||
this.lightAccessor = it
|
||||
|
||||
// replace all chunk sections
|
||||
for ((index, section) in it.withIndex()) {
|
||||
section ?: continue
|
||||
sections[index] = section
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
operator fun set(inChunkPosition: Vec3i, blockState: BlockState?) {
|
||||
getOrPut(inChunkPosition.sectionHeight).setBlockState(inChunkPosition.inChunkSectionPosition, blockState)
|
||||
data.biomeSource?.let {
|
||||
this.biomeSource = it
|
||||
}
|
||||
data.lightAccessor?.let {
|
||||
this.lightAccessor = it
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOrPut(sectionHeight: Int): ChunkSection {
|
||||
if (sections == null) {
|
||||
throw IllegalStateException("Chunk not received/initialized yet!")
|
||||
}
|
||||
return sections!![sectionHeight].let {
|
||||
var section = it
|
||||
if (section == null) {
|
||||
section = ChunkSection()
|
||||
sections!![sectionHeight] = section
|
||||
}
|
||||
section
|
||||
val sections = sections ?: throw NullPointerException("Sections not initialized yet!")
|
||||
val sectionIndex = sectionHeight - lowestSection
|
||||
|
||||
var section = sections[sectionIndex]
|
||||
if (section == null) {
|
||||
section = ChunkSection(connection.registries)
|
||||
sections[sectionIndex] = section
|
||||
}
|
||||
return section
|
||||
}
|
||||
|
||||
fun realTick(connection: PlayConnection, chunkPosition: Vec2i) {
|
||||
fun tick(connection: PlayConnection, chunkPosition: Vec2i) {
|
||||
if (!isFullyLoaded) {
|
||||
return
|
||||
}
|
||||
val sections = sections
|
||||
sections ?: return
|
||||
for ((height, section) in sections.toSynchronizedMap()) {
|
||||
section.realTick(connection, Vec3i.of(chunkPosition, height, Vec3i.EMPTY))
|
||||
val sections = sections!!
|
||||
for ((index, section) in sections.withIndex()) {
|
||||
section ?: continue
|
||||
section.tick(connection, chunkPosition, index - lowestSection)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun getBlockEntity(inChunkPosition: Vec3i): BlockEntity? {
|
||||
return sections?.get(inChunkPosition.sectionHeight)?.getBlockEntity(inChunkPosition.inChunkSectionPosition)
|
||||
}
|
||||
|
||||
operator fun set(inChunkPosition: Vec3i, blockEntity: BlockEntity?) {
|
||||
sections?.get(inChunkPosition.sectionHeight)?.setBlockEntity(inChunkPosition.inChunkSectionPosition, blockEntity)
|
||||
override fun iterator(): Iterator<ChunkSection?> {
|
||||
return sections!!.iterator()
|
||||
}
|
||||
}
|
||||
|
@ -17,20 +17,14 @@ import de.bixilon.minosoft.data.world.biome.source.BiomeSource
|
||||
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||
|
||||
data class ChunkData(
|
||||
var blocks: Map<Int, ChunkSection>? = null,
|
||||
var blocks: Array<ChunkSection?>? = null,
|
||||
var biomeSource: BiomeSource? = null,
|
||||
var lightAccessor: LightAccessor? = null,
|
||||
) {
|
||||
|
||||
fun replace(data: ChunkData) {
|
||||
data.blocks?.let {
|
||||
this.blocks = it
|
||||
}
|
||||
data.biomeSource?.let {
|
||||
this.biomeSource = it
|
||||
}
|
||||
data.lightAccessor?.let {
|
||||
this.lightAccessor = it
|
||||
}
|
||||
data.blocks?.let { this.blocks = it }
|
||||
data.biomeSource?.let { this.biomeSource = it }
|
||||
data.lightAccessor?.let { this.lightAccessor = it }
|
||||
}
|
||||
}
|
||||
|
@ -13,54 +13,69 @@
|
||||
package de.bixilon.minosoft.data.world
|
||||
|
||||
import de.bixilon.minosoft.data.entities.block.BlockEntity
|
||||
import de.bixilon.minosoft.data.registries.biomes.Biome
|
||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
import de.bixilon.minosoft.data.world.block.entities.ArrayBlockEntityProvider
|
||||
import de.bixilon.minosoft.data.world.block.entities.BlockEntityProvider
|
||||
import de.bixilon.minosoft.data.world.block.entities.MapBlockEntityProvider
|
||||
import de.bixilon.minosoft.data.registries.registries.Registries
|
||||
import de.bixilon.minosoft.data.world.container.RegistrySectionDataProvider
|
||||
import de.bixilon.minosoft.data.world.container.SectionDataProvider
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
import glm_.vec2.Vec2i
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
/**
|
||||
* Collection of 16x16x16 blocks
|
||||
*/
|
||||
class ChunkSection(
|
||||
var blocks: Array<BlockState?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION),
|
||||
private var blockEntities: BlockEntityProvider = MapBlockEntityProvider(),
|
||||
val blocks: RegistrySectionDataProvider<BlockState?>,
|
||||
@Deprecated("TODO")
|
||||
val biomes: RegistrySectionDataProvider<Biome>,
|
||||
val blockEntities: SectionDataProvider<BlockEntity?>,
|
||||
@Deprecated("TODO")
|
||||
val light: ByteArray, // packed (skyLight: 0xF0, blockLight: 0x0F)
|
||||
) {
|
||||
|
||||
fun getBlockState(inChunkSectionPositions: Vec3i): BlockState? {
|
||||
return blocks[inChunkSectionPositions.index]
|
||||
}
|
||||
|
||||
fun setBlockState(inChunkSectionPositions: Vec3i, blockState: BlockState?) {
|
||||
blocks[inChunkSectionPositions.index] = blockState
|
||||
}
|
||||
|
||||
fun setData(chunkSection: ChunkSection) {
|
||||
blocks = chunkSection.blocks.clone()
|
||||
blockEntities = chunkSection.blockEntities.clone()
|
||||
}
|
||||
|
||||
fun getBlockEntity(inChunkSectionPositions: Vec3i): BlockEntity? {
|
||||
return blockEntities[inChunkSectionPositions]
|
||||
}
|
||||
|
||||
fun setBlockEntity(inChunkSectionPositions: Vec3i, blockEntity: BlockEntity?) {
|
||||
blockEntities[inChunkSectionPositions] = blockEntity
|
||||
val blockEntities = blockEntities
|
||||
if (blockEntities.size > BlockEntityProvider.BLOCK_ENTITY_MAP_LIMIT_UP && blockEntities is MapBlockEntityProvider) {
|
||||
this.blockEntities = ArrayBlockEntityProvider(blockEntities)
|
||||
} else if (blockEntities.size <= BlockEntityProvider.BLOCK_ENTITY_MAP_LIMIT_DOWN && blockEntities is ArrayBlockEntityProvider) {
|
||||
this.blockEntities = MapBlockEntityProvider(blockEntities)
|
||||
constructor(registries: Registries, blocks: Array<BlockState?>? = null) : this(RegistrySectionDataProvider<BlockState?>(registries.blockStateRegistry.unsafeCast()), RegistrySectionDataProvider(registries.biomeRegistry), SectionDataProvider(), ByteArray(ProtocolDefinition.BLOCKS_PER_SECTION)) {
|
||||
if (blocks != null) {
|
||||
this.blocks.setData(blocks)
|
||||
}
|
||||
}
|
||||
|
||||
fun realTick(connection: PlayConnection, chunkSectionPosition: Vec3i) {
|
||||
blockEntities.forEach { entity, inChunkSectionPosition ->
|
||||
val block = blocks[inChunkSectionPosition.index] ?: return@forEach // maybe block already got destroyed
|
||||
entity.realTick(connection, block, chunkSectionPosition + inChunkSectionPosition)
|
||||
fun tick(connection: PlayConnection, chunkPosition: Vec2i, sectionHeight: Int) {
|
||||
acquire()
|
||||
for ((index, blockEntity) in blockEntities.withIndex()) {
|
||||
blockEntity ?: continue
|
||||
val position = Vec3i.of(chunkPosition, sectionHeight, index.indexPosition)
|
||||
val blockState = blocks[index] ?: continue
|
||||
blockEntity.tick(connection, blockState, position)
|
||||
}
|
||||
release()
|
||||
}
|
||||
|
||||
fun acquire() {
|
||||
blocks.acquire()
|
||||
biomes.acquire()
|
||||
blockEntities.acquire()
|
||||
}
|
||||
|
||||
fun release() {
|
||||
blocks.release()
|
||||
biomes.release()
|
||||
blockEntities.release()
|
||||
}
|
||||
|
||||
fun lock() {
|
||||
blocks.lock()
|
||||
biomes.lock()
|
||||
blockEntities.lock()
|
||||
}
|
||||
|
||||
fun unlock() {
|
||||
blocks.unlock()
|
||||
biomes.unlock()
|
||||
blockEntities.unlock()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -21,7 +21,6 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock
|
||||
import de.bixilon.minosoft.data.registries.dimension.DimensionProperties
|
||||
import de.bixilon.minosoft.data.registries.sounds.SoundEvent
|
||||
import de.bixilon.minosoft.data.registries.tweaker.VersionTweaker
|
||||
import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor
|
||||
import de.bixilon.minosoft.data.world.biome.accessor.NullBiomeAccessor
|
||||
import de.bixilon.minosoft.data.world.light.WorldLightAccessor
|
||||
@ -31,10 +30,8 @@ import de.bixilon.minosoft.gui.rendering.sound.AudioPlayer
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.blockPosition
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkSectionPosition
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.minus
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
|
||||
import de.bixilon.minosoft.modding.event.EventInitiators
|
||||
import de.bixilon.minosoft.modding.event.events.BlockSetEvent
|
||||
import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent
|
||||
@ -43,6 +40,7 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
|
||||
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
|
||||
import de.bixilon.minosoft.util.MMath
|
||||
import de.bixilon.minosoft.util.collections.SynchronizedMap
|
||||
import glm_.func.common.clamp
|
||||
import glm_.vec2.Vec2i
|
||||
import glm_.vec3.Vec3
|
||||
@ -58,7 +56,7 @@ import kotlin.random.Random
|
||||
class World(
|
||||
val connection: PlayConnection,
|
||||
) : BiomeAccessor {
|
||||
val chunks: MutableMap<Vec2i, Chunk> = synchronizedMapOf()
|
||||
val chunks: SynchronizedMap<Vec2i, Chunk> = synchronizedMapOf()
|
||||
val entities = WorldEntities()
|
||||
var hardcore = false
|
||||
var dimension: DimensionProperties? = null
|
||||
@ -81,14 +79,12 @@ class World(
|
||||
return chunks[blockPosition.chunkPosition]?.get(blockPosition.inChunkPosition)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
operator fun get(chunkPosition: Vec2i): Chunk? {
|
||||
return chunks[chunkPosition]
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun getOrCreateChunk(chunkPosition: Vec2i): Chunk {
|
||||
return chunks.getOrPut(chunkPosition) { Chunk() }
|
||||
return chunks.getOrPut(chunkPosition) { Chunk(connection) }
|
||||
}
|
||||
|
||||
fun setBlockState(blockPosition: Vec3i, blockState: BlockState?) {
|
||||
@ -96,32 +92,24 @@ class World(
|
||||
}
|
||||
|
||||
operator fun set(blockPosition: Vec3i, blockState: BlockState?) {
|
||||
val chunkPosition = blockPosition.chunkPosition
|
||||
chunks[chunkPosition]?.let {
|
||||
val sections = it.sections ?: return
|
||||
|
||||
val transformedBlockState = if (connection.version.isFlattened()) {
|
||||
blockState
|
||||
} else {
|
||||
VersionTweaker.transformBlock(blockState, sections, blockPosition.inChunkSectionPosition, blockPosition.sectionHeight)
|
||||
}
|
||||
val inChunkPosition = blockPosition.inChunkPosition
|
||||
val previousBlock = it[inChunkPosition]
|
||||
if (previousBlock == transformedBlockState) {
|
||||
return
|
||||
}
|
||||
previousBlock?.block?.onBreak(connection, blockPosition, previousBlock, it.getBlockEntity(inChunkPosition))
|
||||
blockState?.block?.onPlace(connection, blockPosition, blockState)
|
||||
it[inChunkPosition] = transformedBlockState
|
||||
connection.fireEvent(BlockSetEvent(
|
||||
connection = connection,
|
||||
blockPosition = blockPosition,
|
||||
blockState = transformedBlockState,
|
||||
))
|
||||
val chunk = chunks[blockPosition.chunkPosition] ?: return
|
||||
val inChunkPosition = blockPosition.inChunkPosition
|
||||
val previousBlock = chunk[inChunkPosition]
|
||||
if (previousBlock == blockState) {
|
||||
return
|
||||
}
|
||||
previousBlock?.block?.onBreak(connection, blockPosition, previousBlock, chunk.getBlockEntity(inChunkPosition))
|
||||
blockState?.block?.onPlace(connection, blockPosition, blockState)
|
||||
chunk[inChunkPosition] = blockState
|
||||
connection.fireEvent(BlockSetEvent(
|
||||
connection = connection,
|
||||
blockPosition = blockPosition,
|
||||
blockState = blockState,
|
||||
))
|
||||
}
|
||||
|
||||
fun isPositionChangeable(blockPosition: Vec3i): Boolean {
|
||||
// ToDo: World border
|
||||
val dimension = connection.world.dimension!!
|
||||
return (blockPosition.y >= dimension.minY || blockPosition.y < dimension.height)
|
||||
}
|
||||
@ -134,37 +122,22 @@ class World(
|
||||
}
|
||||
|
||||
fun unloadChunk(chunkPosition: Vec2i) {
|
||||
chunks.remove(chunkPosition)?.let {
|
||||
connection.fireEvent(ChunkUnloadEvent(connection, EventInitiators.UNKNOWN, chunkPosition))
|
||||
}
|
||||
}
|
||||
|
||||
fun replaceChunk(position: Vec2i, chunk: Chunk) {
|
||||
chunks[position] = chunk
|
||||
}
|
||||
|
||||
fun replaceChunks(chunkMap: HashMap<Vec2i, Chunk>) {
|
||||
for ((chunkLocation, chunk) in chunkMap) {
|
||||
chunks[chunkLocation] = chunk
|
||||
}
|
||||
chunks.remove(chunkPosition) ?: return
|
||||
connection.fireEvent(ChunkUnloadEvent(connection, EventInitiators.UNKNOWN, chunkPosition))
|
||||
}
|
||||
|
||||
fun getBlockEntity(blockPosition: Vec3i): BlockEntity? {
|
||||
return get(blockPosition.chunkPosition)?.getBlockEntity(blockPosition.inChunkPosition)
|
||||
}
|
||||
|
||||
operator fun set(blockPosition: Vec3i, blockEntity: BlockEntity?) {
|
||||
get(blockPosition.chunkPosition)?.set(blockPosition.inChunkPosition, blockEntity)
|
||||
}
|
||||
|
||||
fun setBlockEntity(blockPosition: Vec3i, blockEntity: BlockEntity?) {
|
||||
this[blockPosition] = blockEntity
|
||||
get(blockPosition.chunkPosition)?.setBlockEntity(blockPosition.inChunkPosition, blockEntity)
|
||||
}
|
||||
|
||||
|
||||
fun setBlockEntities(blockEntities: Map<Vec3i, BlockEntity>) {
|
||||
for ((blockPosition, entityMetaData) in blockEntities) {
|
||||
set(blockPosition, entityMetaData)
|
||||
for ((blockPosition, blockEntity) in blockEntities) {
|
||||
setBlockEntity(blockPosition, blockEntity)
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,9 +145,9 @@ class World(
|
||||
return biomeAccessor.getBiome(blockPosition)
|
||||
}
|
||||
|
||||
fun realTick() {
|
||||
fun tick() {
|
||||
for ((chunkPosition, chunk) in chunks.toSynchronizedMap()) {
|
||||
chunk.realTick(connection, chunkPosition)
|
||||
chunk.tick(connection, chunkPosition)
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,24 +174,6 @@ class World(
|
||||
return ret.toMap()
|
||||
}
|
||||
|
||||
fun getBlocks(start: Vec3i, end: Vec3i): Map<Vec3i, BlockState> {
|
||||
val blocks: MutableMap<Vec3i, BlockState> = mutableMapOf()
|
||||
|
||||
for (z in start.z..end.z) {
|
||||
for (y in start.y..end.y) {
|
||||
for (x in start.x..end.x) {
|
||||
val blockPosition = Vec3i(x, y, z)
|
||||
this[blockPosition]?.let {
|
||||
blocks[blockPosition] = it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blocks.toMap()
|
||||
}
|
||||
|
||||
|
||||
fun playSoundEvent(resourceLocation: ResourceLocation, position: Vec3i? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
||||
audioPlayer?.playSoundEvent(resourceLocation, position, volume, pitch)
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2021 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.world.container
|
||||
|
||||
import de.bixilon.minosoft.data.registries.registries.registry.AbstractRegistry
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
|
||||
class RegistrySectionDataProvider<T>(
|
||||
val registry: AbstractRegistry<T>,
|
||||
data: Array<Any?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION),
|
||||
) : SectionDataProvider<T>(data) {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun setIdData(ids: Array<Int>) {
|
||||
val data: Array<Any?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION)
|
||||
|
||||
for ((index, id) in ids.withIndex()) {
|
||||
data[index] = registry[id]
|
||||
}
|
||||
|
||||
setData(data as Array<T>)
|
||||
}
|
||||
|
||||
|
||||
override fun copy(): RegistrySectionDataProvider<T> {
|
||||
acquire()
|
||||
val clone = RegistrySectionDataProvider(registry, data.clone())
|
||||
release()
|
||||
|
||||
return clone
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2021 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.world.container
|
||||
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
|
||||
open class SectionDataProvider<T>(
|
||||
data: Array<Any?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION),
|
||||
) : Iterable<T> {
|
||||
protected var data = data
|
||||
private set
|
||||
protected val lock = SemaphoreLock() // lock while reading (blocks writing)
|
||||
var count: Int = 0
|
||||
private set
|
||||
|
||||
init {
|
||||
recalculateCount()
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
operator fun get(index: Int): T {
|
||||
lock.acquire()
|
||||
val value = data[index] as T
|
||||
lock.release()
|
||||
return value
|
||||
}
|
||||
|
||||
private fun recalculateCount() {
|
||||
var count = 0
|
||||
for (value in data) {
|
||||
if (value == null) {
|
||||
continue
|
||||
}
|
||||
count++
|
||||
}
|
||||
this.count = count
|
||||
}
|
||||
|
||||
operator fun get(x: Int, y: Int, z: Int): T {
|
||||
return get(y shl 8 or (z shl 4) or x)
|
||||
}
|
||||
|
||||
operator fun set(x: Int, y: Int, z: Int, value: T) {
|
||||
set(y shl 8 or (z shl 4) or x, value)
|
||||
}
|
||||
|
||||
operator fun set(index: Int, value: T) {
|
||||
lock()
|
||||
val previous = data[index]
|
||||
if (value == null) {
|
||||
if (previous == null) {
|
||||
return
|
||||
}
|
||||
count--
|
||||
} else if (previous == null) {
|
||||
count++
|
||||
}
|
||||
data[index] = value
|
||||
unlock()
|
||||
}
|
||||
|
||||
fun acquire() {
|
||||
lock.acquire()
|
||||
}
|
||||
|
||||
fun release() {
|
||||
lock.release()
|
||||
}
|
||||
|
||||
fun lock() {
|
||||
lock.lock()
|
||||
}
|
||||
|
||||
fun unlock() {
|
||||
lock.unlock()
|
||||
}
|
||||
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@Synchronized
|
||||
fun setData(data: Array<T>) {
|
||||
lock()
|
||||
check(data.size == ProtocolDefinition.BLOCKS_PER_SECTION) { "Size does not match!" }
|
||||
this.data = data as Array<Any?>
|
||||
recalculateCount()
|
||||
unlock()
|
||||
}
|
||||
|
||||
open fun copy(): SectionDataProvider<T> {
|
||||
acquire()
|
||||
val clone = SectionDataProvider<T>(data.clone())
|
||||
release()
|
||||
|
||||
return clone
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun iterator(): Iterator<T> {
|
||||
return data.iterator() as Iterator<T>
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2021 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.world.container
|
||||
|
||||
import java.util.concurrent.Semaphore
|
||||
|
||||
class SemaphoreLock {
|
||||
private val semaphore = Semaphore(Int.MAX_VALUE)
|
||||
|
||||
fun acquire() {
|
||||
semaphore.acquire()
|
||||
}
|
||||
|
||||
fun release() {
|
||||
semaphore.release()
|
||||
}
|
||||
|
||||
fun lock() {
|
||||
semaphore.acquire(Int.MAX_VALUE)
|
||||
}
|
||||
|
||||
fun unlock() {
|
||||
semaphore.release(Int.MAX_VALUE)
|
||||
}
|
||||
}
|
@ -43,8 +43,6 @@ object RenderConstants {
|
||||
const val TEXT_LINE_PADDING = 2
|
||||
val WORD_SEPARATORS = arrayOf(' ', '.', ',', '!', '-', '?')
|
||||
|
||||
const val CHUNK_SECTIONS_PER_MESH = 1
|
||||
|
||||
const val FRUSTUM_CULLING_ENABLED = true
|
||||
const val SHOW_FPS_IN_WINDOW_TITLE = true
|
||||
|
||||
|
@ -29,7 +29,10 @@ import de.bixilon.minosoft.data.world.Chunk
|
||||
import de.bixilon.minosoft.data.world.ChunkSection
|
||||
import de.bixilon.minosoft.data.world.ChunkSection.Companion.indexPosition
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
import de.bixilon.minosoft.gui.rendering.*
|
||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||
import de.bixilon.minosoft.gui.rendering.Renderer
|
||||
import de.bixilon.minosoft.gui.rendering.RendererBuilder
|
||||
import de.bixilon.minosoft.gui.rendering.RenderingStates
|
||||
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMeshCollection
|
||||
import de.bixilon.minosoft.gui.rendering.block.renderable.BlockLikeRenderContext
|
||||
import de.bixilon.minosoft.gui.rendering.input.camera.Frustum
|
||||
@ -171,7 +174,7 @@ class WorldRenderer(
|
||||
|
||||
connection.registerEvent(CallbackEventInvoker.of<ChunkUnloadEvent> { unloadChunk(it.chunkPosition) })
|
||||
|
||||
connection.registerEvent(CallbackEventInvoker.of<ChunkDataChangeEvent> { prepareChunk(it.chunkPosition) })
|
||||
connection.registerEvent(CallbackEventInvoker.of<ChunkDataChangeEvent> { prepareChunk(it.chunkPosition, it.chunk) })
|
||||
|
||||
connection.registerEvent(CallbackEventInvoker.of<BlockSetEvent> { prepareChunkSection(it.blockPosition.chunkPosition, it.blockPosition.sectionHeight) })
|
||||
|
||||
@ -297,7 +300,9 @@ class WorldRenderer(
|
||||
|
||||
var currentChunks: MutableMap<Int, ChunkSection> = synchronizedMapOf()
|
||||
var currentIndex = 0
|
||||
for ((sectionHeight, section) in chunk.sections!!) {
|
||||
for ((index, section) in chunk.withIndex()) {
|
||||
section ?: continue
|
||||
val sectionHeight = index - chunk.lowestSection
|
||||
if (sectionHeight.sectionIndex != currentIndex) {
|
||||
prepareChunkSections(chunkPosition, currentChunks)
|
||||
currentChunks = synchronizedMapOf()
|
||||
@ -419,9 +424,8 @@ class WorldRenderer(
|
||||
private fun prepareChunkSection(chunkPosition: Vec2i, sectionHeight: Int) {
|
||||
val sections: MutableMap<Int, ChunkSection> = synchronizedMapOf()
|
||||
val chunk = world[chunkPosition]!!
|
||||
val lowestSectionHeight = sectionHeight.sectionIndex * RenderConstants.CHUNK_SECTIONS_PER_MESH
|
||||
for (i in lowestSectionHeight until lowestSectionHeight + RenderConstants.CHUNK_SECTIONS_PER_MESH) {
|
||||
sections[i] = chunk.sections?.get(i) ?: continue
|
||||
for ((index, section) in chunk.withIndex()) {
|
||||
sections[index - chunk.lowestSection] = section ?: continue
|
||||
}
|
||||
prepareChunkSections(chunkPosition, sections)
|
||||
}
|
||||
@ -508,13 +512,7 @@ class WorldRenderer(
|
||||
}
|
||||
|
||||
val Int.sectionIndex: Int
|
||||
get() {
|
||||
val divided = this / RenderConstants.CHUNK_SECTIONS_PER_MESH
|
||||
if (this < 0) {
|
||||
return divided - 1
|
||||
}
|
||||
return divided
|
||||
}
|
||||
get() = this
|
||||
|
||||
private operator fun Int.plus(upOrDown: Directions): Int {
|
||||
return this + upOrDown.vector.y
|
||||
|
@ -241,15 +241,16 @@ object VecUtil {
|
||||
return Vec3i(inVec2i.x, y, inVec2i.z)
|
||||
}
|
||||
|
||||
val Vec3i.sectionHeight: Int
|
||||
get() {
|
||||
return if (y < 0) {
|
||||
(y + 1) / ProtocolDefinition.SECTION_HEIGHT_Y - 1
|
||||
} else {
|
||||
y / ProtocolDefinition.SECTION_HEIGHT_Y
|
||||
}
|
||||
val Int.sectionHeight: Int
|
||||
get() = if (this < 0) {
|
||||
(this + 1) / ProtocolDefinition.SECTION_HEIGHT_Y - 1
|
||||
} else {
|
||||
this / ProtocolDefinition.SECTION_HEIGHT_Y
|
||||
}
|
||||
|
||||
val Vec3i.sectionHeight: Int
|
||||
get() = y.sectionHeight
|
||||
|
||||
val Vec3i.entityPosition: Vec3d
|
||||
get() = Vec3d(x + 0.5f, y, z + 0.5f) // ToDo: Confirm
|
||||
|
||||
|
@ -158,7 +158,7 @@ class PlayConnection(
|
||||
})
|
||||
|
||||
worldTickTask = TimeWorker.addTask(TimeWorkerTask(ProtocolDefinition.TICK_TIME, maxDelayTime = ProtocolDefinition.TICK_TIME / 2) {
|
||||
world.realTick()
|
||||
world.tick()
|
||||
})
|
||||
|
||||
randomTickTask = TimeWorker.addTask(TimeWorkerTask(ProtocolDefinition.TICK_TIME, maxDelayTime = ProtocolDefinition.TICK_TIME / 2) {
|
||||
|
@ -45,7 +45,7 @@ class BlockActionS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
return
|
||||
}
|
||||
val blockEntity = factory.build(connection)
|
||||
connection.world[position] = blockEntity
|
||||
connection.world.setBlockEntity(position, blockEntity)
|
||||
blockEntity
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ class BlockEntityMetaDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
connection.world.getBlockEntity(position)?.updateNBT(nbt) ?: let {
|
||||
val blockEntity = DefaultBlockEntityMetaDataFactory.buildBlockEntity(DefaultBlockEntityMetaDataFactory[type]!!, connection)
|
||||
blockEntity.updateNBT(nbt)
|
||||
connection.world[position] = blockEntity
|
||||
connection.world.setBlockEntity(position, blockEntity)
|
||||
}
|
||||
connection.fireEvent(BlockEntityMetaDataChangeEvent(connection, this))
|
||||
}
|
||||
|
@ -15,10 +15,11 @@ package de.bixilon.minosoft.protocol.packets.s2c.play
|
||||
import de.bixilon.minosoft.Minosoft
|
||||
import de.bixilon.minosoft.data.entities.block.BlockEntity
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.data.registries.tweaker.VersionTweaker
|
||||
import de.bixilon.minosoft.data.world.ChunkData
|
||||
import de.bixilon.minosoft.data.world.biome.source.SpatialBiomeArray
|
||||
import de.bixilon.minosoft.datafixer.BlockEntityFixer.fix
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
|
||||
import de.bixilon.minosoft.modding.event.EventInitiators
|
||||
import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent
|
||||
import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent
|
||||
@ -106,10 +107,11 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
buffer.pointer = size + lastPos
|
||||
}
|
||||
if (buffer.versionId >= ProtocolVersions.V_1_9_4) {
|
||||
val positionOffset = Vec3i.of(chunkPosition, dimension.lowestSection, Vec3i.EMPTY)
|
||||
val blockEntitiesCount = buffer.readVarInt()
|
||||
for (i in 0 until blockEntitiesCount) {
|
||||
val nbt = buffer.readNBT().asCompound()
|
||||
val position = Vec3i(nbt["x"]!!.toInt(), nbt["y"]!!.toInt(), nbt["z"]!!.toInt())
|
||||
val position = Vec3i(nbt["x"]!!.toInt(), nbt["y"]!!.toInt(), nbt["z"]!!.toInt()) - positionOffset
|
||||
val resourceLocation = ResourceLocation(nbt["id"].unsafeCast()).fix()
|
||||
val type = buffer.connection.registries.blockEntityTypeRegistry[resourceLocation] ?: let {
|
||||
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.WARN) { "Unknown block entity: $resourceLocation" }
|
||||
@ -124,13 +126,12 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
}
|
||||
|
||||
override fun handle(connection: PlayConnection) {
|
||||
chunkData?.blocks?.let {
|
||||
VersionTweaker.transformSections(it, connection.version.versionId)
|
||||
}
|
||||
chunkData?.let {
|
||||
val chunk = connection.world.getOrCreateChunk(chunkPosition)
|
||||
chunk.setData(chunkData!!)
|
||||
connection.world.setBlockEntities(blockEntities)
|
||||
for ((position, blockEntity) in blockEntities) {
|
||||
chunk.setBlockEntity(position, blockEntity)
|
||||
}
|
||||
connection.fireEvent(ChunkDataChangeEvent(connection, this))
|
||||
} ?: let {
|
||||
connection.world.unloadChunk(chunkPosition)
|
||||
|
@ -14,9 +14,6 @@ package de.bixilon.minosoft.protocol.packets.s2c.play
|
||||
|
||||
|
||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
import de.bixilon.minosoft.data.registries.tweaker.VersionTweaker
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkSectionPosition
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
|
||||
import de.bixilon.minosoft.modding.event.events.MassBlockSetEvent
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
||||
@ -81,21 +78,11 @@ class MassBlockSetS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
|
||||
override fun handle(connection: PlayConnection) {
|
||||
val chunk = connection.world[chunkPosition] ?: return // thanks mojang
|
||||
if (chunk.sections == null) {
|
||||
if (!chunk.blocksInitialized) {
|
||||
return
|
||||
}
|
||||
chunk.setBlocks(blocks)
|
||||
|
||||
// tweak
|
||||
if (!connection.version.isFlattened()) {
|
||||
for ((key, value) in blocks) {
|
||||
val block = VersionTweaker.transformBlock(value, chunk.sections!!, key.inChunkSectionPosition, key.sectionHeight)
|
||||
if (block === value) {
|
||||
continue
|
||||
}
|
||||
chunk[key] = block
|
||||
}
|
||||
}
|
||||
connection.fireEvent(MassBlockSetEvent(connection, this))
|
||||
}
|
||||
|
||||
|
@ -13,10 +13,8 @@
|
||||
package de.bixilon.minosoft.protocol.packets.s2c.play
|
||||
|
||||
import de.bixilon.minosoft.Minosoft
|
||||
import de.bixilon.minosoft.data.registries.tweaker.VersionTweaker
|
||||
import de.bixilon.minosoft.data.world.ChunkData
|
||||
import de.bixilon.minosoft.modding.event.EventInitiators
|
||||
|
||||
import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent
|
||||
import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
@ -73,10 +71,6 @@ class MassChunkDataS2CP() : PlayS2CPacket() {
|
||||
override fun handle(connection: PlayConnection) {
|
||||
// transform data
|
||||
for ((chunkPosition, data) in data) {
|
||||
data?.blocks?.let {
|
||||
VersionTweaker.transformSections(it, connection.version.versionId)
|
||||
}
|
||||
|
||||
data?.let {
|
||||
val chunk = connection.world.getOrCreateChunk(chunkPosition)
|
||||
chunk.setData(data)
|
||||
|
@ -26,7 +26,7 @@ import de.bixilon.minosoft.util.logging.LogMessageType
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
class SignTextSetS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
val signPosition: Vec3i = if (buffer.versionId < ProtocolVersions.V_14W04A) {
|
||||
val position: Vec3i = if (buffer.versionId < ProtocolVersions.V_14W04A) {
|
||||
buffer.readShortBlockPosition()
|
||||
} else {
|
||||
buffer.readBlockPosition()
|
||||
@ -43,16 +43,14 @@ class SignTextSetS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
}
|
||||
|
||||
override fun handle(connection: PlayConnection) {
|
||||
val signBlockEntity = connection.world.getBlockEntity(signPosition)?.unsafeCast<SignBlockEntity>() ?: let {
|
||||
val blockEntity = SignBlockEntity(connection)
|
||||
connection.world[signPosition] = blockEntity
|
||||
blockEntity
|
||||
val signBlockEntity = connection.world.getBlockEntity(position)?.unsafeCast<SignBlockEntity>() ?: SignBlockEntity(connection).apply {
|
||||
connection.world.setBlockEntity(position, this)
|
||||
}
|
||||
|
||||
signBlockEntity.lines = lines
|
||||
}
|
||||
|
||||
override fun log() {
|
||||
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Sign text set (position=$signPosition, lines=$lines" }
|
||||
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Sign text set (position=$position, lines=$lines" }
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ import de.bixilon.minosoft.protocol.packets.s2c.status.StatusPongS2CP
|
||||
|
||||
class PacketTypes {
|
||||
|
||||
@Suppress("UNUSED")
|
||||
enum class C2S(val clazz: Class<out C2SPacket>? = null) {
|
||||
HANDSHAKING_HANDSHAKE(HandshakeC2SP::class.java),
|
||||
STATUS_PING(StatusPingC2SP::class.java),
|
||||
@ -145,6 +146,7 @@ class PacketTypes {
|
||||
}
|
||||
|
||||
|
||||
@Suppress("UNUSED")
|
||||
enum class S2C(
|
||||
val playFactory: ((buffer: PlayInByteBuffer) -> PlayS2CPacket)? = null,
|
||||
val statusFactory: ((buffer: InByteBuffer) -> StatusS2CPacket)? = null,
|
||||
|
@ -24,7 +24,6 @@ import de.bixilon.minosoft.data.world.palette.Palette.Companion.choosePalette
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*
|
||||
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
|
||||
import java.util.*
|
||||
|
||||
|
||||
@ -59,7 +58,7 @@ object ChunkUtil {
|
||||
|
||||
// parse data
|
||||
var arrayPosition = 0
|
||||
val sectionMap: MutableMap<Int, ChunkSection> = synchronizedMapOf()
|
||||
val sections: Array<ChunkSection?> = arrayOfNulls(dimension.sections)
|
||||
for ((sectionIndex, sectionHeight) in (dimension.lowestSection until dimension.highestSection).withIndex()) {
|
||||
if (!sectionBitMask[sectionIndex]) {
|
||||
continue
|
||||
@ -91,9 +90,9 @@ object ChunkUtil {
|
||||
|
||||
blocks[blockNumber] = buffer.connection.registries.blockStateRegistry[blockId] ?: continue
|
||||
}
|
||||
sectionMap[sectionHeight] = ChunkSection(blocks)
|
||||
sections[sectionHeight - dimension.lowestSection] = ChunkSection(buffer.connection.registries, blocks)
|
||||
}
|
||||
chunkData.blocks = sectionMap
|
||||
chunkData.blocks = sections
|
||||
return chunkData
|
||||
}
|
||||
|
||||
@ -125,7 +124,7 @@ object ChunkUtil {
|
||||
}
|
||||
|
||||
var arrayPos = 0
|
||||
val sectionMap: MutableMap<Int, ChunkSection> = synchronizedMapOf()
|
||||
val sections: Array<ChunkSection?> = arrayOfNulls(dimension.sections)
|
||||
for ((sectionIndex, sectionHeight) in (dimension.lowestSection until dimension.highestSection).withIndex()) { // max sections per chunks in chunk column
|
||||
if (!sectionBitMask[sectionIndex]) {
|
||||
continue
|
||||
@ -136,15 +135,15 @@ object ChunkUtil {
|
||||
val block = buffer.connection.registries.blockStateRegistry[blockId] ?: continue
|
||||
blocks[blockNumber] = block
|
||||
}
|
||||
sectionMap[sectionHeight] = ChunkSection(blocks)
|
||||
sections[sectionHeight] = ChunkSection(buffer.connection.registries, blocks)
|
||||
}
|
||||
chunkData.blocks = sectionMap
|
||||
chunkData.blocks = sections
|
||||
return chunkData
|
||||
}
|
||||
|
||||
fun readPaletteChunk(buffer: PlayInByteBuffer, dimension: DimensionProperties, sectionBitMask: BitSet, isFullChunk: Boolean, containsSkyLight: Boolean = false): ChunkData {
|
||||
val chunkData = ChunkData()
|
||||
val sectionMap: MutableMap<Int, ChunkSection> = synchronizedMapOf()
|
||||
val sections: Array<ChunkSection?> = arrayOfNulls(dimension.sections)
|
||||
|
||||
for ((sectionIndex, sectionHeight) in (dimension.lowestSection until sectionBitMask.length()).withIndex()) { // max sections per chunks in chunk column
|
||||
if (!sectionBitMask[sectionIndex]) {
|
||||
@ -193,10 +192,10 @@ object ChunkUtil {
|
||||
// ToDo
|
||||
chunkData.lightAccessor = DummyLightAccessor
|
||||
}
|
||||
sectionMap[sectionHeight] = ChunkSection(blocks)
|
||||
sections[sectionHeight - dimension.lowestSection] = ChunkSection(buffer.connection.registries, blocks)
|
||||
}
|
||||
|
||||
chunkData.blocks = sectionMap
|
||||
chunkData.blocks = sections
|
||||
if (buffer.versionId < V_19W36A && isFullChunk) {
|
||||
chunkData.biomeSource = readLegacyBiomeArray(buffer)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user