Skip to content
This repository has been archived by the owner on Mar 8, 2024. It is now read-only.

Commit

Permalink
Starlight 0.0.2-RC3
Browse files Browse the repository at this point in the history
1. Fix chunk relighting
 In order to make relighting more reliable, move the
 emptiness map lookups to their own cache. This allows us
 to not clobber/use emptiness map values for chunks that were
 not relight during the call.
 More importantly, fix a typo where we supplied the wrong chunk
 argument to the emptiness change function for chunk neighbours -
 this caused the nibbles for the target chunk to be clobbered.

2. Fix broken edge checks
 While edge checks are not currently used, it doesn't mean
 they should be broken. Edge checks should be able to happen
 on null nibbles for block lighting (sky lighting will not have
 nibbles marked null during edge checks).

3. Make handleEmptySectionChanges non-relaxed serverside
 For the server, it should be that the chunks in 1 radius are
 loaded during this call.

4. Fix incorrect neighbour nibble init logic
 We need to be copying the whole array, not just
 the first 9 values.

5. Fix potential missed updateVisible calls
 rewriteNibbleCacheForSkylight could set a value
 in the cache to null and not update the nibble.
 Now the call will call updateVisible when
 removing nibbles from the cache.

6. Fix skylight propagation on the -1 chunk section
 Allow sources to be set up on y=-16, and fix light
 retrieval for y < -16
  • Loading branch information
Spottedleaf committed Dec 28, 2020
1 parent 1da2560 commit 7b0a56c
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 64 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Starlight (BETA)
Starlight (Fabric) (BETA)
==
Fabric mod for completely rewriting the vanilla light engine.

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ minecraft_version=1.16.4
yarn_mappings=1.16.4+build.7
loader_version=0.10.8
# Mod Properties
mod_version=0.0.2-RC2
mod_version=0.0.2-RC3
maven_group=ca.spottedleaf.starlight
archives_base_name=starlight
# Dependencies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ protected boolean canUseChunk(final Chunk chunk) {
return chunk.getStatus().isAtLeast(ChunkStatus.LIGHT) && (this.isClientSide || chunk.isLightOn());
}

@Override
protected boolean[][] getEmptinessMap(final Chunk chunk) {
return null;
}

