diff --git a/ReadMe.md b/ReadMe.md index 27fd18e35..3a098b9d7 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -12,7 +12,7 @@ Minosoft is an open source minecraft client, written from scratch in kotlin (and ## Feature overview - Rendering -- Connect with any version to any server (1.7 - latest) +- Connect with any version to any server (1.7 - 1.19) - ~~Modding~~ - Bleeding edge performance (e.g. incredible start time) - Free (as far as we consider original minecraft as free) and open source @@ -125,11 +125,11 @@ Support for macOS is a delicate topic. Let's say it works for now, but it is not ## Building -1. Install Maven and java 11+ (On Ubuntu based distributions: `sudo apt install maven openjdk-11-jdk`). For Windows users, download and install java from oracle or openjdk. Also download maven and follow along +1. Install Maven and java 11+ (e.g. `sudo apt install maven openjdk-11-jdk`). For Windows users, download and install java from oracle or openjdk. Also download maven and follow along 2. Clone this repository (`git clone https://gitlab.bixilon.de/bixilon/minosoft.git`) 3. Change directory (`cd minosoft`) 4. Optional: Checkout a current feature branch (Warning: might be unstable; might not even build) (`git checkout `) -5. Build and run Minosoft with `mvn clean verify exec:java`. If any errors occur, feel free to open an issue. In this early stage it might be helpful to delete the config file +5. Build and run Minosoft with `mvn clean verify exec:java`. If any errors occur, feel free to open an issue. In this early stage it might be helpful to delete its configuration files 6. (Optional) Build a fat jar with `mvn package`. You'll find the jar with all dependencies in `target/`. Then you don't need to recompile everytime ## Code mirrors diff --git a/src/main/java/de/bixilon/minosoft/data/world/World.kt b/src/main/java/de/bixilon/minosoft/data/world/World.kt index c7b98d076..4ca45ffe9 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/World.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/World.kt @@ -376,24 +376,27 @@ class World( val neighboursPositions = getChunkNeighbourPositions(chunkPosition) val neighbours = getChunkNeighbours(neighboursPositions) - if (neighbours.received) { + val neighboursReceived = neighbours.received + if (neighboursReceived) { chunk.neighbours = neighbours.cast() if (!chunk.biomesInitialized && cacheBiomeAccessor != null && chunk.biomeSource != null && neighbours.canBuildBiomeCache) { chunk.buildBiomeCache() } + } + + + if (checkNeighbours) { + for (index in 0 until 8) { + val neighbour = neighbours[index] ?: continue + onChunkUpdate(neighboursPositions[index], neighbour, false) + } + } + + if (neighboursReceived) { + chunk.recalculateLight() connection.fireEvent(ChunkDataChangeEvent(connection, EventInitiators.UNKNOWN, chunkPosition, chunk)) } - - - if (!checkNeighbours) { - return - } - - for (index in 0 until 8) { - val neighbour = neighbours[index] ?: continue - onChunkUpdate(neighboursPositions[index], neighbour, false) - } } fun getBrightness(position: Vec3i): Float { diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/Chunk.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/Chunk.kt index 7ae62744c..372a4e4a9 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/chunk/Chunk.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/Chunk.kt @@ -59,14 +59,13 @@ class Chunk( val heightmap = IntArray(ProtocolDefinition.SECTION_WIDTH_X * ProtocolDefinition.SECTION_WIDTH_Z) var neighbours: Array? = null - set(value) { + @Synchronized set(value) { if (field.contentEquals(value)) { return } field = value if (value != null) { updateSectionNeighbours(value) - recalculateLight() } } @@ -104,6 +103,7 @@ class Chunk( if (blockEntity == null) { getOrPutBlockEntity(x, y, z) } + // ToDo: Remove section if isEmpty val neighbours = this.neighbours ?: return @@ -250,12 +250,16 @@ class Chunk( if (cacheBiomeAccessor != null && biomesInitialized) { section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor) } + section.neighbours = ChunkUtil.getDirectNeighbours(neighbours, this, sectionHeight) for (neighbour in neighbours) { val neighbourNeighbours = neighbour.neighbours ?: continue neighbour.updateNeighbours(neighbourNeighbours, sectionHeight) } } sections[sectionIndex] = section + + // check light of neighbours to check if their light needs to be traced into our own chunk + section.light.propagateFromNeighbours() } return section } diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/light/SectionLight.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/light/SectionLight.kt index 3da0a8c2e..84ec3d812 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/chunk/light/SectionLight.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/light/SectionLight.kt @@ -42,7 +42,7 @@ class SectionLight( private fun startDecreaseTrace(x: Int, y: Int, z: Int) { // that is kind of hacky, but far easier and kind of faster - val light = this.light[getIndex(x, y, z)].toInt() and 0x0F + val light = this.light[getIndex(x, y, z)].toInt() and BLOCK_LIGHT_MASK decreaseLight(x, y, z, light, true) // just clear the light decreaseLight(x, y, z, light, false) // increase the light in all sections @@ -96,7 +96,7 @@ class SectionLight( } // get block or next luminance level - val currentLight = light[index].toInt() and 0x0F // we just care about block light + val currentLight = light[index].toInt() and BLOCK_LIGHT_MASK // we just care about block light if (currentLight >= nextLuminance) { // light is already higher, no need to trace return @@ -202,4 +202,30 @@ class SectionLight( override operator fun get(index: Int): Byte { return light[index] } + + fun propagateFromNeighbours() { + val neighbours = section.neighbours ?: return + // ToDo(p): this::traceIncrease checks als the block light level, not needed + for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) { + for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) { + neighbours[Directions.O_DOWN]?.let { traceIncrease(x, 0, z, it.light[x, ProtocolDefinition.SECTION_MAX_Y, z].toInt() and BLOCK_LIGHT_MASK) } + neighbours[Directions.O_UP]?.let { traceIncrease(x, ProtocolDefinition.SECTION_MAX_Y, z, it.light[x, 0, z].toInt() and BLOCK_LIGHT_MASK) } + } + for (y in 0 until ProtocolDefinition.SECTION_HEIGHT_Y) { + neighbours[Directions.O_NORTH]?.let { traceIncrease(x, y, 0, it.light[x, y, ProtocolDefinition.SECTION_MAX_Z].toInt() and BLOCK_LIGHT_MASK) } + neighbours[Directions.O_SOUTH]?.let { traceIncrease(x, y, ProtocolDefinition.SECTION_MAX_Z, it.light[x, y, 0].toInt() and BLOCK_LIGHT_MASK) } + } + } + for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) { + for (y in 0 until ProtocolDefinition.SECTION_HEIGHT_Y) { + neighbours[Directions.O_WEST]?.let { traceIncrease(0, y, z, it.light[ProtocolDefinition.SECTION_MAX_Z, y, z].toInt() and BLOCK_LIGHT_MASK) } + neighbours[Directions.O_UP]?.let { traceIncrease(ProtocolDefinition.SECTION_MAX_X, y, z, it.light[0, y, z].toInt() and BLOCK_LIGHT_MASK) } + } + } + } + + companion object { + const val BLOCK_LIGHT_MASK = 0x0F + const val SKY_LIGHT_MASK = 0xF0 + } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/ProtocolDefinition.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/ProtocolDefinition.java index fee1c5fae..81515693d 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/ProtocolDefinition.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/ProtocolDefinition.java @@ -51,11 +51,12 @@ public final class ProtocolDefinition { public static final Pattern MINECRAFT_NAME_VALIDATOR = Pattern.compile("\\w{3,16}"); - public static final int SECTION_WIDTH_X = 16; + public static final int SECTION_LENGTH = 16; + public static final int SECTION_WIDTH_X = SECTION_LENGTH; public static final int SECTION_MAX_X = SECTION_WIDTH_X - 1; - public static final int SECTION_WIDTH_Z = 16; + public static final int SECTION_WIDTH_Z = SECTION_LENGTH; public static final int SECTION_MAX_Z = SECTION_WIDTH_Z - 1; - public static final int SECTION_HEIGHT_Y = 16; + public static final int SECTION_HEIGHT_Y = SECTION_LENGTH; public static final int SECTION_MAX_Y = SECTION_HEIGHT_Y - 1; public static final int BLOCKS_PER_SECTION = SECTION_WIDTH_X * SECTION_HEIGHT_Y * SECTION_WIDTH_X; public static final Vec3i CHUNK_SECTION_SIZE = new Vec3i(ProtocolDefinition.SECTION_WIDTH_X, ProtocolDefinition.SECTION_HEIGHT_Y, ProtocolDefinition.SECTION_WIDTH_Z);