mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-18 11:54:59 -04:00
fix with negative dimensions y > 256, rework chunk reading
This commit is contained in:
parent
44e8b358a2
commit
beaeafbb5b
@ -24,9 +24,11 @@ data class DimensionProperties(
|
||||
val minY: Int = 0,
|
||||
val hasCeiling: Boolean = false,
|
||||
val ultraWarm: Boolean = false,
|
||||
val height: Int = 256,
|
||||
@Deprecated("Height does not differ from logical height in 1.18")
|
||||
val dataHeight: Int = 256,
|
||||
val supports3DBiomes: Boolean = true,
|
||||
) {
|
||||
val height = logicalHeight + minY
|
||||
val lowestSection = if (minY < 0) {
|
||||
(minY + 1) / ProtocolDefinition.SECTION_HEIGHT_Y - 1
|
||||
} else {
|
||||
@ -69,7 +71,7 @@ data class DimensionProperties(
|
||||
minY = data["min_y"]?.toInt() ?: 0,
|
||||
hasCeiling = data["has_ceiling"]?.toBoolean() ?: false,
|
||||
ultraWarm = data["ultrawarm"]?.toBoolean() ?: false,
|
||||
height = data["height"]?.toInt() ?: 256,
|
||||
dataHeight = data["height"]?.toInt() ?: 256,
|
||||
supports3DBiomes = data["supports_3d_biomes"]?.toBoolean() ?: true,
|
||||
)
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ package de.bixilon.minosoft.data.registries.registries.registry
|
||||
import de.bixilon.minosoft.util.collections.Clearable
|
||||
|
||||
interface AbstractRegistry<T> : Iterable<T>, Clearable, Parentable<AbstractRegistry<T>> {
|
||||
|
||||
val size: Int
|
||||
|
||||
operator fun get(any: Any?): T?
|
||||
|
@ -17,8 +17,8 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
|
||||
|
||||
class BlockStateRegistry(var flattened: Boolean) : AbstractRegistry<BlockState> {
|
||||
override var parent: AbstractRegistry<BlockState>? = null
|
||||
class BlockStateRegistry(var flattened: Boolean) : AbstractRegistry<BlockState?> {
|
||||
override var parent: AbstractRegistry<BlockState?>? = null
|
||||
private val idMap: MutableMap<Int, BlockState> = mutableMapOf()
|
||||
|
||||
override val size: Int
|
||||
@ -66,7 +66,7 @@ class BlockStateRegistry(var flattened: Boolean) : AbstractRegistry<BlockState>
|
||||
return forceGet(id)
|
||||
}
|
||||
|
||||
override fun getId(value: BlockState): Int {
|
||||
override fun getId(value: BlockState?): Int {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ class Chunk(
|
||||
data.blocks?.let {
|
||||
for ((index, blocks) in it.withIndex()) {
|
||||
blocks ?: continue
|
||||
val section = getOrPut(index - lowestSection)
|
||||
val section = getOrPut(index + lowestSection)
|
||||
section.blocks = blocks
|
||||
}
|
||||
blocksInitialized = true
|
||||
@ -148,7 +148,7 @@ class Chunk(
|
||||
|
||||
var section = sections[sectionIndex]
|
||||
if (section == null) {
|
||||
section = ChunkSection(connection.registries)
|
||||
section = ChunkSection()
|
||||
val neighbours: Array<Chunk> = world.getChunkNeighbours(chunkPosition).unsafeCast()
|
||||
val cacheBiomeAccessor = world.cacheBiomeAccessor
|
||||
if (cacheBiomeAccessor != null && biomesInitialized && neighboursLoaded) {
|
||||
|
@ -16,11 +16,11 @@ package de.bixilon.minosoft.data.world
|
||||
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.container.RegistrySectionDataProvider
|
||||
import de.bixilon.minosoft.data.world.container.SectionDataProvider
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
class ChunkData(
|
||||
var blocks: Array<RegistrySectionDataProvider<BlockState?>?>? = null,
|
||||
var blocks: Array<SectionDataProvider<BlockState?>?>? = null,
|
||||
var blockEntities: Map<Vec3i, BlockEntity>? = null,
|
||||
var biomeSource: BiomeSource? = null,
|
||||
var light: Array<ByteArray?>? = null,
|
||||
|
@ -15,9 +15,7 @@ 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.registries.registries.Registries
|
||||
import de.bixilon.minosoft.data.world.biome.accessor.NoiseBiomeAccessor
|
||||
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
|
||||
@ -30,14 +28,12 @@ import glm_.vec3.Vec3i
|
||||
* Collection of 16x16x16 blocks
|
||||
*/
|
||||
class ChunkSection(
|
||||
var blocks: RegistrySectionDataProvider<BlockState?>,
|
||||
var biomes: RegistrySectionDataProvider<Biome>,
|
||||
var blockEntities: SectionDataProvider<BlockEntity?>,
|
||||
var light: ByteArray, // packed (skyLight: 0xF0, blockLight: 0x0F)
|
||||
var blocks: SectionDataProvider<BlockState?> = SectionDataProvider(checkSize = true),
|
||||
var biomes: SectionDataProvider<Biome> = SectionDataProvider(checkSize = false),
|
||||
var blockEntities: SectionDataProvider<BlockEntity?> = SectionDataProvider(checkSize = false),
|
||||
var light: ByteArray = ByteArray(ProtocolDefinition.BLOCKS_PER_SECTION), // packed (skyLight: 0xF0, blockLight: 0x0F)
|
||||
) {
|
||||
|
||||
constructor(registries: Registries) : this(RegistrySectionDataProvider<BlockState?>(registries.blockStateRegistry.unsafeCast(), checkSize = true), RegistrySectionDataProvider(registries.biomeRegistry, checkSize = false), SectionDataProvider(checkSize = false), ByteArray(ProtocolDefinition.BLOCKS_PER_SECTION))
|
||||
|
||||
fun tick(connection: PlayConnection, chunkPosition: Vec2i, sectionHeight: Int) {
|
||||
if (blockEntities.isEmpty) {
|
||||
return
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.biome.source
|
||||
|
||||
import de.bixilon.minosoft.data.registries.biomes.Biome
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight
|
||||
|
||||
class PalettedBiomeArray(
|
||||
private val containers: Array<Array<Biome>?>,
|
||||
private val lowestSection: Int,
|
||||
val edgeBits: Int,
|
||||
) : BiomeSource {
|
||||
private val mask = (1 shl edgeBits) - 1
|
||||
|
||||
override fun getBiome(x: Int, y: Int, z: Int): Biome? {
|
||||
return containers.getOrNull(y.sectionHeight - lowestSection)?.get(((((y.sectionHeight and mask) shl edgeBits) or (z and mask)) shl edgeBits) or (x and mask))
|
||||
}
|
||||
}
|
@ -15,14 +15,15 @@ package de.bixilon.minosoft.data.world.container
|
||||
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
import de.bixilon.minosoft.util.ReadWriteLock
|
||||
import glm_.vec3.Vec3i
|
||||
|
||||
open class SectionDataProvider<T>(
|
||||
data: Array<Any?>? = null,
|
||||
class SectionDataProvider<T>(
|
||||
data: Array<T>? = null,
|
||||
val checkSize: Boolean = false,
|
||||
) : Iterable<T> {
|
||||
protected var data = data
|
||||
protected var data: Array<Any?>? = data?.unsafeCast()
|
||||
private set
|
||||
protected val lock = ReadWriteLock() // lock while reading (blocks writing)
|
||||
var count: Int = 0
|
||||
@ -191,9 +192,9 @@ open class SectionDataProvider<T>(
|
||||
unlock()
|
||||
}
|
||||
|
||||
open fun copy(): SectionDataProvider<T> {
|
||||
fun copy(): SectionDataProvider<T> {
|
||||
acquire()
|
||||
val clone = SectionDataProvider<T>(data?.clone())
|
||||
val clone = SectionDataProvider<T>(data?.clone()?.unsafeCast())
|
||||
release()
|
||||
|
||||
return clone
|
||||
|
@ -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.palette
|
||||
|
||||
import de.bixilon.minosoft.data.world.container.palette.data.PaletteData
|
||||
import de.bixilon.minosoft.data.world.container.palette.palettes.Palette
|
||||
|
||||
class PalettedContainer<T>(
|
||||
private val edgeBits: Int,
|
||||
val palette: Palette<T>,
|
||||
val data: PaletteData,
|
||||
) {
|
||||
|
||||
fun get(x: Int, y: Int, z: Int): T {
|
||||
return palette.get(data.get((((y shl edgeBits) or z) shl edgeBits) or x))
|
||||
}
|
||||
|
||||
inline fun <reified V : T> unpack(): Array<V> {
|
||||
val array: Array<V?> = arrayOfNulls(data.size)
|
||||
for (i in array.indices) {
|
||||
array[i] = palette.get(data.get(i)) as V
|
||||
}
|
||||
return array as Array<V>
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.palette
|
||||
|
||||
import de.bixilon.minosoft.data.registries.registries.registry.AbstractRegistry
|
||||
import de.bixilon.minosoft.data.world.container.palette.data.PaletteData
|
||||
import de.bixilon.minosoft.data.world.container.palette.palettes.PaletteFactory
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
|
||||
object PalettedContainerReader {
|
||||
|
||||
fun <T> read(buffer: PlayInByteBuffer, registry: AbstractRegistry<T>, paletteFactory: PaletteFactory): PalettedContainer<T> {
|
||||
val bits = buffer.readUnsignedByte()
|
||||
|
||||
val palette = paletteFactory.createPalette(registry, bits)
|
||||
palette.read(buffer)
|
||||
|
||||
val paletteData = PaletteData.create(buffer.versionId, palette.bits, paletteFactory.containerSize)
|
||||
paletteData.read(buffer)
|
||||
|
||||
return PalettedContainer(paletteFactory.edgeBits, palette, paletteData)
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.palette.data
|
||||
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_1_16
|
||||
|
||||
class ArrayPaletteData(
|
||||
val versionId: Int,
|
||||
val elementBits: Int,
|
||||
override val size: Int,
|
||||
) : PaletteData {
|
||||
init {
|
||||
check(elementBits in 0..32)
|
||||
}
|
||||
|
||||
private lateinit var data: LongArray
|
||||
|
||||
|
||||
override fun read(buffer: PlayInByteBuffer) {
|
||||
data = buffer.readLongArray()
|
||||
}
|
||||
|
||||
override operator fun get(index: Int): Int {
|
||||
val individualValueMask = (1 shl elementBits) - 1
|
||||
|
||||
var blockId: Long = if (versionId < V_1_16) { // ToDo: When did this changed? is just a guess
|
||||
val startLong = index * elementBits / Long.SIZE_BITS
|
||||
val startOffset = index * elementBits % Long.SIZE_BITS
|
||||
val endLong = ((index + 1) * elementBits - 1) / Long.SIZE_BITS
|
||||
|
||||
if (startLong == endLong) {
|
||||
data[startLong] ushr startOffset
|
||||
} else {
|
||||
val endOffset = Long.SIZE_BITS - startOffset
|
||||
data[startLong] ushr startOffset or (data[endLong] shl endOffset)
|
||||
}
|
||||
} else {
|
||||
val startLong = index / (Long.SIZE_BITS / elementBits)
|
||||
val startOffset = index % (Long.SIZE_BITS / elementBits) * elementBits
|
||||
data[startLong] ushr startOffset
|
||||
}
|
||||
|
||||
blockId = blockId and individualValueMask.toLong()
|
||||
|
||||
return blockId.toInt()
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.palette.data
|
||||
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
|
||||
class EmptyPaletteData(override val size: Int) : PaletteData {
|
||||
|
||||
override fun get(index: Int): Int {
|
||||
if (index in 0 until size) {
|
||||
return 0
|
||||
}
|
||||
throw IndexOutOfBoundsException("Index $index > $size")
|
||||
}
|
||||
|
||||
override fun read(buffer: PlayInByteBuffer) {
|
||||
check(buffer.readVarInt() == 0) { "No data expected!" }
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
* 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.
|
||||
*
|
||||
@ -10,25 +10,24 @@
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
package de.bixilon.minosoft.data.world.palette
|
||||
|
||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
package de.bixilon.minosoft.data.world.container.palette.data
|
||||
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
|
||||
interface Palette {
|
||||
interface PaletteData {
|
||||
val size: Int
|
||||
|
||||
fun blockById(id: Int): BlockState?
|
||||
fun get(index: Int): Int
|
||||
|
||||
val bitsPerBlock: Int
|
||||
fun read(buffer: PlayInByteBuffer)
|
||||
|
||||
companion object {
|
||||
fun choosePalette(bitsPerBlock: Int, buffer: PlayInByteBuffer): Palette {
|
||||
if (bitsPerBlock <= 4) {
|
||||
return IndirectPalette(4, buffer)
|
||||
} else if (bitsPerBlock <= 8) {
|
||||
return IndirectPalette(bitsPerBlock, buffer)
|
||||
fun create(versionId: Int, bits: Int, size: Int): PaletteData {
|
||||
return when (bits) {
|
||||
0 -> EmptyPaletteData(size)
|
||||
else -> ArrayPaletteData(versionId, bits, size)
|
||||
}
|
||||
return DirectPalette(buffer)
|
||||
}
|
||||
}
|
||||
}
|
@ -11,34 +11,23 @@
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.world.container
|
||||
package de.bixilon.minosoft.data.world.container.palette.palettes
|
||||
|
||||
import de.bixilon.minosoft.data.registries.registries.registry.AbstractRegistry
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
|
||||
class RegistrySectionDataProvider<T>(
|
||||
val registry: AbstractRegistry<T>,
|
||||
data: Array<Any?>? = null,
|
||||
checkSize: Boolean = false,
|
||||
) : SectionDataProvider<T>(data, checkSize = checkSize) {
|
||||
class ArrayPalette<T>(private val registry: AbstractRegistry<T>, override val bits: Int) : Palette<T> {
|
||||
private var array: Array<Any?> = arrayOfNulls(0)
|
||||
|
||||
override fun read(buffer: PlayInByteBuffer) {
|
||||
array = arrayOfNulls(buffer.readVarInt())
|
||||
for (i in array.indices) {
|
||||
array[i] = registry[buffer.readVarInt()]
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun setIdData(ids: IntArray) {
|
||||
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
|
||||
override fun get(index: Int): T {
|
||||
return array[index] as T
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.palette.palettes
|
||||
|
||||
import de.bixilon.minosoft.data.registries.registries.registry.AbstractRegistry
|
||||
|
||||
object BiomePaletteFactory : PaletteFactory {
|
||||
override val edgeBits = 2
|
||||
|
||||
override fun <T : Any?> createPalette(registry: AbstractRegistry<T>, bits: Int): Palette<T> {
|
||||
return when (bits) {
|
||||
0 -> SingularPalette(registry)
|
||||
1, 2, 3 -> ArrayPalette(registry, bits)
|
||||
else -> RegistryPalette(registry)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.palette.palettes
|
||||
|
||||
import de.bixilon.minosoft.data.registries.registries.registry.AbstractRegistry
|
||||
|
||||
object BlockStatePaletteFactory : PaletteFactory {
|
||||
override val edgeBits = 4
|
||||
|
||||
override fun <T : Any?> createPalette(registry: AbstractRegistry<T>, bits: Int): Palette<T> {
|
||||
return when (bits) {
|
||||
0 -> SingularPalette(registry)
|
||||
1, 2, 3, 4 -> ArrayPalette(registry, 4)
|
||||
5, 6, 7, 8 -> ArrayPalette(registry, bits)
|
||||
else -> RegistryPalette(registry)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.palette.palettes
|
||||
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
|
||||
interface Palette<T> {
|
||||
val bits: Int
|
||||
|
||||
fun read(buffer: PlayInByteBuffer)
|
||||
|
||||
fun get(index: Int): T
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.palette.palettes
|
||||
|
||||
import de.bixilon.minosoft.data.registries.registries.registry.AbstractRegistry
|
||||
|
||||
interface PaletteFactory {
|
||||
val edgeBits: Int
|
||||
val containerSize: Int
|
||||
get() = 1 shl (edgeBits * 3)
|
||||
|
||||
fun <T> createPalette(registry: AbstractRegistry<T>, bits: Int): Palette<T>
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.palette.palettes
|
||||
|
||||
import de.bixilon.minosoft.data.registries.registries.registry.AbstractRegistry
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
import de.bixilon.minosoft.util.MMath
|
||||
|
||||
class RegistryPalette<T>(private val registry: AbstractRegistry<T>) : Palette<T> {
|
||||
override val bits = MMath.ceilLog2(registry.size)
|
||||
|
||||
override fun read(buffer: PlayInByteBuffer) {}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun get(index: Int): T {
|
||||
return registry[index] as T
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.palette.palettes
|
||||
|
||||
import de.bixilon.minosoft.data.registries.registries.registry.AbstractRegistry
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
|
||||
class SingularPalette<T>(private val registry: AbstractRegistry<T>) : Palette<T> {
|
||||
override val bits: Int = 0
|
||||
var item: T? = null
|
||||
private set
|
||||
|
||||
override fun read(buffer: PlayInByteBuffer) {
|
||||
item = registry[buffer.readVarInt()]
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun get(index: Int): T {
|
||||
return item as T
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 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.palette
|
||||
|
||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.ln
|
||||
|
||||
class DirectPalette(buffer: PlayInByteBuffer) : Palette {
|
||||
private var connection: PlayConnection = buffer.connection
|
||||
|
||||
init {
|
||||
if (buffer.versionId < ProtocolVersions.V_17W47A) {
|
||||
buffer.readVarInt()
|
||||
}
|
||||
}
|
||||
|
||||
override fun blockById(id: Int): BlockState? {
|
||||
return connection.registries.blockStateRegistry[id]
|
||||
}
|
||||
|
||||
override val bitsPerBlock: Int
|
||||
get() {
|
||||
if (this.connection.version.versionId < ProtocolVersions.V_18W10D) {
|
||||
return 13
|
||||
}
|
||||
return ceil(ln(connection.registries.blockStateRegistry.size.toDouble()) / ln(2.0)).toInt()
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 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.palette
|
||||
|
||||
import de.bixilon.minosoft.config.StaticConfiguration
|
||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.logging.Log
|
||||
|
||||
class IndirectPalette(
|
||||
override val bitsPerBlock: Int,
|
||||
buffer: PlayInByteBuffer,
|
||||
) : Palette {
|
||||
private val connection = buffer.connection
|
||||
private var palette = buffer.readVarIntArray()
|
||||
|
||||
override fun blockById(id: Int): BlockState? {
|
||||
var blockId = id
|
||||
if (blockId < palette.size) {
|
||||
blockId = palette[blockId]
|
||||
}
|
||||
val block = connection.registries.blockStateRegistry[blockId]
|
||||
|
||||
if (StaticConfiguration.DEBUG_MODE && block == null && blockId != ProtocolDefinition.AIR_BLOCK_ID) {
|
||||
val blockName: String = if (connection.version.isFlattened()) {
|
||||
blockId.toString()
|
||||
} else {
|
||||
"${blockId shr 4}:${blockId and 0x0F} ($blockId)"
|
||||
}
|
||||
Log.warn("Server sent unknown block: $blockName")
|
||||
}
|
||||
return block
|
||||
}
|
||||
}
|
@ -23,9 +23,7 @@ import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY
|
||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_18W44A
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_21W37A
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*
|
||||
import de.bixilon.minosoft.util.KUtil.toInt
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
import de.bixilon.minosoft.util.Util
|
||||
@ -51,62 +49,64 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
init {
|
||||
val dimension = buffer.connection.world.dimension!!
|
||||
chunkPosition = buffer.readChunkPosition()
|
||||
if (buffer.versionId < ProtocolVersions.V_20W45A) {
|
||||
if (buffer.versionId < V_20W45A) {
|
||||
isFullChunk = !buffer.readBoolean()
|
||||
}
|
||||
when {
|
||||
buffer.versionId < ProtocolVersions.V_14W26A -> {
|
||||
val sectionBitMask = BitSet.valueOf(buffer.readByteArray(2))
|
||||
val addBitMask = BitSet.valueOf(buffer.readByteArray(2))
|
||||
if (buffer.versionId < V_14W26A) { // ToDo
|
||||
val sectionBitMask = BitSet.valueOf(buffer.readByteArray(2))
|
||||
val addBitMask = BitSet.valueOf(buffer.readByteArray(2))
|
||||
|
||||
// decompress chunk data
|
||||
val decompressed: PlayInByteBuffer = if (buffer.versionId < ProtocolVersions.V_14W28A) {
|
||||
Util.decompress(buffer.readByteArray(buffer.readInt()), buffer.connection)
|
||||
} else {
|
||||
buffer
|
||||
}
|
||||
val chunkData = ChunkUtil.readChunkPacket(decompressed, dimension, sectionBitMask, addBitMask, !isFullChunk, dimension.hasSkyLight)
|
||||
if (chunkData == null) {
|
||||
unloadChunk = true
|
||||
} else {
|
||||
this.chunkData.replace(chunkData)
|
||||
}
|
||||
// decompress chunk data
|
||||
val decompressed: PlayInByteBuffer = if (buffer.versionId < V_14W28A) {
|
||||
Util.decompress(buffer.readByteArray(buffer.readInt()), buffer.connection)
|
||||
} else {
|
||||
buffer
|
||||
}
|
||||
buffer.versionId < V_21W37A -> {
|
||||
if (buffer.versionId >= ProtocolVersions.V_1_16_PRE7 && buffer.versionId < ProtocolVersions.V_1_16_2_PRE2) {
|
||||
buffer.readBoolean() // ToDo: ignore old data???
|
||||
}
|
||||
val sectionBitMask: BitSet = when {
|
||||
buffer.versionId < ProtocolVersions.V_15W34C -> {
|
||||
BitSet.valueOf(buffer.readByteArray(2))
|
||||
}
|
||||
buffer.versionId < ProtocolVersions.V_15W36D -> {
|
||||
BitSet.valueOf(buffer.readByteArray(4))
|
||||
}
|
||||
buffer.versionId < ProtocolVersions.V_21W03A -> {
|
||||
BitSet.valueOf(longArrayOf(buffer.readVarInt().toLong()))
|
||||
}
|
||||
else -> {
|
||||
BitSet.valueOf(buffer.readLongArray())
|
||||
}
|
||||
}
|
||||
if (buffer.versionId >= V_18W44A) {
|
||||
heightMap = buffer.readNBT()?.compoundCast()
|
||||
}
|
||||
if (!isFullChunk) {
|
||||
this.chunkData.biomeSource = SpatialBiomeArray(buffer.readBiomeArray())
|
||||
}
|
||||
val size = buffer.readVarInt()
|
||||
val lastBufferPosition = buffer.pointer
|
||||
val chunkData = ChunkUtil.readChunkPacket(buffer, dimension, sectionBitMask, null, !isFullChunk, dimension.hasSkyLight)
|
||||
val chunkData = ChunkUtil.readChunkPacket(decompressed, dimension, sectionBitMask, addBitMask, !isFullChunk, dimension.hasSkyLight)
|
||||
if (chunkData == null) {
|
||||
unloadChunk = true
|
||||
} else {
|
||||
this.chunkData.replace(chunkData)
|
||||
}
|
||||
} else {
|
||||
if (buffer.versionId in V_1_16_PRE7 until V_1_16_2_PRE2) {
|
||||
buffer.readBoolean() // ToDo: ignore old data???
|
||||
}
|
||||
val sectionBitMask = when {
|
||||
buffer.versionId < V_15W34C -> BitSet.valueOf(buffer.readByteArray(2))
|
||||
buffer.versionId < V_15W36D -> BitSet.valueOf(buffer.readByteArray(4))
|
||||
buffer.versionId < V_21W03A -> BitSet.valueOf(longArrayOf(buffer.readVarInt().toLong()))
|
||||
buffer.versionId < V_21W37A -> BitSet.valueOf(buffer.readLongArray())
|
||||
else -> null
|
||||
}
|
||||
if (buffer.versionId >= V_18W44A) {
|
||||
heightMap = buffer.readNBT()?.compoundCast()
|
||||
}
|
||||
if (!isFullChunk && buffer.versionId < V_21W37A) {
|
||||
this.chunkData.biomeSource = SpatialBiomeArray(buffer.readBiomeArray())
|
||||
}
|
||||
val size = buffer.readVarInt()
|
||||
val lastBufferPosition = buffer.pointer
|
||||
|
||||
if (buffer.versionId < V_21W37A) {
|
||||
val chunkData = ChunkUtil.readChunkPacket(buffer, dimension, sectionBitMask!!, null, !isFullChunk, dimension.hasSkyLight)
|
||||
if (chunkData == null) {
|
||||
unloadChunk = true
|
||||
} else {
|
||||
this.chunkData.replace(chunkData)
|
||||
}
|
||||
// set position of the byte buffer, because of some reasons HyPixel makes some weird stuff and sends way to much 0 bytes. (~ 190k), thanks @pokechu22
|
||||
buffer.pointer = size + lastBufferPosition
|
||||
if (buffer.versionId >= ProtocolVersions.V_1_9_4) {
|
||||
} else {
|
||||
this.chunkData.replace(ChunkUtil.readPaletteChunk(buffer, dimension, null, isFullChunk = true, containsSkyLight = false))
|
||||
}
|
||||
|
||||
// set position to expected read positions; the server sometimes sends a bunch of useless zeros (~ 190k), thanks @pokechu22
|
||||
buffer.pointer = size + lastBufferPosition
|
||||
|
||||
// block entities
|
||||
when {
|
||||
buffer.versionId < V_1_9_4 -> {
|
||||
}
|
||||
buffer.versionId < V_21W37A -> {
|
||||
val blockEntities: MutableMap<Vec3i, BlockEntity> = mutableMapOf()
|
||||
val positionOffset = Vec3i.of(chunkPosition, dimension.lowestSection, Vec3i.EMPTY)
|
||||
for (i in 0 until buffer.readVarInt()) {
|
||||
@ -123,31 +123,24 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||
}
|
||||
this.chunkData.blockEntities = blockEntities
|
||||
}
|
||||
else -> {
|
||||
val blockEntities: MutableMap<Vec3i, BlockEntity> = mutableMapOf()
|
||||
|
||||
for (i in 0 until buffer.readVarInt()) {
|
||||
val xz = buffer.readUnsignedByte()
|
||||
val y = buffer.readShort()
|
||||
val type = buffer.connection.registries.blockEntityTypeRegistry[buffer.readVarInt()]
|
||||
val nbt = buffer.readNBT().asCompound()
|
||||
val entity = type.build(buffer.connection)
|
||||
entity.updateNBT(nbt)
|
||||
blockEntities[Vec3i(xz shr 4, y, xz and 0x0F)] = entity
|
||||
}
|
||||
this.chunkData.blockEntities = blockEntities
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
heightMap = buffer.readNBT()?.compoundCast()
|
||||
val sectionBuffer = PlayInByteBuffer(buffer.readByteArray(), buffer.connection)
|
||||
|
||||
for (sectionHeight in dimension.lowestSection until dimension.highestSection) {
|
||||
val nonAirBlocks = sectionBuffer.readShort()
|
||||
// ToDo: BlockStates, Biomes
|
||||
}
|
||||
|
||||
val blockEntities: MutableMap<Vec3i, BlockEntity> = mutableMapOf()
|
||||
|
||||
for (i in 0 until buffer.readVarInt()) {
|
||||
val xz = buffer.readUnsignedByte()
|
||||
val y = buffer.readShort()
|
||||
val type = buffer.connection.registries.blockEntityTypeRegistry[buffer.readVarInt()]
|
||||
val nbt = buffer.readNBT().asCompound()
|
||||
val entity = type.build(buffer.connection)
|
||||
entity.updateNBT(nbt)
|
||||
blockEntities[Vec3i(xz shr 4, y, xz and 0x0F)] = entity
|
||||
}
|
||||
chunkData.blockEntities = blockEntities
|
||||
|
||||
val lightPacket = ChunkLightDataS2CP(buffer) { chunkPosition }
|
||||
chunkData.replace(lightPacket.chunkData)
|
||||
if (buffer.versionId >= V_21W37A) {
|
||||
this.chunkData.replace(ChunkLightDataS2CP(buffer) { chunkPosition }.chunkData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,6 +163,12 @@ open class InByteBuffer {
|
||||
return array
|
||||
}
|
||||
|
||||
fun readLongArray(target: LongArray, size: Int = readVarInt()) {
|
||||
for (i in 0 until size) {
|
||||
target[i] = readLong()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun readVarLong(): Long {
|
||||
var byteCount = 0
|
||||
|
@ -15,9 +15,12 @@ package de.bixilon.minosoft.util
|
||||
|
||||
import de.bixilon.minosoft.util.KUtil.decide
|
||||
import glm_.vec2.Vec2i
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.floor
|
||||
import kotlin.math.ln
|
||||
|
||||
object MMath {
|
||||
private const val LN_2 = 0.69314718056 // ln(2.0)
|
||||
|
||||
fun clamp(value: Vec2i, min: Vec2i, max: Vec2i): Vec2i {
|
||||
value.x = clamp(value.x, min.x, max.x)
|
||||
@ -118,4 +121,8 @@ object MMath {
|
||||
val int = this.toInt()
|
||||
return (this > int).decide(int + 1, int)
|
||||
}
|
||||
|
||||
fun ceilLog2(value: Int): Int {
|
||||
return ceil(ln(value.toDouble()) / LN_2).toInt()
|
||||
}
|
||||
}
|
||||
|
@ -20,14 +20,18 @@ import de.bixilon.minosoft.data.registries.dimension.DimensionProperties
|
||||
import de.bixilon.minosoft.data.world.Chunk
|
||||
import de.bixilon.minosoft.data.world.ChunkData
|
||||
import de.bixilon.minosoft.data.world.ChunkSection
|
||||
import de.bixilon.minosoft.data.world.biome.source.PalettedBiomeArray
|
||||
import de.bixilon.minosoft.data.world.biome.source.XZBiomeArray
|
||||
import de.bixilon.minosoft.data.world.container.RegistrySectionDataProvider
|
||||
import de.bixilon.minosoft.data.world.palette.Palette.Companion.choosePalette
|
||||
import de.bixilon.minosoft.data.world.container.SectionDataProvider
|
||||
import de.bixilon.minosoft.data.world.container.palette.PalettedContainer
|
||||
import de.bixilon.minosoft.data.world.container.palette.PalettedContainerReader
|
||||
import de.bixilon.minosoft.data.world.container.palette.palettes.BiomePaletteFactory
|
||||
import de.bixilon.minosoft.data.world.container.palette.palettes.BlockStatePaletteFactory
|
||||
import de.bixilon.minosoft.data.world.container.palette.palettes.SingularPalette
|
||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.abs
|
||||
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.unsafeCast
|
||||
import glm_.vec2.Vec2i
|
||||
import java.util.*
|
||||
|
||||
@ -63,13 +67,13 @@ object ChunkUtil {
|
||||
|
||||
// parse data
|
||||
var arrayPosition = 0
|
||||
val sectionBlocks: Array<RegistrySectionDataProvider<BlockState?>?> = arrayOfNulls(dimension.sections)
|
||||
val sectionBlocks: Array<SectionDataProvider<BlockState?>?> = arrayOfNulls(dimension.sections)
|
||||
for ((sectionIndex, sectionHeight) in (dimension.lowestSection until dimension.highestSection).withIndex()) {
|
||||
if (!sectionBitMask[sectionIndex]) {
|
||||
continue
|
||||
}
|
||||
|
||||
val blocks = arrayOfNulls<BlockState>(ProtocolDefinition.BLOCKS_PER_SECTION)
|
||||
val blocks: Array<BlockState?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION)
|
||||
|
||||
for (blockNumber in 0 until ProtocolDefinition.BLOCKS_PER_SECTION) {
|
||||
var blockId = (blockData[arrayPosition].toInt() and 0xFF) shl 4
|
||||
@ -95,7 +99,7 @@ object ChunkUtil {
|
||||
|
||||
blocks[blockNumber] = buffer.connection.registries.blockStateRegistry[blockId] ?: continue
|
||||
}
|
||||
sectionBlocks[sectionHeight] = RegistrySectionDataProvider(buffer.connection.registries.blockStateRegistry.unsafeCast(), blocks.unsafeCast(), true)
|
||||
sectionBlocks[sectionHeight] = SectionDataProvider(blocks, true)
|
||||
}
|
||||
chunkData.blocks = sectionBlocks
|
||||
return chunkData
|
||||
@ -129,7 +133,7 @@ object ChunkUtil {
|
||||
}
|
||||
|
||||
var arrayPos = 0
|
||||
val sectionBlocks: Array<RegistrySectionDataProvider<BlockState?>?> = arrayOfNulls(dimension.sections)
|
||||
val sectionBlocks: Array<SectionDataProvider<BlockState?>?> = arrayOfNulls(dimension.sections)
|
||||
for ((sectionIndex, sectionHeight) in (dimension.lowestSection until dimension.highestSection).withIndex()) { // max sections per chunks in chunk column
|
||||
if (!sectionBitMask[sectionIndex]) {
|
||||
continue
|
||||
@ -140,56 +144,38 @@ object ChunkUtil {
|
||||
val block = buffer.connection.registries.blockStateRegistry[blockId] ?: continue
|
||||
blocks[blockNumber] = block
|
||||
}
|
||||
sectionBlocks[sectionHeight] = RegistrySectionDataProvider(buffer.connection.registries.blockStateRegistry.unsafeCast(), blocks.unsafeCast(), true)
|
||||
sectionBlocks[sectionHeight] = SectionDataProvider(blocks, true)
|
||||
}
|
||||
chunkData.blocks = sectionBlocks
|
||||
return chunkData
|
||||
}
|
||||
|
||||
fun readPaletteChunk(buffer: PlayInByteBuffer, dimension: DimensionProperties, sectionBitMask: BitSet, isFullChunk: Boolean, containsSkyLight: Boolean = false): ChunkData {
|
||||
fun readPaletteChunk(buffer: PlayInByteBuffer, dimension: DimensionProperties, sectionBitMask: BitSet?, isFullChunk: Boolean, containsSkyLight: Boolean = false): ChunkData {
|
||||
val chunkData = ChunkData()
|
||||
val sectionBlocks: Array<RegistrySectionDataProvider<BlockState?>?> = arrayOfNulls(dimension.sections)
|
||||
val sectionBlocks: Array<SectionDataProvider<BlockState?>?> = arrayOfNulls(dimension.sections)
|
||||
val light: Array<ByteArray?> = arrayOfNulls(dimension.sections)
|
||||
var lightReceived = 0
|
||||
val biomes: Array<Array<Biome>?> = arrayOfNulls(dimension.sections)
|
||||
|
||||
for ((sectionIndex, sectionHeight) in (dimension.lowestSection until sectionBitMask.length()).withIndex()) { // max sections per chunks in chunk column
|
||||
if (!sectionBitMask[sectionIndex]) {
|
||||
for ((sectionIndex, sectionHeight) in (dimension.lowestSection until (sectionBitMask?.length() ?: dimension.highestSection)).withIndex()) { // max sections per chunks in chunk column
|
||||
if (sectionBitMask?.get(sectionIndex) == false) {
|
||||
continue
|
||||
}
|
||||
if (buffer.versionId >= V_18W43A) {
|
||||
buffer.readShort() // block count
|
||||
buffer.readShort() // non-air block count
|
||||
}
|
||||
|
||||
val palette = choosePalette(buffer.readUnsignedByte(), buffer)
|
||||
|
||||
val individualValueMask = (1 shl palette.bitsPerBlock) - 1
|
||||
val blockContainer: PalettedContainer<BlockState?> = PalettedContainerReader.read(buffer, buffer.connection.registries.blockStateRegistry, paletteFactory = BlockStatePaletteFactory)
|
||||
|
||||
val data = buffer.readLongArray()
|
||||
|
||||
val blocks = arrayOfNulls<BlockState>(ProtocolDefinition.BLOCKS_PER_SECTION)
|
||||
for (blockNumber in 0 until ProtocolDefinition.BLOCKS_PER_SECTION) {
|
||||
var blockId: Long = if (buffer.versionId < V_1_16) { // ToDo: When did this changed? is just a guess
|
||||
val startLong = blockNumber * palette.bitsPerBlock / Long.SIZE_BITS
|
||||
val startOffset = blockNumber * palette.bitsPerBlock % Long.SIZE_BITS
|
||||
val endLong = ((blockNumber + 1) * palette.bitsPerBlock - 1) / Long.SIZE_BITS
|
||||
|
||||
if (startLong == endLong) {
|
||||
data[startLong] ushr startOffset
|
||||
} else {
|
||||
val endOffset = Long.SIZE_BITS - startOffset
|
||||
data[startLong] ushr startOffset or (data[endLong] shl endOffset)
|
||||
}
|
||||
} else {
|
||||
val startLong = blockNumber / (Long.SIZE_BITS / palette.bitsPerBlock)
|
||||
val startOffset = blockNumber % (Long.SIZE_BITS / palette.bitsPerBlock) * palette.bitsPerBlock
|
||||
data[startLong] ushr startOffset
|
||||
}
|
||||
|
||||
blockId = blockId and individualValueMask.toLong()
|
||||
|
||||
val block = palette.blockById(blockId.toInt()) ?: continue
|
||||
blocks[blockNumber] = block
|
||||
if (blockContainer.palette !is SingularPalette<*> || blockContainer.palette.item != null) {
|
||||
sectionBlocks[sectionHeight - dimension.lowestSection] = SectionDataProvider(blockContainer.unpack(), checkSize = true)
|
||||
}
|
||||
if (buffer.versionId >= V_21W37A) {
|
||||
val biomeContainer: PalettedContainer<Biome> = PalettedContainerReader.read(buffer, buffer.connection.registries.biomeRegistry, paletteFactory = BiomePaletteFactory)
|
||||
biomes[sectionHeight - dimension.lowestSection] = biomeContainer.unpack()
|
||||
}
|
||||
|
||||
|
||||
if (buffer.versionId < V_18W43A) {
|
||||
val blockLight = buffer.readByteArray(ProtocolDefinition.BLOCKS_PER_SECTION / 2)
|
||||
@ -200,14 +186,15 @@ object ChunkUtil {
|
||||
light[sectionHeight - dimension.lowestSection] = LightUtil.mergeLight(blockLight, skyLight ?: LightUtil.EMPTY_LIGHT_ARRAY)
|
||||
lightReceived++
|
||||
}
|
||||
sectionBlocks[sectionHeight - dimension.lowestSection] = RegistrySectionDataProvider(buffer.connection.registries.blockStateRegistry.unsafeCast(), blocks.unsafeCast(), true)
|
||||
}
|
||||
|
||||
chunkData.blocks = sectionBlocks
|
||||
if (lightReceived > 0) {
|
||||
chunkData.light = light
|
||||
}
|
||||
if (buffer.versionId < V_19W36A && isFullChunk) {
|
||||
if (buffer.versionId >= V_21W37A) {
|
||||
chunkData.biomeSource = PalettedBiomeArray(biomes, dimension.lowestSection, BiomePaletteFactory.edgeBits)
|
||||
} else if (buffer.versionId < V_19W36A && isFullChunk) {
|
||||
chunkData.biomeSource = readLegacyBiomeArray(buffer)
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user