From 4c49c733cde05ec3ec951b776e8e1d6b6fa580f0 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Fri, 26 Feb 2021 15:56:08 +0100 Subject: [PATCH] rendering: wip lightning, change chunk saving structure --- .../data/mappings/tweaker/VersionTweaker.kt | 21 ++- .../minosoft/data/world/BlockPosition.kt | 5 + .../de/bixilon/minosoft/data/world/Chunk.kt | 43 ++++- .../bixilon/minosoft/data/world/ChunkData.kt | 35 ++++ .../minosoft/data/world/ChunkSection.kt | 11 +- .../de/bixilon/minosoft/data/world/World.java | 152 ----------------- .../de/bixilon/minosoft/data/world/World.kt | 105 ++++++++++++ .../data/world/light/ChunkLightAccessor.kt | 28 ++++ .../data/world/light/DummyLightAccessor.kt | 31 ++++ .../data/world/light/LightAccessor.kt | 22 +++ .../palette/{Palette.java => Palette.kt} | 34 ++-- .../minosoft/gui/rendering/chunk/ChunkMesh.kt | 9 +- .../minosoft/gui/rendering/chunk/Frustum.kt | 4 +- .../gui/rendering/chunk/WorldRenderer.kt | 32 ++-- .../chunk/models/renderable/BlockRenderer.kt | 9 +- .../models/renderable/ElementRenderer.kt | 5 +- .../elements/text/HUDDebugScreenElement.kt | 1 + .../gui/rendering/textures/TextureArray.kt | 2 +- .../event/events/ChunkDataChangeEvent.java | 62 ------- .../event/events/ChunkDataChangeEvent.kt | 46 ++++++ .../clientbound/play/PacketBlockChange.java | 2 +- .../clientbound/play/PacketChunkBulk.java | 101 ------------ .../clientbound/play/PacketChunkBulk.kt | 88 ++++++++++ .../clientbound/play/PacketChunkData.java | 153 ------------------ .../clientbound/play/PacketChunkData.kt | 117 ++++++++++++++ .../play/PacketMultiBlockChange.java | 2 +- .../packets/clientbound/play/PacketRespawn.kt | 2 +- .../clientbound/play/PacketUpdateLight.java | 15 +- .../protocol/protocol/InByteBuffer.java | 4 + .../de/bixilon/minosoft/util/ChunkUtil.java | 23 +-- .../rendering/shader/chunk_fragment.glsl | 3 +- .../assets/rendering/shader/chunk_vertex.glsl | 4 + 32 files changed, 625 insertions(+), 546 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt delete mode 100644 src/main/java/de/bixilon/minosoft/data/world/World.java create mode 100644 src/main/java/de/bixilon/minosoft/data/world/World.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/world/light/ChunkLightAccessor.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/world/light/DummyLightAccessor.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/world/light/LightAccessor.kt rename src/main/java/de/bixilon/minosoft/data/world/palette/{Palette.java => Palette.kt} (57%) delete mode 100644 src/main/java/de/bixilon/minosoft/modding/event/events/ChunkDataChangeEvent.java create mode 100644 src/main/java/de/bixilon/minosoft/modding/event/events/ChunkDataChangeEvent.kt delete mode 100644 src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkBulk.java create mode 100644 src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkBulk.kt delete mode 100644 src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.java create mode 100644 src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.kt diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/tweaker/VersionTweaker.kt b/src/main/java/de/bixilon/minosoft/data/mappings/tweaker/VersionTweaker.kt index 799685306..b4916ef38 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/tweaker/VersionTweaker.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/tweaker/VersionTweaker.kt @@ -21,8 +21,7 @@ import de.bixilon.minosoft.data.entities.entities.vehicle.* import de.bixilon.minosoft.data.mappings.ResourceLocation import de.bixilon.minosoft.data.mappings.blocks.BlockState import de.bixilon.minosoft.data.world.BlockInfo -import de.bixilon.minosoft.data.world.Chunk -import de.bixilon.minosoft.data.world.InChunkLocation +import de.bixilon.minosoft.data.world.ChunkSection import de.bixilon.minosoft.data.world.InChunkSectionLocation import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.protocol.protocol.ProtocolVersions @@ -88,14 +87,14 @@ object VersionTweaker { } @JvmStatic - fun transformChunk(chunk: Chunk, versionId: Int): Chunk { + fun transformSections(sections: Map, versionId: Int) { // some blocks need to be tweaked. eg. Grass with a snow block on top becomes snowy grass block if (versionId >= ProtocolDefinition.FLATTING_VERSION_ID) { - return chunk + return } - for ((sectionHeight, section) in chunk.sections) { + for ((sectionHeight, section) in sections) { for ((location, blockInfo) in section.blocks) { - val newBlock = transformBlock(blockInfo.block, chunk, location, sectionHeight) + val newBlock = transformBlock(blockInfo.block, sections, location, sectionHeight) if (newBlock === blockInfo.block) { continue } @@ -106,16 +105,15 @@ object VersionTweaker { section.setBlockInfo(location, BlockInfo(newBlock, blockInfo.metaData)) } } - return chunk } // ToDo: Broken @JvmStatic - fun transformBlock(originalBlock: BlockState, chunk: Chunk, location: InChunkSectionLocation, sectionHeight: Int): BlockState? { + fun transformBlock(originalBlock: BlockState, sections: Map, location: InChunkSectionLocation, sectionHeight: Int): BlockState? { when (originalBlock.owner.resourceLocation) { ResourceLocation("minecraft:grass") -> { - getBlockAbove(chunk, location, sectionHeight)?.let { + getBlockAbove(sections, location, sectionHeight)?.let { if (it.owner.resourceLocation == TweakBlocks.SNOW_RESOURCE_LOCATION || it.owner.resourceLocation == TweakBlocks.SNOW_LAYER_RESOURCE_LOCAION) { return TweakBlocks.GRASS_BLOCK_SNOWY_YES } @@ -126,8 +124,7 @@ object VersionTweaker { return originalBlock } - private fun getBlockAbove(chunk: Chunk, location: InChunkSectionLocation, sectionHeight: Int): BlockState? { - val above = location.getInChunkLocation(sectionHeight) - return chunk.getBlockInfo(InChunkLocation(above.x, above.y + 1, above.z))?.block + private fun getBlockAbove(sections: Map, location: InChunkSectionLocation, sectionHeight: Int): BlockState? { + return sections[sectionHeight]?.getBlockInfo(location)?.block } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/BlockPosition.kt b/src/main/java/de/bixilon/minosoft/data/world/BlockPosition.kt index 4260191c2..6018863e8 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/BlockPosition.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/BlockPosition.kt @@ -13,6 +13,7 @@ package de.bixilon.minosoft.data.world import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition +import glm_.vec3.Vec3 data class BlockPosition(val x: Int, val y: Int, val z: Int) { constructor(chunkLocation: ChunkLocation, sectionHeight: Int, inChunkSectionLocation: InChunkSectionLocation) : this(chunkLocation.x * ProtocolDefinition.SECTION_WIDTH_X + inChunkSectionLocation.x, sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y + inChunkSectionLocation.y, chunkLocation.z * ProtocolDefinition.SECTION_WIDTH_Z + inChunkSectionLocation.z) // ToDo @@ -56,6 +57,10 @@ data class BlockPosition(val x: Int, val y: Int, val z: Int) { } } + fun toVec3(): Vec3 { + return Vec3(x, y, z) + } + override fun toString(): String { return "($x $y $z)" } diff --git a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt index 32ae373ae..985d1d190 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt @@ -14,18 +14,25 @@ package de.bixilon.minosoft.data.world import de.bixilon.minosoft.data.mappings.blocks.BlockState import de.bixilon.minosoft.data.world.biome.BiomeAccessor +import de.bixilon.minosoft.data.world.light.LightAccessor import java.util.* /** * Collection of chunks sections (allocated in y) */ class Chunk( - val sections: MutableMap = mutableMapOf(), - var biomeAccessor: BiomeAccessor, + var sections: MutableMap? = null, + var biomeAccessor: BiomeAccessor? = null, + var lightAccessor: LightAccessor? = null, ) { + private val lock = Object() + val isFullyLoaded: Boolean + get() { + return sections != null && biomeAccessor != null && lightAccessor != null + } fun getBlockInfo(location: InChunkLocation): BlockInfo? { - return sections[location.getSectionHeight()]?.getBlockInfo(location.getInChunkSectionLocation()) + return sections?.get(location.getSectionHeight())?.getBlockInfo(location.getInChunkSectionLocation()) } fun getBlockInfo(x: Int, y: Int, z: Int): BlockInfo? { @@ -38,6 +45,29 @@ class Chunk( } } + fun setData(data: ChunkData, merge: Boolean = false) { + synchronized(lock) { + data.blocks?.let { + if (sections == null) { + sections = mutableMapOf() + } + if (!merge) { + sections?.clear() + } + // replace all chunk sections + for ((sectionHeight, chunkSection) in it) { + getSectionOrCreate(sectionHeight).setData(chunkSection, merge) + } + } + data.biomeAccessor?.let { + this.biomeAccessor = it + } + data.lightAccessor?.let { + this.lightAccessor = it + } + } + } + fun setRawBlocks(blocks: HashMap) { for ((location, blockInfo) in blocks) { setRawBlock(location, blockInfo) @@ -61,11 +91,14 @@ class Chunk( } fun getSectionOrCreate(sectionHeight: Int): ChunkSection { - return sections[sectionHeight].let { + if (sections == null) { + throw IllegalStateException("Chunk not received/initialized yet!") + } + return sections!![sectionHeight].let { var section = it if (section == null) { section = ChunkSection() - sections[sectionHeight] = section + sections!![sectionHeight] = section } section } diff --git a/src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt b/src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt new file mode 100644 index 000000000..b7b404c16 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt @@ -0,0 +1,35 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world + +import de.bixilon.minosoft.data.world.biome.BiomeAccessor +import de.bixilon.minosoft.data.world.light.LightAccessor + +data class ChunkData( + var blocks: Map? = null, + var biomeAccessor: BiomeAccessor? = null, + var lightAccessor: LightAccessor? = null, +) { + fun replace(data: ChunkData) { + data.blocks?.let { + this.blocks = it + } + data.biomeAccessor?.let { + this.biomeAccessor = it + } + data.lightAccessor?.let { + this.lightAccessor = it + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt index 1e7040ff1..d00a1999a 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt @@ -37,10 +37,6 @@ class ChunkSection constructor( return getBlockInfo(InChunkSectionLocation(x, y, z)) } - fun updateStaticData() { - - } - fun setRawBlock(location: InChunkSectionLocation, block: BlockState?) { if (block == null) { setBlockInfo(location, null) @@ -48,4 +44,11 @@ class ChunkSection constructor( } setBlockInfo(location, BlockInfo(block)) } + + fun setData(chunkSection: ChunkSection, merge: Boolean = false) { + if (!merge) { + this.blocks.clear() + } + this.blocks.putAll(chunkSection.blocks) + } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/World.java b/src/main/java/de/bixilon/minosoft/data/world/World.java deleted file mode 100644 index b00ac918d..000000000 --- a/src/main/java/de/bixilon/minosoft/data/world/World.java +++ /dev/null @@ -1,152 +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 . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.data.world; - -import com.google.common.collect.HashBiMap; -import de.bixilon.minosoft.data.entities.block.BlockEntityMetaData; -import de.bixilon.minosoft.data.entities.entities.Entity; -import de.bixilon.minosoft.data.mappings.Dimension; -import de.bixilon.minosoft.data.mappings.blocks.BlockState; - -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Collection of chunks - */ -public class World { - private final ConcurrentHashMap chunks = new ConcurrentHashMap<>(); - private final HashBiMap entityIdMap = HashBiMap.create(); - private final HashBiMap entityUUIDMap = HashBiMap.create(); - private boolean hardcore; - private boolean raining; - private Dimension dimension; // used for sky color, etc - - public ConcurrentHashMap getAllChunks() { - return this.chunks; - } - - @Nullable - public BlockInfo getBlockInfo(BlockPosition pos) { - ChunkLocation loc = pos.getChunkLocation(); - if (getChunk(loc) != null) { - return getChunk(loc).getBlockInfo(pos.getInChunkLocation()); - } - return null; - } - - public Chunk getChunk(ChunkLocation loc) { - return this.chunks.get(loc); - } - - public void setBlock(BlockPosition pos, BlockState block) { - if (getChunk(pos.getChunkLocation()) != null) { - getChunk(pos.getChunkLocation()).setRawBlock(pos.getInChunkLocation(), block); - } - // do nothing if chunk is unloaded - } - - public void unloadChunk(ChunkLocation location) { - this.chunks.remove(location); - } - - public void setChunk(ChunkLocation location, Chunk chunk) { - this.chunks.put(location, chunk); - } - - public void setChunks(HashMap chunkMap) { - chunkMap.forEach(this.chunks::put); - } - - public boolean isHardcore() { - return this.hardcore; - } - - public void setHardcore(boolean hardcore) { - this.hardcore = hardcore; - } - - public boolean isRaining() { - return this.raining; - } - - public void setRaining(boolean raining) { - this.raining = raining; - } - - public void addEntity(Entity entity) { - this.entityIdMap.put(entity.getEntityId(), entity); - this.entityUUIDMap.put(entity.getUUID(), entity); - } - - public Entity getEntity(int id) { - return this.entityIdMap.get(id); - } - - public Entity getEntity(UUID uuid) { - return this.entityUUIDMap.get(uuid); - } - - public void removeEntity(Entity entity) { - this.entityIdMap.inverse().remove(entity); - this.entityUUIDMap.inverse().remove(entity); - } - - public void removeEntity(int entityId) { - removeEntity(this.entityIdMap.get(entityId)); - } - - public void removeEntity(UUID entityUUID) { - removeEntity(this.entityUUIDMap.get(entityUUID)); - } - - public Dimension getDimension() { - return this.dimension; - } - - public void setDimension(Dimension dimension) { - this.dimension = dimension; - } - - public void setBlockEntityData(BlockPosition position, BlockEntityMetaData data) { - Chunk chunk = this.chunks.get(position.getChunkLocation()); - if (chunk == null) { - return; - } - var section = chunk.getSections().get(position.getSectionHeight()); - if (section == null) { - return; - } - var blockInfo = section.getBlockInfo(position.getInChunkSectionLocation()); - if (blockInfo == null) { - return; - } - blockInfo.setMetaData(data); - } - - - public void setBlockEntityData(HashMap blockEntities) { - blockEntities.forEach(this::setBlockEntityData); - } - - public HashBiMap getEntityIdMap() { - return this.entityIdMap; - } - - public HashBiMap getEntityUUIDMap() { - return this.entityUUIDMap; - } -} diff --git a/src/main/java/de/bixilon/minosoft/data/world/World.kt b/src/main/java/de/bixilon/minosoft/data/world/World.kt new file mode 100644 index 000000000..f62d606b1 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/World.kt @@ -0,0 +1,105 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ +package de.bixilon.minosoft.data.world + +import com.google.common.collect.HashBiMap +import de.bixilon.minosoft.data.entities.block.BlockEntityMetaData +import de.bixilon.minosoft.data.entities.entities.Entity +import de.bixilon.minosoft.data.mappings.Dimension +import de.bixilon.minosoft.data.mappings.blocks.BlockState +import java.util.* +import java.util.concurrent.ConcurrentHashMap + +/** + * Collection of chunks + */ +class World { + val chunks = ConcurrentHashMap() + val entityIdMap = HashBiMap.create() + val entityUUIDMap = HashBiMap.create() + var isHardcore = false + var isRaining = false + var dimension: Dimension? = null + + + fun getBlockInfo(blockPosition: BlockPosition): BlockInfo? { + val chunkLocation = blockPosition.getChunkLocation() + return chunks[chunkLocation]?.getBlockInfo(blockPosition.getInChunkLocation()) + } + + fun getChunk(loc: ChunkLocation): Chunk? { + return chunks[loc] + } + + fun getOrCreateChunk(chunkLocation: ChunkLocation): Chunk { + return chunks[chunkLocation] ?: run { + val chunk = Chunk() + chunks[chunkLocation] = chunk + chunk + } + } + + fun setBlock(blockPosition: BlockPosition, block: BlockState?) { + chunks[blockPosition.getChunkLocation()]?.setRawBlock(blockPosition.getInChunkLocation(), block) + } + + fun unloadChunk(location: ChunkLocation) { + chunks.remove(location) + } + + fun replaceChunk(location: ChunkLocation, chunk: Chunk) { + chunks[location] = chunk + } + + fun replaceChunks(chunkMap: HashMap) { + for ((chunkLocation, chunk) in chunkMap) { + chunks[chunkLocation] = chunk + } + } + + fun addEntity(entity: Entity) { + entityIdMap[entity.entityId] = entity + entityUUIDMap[entity.uuid] = entity + } + + fun getEntity(id: Int): Entity? { + return entityIdMap[id] + } + + fun getEntity(uuid: UUID): Entity? { + return entityUUIDMap[uuid] + } + + fun removeEntity(entity: Entity) { + entityIdMap.inverse().remove(entity) + entityUUIDMap.inverse().remove(entity) + } + + fun removeEntity(entityId: Int) { + entityIdMap[entityId]?.let { removeEntity(it) } + } + + fun removeEntity(entityUUID: UUID) { + entityUUIDMap[entityUUID]?.let { removeEntity(it) } + } + + fun setBlockEntityData(position: BlockPosition, data: BlockEntityMetaData?) { + chunks[position.getChunkLocation()]?.sections?.get(position.getSectionHeight())?.getBlockInfo(position.getInChunkSectionLocation())?.metaData = data + } + + fun setBlockEntityData(blockEntities: HashMap) { + for ((blockPosition, entityMetaData) in blockEntities) { + setBlockEntityData(blockPosition, entityMetaData) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/light/ChunkLightAccessor.kt b/src/main/java/de/bixilon/minosoft/data/world/light/ChunkLightAccessor.kt new file mode 100644 index 000000000..5d363261a --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/light/ChunkLightAccessor.kt @@ -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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world.light + +import de.bixilon.minosoft.data.Directions +import de.bixilon.minosoft.data.world.BlockPosition +import de.bixilon.minosoft.data.world.InChunkLocation + +class ChunkLightAccessor( + val blockLightLevel: MutableMap = mutableMapOf(), + val skyLightLevel: MutableMap = mutableMapOf(), +) : LightAccessor { + override fun getLightLevel(blockPosition: BlockPosition, direction: Directions): Int { + val inChunkLocation = blockPosition.getInChunkLocation() + return blockLightLevel[inChunkLocation]?.toInt() ?: 0 + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/light/DummyLightAccessor.kt b/src/main/java/de/bixilon/minosoft/data/world/light/DummyLightAccessor.kt new file mode 100644 index 000000000..40b0c42c5 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/light/DummyLightAccessor.kt @@ -0,0 +1,31 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world.light + +import de.bixilon.minosoft.data.Directions +import de.bixilon.minosoft.data.world.BlockPosition + +object DummyLightAccessor : LightAccessor { + + override fun getLightLevel(blockPosition: BlockPosition, direction: Directions): Int { + return when (direction) { + Directions.NORTH -> 5 + Directions.SOUTH -> 7 + Directions.DOWN -> 3 + Directions.UP -> 9 + Directions.WEST -> 11 + Directions.EAST -> 13 + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/light/LightAccessor.kt b/src/main/java/de/bixilon/minosoft/data/world/light/LightAccessor.kt new file mode 100644 index 000000000..bf48e6af5 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/light/LightAccessor.kt @@ -0,0 +1,22 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world.light + +import de.bixilon.minosoft.data.Directions +import de.bixilon.minosoft.data.world.BlockPosition + +interface LightAccessor { + + fun getLightLevel(blockPosition: BlockPosition, direction: Directions): Int +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/palette/Palette.java b/src/main/java/de/bixilon/minosoft/data/world/palette/Palette.kt similarity index 57% rename from src/main/java/de/bixilon/minosoft/data/world/palette/Palette.java rename to src/main/java/de/bixilon/minosoft/data/world/palette/Palette.kt index 511b89615..44599fa90 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/palette/Palette.java +++ b/src/main/java/de/bixilon/minosoft/data/world/palette/Palette.kt @@ -10,25 +10,27 @@ * * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ +package de.bixilon.minosoft.data.world.palette -package de.bixilon.minosoft.data.world.palette; +import de.bixilon.minosoft.data.mappings.blocks.BlockState +import de.bixilon.minosoft.protocol.protocol.InByteBuffer -import de.bixilon.minosoft.data.mappings.blocks.BlockState; -import de.bixilon.minosoft.protocol.protocol.InByteBuffer; +interface Palette { -public interface Palette { - static Palette choosePalette(int bitsPerBlock) { - if (bitsPerBlock <= 4) { - return new IndirectPalette(4); - } else if (bitsPerBlock <= 8) { - return new IndirectPalette(bitsPerBlock); + fun blockById(id: Int): BlockState? + + val bitsPerBlock: Int + + fun read(buffer: InByteBuffer) + + companion object { + fun choosePalette(bitsPerBlock: Int): Palette { + if (bitsPerBlock <= 4) { + return IndirectPalette(4) + } else if (bitsPerBlock <= 8) { + return IndirectPalette(bitsPerBlock) + } + return DirectPalette() } - return new DirectPalette(); } - - BlockState blockById(int id); - - int getBitsPerBlock(); - - void read(InByteBuffer buffer); } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkMesh.kt index dfafedf5b..fa8c99f73 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkMesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkMesh.kt @@ -29,7 +29,7 @@ class ChunkMesh { private var vbo: Int = 0 private var trianglesCount: Int = 0 - fun addVertex(position: Vec3, textureCoordinates: Vec2, texture: Texture, tintColor: RGBColor?) { + fun addVertex(position: Vec3, textureCoordinates: Vec2, texture: Texture, tintColor: RGBColor?, lightLevel: Float = 0.9f) { data.add(position.x) data.add(position.y) data.add(position.z) @@ -47,6 +47,8 @@ class ChunkMesh { } else { data.add(Float.fromBits(tintColor.color)) } + + data.add(lightLevel) } fun load() { @@ -74,6 +76,9 @@ class ChunkMesh { glVertexAttribPointer(index, 1, GL_FLOAT, false, FLOATS_PER_VERTEX * Float.BYTES, (9 * Float.BYTES).toLong()) glEnableVertexAttribArray(index++) + glVertexAttribPointer(index, 1, GL_FLOAT, false, FLOATS_PER_VERTEX * Float.BYTES, (10 * Float.BYTES).toLong()) + glEnableVertexAttribArray(index++) + // don't remove the ++ above! index.let { } @@ -92,6 +97,6 @@ class ChunkMesh { } companion object { - private const val FLOATS_PER_VERTEX = 10 + private const val FLOATS_PER_VERTEX = 11 } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/Frustum.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/Frustum.kt index e1dc75ac9..fbabaf2f9 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/Frustum.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/Frustum.kt @@ -43,8 +43,8 @@ class Frustum(val camera: Camera) { } fun containsChunk(chunkLocation: ChunkLocation, connection: Connection): Boolean { - val from = Vec3(chunkLocation.x * ProtocolDefinition.SECTION_WIDTH_X, connection.player.world.dimension.minY, chunkLocation.z * ProtocolDefinition.SECTION_WIDTH_Z) - val to = from + Vec3(ProtocolDefinition.SECTION_WIDTH_X, connection.player.world.dimension.logicalHeight, ProtocolDefinition.SECTION_WIDTH_Z) + val from = Vec3(chunkLocation.x * ProtocolDefinition.SECTION_WIDTH_X, connection.player.world.dimension!!.minY, chunkLocation.z * ProtocolDefinition.SECTION_WIDTH_Z) + val to = from + Vec3(ProtocolDefinition.SECTION_WIDTH_X, connection.player.world.dimension!!.logicalHeight, ProtocolDefinition.SECTION_WIDTH_Z) val frustum = Frustum(connection.renderer.renderWindow.camera) return frustum.containsRegion(from, to) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt index 3b70bbdae..5482d45a5 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt @@ -27,7 +27,6 @@ import de.bixilon.minosoft.gui.rendering.textures.TextureArray import de.bixilon.minosoft.protocol.network.Connection import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.util.logging.Log -import glm_.vec3.Vec3 import org.lwjgl.opengl.GL11.GL_CULL_FACE import org.lwjgl.opengl.GL11.glEnable import org.lwjgl.opengl.GL13.glDisable @@ -48,16 +47,16 @@ class WorldRenderer(private val connection: Connection, private val world: World } val mesh = ChunkMesh() - val below = world.allChunks[chunkLocation]?.sections?.get(sectionHeight - 1) - val above = world.allChunks[chunkLocation]?.sections?.get(sectionHeight + 1) + val below = world.chunks[chunkLocation]?.sections?.get(sectionHeight - 1) + val above = world.chunks[chunkLocation]?.sections?.get(sectionHeight + 1) //val north = (world.allChunks[chunkLocation.getLocationByDirection(Directions.NORTH)]?: throw ChunkNotLoadedException("North not loaded")).sections?.get(sectionHeight) //val south = (world.allChunks[chunkLocation.getLocationByDirection(Directions.SOUTH)]?: throw ChunkNotLoadedException("South not loaded")).sections?.get(sectionHeight) //val west = (world.allChunks[chunkLocation.getLocationByDirection(Directions.WEST)]?: throw ChunkNotLoadedException("West not loaded")).sections?.get(sectionHeight) //val east = (world.allChunks[chunkLocation.getLocationByDirection(Directions.EAST)]?: throw ChunkNotLoadedException("North not loaded")).sections?.get(sectionHeight) - val north = world.allChunks[chunkLocation.getLocationByDirection(Directions.NORTH)]?.sections?.get(sectionHeight) - val south = world.allChunks[chunkLocation.getLocationByDirection(Directions.SOUTH)]?.sections?.get(sectionHeight) - val west = world.allChunks[chunkLocation.getLocationByDirection(Directions.WEST)]?.sections?.get(sectionHeight) - val east = world.allChunks[chunkLocation.getLocationByDirection(Directions.EAST)]?.sections?.get(sectionHeight) + val north = world.chunks[chunkLocation.getLocationByDirection(Directions.NORTH)]?.sections?.get(sectionHeight) + val south = world.chunks[chunkLocation.getLocationByDirection(Directions.SOUTH)]?.sections?.get(sectionHeight) + val west = world.chunks[chunkLocation.getLocationByDirection(Directions.WEST)]?.sections?.get(sectionHeight) + val east = world.chunks[chunkLocation.getLocationByDirection(Directions.EAST)]?.sections?.get(sectionHeight) for ((position, blockInfo) in section.blocks) { val blockBelow: BlockInfo? = if (position.y == 0 && below != null) { @@ -90,13 +89,11 @@ class WorldRenderer(private val connection: Connection, private val world: World } else { section.getBlockInfo(position.getLocationByDirection(Directions.EAST)) } - val worldPosition = Vec3(position.x + chunkLocation.x * ProtocolDefinition.SECTION_WIDTH_X, position.y + sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y, position.z + chunkLocation.z * ProtocolDefinition.SECTION_WIDTH_Z) - val blockPosition = BlockPosition(chunkLocation, sectionHeight, position) if (blockPosition == BlockPosition(-103, 3, 288)) { Log.debug("") } - val biome = chunk.biomeAccessor.getBiome(blockPosition) + val biome = chunk.biomeAccessor!!.getBiome(blockPosition) var tintColor: RGBColor? = null if (StaticConfiguration.BIOME_DEBUG_MODE) { @@ -113,7 +110,7 @@ class WorldRenderer(private val connection: Connection, private val world: World blockInfo.block.tintColor?.let { tintColor = it } } - blockInfo.block.getBlockRenderer(blockPosition).render(blockInfo, tintColor, worldPosition, mesh, arrayOf(blockBelow, blockAbove, blockNorth, blockSouth, blockWest, blockEast)) + blockInfo.block.getBlockRenderer(blockPosition).render(blockInfo, chunk.lightAccessor!!, tintColor, blockPosition, mesh, arrayOf(blockBelow, blockAbove, blockNorth, blockSouth, blockWest, blockEast)) } return mesh } @@ -145,7 +142,7 @@ class WorldRenderer(private val connection: Connection, private val world: World } for ((chunkLocation, map) in chunkSectionsToDraw) { - if (! visibleChunks.contains(chunkLocation)) { + if (!visibleChunks.contains(chunkLocation)) { continue } for ((_, mesh) in map) { @@ -171,7 +168,10 @@ class WorldRenderer(private val connection: Connection, private val world: World fun prepareChunk(chunkLocation: ChunkLocation, chunk: Chunk) { chunkSectionsToDraw[chunkLocation] = ConcurrentHashMap() - for ((sectionHeight, section) in chunk.sections) { + if (!chunk.isFullyLoaded) { + return + } + for ((sectionHeight, section) in chunk.sections!!) { prepareChunkSection(chunkLocation, sectionHeight, section, chunk) } } @@ -217,7 +217,7 @@ class WorldRenderer(private val connection: Connection, private val world: World } private fun prepareWorld(world: World) { - for ((chunkLocation, chunk) in world.allChunks) { + for ((chunkLocation, chunk) in world.chunks) { prepareChunk(chunkLocation, chunk) } } @@ -236,4 +236,8 @@ class WorldRenderer(private val connection: Connection, private val world: World } } } + + fun getChunkSize(): Int { + return chunkSectionsToDraw.size + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockRenderer.kt index 574acef44..55542df82 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockRenderer.kt @@ -17,11 +17,12 @@ import com.google.gson.JsonObject import de.bixilon.minosoft.data.Directions import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.data.world.BlockInfo +import de.bixilon.minosoft.data.world.BlockPosition +import de.bixilon.minosoft.data.world.light.LightAccessor import de.bixilon.minosoft.gui.rendering.chunk.ChunkMesh import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModel import de.bixilon.minosoft.gui.rendering.textures.Texture import glm_.mat4x4.Mat4 -import glm_.vec3.Vec3 class BlockRenderer(data: JsonObject, parent: BlockModel) { private val transparentFaces: MutableSet = mutableSetOf() @@ -70,8 +71,8 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) { } } - fun render(blockInfo: BlockInfo, tintColor: RGBColor?, position: Vec3, mesh: ChunkMesh, neighbourBlocks: Array) { - val modelMatrix = Mat4().translate(position) + fun render(blockInfo: BlockInfo, lightAccessor: LightAccessor, tintColor: RGBColor?, position: BlockPosition, mesh: ChunkMesh, neighbourBlocks: Array) { + val modelMatrix = Mat4().translate(position.toVec3()) for (direction in Directions.DIRECTIONS) { for (element in elements) { @@ -91,7 +92,7 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) { continue } - element.render(tintColor, textureMapping, modelMatrix, direction, mesh) + element.render(tintColor, lightAccessor.getLightLevel(position, direction) / 15f, textureMapping, modelMatrix, direction, mesh) } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/ElementRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/ElementRenderer.kt index 2cd839b8b..69b3667a0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/ElementRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/ElementRenderer.kt @@ -50,7 +50,7 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvLock: Boolea } - fun render(tintColor: RGBColor?, textureMapping: MutableMap, modelMatrix: Mat4, direction: Directions, mesh: ChunkMesh) { + fun render(tintColor: RGBColor?, lightLevel: Float, textureMapping: MutableMap, modelMatrix: Mat4, direction: Directions, mesh: ChunkMesh) { val realDirection = directionMapping[direction]!! val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[realDirection.ordinal] @@ -75,7 +75,8 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvLock: Boolea tintColor } else { null - } + }, + lightLevel = lightLevel, ) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/text/HUDDebugScreenElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/text/HUDDebugScreenElement.kt index a08174db1..b1b56a5b5 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/text/HUDDebugScreenElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/text/HUDDebugScreenElement.kt @@ -49,6 +49,7 @@ class HUDDebugScreenElement(private val hudTextElement: HUDTextElement) : HUDTex chatComponents[FontBindings.LEFT_UP]!!.addAll(listOf( "FPS: ${getFPS()}", "Timings: avg ${getAvgFrameTime()}ms, min ${getMinFrameTime()}ms, max ${getMaxFrameTime()}ms", + "Chunks: ${hudTextElement.renderWindow.worldRenderer.getChunkSize()} / ${hudTextElement.connection.player.world.chunks.size}", "Connected to ${hudTextElement.connection.address} with ${hudTextElement.connection.version}", "", "XYZ ${getLocation()}", diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureArray.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureArray.kt index 3f3af6df5..8047a6009 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureArray.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/textures/TextureArray.kt @@ -32,9 +32,9 @@ class TextureArray(val textures: List, val maxWidth: Int, val maxHeight glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT) glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT) glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST) + // glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR) // ToDo: This breaks transparency again glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST) - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, maxWidth, maxHeight, textures.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, null as ByteBuffer?) for (texture in textures) { diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/ChunkDataChangeEvent.java b/src/main/java/de/bixilon/minosoft/modding/event/events/ChunkDataChangeEvent.java deleted file mode 100644 index 2e6d627c8..000000000 --- a/src/main/java/de/bixilon/minosoft/modding/event/events/ChunkDataChangeEvent.java +++ /dev/null @@ -1,62 +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 . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.modding.event.events; - -import de.bixilon.minosoft.data.world.Chunk; -import de.bixilon.minosoft.data.world.ChunkLocation; -import de.bixilon.minosoft.protocol.network.Connection; -import de.bixilon.minosoft.protocol.packets.clientbound.play.PacketChunkData; -import de.bixilon.minosoft.util.nbt.tag.CompoundTag; - -/** - * Fired when a new chunk is received or a full chunk changes - */ -public class ChunkDataChangeEvent extends ConnectionEvent { - private final ChunkLocation location; - private final Chunk chunk; - private final CompoundTag heightMap; - - public ChunkDataChangeEvent(Connection connection, ChunkLocation location, Chunk chunk, CompoundTag heightMap) { - super(connection); - this.location = location; - this.chunk = chunk; - this.heightMap = heightMap; - } - - public ChunkDataChangeEvent(Connection connection, ChunkLocation location, Chunk chunk) { - super(connection); - this.location = location; - this.chunk = chunk; - this.heightMap = new CompoundTag(); - } - - public ChunkDataChangeEvent(Connection connection, PacketChunkData pkg) { - super(connection); - this.location = pkg.getLocation(); - this.chunk = pkg.getChunk(); - this.heightMap = pkg.getHeightMap(); - } - - public ChunkLocation getLocation() { - return this.location; - } - - public Chunk getChunk() { - return this.chunk; - } - - public CompoundTag getHeightMap() { - return this.heightMap; - } -} diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/ChunkDataChangeEvent.kt b/src/main/java/de/bixilon/minosoft/modding/event/events/ChunkDataChangeEvent.kt new file mode 100644 index 000000000..37be9b0f9 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/ChunkDataChangeEvent.kt @@ -0,0 +1,46 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ +package de.bixilon.minosoft.modding.event.events + +import de.bixilon.minosoft.data.world.ChunkData +import de.bixilon.minosoft.data.world.ChunkLocation +import de.bixilon.minosoft.protocol.network.Connection +import de.bixilon.minosoft.protocol.packets.clientbound.play.PacketChunkData +import de.bixilon.minosoft.util.nbt.tag.CompoundTag + +/** + * Fired when a new chunk is received or a full chunk changes + */ +class ChunkDataChangeEvent : ConnectionEvent { + val location: ChunkLocation + val chunkData: ChunkData + val heightMap: CompoundTag? + + constructor(connection: Connection?, location: ChunkLocation, chunkData: ChunkData, heightMap: CompoundTag?) : super(connection) { + this.location = location + this.chunkData = chunkData + this.heightMap = heightMap + } + + constructor(connection: Connection?, location: ChunkLocation, chunkData: ChunkData) : super(connection) { + this.location = location + this.chunkData = chunkData + heightMap = CompoundTag() + } + + constructor(connection: Connection, pkg: PacketChunkData) : super(connection) { + location = pkg.location + chunkData = pkg.chunkData + heightMap = pkg.heightMap + } +} diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketBlockChange.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketBlockChange.java index 0247710f8..74027696e 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketBlockChange.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketBlockChange.java @@ -57,7 +57,7 @@ public class PacketBlockChange extends ClientboundPacket { // tweak if (!connection.getVersion().isFlattened()) { - BlockState block = VersionTweaker.transformBlock(getBlock(), chunk, this.position.getInChunkSectionLocation(), this.position.getSectionHeight()); + BlockState block = VersionTweaker.transformBlock(getBlock(), chunk.getSections(), this.position.getInChunkSectionLocation(), this.position.getSectionHeight()); section.setRawBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), block); } else { section.setRawBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), getBlock()); diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkBulk.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkBulk.java deleted file mode 100644 index 9202afbb4..000000000 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkBulk.java +++ /dev/null @@ -1,101 +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 . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.protocol.packets.clientbound.play; - -import de.bixilon.minosoft.data.mappings.Dimension; -import de.bixilon.minosoft.data.mappings.tweaker.VersionTweaker; -import de.bixilon.minosoft.data.world.Chunk; -import de.bixilon.minosoft.data.world.ChunkLocation; -import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent; -import de.bixilon.minosoft.protocol.network.Connection; -import de.bixilon.minosoft.protocol.packets.ClientboundPacket; -import de.bixilon.minosoft.protocol.protocol.InByteBuffer; -import de.bixilon.minosoft.util.ChunkUtil; -import de.bixilon.minosoft.util.Util; -import de.bixilon.minosoft.util.logging.Log; - -import java.util.HashMap; - -import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_14W26A; -import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_14W28A; - -public class PacketChunkBulk extends ClientboundPacket { - private final HashMap chunks = new HashMap<>(); - - @Override - public boolean read(InByteBuffer buffer) { - Dimension dimension = buffer.getConnection().getPlayer().getWorld().getDimension(); - if (buffer.getVersionId() < V_14W26A) { - int chunkCount = buffer.readUnsignedShort(); - int dataLen = buffer.readInt(); - boolean containsSkyLight = buffer.readBoolean(); - - // decompress chunk data - InByteBuffer decompressed; - if (buffer.getVersionId() < V_14W28A) { - decompressed = Util.decompress(buffer.readBytes(dataLen), buffer.getConnection()); - } else { - decompressed = buffer; - } - - // chunk meta data - for (int i = 0; i < chunkCount; i++) { - int x = buffer.readInt(); - int z = buffer.readInt(); - long[] sectionBitMask = {buffer.readUnsignedShort()}; - int addBitMask = buffer.readUnsignedShort(); - - this.chunks.put(new ChunkLocation(x, z), ChunkUtil.readChunkPacket(decompressed, dimension, sectionBitMask, addBitMask, true, containsSkyLight)); - } - return true; - } - boolean containsSkyLight = buffer.readBoolean(); - int chunkCount = buffer.readVarInt(); - int[] x = new int[chunkCount]; - int[] z = new int[chunkCount]; - long[][] sectionBitMask = new long[chunkCount][]; - - // ToDo: this was still compressed in 14w28a - - for (int i = 0; i < chunkCount; i++) { - x[i] = buffer.readInt(); - z[i] = buffer.readInt(); - sectionBitMask[i] = new long[]{buffer.readUnsignedShort()}; - } - for (int i = 0; i < chunkCount; i++) { - this.chunks.put(new ChunkLocation(x[i], z[i]), ChunkUtil.readChunkPacket(buffer, dimension, sectionBitMask[i], (short) 0, true, containsSkyLight)); - } - return true; - } - - @Override - public void handle(Connection connection) { - this.chunks.values().forEach((chunk) -> VersionTweaker.transformChunk(chunk, connection.getVersion().getVersionId())); - - getChunks().forEach(((location, chunk) -> connection.fireEvent(new ChunkDataChangeEvent(connection, location, chunk)))); - - connection.getPlayer().getWorld().setChunks(getChunks()); - - getChunks().forEach(((location, chunk) -> connection.getRenderer().getRenderWindow().getWorldRenderer().prepareChunk(location, chunk))); - } - - @Override - public void log() { - Log.protocol(String.format("[IN] Chunk bulk packet received (chunks=%s)", this.chunks.size())); - } - - public HashMap getChunks() { - return this.chunks; - } -} diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkBulk.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkBulk.kt new file mode 100644 index 000000000..bc3e641db --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkBulk.kt @@ -0,0 +1,88 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ +package de.bixilon.minosoft.protocol.packets.clientbound.play + +import de.bixilon.minosoft.data.mappings.tweaker.VersionTweaker +import de.bixilon.minosoft.data.world.ChunkData +import de.bixilon.minosoft.data.world.ChunkLocation +import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent +import de.bixilon.minosoft.protocol.network.Connection +import de.bixilon.minosoft.protocol.packets.ClientboundPacket +import de.bixilon.minosoft.protocol.protocol.InByteBuffer +import de.bixilon.minosoft.protocol.protocol.ProtocolVersions +import de.bixilon.minosoft.util.ChunkUtil +import de.bixilon.minosoft.util.Util +import de.bixilon.minosoft.util.logging.Log +import java.util.* + +class PacketChunkBulk : ClientboundPacket() { + val data = HashMap() + + override fun read(buffer: InByteBuffer): Boolean { + val dimension = buffer.connection.player.world.dimension!! + if (buffer.versionId < ProtocolVersions.V_14W26A) { + val chunkCount = buffer.readUnsignedShort() + val dataLength = buffer.readInt() + val containsSkyLight = buffer.readBoolean() + + // decompress chunk data + val decompressed: InByteBuffer = if (buffer.versionId < ProtocolVersions.V_14W28A) { + Util.decompress(buffer.readBytes(dataLength), buffer.connection) + } else { + buffer + } + + // chunk meta data + for (i in 0 until chunkCount) { + val chunkLocation = buffer.readChunkLocation() + val sectionBitMask = longArrayOf(buffer.readUnsignedShort().toLong()) + val addBitMask = buffer.readUnsignedShort() + data[chunkLocation] = ChunkUtil.readChunkPacket(decompressed, dimension, sectionBitMask, addBitMask, true, containsSkyLight) + } + return true + } + val containsSkyLight = buffer.readBoolean() + val chunkCount = buffer.readVarInt() + val x = IntArray(chunkCount) + val z = IntArray(chunkCount) + val sectionBitMask = arrayOfNulls(chunkCount) + + // ToDo: this was still compressed in 14w28a + for (i in 0 until chunkCount) { + x[i] = buffer.readInt() + z[i] = buffer.readInt() + sectionBitMask[i] = longArrayOf(buffer.readUnsignedShort().toLong()) + } + for (i in 0 until chunkCount) { + data[ChunkLocation(x[i], z[i])] = ChunkUtil.readChunkPacket(buffer, dimension, sectionBitMask[i], 0, true, containsSkyLight) + } + return true + } + + override fun handle(connection: Connection) { + // transform data + for ((chunkLocation, data) in data) { + data.blocks?.let { + VersionTweaker.transformSections(it, connection.version.versionId) + } + connection.fireEvent(ChunkDataChangeEvent(connection, chunkLocation, data)) + val chunk = connection.player.world.getOrCreateChunk(chunkLocation) + chunk.setData(data) + connection.renderer.renderWindow.worldRenderer.prepareChunk(chunkLocation, chunk) + } + } + + override fun log() { + Log.protocol("[IN] Chunk bulk packet received (chunks${data.size})") + } +} diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.java deleted file mode 100644 index c9df4e830..000000000 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.java +++ /dev/null @@ -1,153 +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 . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.protocol.packets.clientbound.play; - -import de.bixilon.minosoft.data.entities.block.BlockEntityMetaData; -import de.bixilon.minosoft.data.mappings.Dimension; -import de.bixilon.minosoft.data.mappings.tweaker.VersionTweaker; -import de.bixilon.minosoft.data.world.BlockPosition; -import de.bixilon.minosoft.data.world.Chunk; -import de.bixilon.minosoft.data.world.ChunkLocation; -import de.bixilon.minosoft.data.world.biome.BiomeAccessor; -import de.bixilon.minosoft.data.world.biome.NoiseBiomeAccessor; -import de.bixilon.minosoft.modding.event.events.BlockEntityMetaDataChangeEvent; -import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent; -import de.bixilon.minosoft.protocol.network.Connection; -import de.bixilon.minosoft.protocol.packets.ClientboundPacket; -import de.bixilon.minosoft.protocol.protocol.InByteBuffer; -import de.bixilon.minosoft.util.ChunkUtil; -import de.bixilon.minosoft.util.Util; -import de.bixilon.minosoft.util.logging.Log; -import de.bixilon.minosoft.util.nbt.tag.CompoundTag; - -import java.util.HashMap; - -import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*; - -public class PacketChunkData extends ClientboundPacket { - private final HashMap blockEntities = new HashMap<>(); - private ChunkLocation location; - private Chunk chunk; - private CompoundTag heightMap; - private boolean ignoreOldData; - - @Override - public boolean read(InByteBuffer buffer) { - Dimension dimension = buffer.getConnection().getPlayer().getWorld().getDimension(); - this.location = new ChunkLocation(buffer.readInt(), buffer.readInt()); - - boolean fullChunk = true; - if (buffer.getVersionId() < V_20W45A) { - fullChunk = buffer.readBoolean(); - } - - if (buffer.getVersionId() < V_14W26A) { - long[] sectionBitMasks = {buffer.readUnsignedShort()}; - int addBitMask = buffer.readUnsignedShort(); - - // decompress chunk data - InByteBuffer decompressed; - if (buffer.getVersionId() < V_14W28A) { - decompressed = Util.decompress(buffer.readBytes(buffer.readInt()), buffer.getConnection()); - } else { - decompressed = buffer; - } - - this.chunk = ChunkUtil.readChunkPacket(decompressed, dimension, sectionBitMasks, addBitMask, fullChunk, dimension.getHasSkyLight()); - return true; - } - long[] sectionBitMasks; - if (buffer.getVersionId() < V_15W34C) { - sectionBitMasks = new long[]{buffer.readUnsignedShort()}; - } else if (buffer.getVersionId() < V_15W36D) { - sectionBitMasks = new long[]{buffer.readInt()}; - } else if (buffer.getVersionId() < V_21W03A) { - sectionBitMasks = new long[]{buffer.readVarInt()}; - } else { - sectionBitMasks = buffer.readLongArray(); - } - - if (buffer.getVersionId() >= V_1_16_PRE7 && buffer.getVersionId() < V_1_16_2_PRE2) { - this.ignoreOldData = buffer.readBoolean(); - } - - if (buffer.getVersionId() >= V_18W44A) { - this.heightMap = (CompoundTag) buffer.readNBT(); - } - BiomeAccessor biomeAccessor = null; - if (fullChunk) { - biomeAccessor = new NoiseBiomeAccessor(buffer.readBiomeArray()); - } - - int size = buffer.readVarInt(); - int lastPos = buffer.getPosition(); - - - if (size > 0) { - this.chunk = ChunkUtil.readChunkPacket(buffer, dimension, sectionBitMasks, 0, fullChunk, dimension.getHasSkyLight()); - if (this.chunk != null) { - if (biomeAccessor != null) { - this.chunk.setBiomeAccessor(biomeAccessor); - } - } - // 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.setPosition(size + lastPos); - } - if (buffer.getVersionId() >= V_1_9_4) { - int blockEntitiesCount = buffer.readVarInt(); - for (int i = 0; i < blockEntitiesCount; i++) { - CompoundTag tag = (CompoundTag) buffer.readNBT(); - BlockEntityMetaData data = BlockEntityMetaData.getData(buffer.getConnection(), null, tag); - if (data == null) { - continue; - } - this.blockEntities.put(new BlockPosition(tag.getIntTag("x").getValue(), (short) tag.getIntTag("y").getValue(), tag.getIntTag("z").getValue()), data); - } - } - return true; - } - - @Override - public void handle(Connection connection) { - getBlockEntities().forEach(((position, compoundTag) -> connection.fireEvent(new BlockEntityMetaDataChangeEvent(connection, position, null, compoundTag)))); - VersionTweaker.transformChunk(this.chunk, connection.getVersion().getVersionId()); - - connection.fireEvent(new ChunkDataChangeEvent(connection, this)); - - connection.getPlayer().getWorld().setChunk(getLocation(), getChunk()); - connection.getPlayer().getWorld().setBlockEntityData(getBlockEntities()); - connection.getRenderer().getRenderWindow().getWorldRenderer().prepareChunk(this.location, this.chunk); - } - - @Override - public void log() { - Log.protocol(String.format("[IN] Chunk packet received (chunk: %s)", this.location)); - } - - public ChunkLocation getLocation() { - return this.location; - } - - public Chunk getChunk() { - return this.chunk; - } - - public HashMap getBlockEntities() { - return this.blockEntities; - } - - public CompoundTag getHeightMap() { - return this.heightMap; - } -} diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.kt new file mode 100644 index 000000000..153eac603 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketChunkData.kt @@ -0,0 +1,117 @@ +/* + * 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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ +package de.bixilon.minosoft.protocol.packets.clientbound.play + +import de.bixilon.minosoft.data.entities.block.BlockEntityMetaData +import de.bixilon.minosoft.data.mappings.tweaker.VersionTweaker +import de.bixilon.minosoft.data.world.BlockPosition +import de.bixilon.minosoft.data.world.ChunkData +import de.bixilon.minosoft.data.world.ChunkLocation +import de.bixilon.minosoft.data.world.biome.NoiseBiomeAccessor +import de.bixilon.minosoft.modding.event.events.BlockEntityMetaDataChangeEvent +import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent +import de.bixilon.minosoft.protocol.network.Connection +import de.bixilon.minosoft.protocol.packets.ClientboundPacket +import de.bixilon.minosoft.protocol.protocol.InByteBuffer +import de.bixilon.minosoft.protocol.protocol.ProtocolVersions +import de.bixilon.minosoft.util.ChunkUtil +import de.bixilon.minosoft.util.Util +import de.bixilon.minosoft.util.logging.Log +import de.bixilon.minosoft.util.nbt.tag.CompoundTag +import java.util.* + +class PacketChunkData : ClientboundPacket() { + private val blockEntities = HashMap() + lateinit var location: ChunkLocation + val chunkData: ChunkData = ChunkData() + var heightMap: CompoundTag? = null + private var shouldMerge = false + + override fun read(buffer: InByteBuffer): Boolean { + val dimension = buffer.connection.player.world.dimension + location = ChunkLocation(buffer.readInt(), buffer.readInt()) + if (buffer.versionId < ProtocolVersions.V_20W45A) { + shouldMerge = !buffer.readBoolean() + } + if (buffer.versionId < ProtocolVersions.V_14W26A) { + val sectionBitMasks = longArrayOf(buffer.readUnsignedShort().toLong()) + val addBitMask = buffer.readUnsignedShort() + + // decompress chunk data + val decompressed: InByteBuffer = if (buffer.versionId < ProtocolVersions.V_14W28A) { + Util.decompress(buffer.readBytes(buffer.readInt()), buffer.connection) + } else { + buffer + } + chunkData.replace(ChunkUtil.readChunkPacket(decompressed, dimension, sectionBitMasks, addBitMask, !shouldMerge, dimension!!.hasSkyLight)) + return true + } + val sectionBitMasks: LongArray = when { + buffer.versionId < ProtocolVersions.V_15W34C -> { + longArrayOf(buffer.readUnsignedShort().toLong()) + } + buffer.versionId < ProtocolVersions.V_15W36D -> { + longArrayOf(buffer.readInt().toLong()) + } + buffer.versionId < ProtocolVersions.V_21W03A -> { + longArrayOf(buffer.readVarInt().toLong()) + } + else -> { + buffer.readLongArray() + } + } + if (buffer.versionId >= ProtocolVersions.V_1_16_PRE7 && buffer.versionId < ProtocolVersions.V_1_16_2_PRE2) { + shouldMerge = buffer.readBoolean() + } + if (buffer.versionId >= ProtocolVersions.V_18W44A) { + heightMap = buffer.readNBT() as CompoundTag + } + if (!shouldMerge) { + chunkData.biomeAccessor = NoiseBiomeAccessor(buffer.readBiomeArray()) + } + val size = buffer.readVarInt() + val lastPos = buffer.position + if (size > 0) { + chunkData.replace(ChunkUtil.readChunkPacket(buffer, dimension, sectionBitMasks, 0, !shouldMerge, dimension!!.hasSkyLight)) + // 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.position = size + lastPos + } + if (buffer.versionId >= ProtocolVersions.V_1_9_4) { + val blockEntitiesCount = buffer.readVarInt() + for (i in 0 until blockEntitiesCount) { + val tag = buffer.readNBT() as CompoundTag + val data = BlockEntityMetaData.getData(buffer.connection, null, tag) ?: continue + blockEntities[BlockPosition(tag.getNumberTag("x").asInt, tag.getNumberTag("y").asInt, tag.getNumberTag("z").asInt)] = data + } + } + return true + } + + override fun handle(connection: Connection) { + for ((position, blockEntityMetaData) in blockEntities) { + connection.fireEvent(BlockEntityMetaDataChangeEvent(connection, position, null, blockEntityMetaData)) + } + chunkData.blocks?.let { + VersionTweaker.transformSections(it, connection.version.versionId) + } + connection.fireEvent(ChunkDataChangeEvent(connection, this)) + val chunk = connection.player.world.getOrCreateChunk(location) + chunk.setData(chunkData) + connection.player.world.setBlockEntityData(blockEntities) + connection.renderer.renderWindow.worldRenderer.prepareChunk(location, chunk) + } + + override fun log() { + Log.protocol(String.format("[IN] Chunk packet received (chunk: %s)", location)) + } +} diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketMultiBlockChange.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketMultiBlockChange.java index 565883f96..b834c601e 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketMultiBlockChange.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketMultiBlockChange.java @@ -94,7 +94,7 @@ public class PacketMultiBlockChange extends ClientboundPacket { // tweak if (!connection.getVersion().isFlattened()) { for (Map.Entry entry : getBlocks().entrySet()) { - BlockState block = VersionTweaker.transformBlock(entry.getValue(), chunk, entry.getKey().getInChunkSectionLocation(), entry.getKey().getSectionHeight()); + BlockState block = VersionTweaker.transformBlock(entry.getValue(), chunk.getSections(), entry.getKey().getInChunkSectionLocation(), entry.getKey().getSectionHeight()); if (block == entry.getValue()) { continue; } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketRespawn.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketRespawn.kt index ed0417096..6660e74b8 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketRespawn.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketRespawn.kt @@ -87,7 +87,7 @@ class PacketRespawn : ClientboundPacket() { } // clear all chunks - connection.player.world.allChunks.clear() + connection.player.world.chunks.clear() connection.player.world.dimension = dimension connection.player.isSpawnConfirmed = false connection.player.gameMode = gameMode diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketUpdateLight.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketUpdateLight.java index e3a136b35..9ca3e38dd 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketUpdateLight.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketUpdateLight.java @@ -13,7 +13,10 @@ package de.bixilon.minosoft.protocol.packets.clientbound.play; +import de.bixilon.minosoft.data.world.Chunk; import de.bixilon.minosoft.data.world.ChunkLocation; +import de.bixilon.minosoft.data.world.light.LightAccessor; +import de.bixilon.minosoft.protocol.network.Connection; import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.protocol.InByteBuffer; import de.bixilon.minosoft.util.ChunkUtil; @@ -23,7 +26,8 @@ import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_1_16_PRE3 import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_20W49A; public class PacketUpdateLight extends ClientboundPacket { - ChunkLocation location; + private ChunkLocation location; + private LightAccessor lightAccessor; @Override public boolean read(InByteBuffer buffer) { @@ -48,7 +52,7 @@ public class PacketUpdateLight extends ClientboundPacket { emptySkyLightMask = buffer.readLongArray(); emptyBlockLightMask = buffer.readLongArray(); } - ChunkUtil.readSkyLightPacket(buffer, skyLightMask, blockLightMask, emptyBlockLightMask, emptySkyLightMask); + this.lightAccessor = ChunkUtil.readSkyLightPacket(buffer, skyLightMask, blockLightMask, emptyBlockLightMask, emptySkyLightMask); return true; } @@ -56,4 +60,11 @@ public class PacketUpdateLight extends ClientboundPacket { public void log() { Log.protocol(String.format("[IN] Received light update (location=%s)", this.location)); } + + @Override + public void handle(Connection connection) { + Chunk chunk = connection.getPlayer().getWorld().getOrCreateChunk(this.location); + chunk.setLightAccessor(this.lightAccessor); + connection.getRenderer().getRenderWindow().getWorldRenderer().prepareChunk(this.location, chunk); + } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.java index a84ed7f35..a5b38e1f2 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.java @@ -35,6 +35,7 @@ import de.bixilon.minosoft.data.mappings.particle.data.ParticleData; import de.bixilon.minosoft.data.mappings.recipes.Ingredient; import de.bixilon.minosoft.data.text.ChatComponent; import de.bixilon.minosoft.data.world.BlockPosition; +import de.bixilon.minosoft.data.world.ChunkLocation; import de.bixilon.minosoft.protocol.network.Connection; import de.bixilon.minosoft.util.Util; import de.bixilon.minosoft.util.nbt.tag.*; @@ -591,4 +592,7 @@ public class InByteBuffer { return new ResourceLocation(resourceLocation); } + public ChunkLocation readChunkLocation() { + return new ChunkLocation(readInt(), readInt()); + } } diff --git a/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java b/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java index 0c73eebc6..7bbe82c7e 100644 --- a/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java +++ b/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java @@ -17,12 +17,13 @@ import de.bixilon.minosoft.data.mappings.Dimension; import de.bixilon.minosoft.data.mappings.biomes.Biome; import de.bixilon.minosoft.data.mappings.blocks.BlockState; import de.bixilon.minosoft.data.world.BlockInfo; -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.InChunkSectionLocation; -import de.bixilon.minosoft.data.world.biome.BiomeAccessor; import de.bixilon.minosoft.data.world.biome.DummyBiomeAccessor; import de.bixilon.minosoft.data.world.biome.XZBiomeAccessor; +import de.bixilon.minosoft.data.world.light.DummyLightAccessor; +import de.bixilon.minosoft.data.world.light.LightAccessor; import de.bixilon.minosoft.data.world.palette.Palette; import de.bixilon.minosoft.protocol.protocol.InByteBuffer; import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition; @@ -33,7 +34,7 @@ import java.util.HashMap; import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*; public final class ChunkUtil { - public static Chunk readChunkPacket(InByteBuffer buffer, Dimension dimension, long[] sectionBitMasks, int addBitMask, boolean fullChunk, boolean containsSkyLight) { + public static ChunkData readChunkPacket(InByteBuffer buffer, Dimension dimension, long[] sectionBitMasks, int addBitMask, boolean fullChunk, boolean containsSkyLight) { if (buffer.getVersionId() < V_14W26A) { if (sectionBitMasks[0] == 0x00 && fullChunk) { // unload chunk @@ -97,7 +98,7 @@ public final class ChunkUtil { sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap)); // ToDo } } - return new Chunk(sectionMap, new DummyBiomeAccessor(buffer.getConnection().getMapping().getBiomeRegistry().get(0))); + return new ChunkData(sectionMap, new DummyBiomeAccessor(buffer.getConnection().getMapping().getBiomeRegistry().get(0)), DummyLightAccessor.INSTANCE); } if (buffer.getVersionId() < V_15W35A) { // ToDo: was this really changed in 62? byte sections = BitByte.getBitCount(sectionBitMasks[0]); @@ -143,7 +144,7 @@ public final class ChunkUtil { } sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap)); } - return new Chunk(sectionMap, new DummyBiomeAccessor(buffer.getConnection().getMapping().getBiomeRegistry().get(0))); // ToDo + return new ChunkData(sectionMap, new DummyBiomeAccessor(buffer.getConnection().getMapping().getBiomeRegistry().get(0)), DummyLightAccessor.INSTANCE); // ToDo } // really big thanks to: https://wiki.vg/index.php?title=Chunk_Format&oldid=13712 HashMap sectionMap = new HashMap<>(); @@ -155,7 +156,7 @@ public final class ChunkUtil { if (buffer.getVersionId() >= V_18W43A) { buffer.readShort(); // block count } - Palette palette = Palette.choosePalette(buffer.readUnsignedByte()); + Palette palette = Palette.Companion.choosePalette(buffer.readUnsignedByte()); palette.read(buffer); int individualValueMask = ((1 << palette.getBitsPerBlock()) - 1); @@ -206,21 +207,23 @@ public final class ChunkUtil { sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap)); } - BiomeAccessor biomeAccessor = new DummyBiomeAccessor(buffer.getConnection().getMapping().getBiomeRegistry().get(0)); + ChunkData chunkData = new ChunkData(); + chunkData.setBlocks(sectionMap); if (buffer.getVersionId() < V_19W36A && fullChunk) { Biome[] biomes = new Biome[256]; for (int i = 0; i < biomes.length; i++) { biomes[i] = buffer.getConnection().getMapping().getBiomeRegistry().get(buffer.readInt()); } - biomeAccessor = new XZBiomeAccessor(biomes); + chunkData.setBiomeAccessor(new XZBiomeAccessor(biomes)); } - return new Chunk(sectionMap, biomeAccessor); + return chunkData; } - public static void readSkyLightPacket(InByteBuffer buffer, long[] skyLightMask, long[] blockLightMask, long[] emptyBlockLightMask, long[] emptySkyLightMask) { + public static LightAccessor readSkyLightPacket(InByteBuffer buffer, long[] skyLightMask, long[] blockLightMask, long[] emptyBlockLightMask, long[] emptySkyLightMask) { readLightArray(buffer, BitSet.valueOf(skyLightMask)); readLightArray(buffer, BitSet.valueOf(blockLightMask)); // ToDo + return DummyLightAccessor.INSTANCE; } private static void readLightArray(InByteBuffer buffer, BitSet lightMask) { diff --git a/src/main/resources/assets/rendering/shader/chunk_fragment.glsl b/src/main/resources/assets/rendering/shader/chunk_fragment.glsl index 0a35b606b..02fc76210 100644 --- a/src/main/resources/assets/rendering/shader/chunk_fragment.glsl +++ b/src/main/resources/assets/rendering/shader/chunk_fragment.glsl @@ -17,6 +17,7 @@ out vec4 outColor; in vec3 passTextureCoordinates; in vec4 passTintColor; +in float passLightLevel; uniform sampler2DArray blockTextureArray; @@ -30,5 +31,5 @@ void main() { if (passTintColor.a > 0.0f){ mixedColor *= passTintColor.rgb; } - outColor = vec4(mixedColor, texelColor.a); + outColor = vec4(mixedColor * passLightLevel, texelColor.a); } diff --git a/src/main/resources/assets/rendering/shader/chunk_vertex.glsl b/src/main/resources/assets/rendering/shader/chunk_vertex.glsl index 25f410998..10325ddc9 100644 --- a/src/main/resources/assets/rendering/shader/chunk_vertex.glsl +++ b/src/main/resources/assets/rendering/shader/chunk_vertex.glsl @@ -20,9 +20,11 @@ layout (location = 2) in int textureLayer; layout (location = 3) in vec3 animatedTextureData; layout (location = 4) in uint tintColor; +layout (location = 5) in float lightLevel; out vec3 passTextureCoordinates; out vec4 passTintColor; +out float passLightLevel; uniform mat4 viewProjectionMatrix; uniform int animationTick; @@ -32,6 +34,8 @@ void main() { gl_Position = viewProjectionMatrix * vec4(inPosition, 1.0f); passTintColor = vec4(((tintColor >> 24u) & 0xFFu) / 255.0f, ((tintColor >> 16u) & 0xFFu) / 255.0f, ((tintColor >> 8u) & 0xFFu) / 255.0f, (tintColor & 0xFFu) / 255.0f); + passLightLevel = lightLevel; + if (animatedTextureData.y == 1.0f) { passTextureCoordinates = vec3(textureIndex, textureLayer); return;