change block storage in chunks (wip light, biomes)

This commit is contained in:
Bixilon 2021-02-19 18:13:53 +01:00
parent 5312e0d436
commit 9d5952dd91
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
14 changed files with 350 additions and 384 deletions

View File

@ -1,139 +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.mappings.tweaker;
import de.bixilon.minosoft.data.entities.EntityMetaData;
import de.bixilon.minosoft.data.entities.EntityMetaDataFields;
import de.bixilon.minosoft.data.entities.entities.Entity;
import de.bixilon.minosoft.data.entities.entities.animal.horse.*;
import de.bixilon.minosoft.data.entities.entities.monster.*;
import de.bixilon.minosoft.data.entities.entities.vehicle.*;
import de.bixilon.minosoft.data.mappings.blocks.Block;
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.protocol.protocol.ProtocolDefinition;
import java.util.Map;
import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_1_8_9;
public class VersionTweaker {
// some data was packed in mata data in early versions (1.8). This function converts it to the real identifier
@SuppressWarnings("deprecation")
public static Class<? extends Entity> getRealEntityClass(Class<? extends Entity> fakeClass, EntityMetaData metaData, int versionId) {
if (fakeClass == ZombiePigman.class) {
return ZombifiedPiglin.class;
} else if (fakeClass == Zombie.class) {
if (versionId > V_1_8_9) { // ToDo: No clue here
return fakeClass;
}
if (metaData.getSets().getInt(EntityMetaDataFields.ZOMBIE_SPECIAL_TYPE) == 1) {
return ZombieVillager.class;
}
} else if (fakeClass == Skeleton.class) {
if (versionId > V_1_8_9) { // ToDo: No clue here
return fakeClass;
}
if (metaData.getSets().getInt(EntityMetaDataFields.LEGACY_SKELETON_TYPE) == 1) {
return WitherSkeleton.class;
}
} else if (fakeClass == Guardian.class) {
if (versionId > V_1_8_9) { // ToDo: No clue here
return fakeClass;
}
if (metaData.getSets().getBitMask(EntityMetaDataFields.LEGACY_GUARDIAN_FLAGS, 0x02)) {
return ElderGuardian.class;
}
} else if (fakeClass == Horse.class) {
if (versionId > V_1_8_9) { // ToDo: No clue here
return fakeClass;
}
return switch (metaData.getSets().getByte(EntityMetaDataFields.LEGACY_HORSE_SPECIAL_TYPE)) {
default -> fakeClass;
case 1 -> Donkey.class;
case 2 -> Mule.class;
case 3 -> ZombieHorse.class;
case 4 -> SkeletonHorse.class;
};
}
return fakeClass;
}
public static Class<? extends Entity> getRealEntityObjectClass(Class<? extends Entity> fakeClass, int data, int versionId) {
if (fakeClass == Minecart.class) {
if (versionId > V_1_8_9) { // ToDo: No clue here
return fakeClass;
}
return switch (data) {
default -> fakeClass;
case 1 -> MinecartChest.class;
case 2 -> MinecartFurnace.class;
case 3 -> MinecartTNT.class;
case 4 -> MinecartSpawner.class;
case 5 -> MinecartHopper.class;
case 6 -> MinecartCommandBlock.class;
};
}
return fakeClass;
}
public static Chunk transformChunk(Chunk chunk, int versionId) {
// 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;
}
for (Map.Entry<Integer, ChunkSection> sectionEntry : chunk.getSections().entrySet()) {
for (Map.Entry<InChunkSectionLocation, Block> blockEntry : sectionEntry.getValue().getBlocks().entrySet()) {
Block newBlock = transformBlock(blockEntry.getValue(), chunk, blockEntry.getKey(), sectionEntry.getKey());
if (newBlock == blockEntry.getValue()) {
continue;
}
sectionEntry.getValue().setBlock(blockEntry.getKey(), newBlock);
}
}
return chunk;
}
public static Block transformBlock(Block originalBlock, Chunk chunk, InChunkLocation location) {
return transformBlock(originalBlock, chunk, location.getInChunkSectionLocation(), (byte) (location.getY() / ProtocolDefinition.SECTION_HEIGHT_Y));
}
public static Block transformBlock(Block originalBlock, Chunk chunk, InChunkSectionLocation location, int sectionHeight) {
if (originalBlock == null) {
return null;
}
switch (originalBlock.getIdentifier().getFullIdentifier()) {
case "minecraft:grass" -> {
Block above = getBlockAbove(chunk, location, sectionHeight);
if (above == null) {
break;
}
if (above.equals(TweakBlocks.SNOW) || above.equals(TweakBlocks.SNOW_LAYER)) {
return TweakBlocks.GRASS_BLOCK_SNOWY_YES;
} else {
return TweakBlocks.GRASS_BLOCK_SNOWY_NO;
}
}
// ToDo: all blocks. e.g. doors, etc
}
return originalBlock;
}
private static Block getBlockAbove(Chunk chunk, InChunkSectionLocation location, int sectionHeight) {
return chunk.getBlock(location.getInChunkLocation(sectionHeight));
}
}

