diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/tweaker/VersionTweaker.java b/src/main/java/de/bixilon/minosoft/data/mappings/tweaker/VersionTweaker.java
deleted file mode 100644
index 863c3af43..000000000
--- a/src/main/java/de/bixilon/minosoft/data/mappings/tweaker/VersionTweaker.java
+++ /dev/null
@@ -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 .
- *
- * 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 sectionEntry : chunk.getSections().entrySet()) {
- for (Map.Entry 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));
- }
-}
diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/tweaker/VersionTweaker.kt b/src/main/java/de/bixilon/minosoft/data/mappings/tweaker/VersionTweaker.kt
new file mode 100644
index 000000000..eb31ee94f
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/mappings/tweaker/VersionTweaker.kt
@@ -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 .
+ *
+ * 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, metaData: EntityMetaData, versionId: Int): Class {
+ 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, data: Int, versionId: Int): Class {
+ 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
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/BlockInfo.kt b/src/main/java/de/bixilon/minosoft/data/world/BlockInfo.kt
new file mode 100644
index 000000000..a5f5d02ee
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/world/BlockInfo.kt
@@ -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 .
+ *
+ * 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
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/BlockPosition.kt b/src/main/java/de/bixilon/minosoft/data/world/BlockPosition.kt
index 2f551dcd7..4260191c2 100644
--- a/src/main/java/de/bixilon/minosoft/data/world/BlockPosition.kt
+++ b/src/main/java/de/bixilon/minosoft/data/world/BlockPosition.kt
@@ -45,7 +45,7 @@ data class BlockPosition(val x: Int, val y: Int, val z: Int) {
fun getInChunkSectionLocation(): InChunkSectionLocation {
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 {
diff --git a/src/main/java/de/bixilon/minosoft/data/world/BlockStaticInfo.kt b/src/main/java/de/bixilon/minosoft/data/world/BlockStaticInfo.kt
new file mode 100644
index 000000000..21f577571
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/world/BlockStaticInfo.kt
@@ -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 .
+ *
+ * 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
+)
diff --git a/src/main/java/de/bixilon/minosoft/data/world/Chunk.java b/src/main/java/de/bixilon/minosoft/data/world/Chunk.java
deleted file mode 100644
index f1b804d87..000000000
--- a/src/main/java/de/bixilon/minosoft/data/world/Chunk.java
+++ /dev/null
@@ -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 .
- *
- * 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 sections;
-
- public Chunk(HashMap 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 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 blockEntities) {
- blockEntities.forEach(this::setBlockEntityData);
- }
-
- public HashMap 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;
- }
-}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt
new file mode 100644
index 000000000..5a3d0d0ac
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt
@@ -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 .
+ *
+ * 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 = 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) {
+ for ((location, blockInfo) in blocks) {
+ setBlock(location, blockInfo)
+ }
+ }
+
+ fun setRawBlocks(blocks: HashMap) {
+ 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
+ }
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.java b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.java
deleted file mode 100644
index ba1eda6ab..000000000
--- a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.java
+++ /dev/null
@@ -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 .
- *
- * 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 blocks;
- private final HashMap blockEntityMeta = new HashMap<>();
- private final HashMap light;
- private final HashMap skyLight;
-
- public ChunkSection(HashMap blocks) {
- this(blocks, new HashMap<>(), new HashMap<>());
- }
-
- public ChunkSection(HashMap blocks, HashMap light, HashMap 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 getBlocks() {
- return this.blocks;
- }
-
- public HashMap getBlockEntityMeta() {
- return this.blockEntityMeta;
- }
-
- public HashMap getLight() {
- return this.light;
- }
-
- public HashMap getSkyLight() {
- return this.skyLight;
- }
-
- public BlockEntityMetaData getBlockEntityData(InChunkSectionLocation position) {
- return this.blockEntityMeta.get(position);
- }
-
- public void setBlockEntityData(HashMap blockEntities) {
- blockEntities.forEach(this.blockEntityMeta::put);
- }
-}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt
new file mode 100644
index 000000000..c182b3f3d
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt
@@ -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 .
+ *
+ * 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 = mutableMapOf(),
+ val blocksStaticInfo: MutableMap = 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()))
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/world/World.java b/src/main/java/de/bixilon/minosoft/data/world/World.java
index 01c7cb700..0b11e1441 100644
--- a/src/main/java/de/bixilon/minosoft/data/world/World.java
+++ b/src/main/java/de/bixilon/minosoft/data/world/World.java
@@ -30,19 +30,19 @@ public class World {
private final HashMap chunks = new HashMap<>();
private final HashBiMap entityIdMap = HashBiMap.create();
private final HashBiMap entityUUIDMap = HashBiMap.create();
- boolean hardcore;
- boolean raining;
- Dimension dimension; // used for sky color, etc
+ private boolean hardcore;
+ private boolean raining;
+ private Dimension dimension; // used for sky color, etc
public HashMap getAllChunks() {
return this.chunks;
}
@Nullable
- public Block getBlock(BlockPosition pos) {
+ public BlockInfo getBlockInfo(BlockPosition pos) {
ChunkLocation loc = pos.getChunkLocation();
if (getChunk(loc) != null) {
- return getChunk(loc).getBlock(pos.getInChunkLocation());
+ return getChunk(loc).getBlockInfo(pos.getInChunkLocation());
}
return null;
}
@@ -53,7 +53,7 @@ public class World {
public void setBlock(BlockPosition pos, Block block) {
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
}
@@ -125,16 +125,17 @@ public class World {
if (chunk == null) {
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 blockEntities) {
blockEntities.forEach(this::setBlockEntityData);
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkRenderer.kt
index 16fddfd68..408ec33ba 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkRenderer.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/ChunkRenderer.kt
@@ -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 east = world.allChunks[chunkLocation.getLocationByDirection(Directions.EAST)]?.sections?.get(sectionHeight)
- for ((position, block) in section.blocks) {
- val blockBelow: Block? = if (position.y == 0 && below != null) {
- below.getBlock(position.x, ProtocolDefinition.SECTION_HEIGHT_Y - 1, position.z)
+ for ((position, blockInfo) in section.blocks) {
+ val blockBelow: BlockInfo? = if (position.y == 0 && below != null) {
+ below.getBlockInfo(position.x, ProtocolDefinition.SECTION_HEIGHT_Y - 1, position.z)
} 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) {
- above.getBlock(position.x, 0, position.z)
+ val blockAbove: BlockInfo? = if (position.y == ProtocolDefinition.SECTION_HEIGHT_Y - 1 && above != null) {
+ above.getBlockInfo(position.x, 0, position.z)
} else {
- section.getBlock(position.getLocationByDirection(Directions.UP))
+ section.getBlockInfo(position.getLocationByDirection(Directions.UP))
}
- val blockNorth: Block? = if (position.z == 0 && north != null) {
- north.getBlock(position.x, position.y, ProtocolDefinition.SECTION_WIDTH_Z - 1)
+ val blockNorth: BlockInfo? = if (position.z == 0 && north != null) {
+ north.getBlockInfo(position.x, position.y, ProtocolDefinition.SECTION_WIDTH_Z - 1)
} 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) {
- south.getBlock(position.x, position.y, 0)
+ val blockSouth: BlockInfo? = if (position.z == ProtocolDefinition.SECTION_WIDTH_Z - 1 && south != null) {
+ south.getBlockInfo(position.x, position.y, 0)
} else {
- section.getBlock(position.getLocationByDirection(Directions.SOUTH))
+ section.getBlockInfo(position.getLocationByDirection(Directions.SOUTH))
}
- val blockWest: Block? = if (position.x == 0 && west != null) {
- west.getBlock(ProtocolDefinition.SECTION_WIDTH_X - 1, position.y, position.x)
+ val blockWest: BlockInfo? = if (position.x == 0 && west != null) {
+ west.getBlockInfo(ProtocolDefinition.SECTION_WIDTH_X - 1, position.y, position.x)
} 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) {
- east.getBlock(0, position.y, position.z)
+ val blockEast: BlockInfo? = if (position.x == ProtocolDefinition.SECTION_WIDTH_X - 1 && east != null) {
+ east.getBlockInfo(0, position.y, position.z)
} 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()
}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketBlockChange.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketBlockChange.java
index 37d647e20..e11b10eb4 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketBlockChange.java
+++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketBlockChange.java
@@ -57,11 +57,10 @@ public class PacketBlockChange extends ClientboundPacket {
// tweak
if (!connection.getVersion().isFlattened()) {
- Block block = VersionTweaker.transformBlock(getBlock(), chunk, getPosition().getInChunkLocation());
- section.setBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), block);
+ Block block = VersionTweaker.transformBlock(getBlock(), chunk, this.position.getInChunkSectionLocation(), this.position.getSectionHeight());
+ section.setRawBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), block);
} else {
- Log.debug("Replacing %s with %s", section.getBlock(getPosition().getInChunkLocation().getInChunkSectionLocation()), this.block);
- section.setBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), getBlock());
+ section.setRawBlock(getPosition().getInChunkLocation().getInChunkSectionLocation(), getBlock());
}
connection.getRenderer().getRenderWindow().getChunkRenderer().prepareChunkSection(getPosition().getChunkLocation(), sectionHeight, section);
diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketMultiBlockChange.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketMultiBlockChange.java
index 39b6e8491..69842e3e4 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketMultiBlockChange.java
+++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketMultiBlockChange.java
@@ -33,7 +33,7 @@ import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*;
public class PacketMultiBlockChange extends ClientboundPacket {
private final HashMap blocks = new HashMap<>();
- ChunkLocation location;
+ private ChunkLocation location;
@Override
public boolean read(InByteBuffer buffer) {
@@ -89,16 +89,16 @@ public class PacketMultiBlockChange extends ClientboundPacket {
return;
}
connection.fireEvent(new MultiBlockChangeEvent(connection, this));
- chunk.setBlocks(getBlocks());
+ chunk.setRawBlocks(getBlocks());
// tweak
if (!connection.getVersion().isFlattened()) {
for (Map.Entry 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()) {
continue;
}
- chunk.setBlock(entry.getKey(), block);
+ chunk.setRawBlock(entry.getKey(), block);
}
}
diff --git a/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java b/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java
index e67876a2d..fa7cf332d 100644
--- a/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java
+++ b/src/main/java/de/bixilon/minosoft/util/ChunkUtil.java
@@ -15,6 +15,7 @@ package de.bixilon.minosoft.util;
import de.bixilon.minosoft.data.mappings.Dimension;
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.ChunkSection;
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.HashMap;
+import java.util.Map;
import static de.bixilon.minosoft.protocol.protocol.ProtocolVersions.*;
@@ -56,7 +58,7 @@ public final class ChunkUtil {
HashMap sectionMap = new HashMap<>();
for (int c = 0; c < ProtocolDefinition.SECTIONS_PER_CHUNK; c++) { // max sections per chunks in chunk column
if (BitByte.isBitSet(sectionBitMasks[0], c)) {
- HashMap blockMap = new HashMap<>();
+ HashMap blockMap = new HashMap<>();
for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < ProtocolDefinition.SECTION_WIDTH_Z; nibbleZ++) {
@@ -84,12 +86,12 @@ public final class ChunkUtil {
continue;
}
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++;
}
}
}
- sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap));
+ sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap, Map.of())); // ToDo
}
}
return new Chunk(sectionMap);
@@ -120,7 +122,7 @@ public final class ChunkUtil {
if (!BitByte.isBitSet(sectionBitMasks[0], c)) {
continue;
}
- HashMap blockMap = new HashMap<>();
+ HashMap blockMap = new HashMap<>();
for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < ProtocolDefinition.SECTION_WIDTH_Z; nibbleZ++) {
@@ -131,12 +133,12 @@ public final class ChunkUtil {
arrayPos++;
continue;
}
- blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), block);
+ blockMap.put(new InChunkSectionLocation(nibbleX, nibbleY, nibbleZ), new BlockInfo(block));
arrayPos++;
}
}
}
- sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap));
+ sectionMap.put(dimension.getLowestSection() + c, new ChunkSection(blockMap, Map.of()));
}
return new Chunk(sectionMap);
}
@@ -156,7 +158,7 @@ public final class ChunkUtil {
long[] data = buffer.readLongArray();
- HashMap blockMap = new HashMap<>();
+ HashMap blockMap = new HashMap<>();
for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < ProtocolDefinition.SECTION_WIDTH_Z; nibbleZ++) {
for (int nibbleX = 0; nibbleX < ProtocolDefinition.SECTION_WIDTH_X; nibbleX++) {
@@ -187,7 +189,7 @@ public final class ChunkUtil {
if (block == null) {
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) {
byte[] biomes = buffer.readBytes(256);