get light from edge chunks

This commit is contained in:
Bixilon 2022-09-07 15:42:10 +02:00
parent 959d682eb0
commit db07729325
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
5 changed files with 55 additions and 21 deletions

View File

@ -12,7 +12,7 @@ Minosoft is an open source minecraft client, written from scratch in kotlin (and
## Feature overview ## Feature overview
- Rendering - Rendering
- Connect with any version to any server (1.7 - latest) - Connect with any version to any server (1.7 - 1.19)
- ~~Modding~~ - ~~Modding~~
- Bleeding edge performance (e.g. incredible start time) - Bleeding edge performance (e.g. incredible start time)
- Free (as far as we consider original minecraft as free) and open source - 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 ## 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`) 2. Clone this repository (`git clone https://gitlab.bixilon.de/bixilon/minosoft.git`)
3. Change directory (`cd minosoft`) 3. Change directory (`cd minosoft`)
4. Optional: Checkout a current feature branch (Warning: might be unstable; might not even build) (`git checkout <branch>`) 4. Optional: Checkout a current feature branch (Warning: might be unstable; might not even build) (`git checkout <branch>`)
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 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 ## Code mirrors

View File

@ -376,24 +376,27 @@ class World(
val neighboursPositions = getChunkNeighbourPositions(chunkPosition) val neighboursPositions = getChunkNeighbourPositions(chunkPosition)
val neighbours = getChunkNeighbours(neighboursPositions) val neighbours = getChunkNeighbours(neighboursPositions)
if (neighbours.received) { val neighboursReceived = neighbours.received
if (neighboursReceived) {
chunk.neighbours = neighbours.cast() chunk.neighbours = neighbours.cast()
if (!chunk.biomesInitialized && cacheBiomeAccessor != null && chunk.biomeSource != null && neighbours.canBuildBiomeCache) { if (!chunk.biomesInitialized && cacheBiomeAccessor != null && chunk.biomeSource != null && neighbours.canBuildBiomeCache) {
chunk.buildBiomeCache() 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)) 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 { fun getBrightness(position: Vec3i): Float {

View File

@ -59,14 +59,13 @@ class Chunk(
val heightmap = IntArray(ProtocolDefinition.SECTION_WIDTH_X * ProtocolDefinition.SECTION_WIDTH_Z) val heightmap = IntArray(ProtocolDefinition.SECTION_WIDTH_X * ProtocolDefinition.SECTION_WIDTH_Z)
var neighbours: Array<Chunk>? = null var neighbours: Array<Chunk>? = null
set(value) { @Synchronized set(value) {
if (field.contentEquals(value)) { if (field.contentEquals(value)) {
return return
} }
field = value field = value
if (value != null) { if (value != null) {
updateSectionNeighbours(value) updateSectionNeighbours(value)
recalculateLight()
} }
} }
@ -104,6 +103,7 @@ class Chunk(
if (blockEntity == null) { if (blockEntity == null) {
getOrPutBlockEntity(x, y, z) getOrPutBlockEntity(x, y, z)
} }
// ToDo: Remove section if isEmpty
val neighbours = this.neighbours ?: return val neighbours = this.neighbours ?: return
@ -250,12 +250,16 @@ class Chunk(
if (cacheBiomeAccessor != null && biomesInitialized) { if (cacheBiomeAccessor != null && biomesInitialized) {
section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor) section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor)
} }
section.neighbours = ChunkUtil.getDirectNeighbours(neighbours, this, sectionHeight)
for (neighbour in neighbours) { for (neighbour in neighbours) {
val neighbourNeighbours = neighbour.neighbours ?: continue val neighbourNeighbours = neighbour.neighbours ?: continue
neighbour.updateNeighbours(neighbourNeighbours, sectionHeight) neighbour.updateNeighbours(neighbourNeighbours, sectionHeight)
} }
} }
sections[sectionIndex] = section 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 return section
} }

View File

@ -42,7 +42,7 @@ class SectionLight(
private fun startDecreaseTrace(x: Int, y: Int, z: Int) { private fun startDecreaseTrace(x: Int, y: Int, z: Int) {
// that is kind of hacky, but far easier and kind of faster // 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, true) // just clear the light
decreaseLight(x, y, z, light, false) // increase the light in all sections decreaseLight(x, y, z, light, false) // increase the light in all sections
@ -96,7 +96,7 @@ class SectionLight(
} }
// get block or next luminance level // 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) { if (currentLight >= nextLuminance) {
// light is already higher, no need to trace // light is already higher, no need to trace
return return
@ -202,4 +202,30 @@ class SectionLight(
override operator fun get(index: Int): Byte { override operator fun get(index: Int): Byte {
return light[index] 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
}
} }

View File

@ -51,11 +51,12 @@ public final class ProtocolDefinition {
public static final Pattern MINECRAFT_NAME_VALIDATOR = Pattern.compile("\\w{3,16}"); 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_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_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 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 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); public static final Vec3i CHUNK_SECTION_SIZE = new Vec3i(ProtocolDefinition.SECTION_WIDTH_X, ProtocolDefinition.SECTION_HEIGHT_Y, ProtocolDefinition.SECTION_WIDTH_Z);