View File

@ -0,0 +1,128 @@
/*
* 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.mappings.tweaker
import de.bixilon.minosoft.data.entities.EntityMetaData
import de.bixilon.minosoft.data.entities.EntityMetaDataFields
import de.bixilon.minosoft.data.entities.entities.Entity
import de.bixilon.minosoft.data.entities.entities.animal.horse.*
import de.bixilon.minosoft.data.entities.entities.monster.*
import de.bixilon.minosoft.data.entities.entities.vehicle.*
import de.bixilon.minosoft.data.mappings.blocks.Block
import de.bixilon.minosoft.data.world.*
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
object VersionTweaker {
// some data was packed in mata data in early versions (1.8). This function converts it to the real identifier
@JvmStatic
fun getRealEntityClass(fakeClass: Class<out Entity>, metaData: EntityMetaData, versionId: Int): Class<out Entity> {
if (versionId > ProtocolVersions.V_1_8_9) { // ToDo: No clue here
return fakeClass
}
when (fakeClass) {
ZombiePigman::class.java -> {
return ZombifiedPiglin::class.java
}
Zombie::class.java -> {
if (metaData.sets.getInt(EntityMetaDataFields.ZOMBIE_SPECIAL_TYPE) == 1) {
return ZombieVillager::class.java
}
}
Skeleton::class.java -> {
if (metaData.sets.getInt(EntityMetaDataFields.LEGACY_SKELETON_TYPE) == 1) {
return WitherSkeleton::class.java
}
}
Guardian::class.java -> {
if (metaData.sets.getBitMask(EntityMetaDataFields.LEGACY_GUARDIAN_FLAGS, 0x02)) {
return ElderGuardian::class.java
}
}
Horse::class.java -> {
return when (metaData.sets.getByte(EntityMetaDataFields.LEGACY_HORSE_SPECIAL_TYPE).toInt()) {
1 -> Donkey::class.java
2 -> Mule::class.java
3 -> ZombieHorse::class.java
4 -> SkeletonHorse::class.java
else -> fakeClass
}
}
}
return fakeClass
}
@JvmStatic
fun getRealEntityObjectClass(fakeClass: Class<out Entity>, data: Int, versionId: Int): Class<out Entity> {
if (versionId > ProtocolVersions.V_1_8_9) { // ToDo: No clue here
return fakeClass
}
when (fakeClass) {
Minecart::class.java -> {
return when (data) {
1 -> MinecartChest::class.java
2 -> MinecartFurnace::class.java
3 -> MinecartTNT::class.java
4 -> MinecartSpawner::class.java
5 -> MinecartHopper::class.java
6 -> MinecartCommandBlock::class.java
else -> fakeClass
}
}
}
return fakeClass
}
@JvmStatic
fun transformChunk(chunk: Chunk, versionId: Int): Chunk {
// 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
}
for ((sectionHeight, section) in chunk.sections) {
for ((location, blockInfo) in section.blocks) {
val newBlock = transformBlock(blockInfo.block, chunk, location, sectionHeight)
if (newBlock === blockInfo.block) {
continue
}
if (newBlock == null) {
section.setBlockInfo(location, null)
continue
}
section.setBlockInfo(location, BlockInfo(newBlock, blockInfo.metaData, section.blocksStaticInfo[location] ?: BlockStaticInfo()))
}
}
return chunk
}
@JvmStatic
fun transformBlock(originalBlock: Block, chunk: Chunk, location: InChunkSectionLocation, sectionHeight: Int): Block? {
when (originalBlock.identifier.fullIdentifier) {
"minecraft:grass" -> {
getBlockAbove(chunk, location, sectionHeight)?.let {
if (it == TweakBlocks.SNOW || it == TweakBlocks.SNOW_LAYER) {
return TweakBlocks.GRASS_BLOCK_SNOWY_YES
}
}
return TweakBlocks.GRASS_BLOCK_SNOWY_NO
}
}
return originalBlock
}
private fun getBlockAbove(chunk: Chunk, location: InChunkSectionLocation, sectionHeight: Int): Block? {
val above = location.getInChunkLocation(sectionHeight)
return chunk.getBlockInfo(InChunkLocation(above.x, above.y + 1, above.z))?.block
}
}

View File

@ -0,0 +1,25 @@
/*
* 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.entities.block.BlockEntityMetaData
import de.bixilon.minosoft.data.mappings.blocks.Block
data class BlockInfo(
val block: Block,
var metaData: BlockEntityMetaData? = null,
val info: BlockStaticInfo = BlockStaticInfo(),
) {
constructor(block: Block) : this(block, null) // ToDo: For java compatibility
}

View File

@ -45,7 +45,7 @@ data class BlockPosition(val x: Int, val y: Int, val z: Int) {
fun getInChunkSectionLocation(): InChunkSectionLocation { fun getInChunkSectionLocation(): InChunkSectionLocation {
val location = getInChunkLocation() val location = getInChunkLocation()
return InChunkSectionLocation(location.x, this.y % ProtocolDefinition.SECTION_HEIGHT_Y, location.z) return InChunkSectionLocation(location.x, getSectionHeight(), location.z)
} }
fun getSectionHeight(): Int { fun getSectionHeight(): Int {

View File

@ -0,0 +1,20 @@
/*
* 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
data class BlockStaticInfo(
var light: Int = 15,
var skyLight: Int = 15,
// ToDo: Biome
)

View File

@ -1,99 +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 de.bixilon.minosoft.data.entities.block.BlockEntityMetaData;
import de.bixilon.minosoft.data.mappings.blocks.Block;
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition;
import java.util.HashMap;
/**
* Collection of 16 chunks sections
*/
public class Chunk {
private final HashMap<Integer, ChunkSection> sections;
public Chunk(HashMap<Integer, ChunkSection> sections) {
this.sections = sections;
}
public Block getBlock(InChunkLocation location) {
return getBlock(location.getX(), location.getY(), location.getZ());
}
public Block getBlock(int x, int y, int z) {
int section = (y / ProtocolDefinition.SECTION_HEIGHT_Y);
if (!this.sections.containsKey(section)) {
return null;
}
return this.sections.get(section).getBlock(x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z);
}
public void setBlock(int x, int y, int z, Block block) {
int section = y / ProtocolDefinition.SECTION_HEIGHT_Y;
createSection(section);
this.sections.get(section).setBlock(x, y % 16, z, block);
}
void createSection(int height) {
if (this.sections.get(height) == null) {
// section was empty before, creating it
this.sections.put(height, new ChunkSection());
}
}
public void setBlocks(HashMap<InChunkLocation, Block> blocks) {
blocks.forEach(this::setBlock);
}
public void setBlock(InChunkLocation location, Block block) {
int section = (location.getY() / ProtocolDefinition.SECTION_HEIGHT_Y);
createSection(section);
this.sections.get(section).setBlock(location.getInChunkSectionLocation(), block);
}
public void setBlockEntityData(InChunkLocation position, BlockEntityMetaData data) {
ChunkSection section = this.sections.get((position.getY() / ProtocolDefinition.SECTION_HEIGHT_Y));
if (section == null) {
return;
}
section.setBlockEntityData(position.getInChunkSectionLocation(), data);
}
public BlockEntityMetaData getBlockEntityData(InChunkLocation position) {
ChunkSection section = this.sections.get((position.getY() / ProtocolDefinition.SECTION_HEIGHT_Y));
if (section == null) {
return null;
}
return section.getBlockEntityData(position.getInChunkSectionLocation());
}
public void setBlockEntityData(HashMap<InChunkLocation, BlockEntityMetaData> blockEntities) {
blockEntities.forEach(this::setBlockEntityData);
}
public HashMap<Integer, ChunkSection> getSections() {
return this.sections;
}
public ChunkSection getSectionOrCreate(int sectionHeight) {
ChunkSection section = this.sections.get(sectionHeight);
if (section == null) {
section = new ChunkSection();
this.sections.put(sectionHeight, section);
}
return section;
}
}