@Override
protected void handleEmptySectionChanges(final ChunkProvider lightAccess, final Chunk chunk,
final Boolean[] emptinessChanges, final boolean unlit) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ protected void handleEmptySectionChanges(final ChunkProvider lightAccess, final
final int chunkX = chunk.getPos().x;
final int chunkZ = chunk.getPos().z;

final boolean[][] chunkEmptinessMap = this.getEmptinessMap(chunkX, chunkZ);

// index = (cx + 2) + 5*(cz + 2)
long loadedNeighboursBitset = 0L;
long unloadedNeighbourBitset = 0L;
Expand All @@ -60,7 +62,7 @@ protected void handleEmptySectionChanges(final ChunkProvider lightAccess, final
continue;
}

final boolean[][] neighbourEmptinessMap = ((ExtendedChunk)neighbour).getEmptinessMap();
final boolean[][] neighbourEmptinessMap = this.getEmptinessMap(dx + chunkX, dz + chunkZ);
for (int i = 0; i < neighbourEmptinessMap.length; ++i) {
// index = (cx + 1) + 3*(cz + 1)
final int dx2 = (i % 3) - 1;
Expand All @@ -80,14 +82,11 @@ protected void handleEmptySectionChanges(final ChunkProvider lightAccess, final
loadedNeighboursBitset |= 1L << ((0 + 2) + 5*(0 + 2));

final boolean[] needsDeInitCheck = new boolean[9];
final boolean needsInit = ((ExtendedChunk)chunk).getEmptinessMap()[ExtendedChunk.getEmptinessMapIndex(0, 0)] == null;
final boolean needsInit = unlit || chunkEmptinessMap[ExtendedChunk.getEmptinessMapIndex(0, 0)] == null;
if (needsInit) {
((ExtendedChunk)chunk).getEmptinessMap()[ExtendedChunk.getEmptinessMapIndex(0, 0)] = new boolean[16];
chunkEmptinessMap[ExtendedChunk.getEmptinessMapIndex(0, 0)] = new boolean[16];;
}

// index = (cx + 2) + 5*(cz + 2)
final boolean[][] chunkEmptinessMap = ((ExtendedChunk)chunk).getEmptinessMap();

// this chunk is new, so we need to init neighbours
// because this chunk might have been modified inbetween loading/saving, we have to rewrite the emptiness map
// for our neighbours, so don't bother checking if they exist & whether they even needed a de-init recalc
Expand All @@ -99,19 +98,20 @@ protected void handleEmptySectionChanges(final ChunkProvider lightAccess, final
// when it does though, it'll come by and initialise our map for it
continue;
}
final boolean[][] neighbourEmptinessMap = this.getEmptinessMap(dx + chunkX, dz + chunkZ);

if (needsInit && (dx | dz) != 0) {
// init neighbour
neighbour.getEmptinessMap()[ExtendedChunk.getEmptinessMapIndex(-dx, -dz)] = new boolean[16];
neighbourEmptinessMap[ExtendedChunk.getEmptinessMapIndex(-dx, -dz)] = new boolean[16];

if (neighbour.getEmptinessMap()[ExtendedChunk.getEmptinessMapIndex(0, 0)] != null) {
if (neighbourEmptinessMap[ExtendedChunk.getEmptinessMapIndex(0, 0)] != null) {
// init ourselves
System.arraycopy(
neighbour.getEmptinessMap()[ExtendedChunk.getEmptinessMapIndex(0, 0)],
neighbourEmptinessMap[ExtendedChunk.getEmptinessMapIndex(0, 0)],
0,
chunkEmptinessMap[ExtendedChunk.getEmptinessMapIndex(dx, dz)] = new boolean[16],
0,
9
16
);
}
}
Expand Down Expand Up @@ -161,7 +161,7 @@ protected void handleEmptySectionChanges(final ChunkProvider lightAccess, final
}

// update neighbour map
neighbour.getEmptinessMap()[ExtendedChunk.getEmptinessMapIndex(-dx, -dz)][sectionY] = empty;
this.getEmptinessMap(dx + chunkX, dz + chunkZ)[ExtendedChunk.getEmptinessMapIndex(-dx, -dz)][sectionY] = empty;
}
}
}
Expand All @@ -176,11 +176,11 @@ protected void handleEmptySectionChanges(final ChunkProvider lightAccess, final
final int neighbourX = (i % 3) - 1 + chunkX;
final int neighbourZ = (i / 3) - 1 + chunkZ;

final boolean[][] neighbourEmptinessMap = ((ExtendedChunk)this.getChunkInCache(neighbourX, neighbourZ)).getEmptinessMap();
final boolean[][] neighbourEmptinessMap = this.getEmptinessMap(neighbourX, neighbourZ);

for (int sectionY = 16; sectionY >= -1; --sectionY) {
final SWMRNibbleArray nibble = this.getNibbleFromCache(neighbourX, sectionY, neighbourZ);
if (nibble.isNullNibbleUpdating()) {
if (nibble == null || nibble.isNullNibbleUpdating()) {
// already null
continue;
}
Expand Down Expand Up @@ -234,8 +234,7 @@ protected final void initNibbleForLitChunk(final SWMRNibbleArray currNibble, fin
return;
}

final boolean[] emptinessMap = ((ExtendedChunk)this.getChunkInCache(chunkX, chunkZ))
.getEmptinessMap()[ExtendedChunk.getEmptinessMapIndex(0, 0)];
final boolean[] emptinessMap = this.getEmptinessMap(chunkX, chunkZ)[ExtendedChunk.getEmptinessMapIndex(0, 0)];

// are we above this chunk's lowest empty section?
int lowestY = -2;
Expand Down Expand Up @@ -284,6 +283,7 @@ protected final void rewriteNibbleCacheForSkylight(final Chunk chunk) {
if (nibble != null && nibble.isNullNibbleUpdating()) {
// stop propagation in these areas
this.nibbleCache[index] = null;
nibble.updateVisible();
}
}
}
Expand Down Expand Up @@ -361,6 +361,11 @@ protected SWMRNibbleArray[] getNibblesOnChunk(final Chunk chunk) {
return ((ExtendedChunk)chunk).getSkyNibbles();
}

@Override
protected boolean[][] getEmptinessMap(final Chunk chunk) {
return ((ExtendedChunk)chunk).getEmptinessMap();
}

@Override
protected void setNibbles(final Chunk chunk, final SWMRNibbleArray[] to) {
((ExtendedChunk)chunk).setSkyNibbles(to);
Expand Down Expand Up @@ -472,7 +477,7 @@ protected void propagateBlockChanges(final ChunkProvider lightAccess, final Chun
// ensure section is checked
this.checkNullSection(columnX >> 4, maxPropagationY >> 4, columnZ >> 4, true);

for (int currY = maxPropagationY; currY >= -15; --currY) {
for (int currY = maxPropagationY; currY >= (-1 << 4); --currY) {
if ((currY & 15) == 15) {
// ensure section is checked
this.checkNullSection(columnX >> 4, (currY >> 4), columnZ >> 4, true);
Expand Down Expand Up @@ -611,7 +616,7 @@ protected void lightChunk(final ChunkProvider lightAccess, final Chunk chunk, fi
final int maxZ = worldChunkZ + 16;
for (int currZ = minZ; currZ <= maxZ; ++currZ) {
for (int currX = minX; currX <= maxX; ++currX) {
int maxY = -33;
int maxY = ((-1 -1) << 4);

// ensure the section below is always checked
this.checkNullSection(currX >> 4, highestNonEmptySection, currZ >> 4, false);
Expand Down Expand Up @@ -725,12 +730,12 @@ protected void lightChunk(final ChunkProvider lightAccess, final Chunk chunk, fi
// not required to propagate here, but this will reduce the hit of the edge checks
this.performLightIncrease(lightAccess);

for (int y = -1; y <= 16; ++y) {
for (int y = 16; y >= -1; --y) {
this.checkNullSection(chunkX, y, chunkZ, false);
}
this.checkChunkEdges(lightAccess, chunk, -1, 16);
} else {
for (int y = -1; y <= highestNonEmptySection; ++y) {
for (int y = highestNonEmptySection; y >= -1; --y) {
this.checkNullSection(chunkX, y, chunkZ, false);
}
this.propagateNeighbourLevels(lightAccess, chunk, -1, highestNonEmptySection);
Expand Down Expand Up @@ -797,7 +802,7 @@ protected final int tryPropagateSkylight(final BlockView world, final int worldX
above = AIR_BLOCK_STATE;
}

for (;startY >= -15; --startY) {
for (;startY >= (-1 << 4); --startY) {
if ((startY & 15) == 15) {
// ensure this section is always checked
this.checkNullSection(worldX >> 4, startY >> 4, worldZ >> 4, extrudeInitialised);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ public AxisDirection getOpposite() {
// index = x + (z * 5)
protected final Chunk[] chunkCache = new Chunk[5 * 5];

// index = x + (z * 5)
protected final boolean[][][] emptinessMapCache = new boolean[5 * 5][][];

protected final BlockPos.Mutable mutablePos1 = new BlockPos.Mutable();
protected final BlockPos.Mutable mutablePos2 = new BlockPos.Mutable();
protected final BlockPos.Mutable mutablePos3 = new BlockPos.Mutable();
Expand Down Expand Up @@ -176,6 +179,7 @@ protected final void setupCaches(final ChunkProvider chunkProvider, final int ce
this.setChunkInCache(cx, cz, chunk);
this.setBlocksForChunkInCache(cx, cz, chunk.getSectionArray());
this.setNibblesForChunkInCache(cx, cz, this.getNibblesOnChunk(chunk));
this.setEmptinessMapCache(cx, cz, this.getEmptinessMap(chunk));
}
}
}
Expand Down Expand Up @@ -247,6 +251,7 @@ protected final void destroyCaches() {
Arrays.fill(this.sectionCache, null);
Arrays.fill(this.nibbleCache, null);
Arrays.fill(this.chunkCache, null);
Arrays.fill(this.emptinessMapCache, null);
if (this.isClientSide) {
Arrays.fill(this.notifyUpdateCache, false);
}
Expand Down Expand Up @@ -349,6 +354,14 @@ protected final void setLightLevel(final int sectionIndex, final int localIndex,
}
}

protected final boolean[][] getEmptinessMap(final int chunkX, final int chunkZ) {
return this.emptinessMapCache[chunkX + 5*chunkZ + this.chunkIndexOffset];
}

protected final void setEmptinessMapCache(final int chunkX, final int chunkZ, final boolean[][] emptinessMap) {
this.emptinessMapCache[chunkX + 5*chunkZ + this.chunkIndexOffset] = emptinessMap;
}

public static SWMRNibbleArray[] getFilledEmptyLight() {
final SWMRNibbleArray[] ret = getEmptyLightArray();

Expand All @@ -363,13 +376,14 @@ public static SWMRNibbleArray[] getEmptyLightArray() {
return new SWMRNibbleArray[16 - (-1) + 1];
}

protected abstract boolean[][] getEmptinessMap(final Chunk chunk);

protected abstract SWMRNibbleArray[] getNibblesOnChunk(final Chunk chunk);

protected abstract void setNibbles(final Chunk chunk, final SWMRNibbleArray[] to);

protected abstract boolean canUseChunk(final Chunk chunk);

// TODO include section changes
public final void blocksChangedInChunk(final ChunkProvider lightAccess, final int chunkX, final int chunkZ,
final Set<BlockPos> positions, final Boolean[] changedSections) {
this.setupCaches(lightAccess, chunkX * 16 + 7, 128, chunkZ * 16 + 7, this.isClientSide);
Expand Down Expand Up @@ -410,7 +424,7 @@ protected void checkChunkEdge(final ChunkProvider lightAccess, final Chunk chunk
final SWMRNibbleArray neighbourNibble = this.getNibbleFromCache(chunkX + neighbourOffX,
chunkY, chunkZ + neighbourOffZ);

if (neighbourNibble == null || neighbourNibble.isNullNibbleUpdating()) {
if (neighbourNibble == null) {
continue;
}

Expand Down Expand Up @@ -527,7 +541,7 @@ protected final void propagateNeighbourLevels(final ChunkProvider lightAccess, f

for (int currSectionY = toSection; currSectionY >= fromSection; --currSectionY) {
final SWMRNibbleArray currNibble = this.getNibbleFromCache(chunkX, currSectionY, chunkZ);
if (this.skylightPropagator && currNibble == null) {
if (currNibble == null) {
continue;
}
for (final AxisDirection direction : ONLY_HORIZONTAL_DIRECTIONS) {
Expand All @@ -537,16 +551,7 @@ protected final void propagateNeighbourLevels(final ChunkProvider lightAccess, f
final SWMRNibbleArray neighbourNibble = this.getNibbleFromCache(chunkX + neighbourOffX,
currSectionY, chunkZ + neighbourOffZ);

if (neighbourNibble == null || neighbourNibble.isNullNibbleUpdating()) {
continue;
}

if (this.skylightPropagator && currNibble.isNullNibbleUpdating()) {
// TODO in what situation does this happen? Pretty sure it's erroneous.
continue;
}

if (!neighbourNibble.isInitialisedUpdating()) {
if (neighbourNibble == null || !neighbourNibble.isInitialisedUpdating()) {
// can't pull from 0
continue;
}
Expand Down Expand Up @@ -588,9 +593,9 @@ protected final void propagateNeighbourLevels(final ChunkProvider lightAccess, f
for (int currY = currSectionY << 4, maxY = currY | 15; currY <= maxY; ++currY) {
for (int i = 0, currX = startX, currZ = startZ; i < 16; ++i, currX += incX, currZ += incZ) {
final int level = neighbourNibble.getUpdating(
(currX & 15) |
(currZ & 15) << 4 |
(currY & 15) << 8
(currX & 15)
| ((currZ & 15) << 4)
| ((currY & 15) << 8)
);

if (level <= 1) {
Expand Down Expand Up @@ -627,7 +632,7 @@ public static Boolean[] getEmptySectionsForChunk(final Chunk chunk) {

public final void handleEmptySectionChanges(final ChunkProvider lightAccess, final int chunkX, final int chunkZ,
final Boolean[] emptinessChanges) {
this.setupCaches(lightAccess, chunkX * 16 + 7, 128, chunkZ * 16 + 7, true);
this.setupCaches(lightAccess, chunkX * 16 + 7, 128, chunkZ * 16 + 7, this.isClientSide);
if (this.isClientSide) {
// force current chunk into cache
final Chunk chunk = (Chunk)lightAccess.getChunk(chunkX, chunkZ);
Expand All @@ -638,6 +643,7 @@ public final void handleEmptySectionChanges(final ChunkProvider lightAccess, fin
this.setChunkInCache(chunkX, chunkZ, chunk);
this.setBlocksForChunkInCache(chunkX, chunkZ, chunk.getSectionArray());
this.setNibblesForChunkInCache(chunkX, chunkZ, this.getNibblesOnChunk(chunk));
this.setEmptinessMapCache(chunkX, chunkZ, this.getEmptinessMap(chunk));
}
try {
final Chunk chunk = this.getChunkInCache(chunkX, chunkZ);
Expand Down Expand Up @@ -701,6 +707,7 @@ public final void light(final ChunkProvider lightAccess, final int chunkX, final
this.setChunkInCache(chunkX, chunkZ, chunk);
this.setBlocksForChunkInCache(chunkX, chunkZ, chunk.getSectionArray());
this.setNibblesForChunkInCache(chunkX, chunkZ, this.getNibblesOnChunk(chunk));
this.setEmptinessMapCache(chunkX, chunkZ, this.getEmptinessMap(chunk));

try {
this.handleEmptySectionChanges(lightAccess, chunk, emptySections, true);
Expand All @@ -721,10 +728,13 @@ protected final void relightChunk(final ChunkProvider lightAccess, final Chunk c
this.setupEncodeOffset(chunkPos.x * 16 + 7, 128, chunkPos.z * 16 + 7);

try {
final SWMRNibbleArray[] chunkNibbles = getFilledEmptyLight();

this.setChunkInCache(chunkPos.x, chunkPos.z, chunk);
this.setBlocksForChunkInCache(chunkPos.x, chunkPos.z, chunk.getSectionArray());
final SWMRNibbleArray[] chunkNibbles = getFilledEmptyLight();
this.setNibblesForChunkInCache(chunkPos.x, chunkPos.z, chunkNibbles);
this.setEmptinessMapCache(chunkPos.x, chunkPos.z, new boolean[9][]);

this.handleEmptySectionChanges(lightAccess, chunk, getEmptySectionsForChunk(chunk), true);
this.lightChunk(lightAccess, chunk, false);

Expand All @@ -745,7 +755,9 @@ protected final void relightChunk(final ChunkProvider lightAccess, final Chunk c
this.setChunkInCache(cx, cz, neighbourChunk);
this.setBlocksForChunkInCache(cx, cz, neighbourChunk.getSectionArray());
this.setNibblesForChunkInCache(cx, cz, getFilledEmptyLight());
this.handleEmptySectionChanges(lightAccess, chunk, getEmptySectionsForChunk(neighbourChunk), true);
this.setEmptinessMapCache(cx, cz, new boolean[9][]);

this.handleEmptySectionChanges(lightAccess, neighbourChunk, getEmptySectionsForChunk(neighbourChunk), true);
this.lightChunk(lightAccess, neighbourChunk, false);
}
}
Expand Down
Loading

0 comments on commit 7b0a56c

Please sign in to comment.