mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-16 10:55:01 -04:00
rendering: wip lightning, change chunk saving structure
This commit is contained in:
parent
7fe1a40fc5
commit
4c49c733cd
@ -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.ResourceLocation
|
||||||
import de.bixilon.minosoft.data.mappings.blocks.BlockState
|
import de.bixilon.minosoft.data.mappings.blocks.BlockState
|
||||||
import de.bixilon.minosoft.data.world.BlockInfo
|
import de.bixilon.minosoft.data.world.BlockInfo
|
||||||
import de.bixilon.minosoft.data.world.Chunk
|
import de.bixilon.minosoft.data.world.ChunkSection
|
||||||
import de.bixilon.minosoft.data.world.InChunkLocation
|
|
||||||
import de.bixilon.minosoft.data.world.InChunkSectionLocation
|
import de.bixilon.minosoft.data.world.InChunkSectionLocation
|
||||||
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
|
||||||
@ -88,14 +87,14 @@ object VersionTweaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun transformChunk(chunk: Chunk, versionId: Int): Chunk {
|
fun transformSections(sections: Map<Int, ChunkSection>, versionId: Int) {
|
||||||
// some blocks need to be tweaked. eg. Grass with a snow block on top becomes snowy grass block
|
// some blocks need to be tweaked. eg. Grass with a snow block on top becomes snowy grass block
|
||||||
if (versionId >= ProtocolDefinition.FLATTING_VERSION_ID) {
|
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) {
|
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) {
|
if (newBlock === blockInfo.block) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -106,16 +105,15 @@ object VersionTweaker {
|
|||||||
section.setBlockInfo(location, BlockInfo(newBlock, blockInfo.metaData))
|
section.setBlockInfo(location, BlockInfo(newBlock, blockInfo.metaData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return chunk
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ToDo: Broken
|
// ToDo: Broken
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun transformBlock(originalBlock: BlockState, chunk: Chunk, location: InChunkSectionLocation, sectionHeight: Int): BlockState? {
|
fun transformBlock(originalBlock: BlockState, sections: Map<Int, ChunkSection>, location: InChunkSectionLocation, sectionHeight: Int): BlockState? {
|
||||||
when (originalBlock.owner.resourceLocation) {
|
when (originalBlock.owner.resourceLocation) {
|
||||||
ResourceLocation("minecraft:grass") -> {
|
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) {
|
if (it.owner.resourceLocation == TweakBlocks.SNOW_RESOURCE_LOCATION || it.owner.resourceLocation == TweakBlocks.SNOW_LAYER_RESOURCE_LOCAION) {
|
||||||
return TweakBlocks.GRASS_BLOCK_SNOWY_YES
|
return TweakBlocks.GRASS_BLOCK_SNOWY_YES
|
||||||
}
|
}
|
||||||
@ -126,8 +124,7 @@ object VersionTweaker {
|
|||||||
return originalBlock
|
return originalBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getBlockAbove(chunk: Chunk, location: InChunkSectionLocation, sectionHeight: Int): BlockState? {
|
private fun getBlockAbove(sections: Map<Int, ChunkSection>, location: InChunkSectionLocation, sectionHeight: Int): BlockState? {
|
||||||
val above = location.getInChunkLocation(sectionHeight)
|
return sections[sectionHeight]?.getBlockInfo(location)?.block
|
||||||
return chunk.getBlockInfo(InChunkLocation(above.x, above.y + 1, above.z))?.block
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
package de.bixilon.minosoft.data.world
|
package de.bixilon.minosoft.data.world
|
||||||
|
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
data class BlockPosition(val x: Int, val y: Int, val z: Int) {
|
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
|
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 {
|
override fun toString(): String {
|
||||||
return "($x $y $z)"
|
return "($x $y $z)"
|
||||||
}
|
}
|
||||||
|
@ -14,18 +14,25 @@ package de.bixilon.minosoft.data.world
|
|||||||
|
|
||||||
import de.bixilon.minosoft.data.mappings.blocks.BlockState
|
import de.bixilon.minosoft.data.mappings.blocks.BlockState
|
||||||
import de.bixilon.minosoft.data.world.biome.BiomeAccessor
|
import de.bixilon.minosoft.data.world.biome.BiomeAccessor
|
||||||
|
import de.bixilon.minosoft.data.world.light.LightAccessor
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of chunks sections (allocated in y)
|
* Collection of chunks sections (allocated in y)
|
||||||
*/
|
*/
|
||||||
class Chunk(
|
class Chunk(
|
||||||
val sections: MutableMap<Int, ChunkSection> = mutableMapOf(),
|
var sections: MutableMap<Int, ChunkSection>? = null,
|
||||||
var biomeAccessor: BiomeAccessor,
|
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? {
|
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? {
|
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<InChunkLocation, BlockState?>) {
|
fun setRawBlocks(blocks: HashMap<InChunkLocation, BlockState?>) {
|
||||||
for ((location, blockInfo) in blocks) {
|
for ((location, blockInfo) in blocks) {
|
||||||
setRawBlock(location, blockInfo)
|
setRawBlock(location, blockInfo)
|
||||||
@ -61,11 +91,14 @@ class Chunk(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getSectionOrCreate(sectionHeight: Int): ChunkSection {
|
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
|
var section = it
|
||||||
if (section == null) {
|
if (section == null) {
|
||||||
section = ChunkSection()
|
section = ChunkSection()
|
||||||
sections[sectionHeight] = section
|
sections!![sectionHeight] = section
|
||||||
}
|
}
|
||||||
section
|
section
|
||||||
}
|
}
|
||||||
|
35
src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt
Normal file
35
src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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<Int, ChunkSection>? = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -37,10 +37,6 @@ class ChunkSection constructor(
|
|||||||
return getBlockInfo(InChunkSectionLocation(x, y, z))
|
return getBlockInfo(InChunkSectionLocation(x, y, z))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateStaticData() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setRawBlock(location: InChunkSectionLocation, block: BlockState?) {
|
fun setRawBlock(location: InChunkSectionLocation, block: BlockState?) {
|
||||||
if (block == null) {
|
if (block == null) {
|
||||||
setBlockInfo(location, null)
|
setBlockInfo(location, null)
|
||||||
@ -48,4 +44,11 @@ class ChunkSection constructor(
|
|||||||
}
|
}
|
||||||
setBlockInfo(location, BlockInfo(block))
|
setBlockInfo(location, BlockInfo(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setData(chunkSection: ChunkSection, merge: Boolean = false) {
|
||||||
|
if (!merge) {
|
||||||
|
this.blocks.clear()
|
||||||
|
}
|
||||||
|
this.blocks.putAll(chunkSection.blocks)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* 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<ChunkLocation, Chunk> chunks = new ConcurrentHashMap<>();
|
|
||||||
private final HashBiMap<Integer, Entity> entityIdMap = HashBiMap.create();
|
|
||||||
private final HashBiMap<UUID, Entity> entityUUIDMap = HashBiMap.create();
|
|
||||||
private boolean hardcore;
|
|
||||||
private boolean raining;
|
|
||||||
private Dimension dimension; // used for sky color, etc
|
|
||||||
|
|
||||||
public ConcurrentHashMap<ChunkLocation, Chunk> 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<ChunkLocation, Chunk> 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<BlockPosition, BlockEntityMetaData> blockEntities) {
|
|
||||||
blockEntities.forEach(this::setBlockEntityData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashBiMap<Integer, Entity> getEntityIdMap() {
|
|
||||||
return this.entityIdMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashBiMap<UUID, Entity> getEntityUUIDMap() {
|
|
||||||
return this.entityUUIDMap;
|
|
||||||
}
|
|
||||||
}
|
|
105
src/main/java/de/bixilon/minosoft/data/world/World.kt
Normal file
105
src/main/java/de/bixilon/minosoft/data/world/World.kt
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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<ChunkLocation, Chunk>()
|
||||||
|
val entityIdMap = HashBiMap.create<Int, Entity>()
|
||||||
|
val entityUUIDMap = HashBiMap.create<UUID, Entity>()
|
||||||
|
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<ChunkLocation, Chunk>) {
|
||||||
|
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<BlockPosition, BlockEntityMetaData>) {
|
||||||
|
for ((blockPosition, entityMetaData) in blockEntities) {
|
||||||
|
setBlockEntityData(blockPosition, entityMetaData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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.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<InChunkLocation, Byte> = mutableMapOf(),
|
||||||
|
val skyLightLevel: MutableMap<InChunkLocation, Byte> = mutableMapOf(),
|
||||||
|
) : LightAccessor {
|
||||||
|
override fun getLightLevel(blockPosition: BlockPosition, direction: Directions): Int {
|
||||||
|
val inChunkLocation = blockPosition.getInChunkLocation()
|
||||||
|
return blockLightLevel[inChunkLocation]?.toInt() ?: 0
|
||||||
|
}
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
}
|
@ -10,25 +10,27 @@
|
|||||||
*
|
*
|
||||||
* 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
|
||||||
|
|
||||||
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;
|
interface Palette {
|
||||||
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
|
|
||||||
|
|
||||||
public interface Palette {
|
fun blockById(id: Int): BlockState?
|
||||||
static Palette choosePalette(int bitsPerBlock) {
|
|
||||||
if (bitsPerBlock <= 4) {
|
val bitsPerBlock: Int
|
||||||
return new IndirectPalette(4);
|
|
||||||
} else if (bitsPerBlock <= 8) {
|
fun read(buffer: InByteBuffer)
|
||||||
return new IndirectPalette(bitsPerBlock);
|
|
||||||
|
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);
|
|
||||||
}
|
}
|
@ -29,7 +29,7 @@ class ChunkMesh {
|
|||||||
private var vbo: Int = 0
|
private var vbo: Int = 0
|
||||||
private var trianglesCount: 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.x)
|
||||||
data.add(position.y)
|
data.add(position.y)
|
||||||
data.add(position.z)
|
data.add(position.z)
|
||||||
@ -47,6 +47,8 @@ class ChunkMesh {
|
|||||||
} else {
|
} else {
|
||||||
data.add(Float.fromBits(tintColor.color))
|
data.add(Float.fromBits(tintColor.color))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.add(lightLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun load() {
|
fun load() {
|
||||||
@ -74,6 +76,9 @@ class ChunkMesh {
|
|||||||
glVertexAttribPointer(index, 1, GL_FLOAT, false, FLOATS_PER_VERTEX * Float.BYTES, (9 * Float.BYTES).toLong())
|
glVertexAttribPointer(index, 1, GL_FLOAT, false, FLOATS_PER_VERTEX * Float.BYTES, (9 * Float.BYTES).toLong())
|
||||||
glEnableVertexAttribArray(index++)
|
glEnableVertexAttribArray(index++)
|
||||||
|
|
||||||
|
glVertexAttribPointer(index, 1, GL_FLOAT, false, FLOATS_PER_VERTEX * Float.BYTES, (10 * Float.BYTES).toLong())
|
||||||
|
glEnableVertexAttribArray(index++)
|
||||||
|
|
||||||
// don't remove the ++ above!
|
// don't remove the ++ above!
|
||||||
index.let { }
|
index.let { }
|
||||||
|
|
||||||
@ -92,6 +97,6 @@ class ChunkMesh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val FLOATS_PER_VERTEX = 10
|
private const val FLOATS_PER_VERTEX = 11
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,8 @@ class Frustum(val camera: Camera) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun containsChunk(chunkLocation: ChunkLocation, connection: Connection): Boolean {
|
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 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 to = from + Vec3(ProtocolDefinition.SECTION_WIDTH_X, connection.player.world.dimension!!.logicalHeight, ProtocolDefinition.SECTION_WIDTH_Z)
|
||||||
val frustum = Frustum(connection.renderer.renderWindow.camera)
|
val frustum = Frustum(connection.renderer.renderWindow.camera)
|
||||||
return frustum.containsRegion(from, to)
|
return frustum.containsRegion(from, to)
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import de.bixilon.minosoft.gui.rendering.textures.TextureArray
|
|||||||
import de.bixilon.minosoft.protocol.network.Connection
|
import de.bixilon.minosoft.protocol.network.Connection
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
import de.bixilon.minosoft.util.logging.Log
|
import de.bixilon.minosoft.util.logging.Log
|
||||||
import glm_.vec3.Vec3
|
|
||||||
import org.lwjgl.opengl.GL11.GL_CULL_FACE
|
import org.lwjgl.opengl.GL11.GL_CULL_FACE
|
||||||
import org.lwjgl.opengl.GL11.glEnable
|
import org.lwjgl.opengl.GL11.glEnable
|
||||||
import org.lwjgl.opengl.GL13.glDisable
|
import org.lwjgl.opengl.GL13.glDisable
|
||||||
@ -48,16 +47,16 @@ class WorldRenderer(private val connection: Connection, private val world: World
|
|||||||
}
|
}
|
||||||
val mesh = ChunkMesh()
|
val mesh = ChunkMesh()
|
||||||
|
|
||||||
val below = world.allChunks[chunkLocation]?.sections?.get(sectionHeight - 1)
|
val below = world.chunks[chunkLocation]?.sections?.get(sectionHeight - 1)
|
||||||
val above = world.allChunks[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 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 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 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 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 north = world.chunks[chunkLocation.getLocationByDirection(Directions.NORTH)]?.sections?.get(sectionHeight)
|
||||||
val south = world.allChunks[chunkLocation.getLocationByDirection(Directions.SOUTH)]?.sections?.get(sectionHeight)
|
val south = world.chunks[chunkLocation.getLocationByDirection(Directions.SOUTH)]?.sections?.get(sectionHeight)
|
||||||
val west = world.allChunks[chunkLocation.getLocationByDirection(Directions.WEST)]?.sections?.get(sectionHeight)
|
val west = world.chunks[chunkLocation.getLocationByDirection(Directions.WEST)]?.sections?.get(sectionHeight)
|
||||||
val east = world.allChunks[chunkLocation.getLocationByDirection(Directions.EAST)]?.sections?.get(sectionHeight)
|
val east = world.chunks[chunkLocation.getLocationByDirection(Directions.EAST)]?.sections?.get(sectionHeight)
|
||||||
|
|
||||||
for ((position, blockInfo) in section.blocks) {
|
for ((position, blockInfo) in section.blocks) {
|
||||||
val blockBelow: BlockInfo? = if (position.y == 0 && below != null) {
|
val blockBelow: BlockInfo? = if (position.y == 0 && below != null) {
|
||||||
@ -90,13 +89,11 @@ class WorldRenderer(private val connection: Connection, private val world: World
|
|||||||
} else {
|
} else {
|
||||||
section.getBlockInfo(position.getLocationByDirection(Directions.EAST))
|
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)
|
val blockPosition = BlockPosition(chunkLocation, sectionHeight, position)
|
||||||
if (blockPosition == BlockPosition(-103, 3, 288)) {
|
if (blockPosition == BlockPosition(-103, 3, 288)) {
|
||||||
Log.debug("")
|
Log.debug("")
|
||||||
}
|
}
|
||||||
val biome = chunk.biomeAccessor.getBiome(blockPosition)
|
val biome = chunk.biomeAccessor!!.getBiome(blockPosition)
|
||||||
|
|
||||||
var tintColor: RGBColor? = null
|
var tintColor: RGBColor? = null
|
||||||
if (StaticConfiguration.BIOME_DEBUG_MODE) {
|
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.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
|
return mesh
|
||||||
}
|
}
|
||||||
@ -145,7 +142,7 @@ class WorldRenderer(private val connection: Connection, private val world: World
|
|||||||
}
|
}
|
||||||
|
|
||||||
for ((chunkLocation, map) in chunkSectionsToDraw) {
|
for ((chunkLocation, map) in chunkSectionsToDraw) {
|
||||||
if (! visibleChunks.contains(chunkLocation)) {
|
if (!visibleChunks.contains(chunkLocation)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for ((_, mesh) in map) {
|
for ((_, mesh) in map) {
|
||||||
@ -171,7 +168,10 @@ class WorldRenderer(private val connection: Connection, private val world: World
|
|||||||
|
|
||||||
fun prepareChunk(chunkLocation: ChunkLocation, chunk: Chunk) {
|
fun prepareChunk(chunkLocation: ChunkLocation, chunk: Chunk) {
|
||||||
chunkSectionsToDraw[chunkLocation] = ConcurrentHashMap()
|
chunkSectionsToDraw[chunkLocation] = ConcurrentHashMap()
|
||||||
for ((sectionHeight, section) in chunk.sections) {
|
if (!chunk.isFullyLoaded) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for ((sectionHeight, section) in chunk.sections!!) {
|
||||||
prepareChunkSection(chunkLocation, sectionHeight, section, chunk)
|
prepareChunkSection(chunkLocation, sectionHeight, section, chunk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,7 +217,7 @@ class WorldRenderer(private val connection: Connection, private val world: World
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun prepareWorld(world: World) {
|
private fun prepareWorld(world: World) {
|
||||||
for ((chunkLocation, chunk) in world.allChunks) {
|
for ((chunkLocation, chunk) in world.chunks) {
|
||||||
prepareChunk(chunkLocation, chunk)
|
prepareChunk(chunkLocation, chunk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,4 +236,8 @@ class WorldRenderer(private val connection: Connection, private val world: World
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getChunkSize(): Int {
|
||||||
|
return chunkSectionsToDraw.size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,12 @@ import com.google.gson.JsonObject
|
|||||||
import de.bixilon.minosoft.data.Directions
|
import de.bixilon.minosoft.data.Directions
|
||||||
import de.bixilon.minosoft.data.text.RGBColor
|
import de.bixilon.minosoft.data.text.RGBColor
|
||||||
import de.bixilon.minosoft.data.world.BlockInfo
|
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.ChunkMesh
|
||||||
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModel
|
import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModel
|
||||||
import de.bixilon.minosoft.gui.rendering.textures.Texture
|
import de.bixilon.minosoft.gui.rendering.textures.Texture
|
||||||
import glm_.mat4x4.Mat4
|
import glm_.mat4x4.Mat4
|
||||||
import glm_.vec3.Vec3
|
|
||||||
|
|
||||||
class BlockRenderer(data: JsonObject, parent: BlockModel) {
|
class BlockRenderer(data: JsonObject, parent: BlockModel) {
|
||||||
private val transparentFaces: MutableSet<Directions> = mutableSetOf()
|
private val transparentFaces: MutableSet<Directions> = mutableSetOf()
|
||||||
@ -70,8 +71,8 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun render(blockInfo: BlockInfo, tintColor: RGBColor?, position: Vec3, mesh: ChunkMesh, neighbourBlocks: Array<BlockInfo?>) {
|
fun render(blockInfo: BlockInfo, lightAccessor: LightAccessor, tintColor: RGBColor?, position: BlockPosition, mesh: ChunkMesh, neighbourBlocks: Array<BlockInfo?>) {
|
||||||
val modelMatrix = Mat4().translate(position)
|
val modelMatrix = Mat4().translate(position.toVec3())
|
||||||
|
|
||||||
for (direction in Directions.DIRECTIONS) {
|
for (direction in Directions.DIRECTIONS) {
|
||||||
for (element in elements) {
|
for (element in elements) {
|
||||||
@ -91,7 +92,7 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
element.render(tintColor, textureMapping, modelMatrix, direction, mesh)
|
element.render(tintColor, lightAccessor.getLightLevel(position, direction) / 15f, textureMapping, modelMatrix, direction, mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvLock: Boolea
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun render(tintColor: RGBColor?, textureMapping: MutableMap<String, Texture>, modelMatrix: Mat4, direction: Directions, mesh: ChunkMesh) {
|
fun render(tintColor: RGBColor?, lightLevel: Float, textureMapping: MutableMap<String, Texture>, modelMatrix: Mat4, direction: Directions, mesh: ChunkMesh) {
|
||||||
val realDirection = directionMapping[direction]!!
|
val realDirection = directionMapping[direction]!!
|
||||||
val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[realDirection.ordinal]
|
val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[realDirection.ordinal]
|
||||||
|
|
||||||
@ -75,7 +75,8 @@ class ElementRenderer(element: BlockModelElement, rotation: Vec3, uvLock: Boolea
|
|||||||
tintColor
|
tintColor
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
},
|
||||||
|
lightLevel = lightLevel,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ class HUDDebugScreenElement(private val hudTextElement: HUDTextElement) : HUDTex
|
|||||||
chatComponents[FontBindings.LEFT_UP]!!.addAll(listOf(
|
chatComponents[FontBindings.LEFT_UP]!!.addAll(listOf(
|
||||||
"FPS: ${getFPS()}",
|
"FPS: ${getFPS()}",
|
||||||
"Timings: avg ${getAvgFrameTime()}ms, min ${getMinFrameTime()}ms, max ${getMaxFrameTime()}ms",
|
"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}",
|
"Connected to ${hudTextElement.connection.address} with ${hudTextElement.connection.version}",
|
||||||
"",
|
"",
|
||||||
"XYZ ${getLocation()}",
|
"XYZ ${getLocation()}",
|
||||||
|
@ -32,9 +32,9 @@ class TextureArray(val textures: List<Texture>, val maxWidth: Int, val maxHeight
|
|||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT)
|
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_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)
|
||||||
|
// 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)
|
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?)
|
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) {
|
for (texture in textures) {
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
}
|
||||||
|
}
|
@ -57,7 +57,7 @@ public class PacketBlockChange extends ClientboundPacket {
|
|||||||
|
|
||||||
// tweak
|
// tweak
|
||||||
if (!connection.getVersion().isFlattened()) {
|
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);
|
section.setRawBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), block);
|
||||||
} else {
|
} else {
|
||||||
section.setRawBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), getBlock());
|
section.setRawBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), getBlock());
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* 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<ChunkLocation, Chunk> 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<ChunkLocation, Chunk> getChunks() {
|
|
||||||
return this.chunks;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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<ChunkLocation, ChunkData>()
|
||||||
|
|
||||||
|
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<LongArray>(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})")
|
||||||
|
}
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* 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<BlockPosition, BlockEntityMetaData> 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<BlockPosition, BlockEntityMetaData> getBlockEntities() {
|
|
||||||
return this.blockEntities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompoundTag getHeightMap() {
|
|
||||||
return this.heightMap;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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<BlockPosition, BlockEntityMetaData>()
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
@ -94,7 +94,7 @@ public class PacketMultiBlockChange extends ClientboundPacket {
|
|||||||
// tweak
|
// tweak
|
||||||
if (!connection.getVersion().isFlattened()) {
|
if (!connection.getVersion().isFlattened()) {
|
||||||
for (Map.Entry<InChunkLocation, BlockState> entry : getBlocks().entrySet()) {
|
for (Map.Entry<InChunkLocation, BlockState> 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()) {
|
if (block == entry.getValue()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ class PacketRespawn : ClientboundPacket() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// clear all chunks
|
// clear all chunks
|
||||||
connection.player.world.allChunks.clear()
|
connection.player.world.chunks.clear()
|
||||||
connection.player.world.dimension = dimension
|
connection.player.world.dimension = dimension
|
||||||
connection.player.isSpawnConfirmed = false
|
connection.player.isSpawnConfirmed = false
|
||||||
connection.player.gameMode = gameMode
|
connection.player.gameMode = gameMode
|
||||||
|
@ -13,7 +13,10 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.protocol.packets.clientbound.play;
|
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.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.packets.ClientboundPacket;
|
||||||
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
|
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
|
||||||
import de.bixilon.minosoft.util.ChunkUtil;
|
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;
|
import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_20W49A;
|
||||||
|
|
||||||
public class PacketUpdateLight extends ClientboundPacket {
|
public class PacketUpdateLight extends ClientboundPacket {
|
||||||
ChunkLocation location;
|
private ChunkLocation location;
|
||||||
|
private LightAccessor lightAccessor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean read(InByteBuffer buffer) {
|
public boolean read(InByteBuffer buffer) {
|
||||||
@ -48,7 +52,7 @@ public class PacketUpdateLight extends ClientboundPacket {
|
|||||||
emptySkyLightMask = buffer.readLongArray();
|
emptySkyLightMask = buffer.readLongArray();
|
||||||
emptyBlockLightMask = buffer.readLongArray();
|
emptyBlockLightMask = buffer.readLongArray();
|
||||||
}
|
}
|
||||||
ChunkUtil.readSkyLightPacket(buffer, skyLightMask, blockLightMask, emptyBlockLightMask, emptySkyLightMask);
|
this.lightAccessor = ChunkUtil.readSkyLightPacket(buffer, skyLightMask, blockLightMask, emptyBlockLightMask, emptySkyLightMask);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,4 +60,11 @@ public class PacketUpdateLight extends ClientboundPacket {
|
|||||||
public void log() {
|
public void log() {
|
||||||
Log.protocol(String.format("[IN] Received light update (location=%s)", this.location));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.mappings.recipes.Ingredient;
|
||||||
import de.bixilon.minosoft.data.text.ChatComponent;
|
import de.bixilon.minosoft.data.text.ChatComponent;
|
||||||
import de.bixilon.minosoft.data.world.BlockPosition;
|
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.protocol.network.Connection;
|
||||||
import de.bixilon.minosoft.util.Util;
|
import de.bixilon.minosoft.util.Util;
|
||||||
import de.bixilon.minosoft.util.nbt.tag.*;
|
import de.bixilon.minosoft.util.nbt.tag.*;
|
||||||
@ -591,4 +592,7 @@ public class InByteBuffer {
|
|||||||
return new ResourceLocation(resourceLocation);
|
return new ResourceLocation(resourceLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ChunkLocation readChunkLocation() {
|
||||||
|
return new ChunkLocation(readInt(), readInt());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.biomes.Biome;
|
||||||
import de.bixilon.minosoft.data.mappings.blocks.BlockState;
|
import de.bixilon.minosoft.data.mappings.blocks.BlockState;
|
||||||
import de.bixilon.minosoft.data.world.BlockInfo;
|
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.ChunkSection;
|
||||||
import de.bixilon.minosoft.data.world.InChunkSectionLocation;
|
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.DummyBiomeAccessor;
|
||||||
import de.bixilon.minosoft.data.world.biome.XZBiomeAccessor;
|
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.data.world.palette.Palette;
|
||||||
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
|
import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition;
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition;
|
||||||
@ -33,7 +34,7 @@ import java.util.HashMap;
|
|||||||
import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*;
|
import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*;
|
||||||
|
|
||||||
public final class ChunkUtil {
|
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 (buffer.getVersionId() < V_14W26A) {
|
||||||
if (sectionBitMasks[0] == 0x00 && fullChunk) {
|
if (sectionBitMasks[0] == 0x00 && fullChunk) {
|
||||||
// unload chunk
|
// unload chunk
|
||||||
@ -97,7 +98,7 @@ public final class ChunkUtil {
|
|||||||
sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap)); // ToDo
|
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?
|
if (buffer.getVersionId() < V_15W35A) { // ToDo: was this really changed in 62?
|
||||||
byte sections = BitByte.getBitCount(sectionBitMasks[0]);
|
byte sections = BitByte.getBitCount(sectionBitMasks[0]);
|
||||||
@ -143,7 +144,7 @@ public final class ChunkUtil {
|
|||||||
}
|
}
|
||||||
sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap));
|
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
|
// really big thanks to: https://wiki.vg/index.php?title=Chunk_Format&oldid=13712
|
||||||
HashMap<Integer, ChunkSection> sectionMap = new HashMap<>();
|
HashMap<Integer, ChunkSection> sectionMap = new HashMap<>();
|
||||||
@ -155,7 +156,7 @@ public final class ChunkUtil {
|
|||||||
if (buffer.getVersionId() >= V_18W43A) {
|
if (buffer.getVersionId() >= V_18W43A) {
|
||||||
buffer.readShort(); // block count
|
buffer.readShort(); // block count
|
||||||
}
|
}
|
||||||
Palette palette = Palette.choosePalette(buffer.readUnsignedByte());
|
Palette palette = Palette.Companion.choosePalette(buffer.readUnsignedByte());
|
||||||
palette.read(buffer);
|
palette.read(buffer);
|
||||||
int individualValueMask = ((1 << palette.getBitsPerBlock()) - 1);
|
int individualValueMask = ((1 << palette.getBitsPerBlock()) - 1);
|
||||||
|
|
||||||
@ -206,21 +207,23 @@ public final class ChunkUtil {
|
|||||||
|
|
||||||
sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap));
|
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) {
|
if (buffer.getVersionId() < V_19W36A && fullChunk) {
|
||||||
Biome[] biomes = new Biome[256];
|
Biome[] biomes = new Biome[256];
|
||||||
for (int i = 0; i < biomes.length; i++) {
|
for (int i = 0; i < biomes.length; i++) {
|
||||||
biomes[i] = buffer.getConnection().getMapping().getBiomeRegistry().get(buffer.readInt());
|
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(skyLightMask));
|
||||||
readLightArray(buffer, BitSet.valueOf(blockLightMask));
|
readLightArray(buffer, BitSet.valueOf(blockLightMask));
|
||||||
// ToDo
|
// ToDo
|
||||||
|
return DummyLightAccessor.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void readLightArray(InByteBuffer buffer, BitSet lightMask) {
|
private static void readLightArray(InByteBuffer buffer, BitSet lightMask) {
|
||||||
|
@ -17,6 +17,7 @@ out vec4 outColor;
|
|||||||
|
|
||||||
in vec3 passTextureCoordinates;
|
in vec3 passTextureCoordinates;
|
||||||
in vec4 passTintColor;
|
in vec4 passTintColor;
|
||||||
|
in float passLightLevel;
|
||||||
|
|
||||||
uniform sampler2DArray blockTextureArray;
|
uniform sampler2DArray blockTextureArray;
|
||||||
|
|
||||||
@ -30,5 +31,5 @@ void main() {
|
|||||||
if (passTintColor.a > 0.0f){
|
if (passTintColor.a > 0.0f){
|
||||||
mixedColor *= passTintColor.rgb;
|
mixedColor *= passTintColor.rgb;
|
||||||
}
|
}
|
||||||
outColor = vec4(mixedColor, texelColor.a);
|
outColor = vec4(mixedColor * passLightLevel, texelColor.a);
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,11 @@ layout (location = 2) in int textureLayer;
|
|||||||
layout (location = 3) in vec3 animatedTextureData;
|
layout (location = 3) in vec3 animatedTextureData;
|
||||||
|
|
||||||
layout (location = 4) in uint tintColor;
|
layout (location = 4) in uint tintColor;
|
||||||
|
layout (location = 5) in float lightLevel;
|
||||||
|
|
||||||
out vec3 passTextureCoordinates;
|
out vec3 passTextureCoordinates;
|
||||||
out vec4 passTintColor;
|
out vec4 passTintColor;
|
||||||
|
out float passLightLevel;
|
||||||
|
|
||||||
uniform mat4 viewProjectionMatrix;
|
uniform mat4 viewProjectionMatrix;
|
||||||
uniform int animationTick;
|
uniform int animationTick;
|
||||||
@ -32,6 +34,8 @@ void main() {
|
|||||||
gl_Position = viewProjectionMatrix * vec4(inPosition, 1.0f);
|
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);
|
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) {
|
if (animatedTextureData.y == 1.0f) {
|
||||||
passTextureCoordinates = vec3(textureIndex, textureLayer);
|
passTextureCoordinates = vec3(textureIndex, textureLayer);
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user