View File

@ -0,0 +1,69 @@
/*
* 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 de.bixilon.minosoft.data.mappings.blocks.Block
import java.util.*
/**
* Collection of chunks sections (allocated in y)
*/
class Chunk(val sections: MutableMap<Int, ChunkSection> = mutableMapOf()) {
fun getBlockInfo(location: InChunkLocation): BlockInfo? {
return sections[location.getSectionHeight()]?.getBlockInfo(location.getInChunkSectionLocation())
}
fun getBlockInfo(x: Int, y: Int, z: Int): BlockInfo? {
return getBlockInfo(InChunkLocation(x, y, z))
}
fun setBlocks(blocks: HashMap<InChunkLocation, BlockInfo?>) {
for ((location, blockInfo) in blocks) {
setBlock(location, blockInfo)
}
}
fun setRawBlocks(blocks: HashMap<InChunkLocation, Block?>) {
for ((location, blockInfo) in blocks) {
setRawBlock(location, blockInfo)
}
}
fun setBlock(location: InChunkLocation, block: BlockInfo?) {
getSectionOrCreate(location.getSectionHeight()).setBlockInfo(location.getInChunkSectionLocation(), block)
}
fun setRawBlock(location: InChunkLocation, block: Block?) {
getSectionOrCreate(location.getSectionHeight()).let {
val inChunkSectionLocation = location.getInChunkSectionLocation()
if (block == null) {
it.blocks.remove(inChunkSectionLocation)
return
}
it.setBlockInfo(inChunkSectionLocation, BlockInfo(block, info = it.blocksStaticInfo[inChunkSectionLocation] ?: BlockStaticInfo()))
}
}
fun getSectionOrCreate(sectionHeight: Int): ChunkSection {
return sections[sectionHeight].let {
var section = it
if (section == null) {
section = ChunkSection()
sections[sectionHeight] = section
}
section
}
}
}

