344 lines
16 KiB
Java
344 lines
16 KiB
Java
package net.minecraft.world.level.lighting;
|
|
|
|
import java.util.Objects;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.core.SectionPos;
|
|
import net.minecraft.world.level.ChunkPos;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.chunk.DataLayer;
|
|
import net.minecraft.world.level.chunk.LightChunk;
|
|
import net.minecraft.world.level.chunk.LightChunkGetter;
|
|
import org.jetbrains.annotations.VisibleForTesting;
|
|
|
|
public final class SkyLightEngine extends LightEngine<SkyLightSectionStorage.SkyDataLayerStorageMap, SkyLightSectionStorage> {
|
|
private static final long REMOVE_TOP_SKY_SOURCE_ENTRY = LightEngine.QueueEntry.decreaseAllDirections(15);
|
|
private static final long REMOVE_SKY_SOURCE_ENTRY = LightEngine.QueueEntry.decreaseSkipOneDirection(15, Direction.UP);
|
|
private static final long ADD_SKY_SOURCE_ENTRY = LightEngine.QueueEntry.increaseSkipOneDirection(15, false, Direction.UP);
|
|
private final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
|
|
private final ChunkSkyLightSources emptyChunkSources;
|
|
|
|
public SkyLightEngine(LightChunkGetter p_75843_) {
|
|
this(p_75843_, new SkyLightSectionStorage(p_75843_));
|
|
}
|
|
|
|
@VisibleForTesting
|
|
protected SkyLightEngine(LightChunkGetter p_282215_, SkyLightSectionStorage p_282341_) {
|
|
super(p_282215_, p_282341_);
|
|
this.emptyChunkSources = new ChunkSkyLightSources(p_282215_.getLevel());
|
|
}
|
|
|
|
private static boolean isSourceLevel(int p_285004_) {
|
|
return p_285004_ == 15;
|
|
}
|
|
|
|
private int getLowestSourceY(int p_285058_, int p_285191_, int p_285111_) {
|
|
ChunkSkyLightSources chunkskylightsources = this.getChunkSources(SectionPos.blockToSectionCoord(p_285058_), SectionPos.blockToSectionCoord(p_285191_));
|
|
return chunkskylightsources == null ? p_285111_ : chunkskylightsources.getLowestSourceY(SectionPos.sectionRelative(p_285058_), SectionPos.sectionRelative(p_285191_));
|
|
}
|
|
|
|
@Nullable
|
|
private ChunkSkyLightSources getChunkSources(int p_285270_, int p_285307_) {
|
|
LightChunk lightchunk = this.chunkSource.getChunkForLighting(p_285270_, p_285307_);
|
|
return lightchunk != null ? lightchunk.getSkyLightSources() : null;
|
|
}
|
|
|
|
@Override
|
|
protected void checkNode(long p_75859_) {
|
|
int i = BlockPos.getX(p_75859_);
|
|
int j = BlockPos.getY(p_75859_);
|
|
int k = BlockPos.getZ(p_75859_);
|
|
long l = SectionPos.blockToSection(p_75859_);
|
|
int i1 = this.storage.lightOnInSection(l) ? this.getLowestSourceY(i, k, Integer.MAX_VALUE) : Integer.MAX_VALUE;
|
|
if (i1 != Integer.MAX_VALUE) {
|
|
this.updateSourcesInColumn(i, k, i1);
|
|
}
|
|
|
|
if (this.storage.storingLightForSection(l)) {
|
|
boolean flag = j >= i1;
|
|
if (flag) {
|
|
this.enqueueDecrease(p_75859_, REMOVE_SKY_SOURCE_ENTRY);
|
|
this.enqueueIncrease(p_75859_, ADD_SKY_SOURCE_ENTRY);
|
|
} else {
|
|
int j1 = this.storage.getStoredLevel(p_75859_);
|
|
if (j1 > 0) {
|
|
this.storage.setStoredLevel(p_75859_, 0);
|
|
this.enqueueDecrease(p_75859_, LightEngine.QueueEntry.decreaseAllDirections(j1));
|
|
} else {
|
|
this.enqueueDecrease(p_75859_, PULL_LIGHT_IN_ENTRY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void updateSourcesInColumn(int p_285053_, int p_285140_, int p_285337_) {
|
|
int i = SectionPos.sectionToBlockCoord(this.storage.getBottomSectionY());
|
|
this.removeSourcesBelow(p_285053_, p_285140_, p_285337_, i);
|
|
this.addSourcesAbove(p_285053_, p_285140_, p_285337_, i);
|
|
}
|
|
|
|
private void removeSourcesBelow(int p_285475_, int p_285138_, int p_285130_, int p_285112_) {
|
|
if (p_285130_ > p_285112_) {
|
|
int i = SectionPos.blockToSectionCoord(p_285475_);
|
|
int j = SectionPos.blockToSectionCoord(p_285138_);
|
|
int k = p_285130_ - 1;
|
|
|
|
for (int l = SectionPos.blockToSectionCoord(k); this.storage.hasLightDataAtOrBelow(l); l--) {
|
|
if (this.storage.storingLightForSection(SectionPos.asLong(i, l, j))) {
|
|
int i1 = SectionPos.sectionToBlockCoord(l);
|
|
int j1 = i1 + 15;
|
|
|
|
for (int k1 = Math.min(j1, k); k1 >= i1; k1--) {
|
|
long l1 = BlockPos.asLong(p_285475_, k1, p_285138_);
|
|
if (!isSourceLevel(this.storage.getStoredLevel(l1))) {
|
|
return;
|
|
}
|
|
|
|
this.storage.setStoredLevel(l1, 0);
|
|
this.enqueueDecrease(l1, k1 == p_285130_ - 1 ? REMOVE_TOP_SKY_SOURCE_ENTRY : REMOVE_SKY_SOURCE_ENTRY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void addSourcesAbove(int p_285241_, int p_285212_, int p_284972_, int p_285134_) {
|
|
int i = SectionPos.blockToSectionCoord(p_285241_);
|
|
int j = SectionPos.blockToSectionCoord(p_285212_);
|
|
int k = Math.max(
|
|
Math.max(this.getLowestSourceY(p_285241_ - 1, p_285212_, Integer.MIN_VALUE), this.getLowestSourceY(p_285241_ + 1, p_285212_, Integer.MIN_VALUE)),
|
|
Math.max(this.getLowestSourceY(p_285241_, p_285212_ - 1, Integer.MIN_VALUE), this.getLowestSourceY(p_285241_, p_285212_ + 1, Integer.MIN_VALUE))
|
|
);
|
|
int l = Math.max(p_284972_, p_285134_);
|
|
|
|
for (long i1 = SectionPos.asLong(i, SectionPos.blockToSectionCoord(l), j); !this.storage.isAboveData(i1); i1 = SectionPos.offset(i1, Direction.UP)) {
|
|
if (this.storage.storingLightForSection(i1)) {
|
|
int j1 = SectionPos.sectionToBlockCoord(SectionPos.y(i1));
|
|
int k1 = j1 + 15;
|
|
|
|
for (int l1 = Math.max(j1, l); l1 <= k1; l1++) {
|
|
long i2 = BlockPos.asLong(p_285241_, l1, p_285212_);
|
|
if (isSourceLevel(this.storage.getStoredLevel(i2))) {
|
|
return;
|
|
}
|
|
|
|
this.storage.setStoredLevel(i2, 15);
|
|
if (l1 < k || l1 == p_284972_) {
|
|
this.enqueueIncrease(i2, ADD_SKY_SOURCE_ENTRY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void propagateIncrease(long p_285341_, long p_285204_, int p_285003_) {
|
|
BlockState blockstate = null;
|
|
int i = this.countEmptySectionsBelowIfAtBorder(p_285341_);
|
|
|
|
for (Direction direction : PROPAGATION_DIRECTIONS) {
|
|
if (LightEngine.QueueEntry.shouldPropagateInDirection(p_285204_, direction)) {
|
|
long j = BlockPos.offset(p_285341_, direction);
|
|
if (this.storage.storingLightForSection(SectionPos.blockToSection(j))) {
|
|
int k = this.storage.getStoredLevel(j);
|
|
int l = p_285003_ - 1;
|
|
if (l > k) {
|
|
this.mutablePos.set(j);
|
|
BlockState blockstate1 = this.getState(this.mutablePos);
|
|
int i1 = p_285003_ - this.getOpacity(blockstate1);
|
|
if (i1 > k) {
|
|
if (blockstate == null) {
|
|
blockstate = LightEngine.QueueEntry.isFromEmptyShape(p_285204_)
|
|
? Blocks.AIR.defaultBlockState()
|
|
: this.getState(this.mutablePos.set(p_285341_));
|
|
}
|
|
|
|
if (!this.shapeOccludes(blockstate, blockstate1, direction)) {
|
|
this.storage.setStoredLevel(j, i1);
|
|
if (i1 > 1) {
|
|
this.enqueueIncrease(j, LightEngine.QueueEntry.increaseSkipOneDirection(i1, isEmptyShape(blockstate1), direction.getOpposite()));
|
|
}
|
|
|
|
this.propagateFromEmptySections(j, direction, i1, true, i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void propagateDecrease(long p_285015_, long p_285395_) {
|
|
int i = this.countEmptySectionsBelowIfAtBorder(p_285015_);
|
|
int j = LightEngine.QueueEntry.getFromLevel(p_285395_);
|
|
|
|
for (Direction direction : PROPAGATION_DIRECTIONS) {
|
|
if (LightEngine.QueueEntry.shouldPropagateInDirection(p_285395_, direction)) {
|
|
long k = BlockPos.offset(p_285015_, direction);
|
|
if (this.storage.storingLightForSection(SectionPos.blockToSection(k))) {
|
|
int l = this.storage.getStoredLevel(k);
|
|
if (l != 0) {
|
|
if (l <= j - 1) {
|
|
this.storage.setStoredLevel(k, 0);
|
|
this.enqueueDecrease(k, LightEngine.QueueEntry.decreaseSkipOneDirection(l, direction.getOpposite()));
|
|
this.propagateFromEmptySections(k, direction, l, false, i);
|
|
} else {
|
|
this.enqueueIncrease(k, LightEngine.QueueEntry.increaseOnlyOneDirection(l, false, direction.getOpposite()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private int countEmptySectionsBelowIfAtBorder(long p_285356_) {
|
|
int i = BlockPos.getY(p_285356_);
|
|
int j = SectionPos.sectionRelative(i);
|
|
if (j != 0) {
|
|
return 0;
|
|
} else {
|
|
int k = BlockPos.getX(p_285356_);
|
|
int l = BlockPos.getZ(p_285356_);
|
|
int i1 = SectionPos.sectionRelative(k);
|
|
int j1 = SectionPos.sectionRelative(l);
|
|
if (i1 != 0 && i1 != 15 && j1 != 0 && j1 != 15) {
|
|
return 0;
|
|
} else {
|
|
int k1 = SectionPos.blockToSectionCoord(k);
|
|
int l1 = SectionPos.blockToSectionCoord(i);
|
|
int i2 = SectionPos.blockToSectionCoord(l);
|
|
int j2 = 0;
|
|
|
|
while (!this.storage.storingLightForSection(SectionPos.asLong(k1, l1 - j2 - 1, i2)) && this.storage.hasLightDataAtOrBelow(l1 - j2 - 1)) {
|
|
j2++;
|
|
}
|
|
|
|
return j2;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void propagateFromEmptySections(long p_284965_, Direction p_285308_, int p_284977_, boolean p_285001_, int p_285052_) {
|
|
if (p_285052_ != 0) {
|
|
int i = BlockPos.getX(p_284965_);
|
|
int j = BlockPos.getZ(p_284965_);
|
|
if (crossedSectionEdge(p_285308_, SectionPos.sectionRelative(i), SectionPos.sectionRelative(j))) {
|
|
int k = BlockPos.getY(p_284965_);
|
|
int l = SectionPos.blockToSectionCoord(i);
|
|
int i1 = SectionPos.blockToSectionCoord(j);
|
|
int j1 = SectionPos.blockToSectionCoord(k) - 1;
|
|
int k1 = j1 - p_285052_ + 1;
|
|
|
|
while (j1 >= k1) {
|
|
if (!this.storage.storingLightForSection(SectionPos.asLong(l, j1, i1))) {
|
|
j1--;
|
|
} else {
|
|
int l1 = SectionPos.sectionToBlockCoord(j1);
|
|
|
|
for (int i2 = 15; i2 >= 0; i2--) {
|
|
long j2 = BlockPos.asLong(i, l1 + i2, j);
|
|
if (p_285001_) {
|
|
this.storage.setStoredLevel(j2, p_284977_);
|
|
if (p_284977_ > 1) {
|
|
this.enqueueIncrease(j2, LightEngine.QueueEntry.increaseSkipOneDirection(p_284977_, true, p_285308_.getOpposite()));
|
|
}
|
|
} else {
|
|
this.storage.setStoredLevel(j2, 0);
|
|
this.enqueueDecrease(j2, LightEngine.QueueEntry.decreaseSkipOneDirection(p_284977_, p_285308_.getOpposite()));
|
|
}
|
|
}
|
|
|
|
j1--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static boolean crossedSectionEdge(Direction p_285014_, int p_284991_, int p_285468_) {
|
|
return switch (p_285014_) {
|
|
case NORTH -> p_285468_ == 15;
|
|
case SOUTH -> p_285468_ == 0;
|
|
case WEST -> p_284991_ == 15;
|
|
case EAST -> p_284991_ == 0;
|
|
default -> false;
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public void setLightEnabled(ChunkPos p_285459_, boolean p_285013_) {
|
|
super.setLightEnabled(p_285459_, p_285013_);
|
|
if (p_285013_) {
|
|
ChunkSkyLightSources chunkskylightsources = Objects.requireNonNullElse(this.getChunkSources(p_285459_.x, p_285459_.z), this.emptyChunkSources);
|
|
int i = chunkskylightsources.getHighestLowestSourceY() - 1;
|
|
int j = SectionPos.blockToSectionCoord(i) + 1;
|
|
long k = SectionPos.getZeroNode(p_285459_.x, p_285459_.z);
|
|
int l = this.storage.getTopSectionY(k);
|
|
int i1 = Math.max(this.storage.getBottomSectionY(), j);
|
|
|
|
for (int j1 = l - 1; j1 >= i1; j1--) {
|
|
DataLayer datalayer = this.storage.getDataLayerToWrite(SectionPos.asLong(p_285459_.x, j1, p_285459_.z));
|
|
if (datalayer != null && datalayer.isEmpty()) {
|
|
datalayer.fill(15);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void propagateLightSources(ChunkPos p_285333_) {
|
|
long i = SectionPos.getZeroNode(p_285333_.x, p_285333_.z);
|
|
this.storage.setLightEnabled(i, true);
|
|
ChunkSkyLightSources chunkskylightsources = Objects.requireNonNullElse(this.getChunkSources(p_285333_.x, p_285333_.z), this.emptyChunkSources);
|
|
ChunkSkyLightSources chunkskylightsources1 = Objects.requireNonNullElse(this.getChunkSources(p_285333_.x, p_285333_.z - 1), this.emptyChunkSources);
|
|
ChunkSkyLightSources chunkskylightsources2 = Objects.requireNonNullElse(this.getChunkSources(p_285333_.x, p_285333_.z + 1), this.emptyChunkSources);
|
|
ChunkSkyLightSources chunkskylightsources3 = Objects.requireNonNullElse(this.getChunkSources(p_285333_.x - 1, p_285333_.z), this.emptyChunkSources);
|
|
ChunkSkyLightSources chunkskylightsources4 = Objects.requireNonNullElse(this.getChunkSources(p_285333_.x + 1, p_285333_.z), this.emptyChunkSources);
|
|
int j = this.storage.getTopSectionY(i);
|
|
int k = this.storage.getBottomSectionY();
|
|
int l = SectionPos.sectionToBlockCoord(p_285333_.x);
|
|
int i1 = SectionPos.sectionToBlockCoord(p_285333_.z);
|
|
|
|
for (int j1 = j - 1; j1 >= k; j1--) {
|
|
long k1 = SectionPos.asLong(p_285333_.x, j1, p_285333_.z);
|
|
DataLayer datalayer = this.storage.getDataLayerToWrite(k1);
|
|
if (datalayer != null) {
|
|
int l1 = SectionPos.sectionToBlockCoord(j1);
|
|
int i2 = l1 + 15;
|
|
boolean flag = false;
|
|
|
|
for (int j2 = 0; j2 < 16; j2++) {
|
|
for (int k2 = 0; k2 < 16; k2++) {
|
|
int l2 = chunkskylightsources.getLowestSourceY(k2, j2);
|
|
if (l2 <= i2) {
|
|
int i3 = j2 == 0 ? chunkskylightsources1.getLowestSourceY(k2, 15) : chunkskylightsources.getLowestSourceY(k2, j2 - 1);
|
|
int j3 = j2 == 15 ? chunkskylightsources2.getLowestSourceY(k2, 0) : chunkskylightsources.getLowestSourceY(k2, j2 + 1);
|
|
int k3 = k2 == 0 ? chunkskylightsources3.getLowestSourceY(15, j2) : chunkskylightsources.getLowestSourceY(k2 - 1, j2);
|
|
int l3 = k2 == 15 ? chunkskylightsources4.getLowestSourceY(0, j2) : chunkskylightsources.getLowestSourceY(k2 + 1, j2);
|
|
int i4 = Math.max(Math.max(i3, j3), Math.max(k3, l3));
|
|
|
|
for (int j4 = i2; j4 >= Math.max(l1, l2); j4--) {
|
|
datalayer.set(k2, SectionPos.sectionRelative(j4), j2, 15);
|
|
if (j4 == l2 || j4 < i4) {
|
|
long k4 = BlockPos.asLong(l + k2, j4, i1 + j2);
|
|
this.enqueueIncrease(k4, LightEngine.QueueEntry.increaseSkySourceInDirections(j4 == l2, j4 < i3, j4 < j3, j4 < k3, j4 < l3));
|
|
}
|
|
}
|
|
|
|
if (l2 < l1) {
|
|
flag = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!flag) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |