|
5 | 5 | import ca.spottedleaf.starlight.common.chunk.ExtendedChunkSection; |
6 | 6 | import ca.spottedleaf.starlight.common.util.WorldUtil; |
7 | 7 | import it.unimi.dsi.fastutil.shorts.ShortCollection; |
| 8 | +import it.unimi.dsi.fastutil.shorts.ShortIterator; |
8 | 9 | import net.minecraft.block.BlockState; |
9 | 10 | import net.minecraft.util.math.BlockPos; |
10 | 11 | import net.minecraft.util.math.ChunkPos; |
@@ -345,13 +346,28 @@ protected boolean canUseChunk(final Chunk chunk) { |
345 | 346 | @Override |
346 | 347 | protected void checkChunkEdges(final ChunkProvider lightAccess, final Chunk chunk, final int fromSection, |
347 | 348 | final int toSection) { |
| 349 | + Arrays.fill(this.nullPropagationCheckCache, false); |
348 | 350 | this.rewriteNibbleCacheForSkylight(chunk); |
| 351 | + final int chunkX = chunk.getPos().x; |
| 352 | + final int chunkZ = chunk.getPos().z; |
| 353 | + for (int y = toSection; y >= fromSection; --y) { |
| 354 | + this.checkNullSection(chunkX, y, chunkZ, true); |
| 355 | + } |
| 356 | + |
349 | 357 | super.checkChunkEdges(lightAccess, chunk, fromSection, toSection); |
350 | 358 | } |
351 | 359 |
|
352 | 360 | @Override |
353 | | - protected void checkChunkEdges(ChunkProvider lightAccess, Chunk chunk, ShortCollection sections) { |
| 361 | + protected void checkChunkEdges(final ChunkProvider lightAccess, final Chunk chunk, final ShortCollection sections) { |
| 362 | + Arrays.fill(this.nullPropagationCheckCache, false); |
354 | 363 | this.rewriteNibbleCacheForSkylight(chunk); |
| 364 | + final int chunkX = chunk.getPos().x; |
| 365 | + final int chunkZ = chunk.getPos().z; |
| 366 | + for (final ShortIterator iterator = sections.iterator(); iterator.hasNext();) { |
| 367 | + final int y = (int)iterator.nextShort(); |
| 368 | + this.checkNullSection(chunkX, y, chunkZ, true); |
| 369 | + } |
| 370 | + |
355 | 371 | super.checkChunkEdges(lightAccess, chunk, sections); |
356 | 372 | } |
357 | 373 |
|
@@ -385,6 +401,88 @@ protected void checkBlock(final ChunkProvider lightAccess, final int worldX, fin |
385 | 401 | ); |
386 | 402 | } |
387 | 403 |
|
| 404 | + protected final BlockPos.Mutable recalcCenterPos = new BlockPos.Mutable(); |
| 405 | + protected final BlockPos.Mutable recalcNeighbourPos = new BlockPos.Mutable(); |
| 406 | + |
| 407 | + @Override |
| 408 | + protected int calculateLightValue(final ChunkProvider lightAccess, final int worldX, final int worldY, final int worldZ, |
| 409 | + final int expect, final VariableBlockLightHandler customBlockLight) { |
| 410 | + if (expect == 15) { |
| 411 | + return expect; |
| 412 | + } |
| 413 | + |
| 414 | + final int sectionOffset = this.chunkSectionIndexOffset; |
| 415 | + final int opacity; |
| 416 | + final BlockState conditionallyOpaqueState; |
| 417 | + switch ((int)this.getKnownTransparency(worldX, worldY, worldZ)) { |
| 418 | + case (int)ExtendedChunkSection.BLOCK_IS_TRANSPARENT: |
| 419 | + opacity = 1; |
| 420 | + conditionallyOpaqueState = null; |
| 421 | + break; |
| 422 | + case (int)ExtendedChunkSection.BLOCK_IS_FULL_OPAQUE: |
| 423 | + return 0; |
| 424 | + case (int)ExtendedChunkSection.BLOCK_UNKNOWN_TRANSPARENCY: |
| 425 | + opacity = Math.max(1, ((ExtendedAbstractBlockState)this.getBlockState(worldX, worldY, worldZ)).getOpacityIfCached()); |
| 426 | + conditionallyOpaqueState = null; |
| 427 | + if (opacity >= 15) { |
| 428 | + return 0; |
| 429 | + } |
| 430 | + break; |
| 431 | + // variable opacity | conditionally full opaque |
| 432 | + case (int)ExtendedChunkSection.BLOCK_SPECIAL_TRANSPARENCY: |
| 433 | + default: |
| 434 | + this.recalcCenterPos.set(worldX, worldY, worldZ); |
| 435 | + final BlockState state = this.getBlockState(worldX, worldY, worldZ); |
| 436 | + opacity = Math.max(1, state.getOpacity(lightAccess.getWorld(), this.recalcCenterPos)); |
| 437 | + if (((ExtendedAbstractBlockState)state).isConditionallyFullOpaque()) { |
| 438 | + conditionallyOpaqueState = state; |
| 439 | + } else { |
| 440 | + conditionallyOpaqueState = null; |
| 441 | + } |
| 442 | + } |
| 443 | + |
| 444 | + int level = 0; |
| 445 | + |
| 446 | + for (final AxisDirection direction : AXIS_DIRECTIONS) { |
| 447 | + final int offX = worldX + direction.x; |
| 448 | + final int offY = worldY + direction.y; |
| 449 | + final int offZ = worldZ + direction.z; |
| 450 | + |
| 451 | + final int sectionIndex = (offX >> 4) + 5 * (offZ >> 4) + (5 * 5) * (offY >> 4) + sectionOffset; |
| 452 | + |
| 453 | + final int neighbourLevel = this.getLightLevel(sectionIndex, (offX & 15) | ((offZ & 15) << 4) | ((offY & 15) << 8)); |
| 454 | + |
| 455 | + if ((neighbourLevel - 1) <= level) { |
| 456 | + // don't need to test transparency, we know it wont affect the result. |
| 457 | + continue; |
| 458 | + } |
| 459 | + |
| 460 | + final long neighbourOpacity = this.getKnownTransparency(sectionIndex, (offY & 15) | ((offX & 15) << 4) | ((offZ & 15) << 8)); |
| 461 | + |
| 462 | + if (neighbourOpacity == ExtendedChunkSection.BLOCK_SPECIAL_TRANSPARENCY) { |
| 463 | + // here the block can be conditionally opaque (i.e light cannot propagate from it), so we need to test that |
| 464 | + // we don't read the blockstate because most of the time this is false, so using the faster |
| 465 | + // known transparency lookup results in a net win |
| 466 | + final BlockState neighbourState = this.getBlockState(offX, offY, offZ); |
| 467 | + this.recalcNeighbourPos.set(offX, offY, offZ); |
| 468 | + final VoxelShape neighbourFace = neighbourState.getCullingFace(lightAccess.getWorld(), this.recalcNeighbourPos, direction.opposite.nms); |
| 469 | + final VoxelShape thisFace = conditionallyOpaqueState == null ? VoxelShapes.empty() : conditionallyOpaqueState.getCullingFace(lightAccess.getWorld(), this.recalcCenterPos, direction.nms); |
| 470 | + if (VoxelShapes.unionCoversFullCube(thisFace, neighbourFace)) { |
| 471 | + // not allowed to propagate |
| 472 | + continue; |
| 473 | + } |
| 474 | + } |
| 475 | + |
| 476 | + final int calculated = neighbourLevel - opacity; |
| 477 | + level = Math.max(calculated, level); |
| 478 | + if (level > expect) { |
| 479 | + return level; |
| 480 | + } |
| 481 | + } |
| 482 | + |
| 483 | + return level; |
| 484 | + } |
| 485 | + |
388 | 486 | @Override |
389 | 487 | protected void propagateBlockChanges(final ChunkProvider lightAccess, final Chunk atChunk, final Set<BlockPos> positions) { |
390 | 488 | this.rewriteNibbleCacheForSkylight(atChunk); |
@@ -597,7 +695,7 @@ protected void lightChunk(final ChunkProvider lightAccess, final Chunk chunk, fi |
597 | 695 | } |
598 | 696 |
|
599 | 697 | final int highestBitSet = 63 ^ Long.numberOfLeadingZeros(bitset); // from [0, 63] |
600 | | - final int highestYValue = highestBitSet; // y = highest bit set / bits per block |
| 698 | + final int highestYValue = highestBitSet >>> 1; // y = highest bit set / bits per block |
601 | 699 | maxY = highestYValue | (sectionY << 4); |
602 | 700 | break; |
603 | 701 | } |
@@ -686,10 +784,11 @@ protected void lightChunk(final ChunkProvider lightAccess, final Chunk chunk, fi |
686 | 784 | // not required to propagate here, but this will reduce the hit of the edge checks |
687 | 785 | this.performLightIncrease(lightAccess); |
688 | 786 |
|
689 | | - for (int y = this.maxLightSection; y >= this.minLightSection; --y) { |
| 787 | + for (int y = highestNonEmptySection; y >= this.minLightSection; --y) { |
690 | 788 | this.checkNullSection(chunkX, y, chunkZ, false); |
691 | 789 | } |
692 | | - this.checkChunkEdges(lightAccess, chunk, this.minLightSection, this.maxLightSection); |
| 790 | + // no need to rewrite the nibble cache again |
| 791 | + super.checkChunkEdges(lightAccess, chunk, this.minLightSection, highestNonEmptySection); |
693 | 792 | } else { |
694 | 793 | for (int y = highestNonEmptySection; y >= this.minLightSection; --y) { |
695 | 794 | this.checkNullSection(chunkX, y, chunkZ, false); |
|
0 commit comments