View File

@ -1,94 +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 de.bixilon.minosoft.data.entities.block.BlockEntityMetaData;
import de.bixilon.minosoft.data.mappings.blocks.Block;
import java.util.HashMap;
/**
* Collection of 16x16x16 blocks
*/
public class ChunkSection {
private final HashMap<InChunkSectionLocation, Block> blocks;
private final HashMap<InChunkSectionLocation, BlockEntityMetaData> blockEntityMeta = new HashMap<>();
private final HashMap<InChunkSectionLocation, Byte> light;
private final HashMap<InChunkSectionLocation, Byte> skyLight;
public ChunkSection(HashMap<InChunkSectionLocation, Block> blocks) {
this(blocks, new HashMap<>(), new HashMap<>());
}
public ChunkSection(HashMap<InChunkSectionLocation, Block> blocks, HashMap<InChunkSectionLocation, Byte> light, HashMap<InChunkSectionLocation, Byte> skyLight) {
this.blocks = blocks;
this.light = light;
this.skyLight = skyLight;
}
public ChunkSection() {
this(new HashMap<>());
}
public Block getBlock(int x, int y, int z) {
return getBlock(new InChunkSectionLocation(x, y, z));
}
public Block getBlock(InChunkSectionLocation loc) {
return this.blocks.get(loc);
}
public void setBlock(int x, int y, int z, Block block) {
setBlock(new InChunkSectionLocation(x, y, z), block);
}
public void setBlock(InChunkSectionLocation location, Block block) {
if (block == null) {
this.blocks.remove(location);
this.blockEntityMeta.remove(location);
return;
}
this.blocks.put(location, block);
this.blockEntityMeta.remove(location);
}
public void setBlockEntityData(InChunkSectionLocation position, BlockEntityMetaData data) {
// ToDo check if block is really a block entity (command block, spawner, skull, flower pot)
this.blockEntityMeta.put(position, data);
}
public HashMap<InChunkSectionLocation, Block> getBlocks() {
return this.blocks;
}
public HashMap<InChunkSectionLocation, BlockEntityMetaData> getBlockEntityMeta() {
return this.blockEntityMeta;
}
public HashMap<InChunkSectionLocation, Byte> getLight() {
return this.light;
}
public HashMap<InChunkSectionLocation, Byte> getSkyLight() {
return this.skyLight;
}
public BlockEntityMetaData getBlockEntityData(InChunkSectionLocation position) {
return this.blockEntityMeta.get(position);
}
public void setBlockEntityData(HashMap<InChunkSectionLocation, BlockEntityMetaData> blockEntities) {
blockEntities.forEach(this.blockEntityMeta::put);
}
}

