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 minY: Int = 0,
|
||||||
val hasCeiling: Boolean = false,
|
val hasCeiling: Boolean = false,
|
||||||
val ultraWarm: 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 supports3DBiomes: Boolean = true,
|
||||||
) {
|
) {
|
||||||
|
val height = logicalHeight + minY
|
||||||
val lowestSection = if (minY < 0) {
|
val lowestSection = if (minY < 0) {
|
||||||
(minY + 1) / ProtocolDefinition.SECTION_HEIGHT_Y - 1
|
(minY + 1) / ProtocolDefinition.SECTION_HEIGHT_Y - 1
|
||||||
} else {
|
} else {
|
||||||
@ -69,7 +71,7 @@ data class DimensionProperties(
|
|||||||
minY = data["min_y"]?.toInt() ?: 0,
|
minY = data["min_y"]?.toInt() ?: 0,
|
||||||
hasCeiling = data["has_ceiling"]?.toBoolean() ?: false,
|
hasCeiling = data["has_ceiling"]?.toBoolean() ?: false,
|
||||||
ultraWarm = data["ultrawarm"]?.toBoolean() ?: false,
|
ultraWarm = data["ultrawarm"]?.toBoolean() ?: false,
|
||||||
height = data["height"]?.toInt() ?: 256,
|
dataHeight = data["height"]?.toInt() ?: 256,
|
||||||
supports3DBiomes = data["supports_3d_biomes"]?.toBoolean() ?: true,
|
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
|
import de.bixilon.minosoft.util.collections.Clearable
|
||||||
|
|
||||||
interface AbstractRegistry<T> : Iterable<T>, Clearable, Parentable<AbstractRegistry<T>> {
|
interface AbstractRegistry<T> : Iterable<T>, Clearable, Parentable<AbstractRegistry<T>> {
|
||||||
|
|
||||||
val size: Int
|
val size: Int
|
||||||
|
|
||||||
operator fun get(any: Any?): T?
|
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.protocol.protocol.ProtocolDefinition
|
||||||
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
|
import de.bixilon.minosoft.util.KUtil.toSynchronizedMap
|
||||||
|
|
||||||
class BlockStateRegistry(var flattened: Boolean) : AbstractRegistry<BlockState> {
|
class BlockStateRegistry(var flattened: Boolean) : AbstractRegistry<BlockState?> {
|
||||||
override var parent: AbstractRegistry<BlockState>? = null
|
override var parent: AbstractRegistry<BlockState?>? = null
|
||||||
private val idMap: MutableMap<Int, BlockState> = mutableMapOf()
|
private val idMap: MutableMap<Int, BlockState> = mutableMapOf()
|
||||||
|
|
||||||
override val size: Int
|
override val size: Int
|
||||||
@ -66,7 +66,7 @@ class BlockStateRegistry(var flattened: Boolean) : AbstractRegistry<BlockState>
|
|||||||
return forceGet(id)
|
return forceGet(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getId(value: BlockState): Int {
|
override fun getId(value: BlockState?): Int {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ class Chunk(
|
|||||||
data.blocks?.let {
|
data.blocks?.let {
|
||||||
for ((index, blocks) in it.withIndex()) {
|
for ((index, blocks) in it.withIndex()) {
|
||||||
blocks ?: continue
|
blocks ?: continue
|
||||||
val section = getOrPut(index - lowestSection)
|
val section = getOrPut(index + lowestSection)
|
||||||
section.blocks = blocks
|
section.blocks = blocks
|
||||||
}
|
}
|
||||||
blocksInitialized = true
|
blocksInitialized = true
|
||||||
@ -148,7 +148,7 @@ class Chunk(
|
|||||||
|
|
||||||
var section = sections[sectionIndex]
|
var section = sections[sectionIndex]
|
||||||
if (section == null) {
|
if (section == null) {
|
||||||
section = ChunkSection(connection.registries)
|
section = ChunkSection()
|
||||||
val neighbours: Array<Chunk> = world.getChunkNeighbours(chunkPosition).unsafeCast()
|
val neighbours: Array<Chunk> = world.getChunkNeighbours(chunkPosition).unsafeCast()
|
||||||
val cacheBiomeAccessor = world.cacheBiomeAccessor
|
val cacheBiomeAccessor = world.cacheBiomeAccessor
|
||||||
if (cacheBiomeAccessor != null && biomesInitialized && neighboursLoaded) {
|
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.entities.block.BlockEntity
|
||||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||||
import de.bixilon.minosoft.data.world.biome.source.BiomeSource
|
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
|
import glm_.vec3.Vec3i
|
||||||
|
|
||||||
class ChunkData(
|
class ChunkData(
|
||||||
var blocks: Array<RegistrySectionDataProvider<BlockState?>?>? = null,
|
var blocks: Array<SectionDataProvider<BlockState?>?>? = null,
|
||||||
var blockEntities: Map<Vec3i, BlockEntity>? = null,
|
var blockEntities: Map<Vec3i, BlockEntity>? = null,
|
||||||
var biomeSource: BiomeSource? = null,
|
var biomeSource: BiomeSource? = null,
|
||||||
var light: Array<ByteArray?>? = 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.entities.block.BlockEntity
|
||||||
import de.bixilon.minosoft.data.registries.biomes.Biome
|
import de.bixilon.minosoft.data.registries.biomes.Biome
|
||||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
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.biome.accessor.NoiseBiomeAccessor
|
||||||
import de.bixilon.minosoft.data.world.container.RegistrySectionDataProvider
|
|
||||||
import de.bixilon.minosoft.data.world.container.SectionDataProvider
|
import de.bixilon.minosoft.data.world.container.SectionDataProvider
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.of
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
@ -30,14 +28,12 @@ import glm_.vec3.Vec3i
|
|||||||
* Collection of 16x16x16 blocks
|
* Collection of 16x16x16 blocks
|
||||||
*/
|
*/
|
||||||
class ChunkSection(
|
class ChunkSection(
|
||||||
var blocks: RegistrySectionDataProvider<BlockState?>,
|
var blocks: SectionDataProvider<BlockState?> = SectionDataProvider(checkSize = true),
|
||||||
var biomes: RegistrySectionDataProvider<Biome>,
|
var biomes: SectionDataProvider<Biome> = SectionDataProvider(checkSize = false),
|
||||||
var blockEntities: SectionDataProvider<BlockEntity?>,
|
var blockEntities: SectionDataProvider<BlockEntity?> = SectionDataProvider(checkSize = false),
|
||||||
var light: ByteArray, // packed (skyLight: 0xF0, blockLight: 0x0F)
|
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) {
|
fun tick(connection: PlayConnection, chunkPosition: Vec2i, sectionHeight: Int) {
|
||||||
if (blockEntities.isEmpty) {
|
if (blockEntities.isEmpty) {
|
||||||
return
|
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.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
|
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||||
import de.bixilon.minosoft.util.ReadWriteLock
|
import de.bixilon.minosoft.util.ReadWriteLock
|
||||||
import glm_.vec3.Vec3i
|
import glm_.vec3.Vec3i
|
||||||
|
|
||||||
open class SectionDataProvider<T>(
|
class SectionDataProvider<T>(
|
||||||
data: Array<Any?>? = null,
|
data: Array<T>? = null,
|
||||||
val checkSize: Boolean = false,
|
val checkSize: Boolean = false,
|
||||||
) : Iterable<T> {
|
) : Iterable<T> {
|
||||||
protected var data = data
|
protected var data: Array<Any?>? = data?.unsafeCast()
|
||||||
private set
|
private set
|
||||||
protected val lock = ReadWriteLock() // lock while reading (blocks writing)
|
protected val lock = ReadWriteLock() // lock while reading (blocks writing)
|
||||||
var count: Int = 0
|
var count: Int = 0
|
||||||
@ -191,9 +192,9 @@ open class SectionDataProvider<T>(
|
|||||||
unlock()
|
unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun copy(): SectionDataProvider<T> {
|
fun copy(): SectionDataProvider<T> {
|
||||||
acquire()
|
acquire()
|
||||||
val clone = SectionDataProvider<T>(data?.clone())
|
val clone = SectionDataProvider<T>(data?.clone()?.unsafeCast())
|
||||||
release()
|
release()
|
||||||
|
|
||||||
return clone
|
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
|
* 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.
|
* 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.
|
* 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
|
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 {
|
companion object {
|
||||||
fun choosePalette(bitsPerBlock: Int, buffer: PlayInByteBuffer): Palette {
|
fun create(versionId: Int, bits: Int, size: Int): PaletteData {
|
||||||
if (bitsPerBlock <= 4) {
|
return when (bits) {
|
||||||
return IndirectPalette(4, buffer)
|
0 -> EmptyPaletteData(size)
|
||||||
} else if (bitsPerBlock <= 8) {
|
else -> ArrayPaletteData(versionId, bits, size)
|
||||||
return IndirectPalette(bitsPerBlock, buffer)
|
|
||||||
}
|
}
|
||||||
return DirectPalette(buffer)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,34 +11,23 @@
|
|||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
* 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.data.registries.registries.registry.AbstractRegistry
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||||
|
|
||||||
class RegistrySectionDataProvider<T>(
|
class ArrayPalette<T>(private val registry: AbstractRegistry<T>, override val bits: Int) : Palette<T> {
|
||||||
val registry: AbstractRegistry<T>,
|
private var array: Array<Any?> = arrayOfNulls(0)
|
||||||
data: Array<Any?>? = null,
|
|
||||||
checkSize: Boolean = false,
|
override fun read(buffer: PlayInByteBuffer) {
|
||||||
) : SectionDataProvider<T>(data, checkSize = checkSize) {
|
array = arrayOfNulls(buffer.readVarInt())
|
||||||
|
for (i in array.indices) {
|
||||||
|
array[i] = registry[buffer.readVarInt()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun setIdData(ids: IntArray) {
|
override fun get(index: Int): T {
|
||||||
val data: Array<Any?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION)
|
return array[index] as T
|
||||||
|
|
||||||
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,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.network.connection.play.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
||||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
|
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.util.KUtil.toInt
|
import de.bixilon.minosoft.util.KUtil.toInt
|
||||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||||
import de.bixilon.minosoft.util.Util
|
import de.bixilon.minosoft.util.Util
|
||||||
@ -51,62 +49,64 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
|||||||
init {
|
init {
|
||||||
val dimension = buffer.connection.world.dimension!!
|
val dimension = buffer.connection.world.dimension!!
|
||||||
chunkPosition = buffer.readChunkPosition()
|
chunkPosition = buffer.readChunkPosition()
|
||||||
if (buffer.versionId < ProtocolVersions.V_20W45A) {
|
if (buffer.versionId < V_20W45A) {
|
||||||
isFullChunk = !buffer.readBoolean()
|
isFullChunk = !buffer.readBoolean()
|
||||||
}
|
}
|
||||||
when {
|
if (buffer.versionId < V_14W26A) { // ToDo
|
||||||
buffer.versionId < ProtocolVersions.V_14W26A -> {
|
val sectionBitMask = BitSet.valueOf(buffer.readByteArray(2))
|
||||||
val sectionBitMask = BitSet.valueOf(buffer.readByteArray(2))
|
val addBitMask = BitSet.valueOf(buffer.readByteArray(2))
|
||||||
val addBitMask = BitSet.valueOf(buffer.readByteArray(2))
|
|
||||||
|
|
||||||
// decompress chunk data
|
// decompress chunk data
|
||||||
val decompressed: PlayInByteBuffer = if (buffer.versionId < ProtocolVersions.V_14W28A) {
|
val decompressed: PlayInByteBuffer = if (buffer.versionId < V_14W28A) {
|
||||||
Util.decompress(buffer.readByteArray(buffer.readInt()), buffer.connection)
|
Util.decompress(buffer.readByteArray(buffer.readInt()), buffer.connection)
|
||||||
} else {
|
} else {
|
||||||
buffer
|
buffer
|
||||||
}
|
|
||||||
val chunkData = ChunkUtil.readChunkPacket(decompressed, dimension, sectionBitMask, addBitMask, !isFullChunk, dimension.hasSkyLight)
|
|
||||||
if (chunkData == null) {
|
|
||||||
unloadChunk = true
|
|
||||||
} else {
|
|
||||||
this.chunkData.replace(chunkData)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
buffer.versionId < V_21W37A -> {
|
val chunkData = ChunkUtil.readChunkPacket(decompressed, dimension, sectionBitMask, addBitMask, !isFullChunk, dimension.hasSkyLight)
|
||||||
if (buffer.versionId >= ProtocolVersions.V_1_16_PRE7 && buffer.versionId < ProtocolVersions.V_1_16_2_PRE2) {
|
if (chunkData == null) {
|
||||||
buffer.readBoolean() // ToDo: ignore old data???
|
unloadChunk = true
|
||||||
}
|
} else {
|
||||||
val sectionBitMask: BitSet = when {
|
this.chunkData.replace(chunkData)
|
||||||
buffer.versionId < ProtocolVersions.V_15W34C -> {
|
}
|
||||||
BitSet.valueOf(buffer.readByteArray(2))
|
} else {
|
||||||
}
|
if (buffer.versionId in V_1_16_PRE7 until V_1_16_2_PRE2) {
|
||||||
buffer.versionId < ProtocolVersions.V_15W36D -> {
|
buffer.readBoolean() // ToDo: ignore old data???
|
||||||
BitSet.valueOf(buffer.readByteArray(4))
|
}
|
||||||
}
|
val sectionBitMask = when {
|
||||||
buffer.versionId < ProtocolVersions.V_21W03A -> {
|
buffer.versionId < V_15W34C -> BitSet.valueOf(buffer.readByteArray(2))
|
||||||
BitSet.valueOf(longArrayOf(buffer.readVarInt().toLong()))
|
buffer.versionId < V_15W36D -> BitSet.valueOf(buffer.readByteArray(4))
|
||||||
}
|
buffer.versionId < V_21W03A -> BitSet.valueOf(longArrayOf(buffer.readVarInt().toLong()))
|
||||||
else -> {
|
buffer.versionId < V_21W37A -> BitSet.valueOf(buffer.readLongArray())
|
||||||
BitSet.valueOf(buffer.readLongArray())
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
if (buffer.versionId >= V_18W44A) {
|
||||||
if (buffer.versionId >= V_18W44A) {
|
heightMap = buffer.readNBT()?.compoundCast()
|
||||||
heightMap = buffer.readNBT()?.compoundCast()
|
}
|
||||||
}
|
if (!isFullChunk && buffer.versionId < V_21W37A) {
|
||||||
if (!isFullChunk) {
|
this.chunkData.biomeSource = SpatialBiomeArray(buffer.readBiomeArray())
|
||||||
this.chunkData.biomeSource = SpatialBiomeArray(buffer.readBiomeArray())
|
}
|
||||||
}
|
val size = buffer.readVarInt()
|
||||||
val size = buffer.readVarInt()
|
val lastBufferPosition = buffer.pointer
|
||||||
val lastBufferPosition = buffer.pointer
|
|
||||||
val chunkData = ChunkUtil.readChunkPacket(buffer, dimension, sectionBitMask, null, !isFullChunk, dimension.hasSkyLight)
|
if (buffer.versionId < V_21W37A) {
|
||||||
|
val chunkData = ChunkUtil.readChunkPacket(buffer, dimension, sectionBitMask!!, null, !isFullChunk, dimension.hasSkyLight)
|
||||||
if (chunkData == null) {
|
if (chunkData == null) {
|
||||||
unloadChunk = true
|
unloadChunk = true
|
||||||
} else {
|
} else {
|
||||||
this.chunkData.replace(chunkData)
|
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
|
} else {
|
||||||
buffer.pointer = size + lastBufferPosition
|
this.chunkData.replace(ChunkUtil.readPaletteChunk(buffer, dimension, null, isFullChunk = true, containsSkyLight = false))
|
||||||
if (buffer.versionId >= ProtocolVersions.V_1_9_4) {
|
}
|
||||||
|
|
||||||
|
// 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 blockEntities: MutableMap<Vec3i, BlockEntity> = mutableMapOf()
|
||||||
val positionOffset = Vec3i.of(chunkPosition, dimension.lowestSection, Vec3i.EMPTY)
|
val positionOffset = Vec3i.of(chunkPosition, dimension.lowestSection, Vec3i.EMPTY)
|
||||||
for (i in 0 until buffer.readVarInt()) {
|
for (i in 0 until buffer.readVarInt()) {
|
||||||
@ -123,31 +123,24 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
|||||||
}
|
}
|
||||||
this.chunkData.blockEntities = blockEntities
|
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) {
|
if (buffer.versionId >= V_21W37A) {
|
||||||
val nonAirBlocks = sectionBuffer.readShort()
|
this.chunkData.replace(ChunkLightDataS2CP(buffer) { chunkPosition }.chunkData)
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,6 +163,12 @@ open class InByteBuffer {
|
|||||||
return array
|
return array
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun readLongArray(target: LongArray, size: Int = readVarInt()) {
|
||||||
|
for (i in 0 until size) {
|
||||||
|
target[i] = readLong()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun readVarLong(): Long {
|
fun readVarLong(): Long {
|
||||||
var byteCount = 0
|
var byteCount = 0
|
||||||
|
@ -15,9 +15,12 @@ package de.bixilon.minosoft.util
|
|||||||
|
|
||||||
import de.bixilon.minosoft.util.KUtil.decide
|
import de.bixilon.minosoft.util.KUtil.decide
|
||||||
import glm_.vec2.Vec2i
|
import glm_.vec2.Vec2i
|
||||||
|
import kotlin.math.ceil
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
|
import kotlin.math.ln
|
||||||
|
|
||||||
object MMath {
|
object MMath {
|
||||||
|
private const val LN_2 = 0.69314718056 // ln(2.0)
|
||||||
|
|
||||||
fun clamp(value: Vec2i, min: Vec2i, max: Vec2i): Vec2i {
|
fun clamp(value: Vec2i, min: Vec2i, max: Vec2i): Vec2i {
|
||||||
value.x = clamp(value.x, min.x, max.x)
|
value.x = clamp(value.x, min.x, max.x)
|
||||||
@ -118,4 +121,8 @@ object MMath {
|
|||||||
val int = this.toInt()
|
val int = this.toInt()
|
||||||
return (this > int).decide(int + 1, int)
|
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.Chunk
|
||||||
import de.bixilon.minosoft.data.world.ChunkData
|
import de.bixilon.minosoft.data.world.ChunkData
|
||||||
import de.bixilon.minosoft.data.world.ChunkSection
|
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.biome.source.XZBiomeArray
|
||||||
import de.bixilon.minosoft.data.world.container.RegistrySectionDataProvider
|
import de.bixilon.minosoft.data.world.container.SectionDataProvider
|
||||||
import de.bixilon.minosoft.data.world.palette.Palette.Companion.choosePalette
|
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.gui.rendering.util.vec.vec2.Vec2iUtil.abs
|
||||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*
|
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*
|
||||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
|
||||||
import glm_.vec2.Vec2i
|
import glm_.vec2.Vec2i
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -63,13 +67,13 @@ object ChunkUtil {
|
|||||||
|
|
||||||
// parse data
|
// parse data
|
||||||
var arrayPosition = 0
|
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()) {
|
for ((sectionIndex, sectionHeight) in (dimension.lowestSection until dimension.highestSection).withIndex()) {
|
||||||
if (!sectionBitMask[sectionIndex]) {
|
if (!sectionBitMask[sectionIndex]) {
|
||||||
continue
|
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) {
|
for (blockNumber in 0 until ProtocolDefinition.BLOCKS_PER_SECTION) {
|
||||||
var blockId = (blockData[arrayPosition].toInt() and 0xFF) shl 4
|
var blockId = (blockData[arrayPosition].toInt() and 0xFF) shl 4
|
||||||
@ -95,7 +99,7 @@ object ChunkUtil {
|
|||||||
|
|
||||||
blocks[blockNumber] = buffer.connection.registries.blockStateRegistry[blockId] ?: continue
|
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
|
chunkData.blocks = sectionBlocks
|
||||||
return chunkData
|
return chunkData
|
||||||
@ -129,7 +133,7 @@ object ChunkUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var arrayPos = 0
|
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
|
for ((sectionIndex, sectionHeight) in (dimension.lowestSection until dimension.highestSection).withIndex()) { // max sections per chunks in chunk column
|
||||||
if (!sectionBitMask[sectionIndex]) {
|
if (!sectionBitMask[sectionIndex]) {
|
||||||
continue
|
continue
|
||||||
@ -140,56 +144,38 @@ object ChunkUtil {
|
|||||||
val block = buffer.connection.registries.blockStateRegistry[blockId] ?: continue
|
val block = buffer.connection.registries.blockStateRegistry[blockId] ?: continue
|
||||||
blocks[blockNumber] = block
|
blocks[blockNumber] = block
|
||||||
}
|
}
|
||||||
sectionBlocks[sectionHeight] = RegistrySectionDataProvider(buffer.connection.registries.blockStateRegistry.unsafeCast(), blocks.unsafeCast(), true)
|
sectionBlocks[sectionHeight] = SectionDataProvider(blocks, true)
|
||||||
}
|
}
|
||||||
chunkData.blocks = sectionBlocks
|
chunkData.blocks = sectionBlocks
|
||||||
return chunkData
|
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 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)
|
val light: Array<ByteArray?> = arrayOfNulls(dimension.sections)
|
||||||
var lightReceived = 0
|
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
|
for ((sectionIndex, sectionHeight) in (dimension.lowestSection until (sectionBitMask?.length() ?: dimension.highestSection)).withIndex()) { // max sections per chunks in chunk column
|
||||||
if (!sectionBitMask[sectionIndex]) {
|
if (sectionBitMask?.get(sectionIndex) == false) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (buffer.versionId >= V_18W43A) {
|
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()
|
if (blockContainer.palette !is SingularPalette<*> || blockContainer.palette.item != null) {
|
||||||
|
sectionBlocks[sectionHeight - dimension.lowestSection] = SectionDataProvider(blockContainer.unpack(), checkSize = true)
|
||||||
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 (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) {
|
if (buffer.versionId < V_18W43A) {
|
||||||
val blockLight = buffer.readByteArray(ProtocolDefinition.BLOCKS_PER_SECTION / 2)
|
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)
|
light[sectionHeight - dimension.lowestSection] = LightUtil.mergeLight(blockLight, skyLight ?: LightUtil.EMPTY_LIGHT_ARRAY)
|
||||||
lightReceived++
|
lightReceived++
|
||||||
}
|
}
|
||||||
sectionBlocks[sectionHeight - dimension.lowestSection] = RegistrySectionDataProvider(buffer.connection.registries.blockStateRegistry.unsafeCast(), blocks.unsafeCast(), true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chunkData.blocks = sectionBlocks
|
chunkData.blocks = sectionBlocks
|
||||||
if (lightReceived > 0) {
|
if (lightReceived > 0) {
|
||||||
chunkData.light = light
|
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)
|
chunkData.biomeSource = readLegacyBiomeArray(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user