View File

@ -0,0 +1,52 @@
/*
* 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 de.bixilon.minosoft.data.mappings.blocks.Block
/**
* Collection of 16x16x16 blocks
*/
class ChunkSection constructor(
val blocks: MutableMap<InChunkSectionLocation, BlockInfo> = mutableMapOf(),
val blocksStaticInfo: MutableMap<InChunkSectionLocation, BlockStaticInfo> = mutableMapOf(),
) {
fun getBlockInfo(location: InChunkSectionLocation): BlockInfo? {
return blocks[location]
}
fun setBlockInfo(location: InChunkSectionLocation, blockInfo: BlockInfo?) {
if (blockInfo == null) {
blocks.remove(location)
return
}
blocks[location] = blockInfo
}
fun getBlockInfo(x: Int, y: Int, z: Int): BlockInfo? {
return getBlockInfo(InChunkSectionLocation(x, y, z))
}
fun updateStaticData() {
}
fun setRawBlock(location: InChunkSectionLocation, block: Block?) {
if (block == null) {
setBlockInfo(location, null)
return
}
setBlockInfo(location, BlockInfo(block, info = blocksStaticInfo[location] ?: BlockStaticInfo()))
}
}

View File

@ -30,19 +30,19 @@ public class World {
private final HashMap<ChunkLocation, Chunk> chunks = new HashMap<>(); private final HashMap<ChunkLocation, Chunk> chunks = new HashMap<>();
private final HashBiMap<Integer, Entity> entityIdMap = HashBiMap.create(); private final HashBiMap<Integer, Entity> entityIdMap = HashBiMap.create();
private final HashBiMap<UUID, Entity> entityUUIDMap = HashBiMap.create(); private final HashBiMap<UUID, Entity> entityUUIDMap = HashBiMap.create();
boolean hardcore; private boolean hardcore;
boolean raining; private boolean raining;
Dimension dimension; // used for sky color, etc private Dimension dimension; // used for sky color, etc
public HashMap<ChunkLocation, Chunk> getAllChunks() { public HashMap<ChunkLocation, Chunk> getAllChunks() {
return this.chunks; return this.chunks;
} }
@Nullable @Nullable
public Block getBlock(BlockPosition pos) { public BlockInfo getBlockInfo(BlockPosition pos) {
ChunkLocation loc = pos.getChunkLocation(); ChunkLocation loc = pos.getChunkLocation();
if (getChunk(loc) != null) { if (getChunk(loc) != null) {
return getChunk(loc).getBlock(pos.getInChunkLocation()); return getChunk(loc).getBlockInfo(pos.getInChunkLocation());
} }
return null; return null;
} }
@ -53,7 +53,7 @@ public class World {
public void setBlock(BlockPosition pos, Block block) { public void setBlock(BlockPosition pos, Block block) {
if (getChunk(pos.getChunkLocation()) != null) { if (getChunk(pos.getChunkLocation()) != null) {
getChunk(pos.getChunkLocation()).setBlock(pos.getInChunkLocation(), block); getChunk(pos.getChunkLocation()).setRawBlock(pos.getInChunkLocation(), block);
} }
// do nothing if chunk is unloaded // do nothing if chunk is unloaded
} }
@ -125,16 +125,17 @@ public class World {
if (chunk == null) { if (chunk == null) {
return; return;
} }
chunk.setBlockEntityData(position.getInChunkLocation(), data); 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 BlockEntityMetaData getBlockEntityData(BlockPosition position) {
Chunk chunk = this.chunks.get(position.getChunkLocation());
if (chunk == null) {
return null;
}
return chunk.getBlockEntityData(position.getInChunkLocation());
}
public void setBlockEntityData(HashMap<BlockPosition, BlockEntityMetaData> blockEntities) { public void setBlockEntityData(HashMap<BlockPosition, BlockEntityMetaData> blockEntities) {
blockEntities.forEach(this::setBlockEntityData); blockEntities.forEach(this::setBlockEntityData);

View File

@ -53,38 +53,40 @@ class ChunkRenderer(private val connection: Connection, private val world: World
val west = world.allChunks[chunkLocation.getLocationByDirection(Directions.WEST)]?.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 east = world.allChunks[chunkLocation.getLocationByDirection(Directions.EAST)]?.sections?.get(sectionHeight)
for ((position, block) in section.blocks) { for ((position, blockInfo) in section.blocks) {
val blockBelow: Block? = if (position.y == 0 && below != null) { val blockBelow: BlockInfo? = if (position.y == 0 && below != null) {
below.getBlock(position.x, ProtocolDefinition.SECTION_HEIGHT_Y - 1, position.z) below.getBlockInfo(position.x, ProtocolDefinition.SECTION_HEIGHT_Y - 1, position.z)
} else { } else {
section.getBlock(position.getLocationByDirection(Directions.DOWN)) section.getBlockInfo(position.getLocationByDirection(Directions.DOWN))
} }
val blockAbove: Block? = if (position.y == ProtocolDefinition.SECTION_HEIGHT_Y - 1 && above != null) { val blockAbove: BlockInfo? = if (position.y == ProtocolDefinition.SECTION_HEIGHT_Y - 1 && above != null) {
above.getBlock(position.x, 0, position.z) above.getBlockInfo(position.x, 0, position.z)
} else { } else {
section.getBlock(position.getLocationByDirection(Directions.UP)) section.getBlockInfo(position.getLocationByDirection(Directions.UP))
} }
val blockNorth: Block? = if (position.z == 0 && north != null) { val blockNorth: BlockInfo? = if (position.z == 0 && north != null) {
north.getBlock(position.x, position.y, ProtocolDefinition.SECTION_WIDTH_Z - 1) north.getBlockInfo(position.x, position.y, ProtocolDefinition.SECTION_WIDTH_Z - 1)
} else { } else {
section.getBlock(position.getLocationByDirection(Directions.NORTH)) section.getBlockInfo(position.getLocationByDirection(Directions.NORTH))
} }
val blockSouth: Block? = if (position.z == ProtocolDefinition.SECTION_WIDTH_Z - 1 && south != null) { val blockSouth: BlockInfo? = if (position.z == ProtocolDefinition.SECTION_WIDTH_Z - 1 && south != null) {
south.getBlock(position.x, position.y, 0) south.getBlockInfo(position.x, position.y, 0)
} else { } else {
section.getBlock(position.getLocationByDirection(Directions.SOUTH)) section.getBlockInfo(position.getLocationByDirection(Directions.SOUTH))
} }
val blockWest: Block? = if (position.x == 0 && west != null) { val blockWest: BlockInfo? = if (position.x == 0 && west != null) {
west.getBlock(ProtocolDefinition.SECTION_WIDTH_X - 1, position.y, position.x) west.getBlockInfo(ProtocolDefinition.SECTION_WIDTH_X - 1, position.y, position.x)
} else { } else {
section.getBlock(position.getLocationByDirection(Directions.WEST)) section.getBlockInfo(position.getLocationByDirection(Directions.WEST))
} }
val blockEast: Block? = if (position.x == ProtocolDefinition.SECTION_WIDTH_X - 1 && east != null) { val blockEast: BlockInfo? = if (position.x == ProtocolDefinition.SECTION_WIDTH_X - 1 && east != null) {
east.getBlock(0, position.y, position.z) east.getBlockInfo(0, position.y, position.z)
} else { } else {
section.getBlock(position.getLocationByDirection(Directions.EAST)) section.getBlockInfo(position.getLocationByDirection(Directions.EAST))
} }
block.getBlockRenderer(BlockPosition(chunkLocation, sectionHeight, position)).render(Vec3(position.x + chunkLocation.x * ProtocolDefinition.SECTION_WIDTH_X, position.y + sectionHeight * ProtocolDefinition.SECTION_HEIGHT_Y, position.z + chunkLocation.z * ProtocolDefinition.SECTION_WIDTH_Z), data, arrayOf(blockBelow, blockAbove, blockNorth, blockSouth, blockWest, blockEast)) 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)
blockInfo.block.getBlockRenderer(BlockPosition(chunkLocation, sectionHeight, position)).render(blockInfo, worldPosition, arrayOf(blockBelow, blockAbove, blockNorth, blockSouth, blockWest, blockEast))
} }
return data.toFloatArray() return data.toFloatArray()
} }

View File

@ -57,11 +57,10 @@ public class PacketBlockChange extends ClientboundPacket {
// tweak // tweak
if (!connection.getVersion().isFlattened()) { if (!connection.getVersion().isFlattened()) {
Block block = VersionTweaker.transformBlock(getBlock(), chunk, getPosition().getInChunkLocation()); Block block = VersionTweaker.transformBlock(getBlock(), chunk, this.position.getInChunkSectionLocation(), this.position.getSectionHeight());
section.setBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), block); section.setRawBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), block);
} else { } else {
Log.debug("Replacing %s with %s", section.getBlock(getPosition().getInChunkLocation().getInChunkSectionLocation()), this.block); section.setRawBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), getBlock());
section.setBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), getBlock());
} }
connection.getRenderer().getRenderWindow().getChunkRenderer().prepareChunkSection(getPosition().getChunkLocation(), sectionHeight, section); connection.getRenderer().getRenderWindow().getChunkRenderer().prepareChunkSection(getPosition().getChunkLocation(), sectionHeight, section);

View File

@ -33,7 +33,7 @@ import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*;
public class PacketMultiBlockChange extends ClientboundPacket { public class PacketMultiBlockChange extends ClientboundPacket {
private final HashMap<InChunkLocation, Block> blocks = new HashMap<>(); private final HashMap<InChunkLocation, Block> blocks = new HashMap<>();
ChunkLocation location; private ChunkLocation location;
@Override @Override
public boolean read(InByteBuffer buffer) { public boolean read(InByteBuffer buffer) {
@ -89,16 +89,16 @@ public class PacketMultiBlockChange extends ClientboundPacket {
return; return;
} }
connection.fireEvent(new MultiBlockChangeEvent(connection, this)); connection.fireEvent(new MultiBlockChangeEvent(connection, this));
chunk.setBlocks(getBlocks()); chunk.setRawBlocks(getBlocks());
// tweak // tweak
if (!connection.getVersion().isFlattened()) { if (!connection.getVersion().isFlattened()) {
for (Map.Entry<InChunkLocation, Block> entry : getBlocks().entrySet()) { for (Map.Entry<InChunkLocation, Block> entry : getBlocks().entrySet()) {
Block block = VersionTweaker.transformBlock(entry.getValue(), chunk, entry.getKey()); Block block = VersionTweaker.transformBlock(entry.getValue(), chunk, entry.getKey().getInChunkSectionLocation(), entry.getKey().getSectionHeight());
if (block == entry.getValue()) { if (block == entry.getValue()) {
continue; continue;
} }
chunk.setBlock(entry.getKey(), block); chunk.setRawBlock(entry.getKey(), block);
} }
} }

View File

@ -15,6 +15,7 @@ package de.bixilon.minosoft.util;
import de.bixilon.minosoft.data.mappings.Dimension; import de.bixilon.minosoft.data.mappings.Dimension;
import de.bixilon.minosoft.data.mappings.blocks.Block; import de.bixilon.minosoft.data.mappings.blocks.Block;
import de.bixilon.minosoft.data.world.BlockInfo;
import de.bixilon.minosoft.data.world.Chunk; import de.bixilon.minosoft.data.world.Chunk;
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;
@ -24,6 +25,7 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition;
import java.util.BitSet; import java.util.BitSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*; import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*;
@ -56,7 +58,7 @@ public final class ChunkUtil {
HashMap<Integer, ChunkSection> sectionMap = new HashMap<>(); HashMap<Integer, ChunkSection> sectionMap = new HashMap<>();
for (int c = 0; c < ProtocolDefinition.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column for (int c = 0; c < ProtocolDefinition.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column
if (BitByte.isBitSet(sectionBitMasks[0], c)) { if (BitByte.isBitSet(sectionBitMasks[0], c)) {
HashMap<InChunkSectionLocation, Block> blockMap = new HashMap<>(); HashMap<InChunkSectionLocation, BlockInfo> blockMap = new HashMap<>();
for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) { for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < ProtocolDefinition.SECTION_WIDTH_Z; nibbleZ++) { for (int nibbleZ = 0; nibbleZ < ProtocolDefinition.SECTION_WIDTH_Z; nibbleZ++) {
@ -84,12 +86,12 @@ public final class ChunkUtil {
continue; continue;
} }
Block block = buffer.getConnection().getMapping().getBlock(fullBlockId); Block block = buffer.getConnection().getMapping().getBlock(fullBlockId);
blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), block); blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), new BlockInfo(block));
arrayPos++; arrayPos++;
} }
} }
} }
sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap)); sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap, Map.of())); // ToDo
} }
} }
return new Chunk(sectionMap); return new Chunk(sectionMap);
@ -120,7 +122,7 @@ public final class ChunkUtil {
if (!BitByte.isBitSet(sectionBitMasks[0], c)) { if (!BitByte.isBitSet(sectionBitMasks[0], c)) {
continue; continue;
} }
HashMap<InChunkSectionLocation, Block> blockMap = new HashMap<>(); HashMap<InChunkSectionLocation, BlockInfo> blockMap = new HashMap<>();
for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) { for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < ProtocolDefinition.SECTION_WIDTH_Z; nibbleZ++) { for (int nibbleZ = 0; nibbleZ < ProtocolDefinition.SECTION_WIDTH_Z; nibbleZ++) {
@ -131,12 +133,12 @@ public final class ChunkUtil {
arrayPos++; arrayPos++;
continue; continue;
} }
blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), block); blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), new BlockInfo(block));
arrayPos++; arrayPos++;
} }
} }
} }
sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap)); sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap, Map.of()));
} }
return new Chunk(sectionMap); return new Chunk(sectionMap);
} }
@ -156,7 +158,7 @@ public final class ChunkUtil {
long[] data = buffer.readLongArray(); long[] data = buffer.readLongArray();
HashMap<InChunkSectionLocation, Block> blockMap = new HashMap<>(); HashMap<InChunkSectionLocation, BlockInfo> blockMap = new HashMap<>();
for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) { for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < ProtocolDefinition.SECTION_WIDTH_Z; nibbleZ++) { for (int nibbleZ = 0; nibbleZ < ProtocolDefinition.SECTION_WIDTH_Z; nibbleZ++) {
for (int nibbleX = 0; nibbleX < ProtocolDefinition.SECTION_WIDTH_X; nibbleX++) { for (int nibbleX = 0; nibbleX < ProtocolDefinition.SECTION_WIDTH_X; nibbleX++) {
@ -187,7 +189,7 @@ public final class ChunkUtil {
if (block == null) { if (block == null) {
continue; continue;
} }
blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), block); blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), new BlockInfo(block));
} }
} }
} }
@ -199,7 +201,7 @@ public final class ChunkUtil {
} }
} }
sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap)); sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap, Map.of()));
} }
if (buffer.getVersionId() < V_19W36A) { if (buffer.getVersionId() < V_19W36A) {
byte[] biomes = buffer.readBytes(256); byte[] biomes = buffer.readBytes(256);