propagate weeping sky in initial lighting pass

This commit is contained in:
techno-sam
2025-08-31 23:22:25 +02:00
parent 82b6f661b9
commit 72588b02b6
3 changed files with 109 additions and 0 deletions
@@ -14,6 +14,7 @@ import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.ChunkSectionPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkNibbleArray;
import net.minecraft.world.chunk.ChunkProvider;
import net.minecraft.world.chunk.ChunkToNibbleArrayMap;
import net.minecraft.world.chunk.light.ChunkLightProvider;
@@ -232,4 +233,101 @@ public abstract class ChunkSkyLightProviderMixin<M extends ChunkToNibbleArrayMap
weepingStorage.clearTempRunSplits(localX, localZ);
}
@Inject(method = "propagateLight", at = @At("RETURN"))
private void propagateWeepingLight(ChunkPos chunkPos, CallbackInfo ci,
@Local(name = "sourcesO") ChunkSkyLight sourcesO,
@Local(name = "sourcesZN") ChunkSkyLight sourcesZN,
@Local(name = "sourcesZP") ChunkSkyLight sourcesZP,
@Local(name = "sourcesXN") ChunkSkyLight sourcesXN,
@Local(name = "sourcesXP") ChunkSkyLight sourcesXP
) {
WeepingStorage weepingStorage = ((ChunkSkyLight_Duck) sourcesO).crystalline_sky$getWeepingStorage();
if (weepingStorage == null) return;
boolean hasAny = false;
Outer: for (int localX = 0; localX < 16; localX++) {
for (int localZ = 0; localZ < 16; localZ++) {
if (!weepingStorage.isColumnEmpty(localX, localZ)) {
hasAny = true;
break Outer;
}
}
}
if (!hasAny)
return;
long packedZeroPos = ChunkSectionPos.withZeroY(chunkPos.x, chunkPos.z);
SkyLightStorageAccessor lightStorageAccessor = (SkyLightStorageAccessor) this.lightStorage;
int topSectionY = lightStorageAccessor.crystalline_sky$getTopSectionForColumn(packedZeroPos);
int bottomSectionY = lightStorageAccessor.crystalline_sky$getMinSectionY();
int baseX = ChunkSectionPos.getBlockCoord(chunkPos.x);
int baseZ = ChunkSectionPos.getBlockCoord(chunkPos.z);
int minY = ChunkSectionPos.getBlockCoord(bottomSectionY);
ChunkNibbleArray[] lightArrays = new ChunkNibbleArray[topSectionY - bottomSectionY];
for (int sectionY = topSectionY - 1; sectionY >= bottomSectionY; sectionY--) {
long packedSectionPos = ChunkSectionPos.asLong(chunkPos.x, sectionY, chunkPos.z);
lightArrays[sectionY - bottomSectionY] = lightStorageAccessor.crystalline_sky$method_51547(packedSectionPos);
}
for (int localZ = 0; localZ < 16; localZ++) {
for (int localX = 0; localX < 16; localX++) {
if (weepingStorage.isColumnEmpty(localX, localZ)) continue;
int lowestSourceY = sourcesO.get(localX, localZ);
int effectiveLowestSourceY = lowestSourceY <= minY ? Integer.MIN_VALUE : lowestSourceY;
if (effectiveLowestSourceY == Integer.MIN_VALUE) continue;
int minSourceY_ZN = localZ == 0 ? sourcesZN.get(localX, 15) : sourcesO.get(localX, localZ - 1);
int minSourceY_ZP = localZ == 15 ? sourcesZP.get(localX, 0) : sourcesO.get(localX, localZ + 1);
int minSourceY_XN = localX == 0 ? sourcesXN.get(15, localZ) : sourcesO.get(localX - 1, localZ);
int minSourceY_XP = localX == 15 ? sourcesXP.get(0, localZ) : sourcesO.get(localX + 1, localZ);
int minSourceY_max = Math.max(Math.max(minSourceY_ZN, minSourceY_ZP), Math.max(minSourceY_XN, minSourceY_XP));
for (WeepingStorage.Run run : weepingStorage.iterateLitRuns(localX, localZ, effectiveLowestSourceY)) {
if (run.topY() == Integer.MAX_VALUE) {
if (run.bottomY() == effectiveLowestSourceY) {
continue;
} else {
run = run.withTopY(effectiveLowestSourceY - 1);
}
}
int lowestRelevantY = Math.max(run.bottomY(), minY);
for (int sectionY = ChunkSectionPos.getSectionCoord(lowestRelevantY); sectionY <= topSectionY - 1; sectionY++) {
ChunkNibbleArray lightArray = lightArrays[sectionY - bottomSectionY];
if (lightArray == null) continue;
int minYInSection = ChunkSectionPos.getBlockCoord(sectionY);
int maxYInSection = minYInSection + 15;
if (minYInSection > run.topY()) { // todone break outer early if we're above run.topY()
break;
}
for (int it_y = Math.max(minYInSection, lowestRelevantY); it_y <= Math.min(maxYInSection, run.topY()); it_y++) {
lightArray.set(localX, ChunkSectionPos.getLocalCoord(it_y), localZ, 15);
if (it_y == lowestRelevantY || it_y < minSourceY_max) {
long it_pos = BlockPos.asLong(baseX + localX, it_y, baseZ + localZ);
enqueueIncrease(
it_pos,
QueueEntry.increaseSkySourceInDirections(
it_y == lowestRelevantY,
it_y < minSourceY_ZN,
it_y < minSourceY_ZP,
it_y < minSourceY_XN,
it_y < minSourceY_XP
)
);
}
}
}
}
}
}
}
}
@@ -1,6 +1,8 @@
package io.github.slimeistdev.crystalline_sky.mixin;
import net.minecraft.world.chunk.ChunkNibbleArray;
import net.minecraft.world.chunk.light.LightStorage;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@@ -17,4 +19,7 @@ public interface LightStorageAccessor {
@Invoker("set")
void crystalline_sky$set(long blockPos, int lightLevel);
@Invoker("method_51547")
@Nullable ChunkNibbleArray crystalline_sky$method_51547(long sectionPos);
}
@@ -11,4 +11,10 @@ public interface SkyLightStorageAccessor extends LightStorageAccessor {
@Invoker("isAtOrAboveTopmostSection")
boolean crystalline_sky$isAtOrAboveTopmostSection(long sectionPos);
@Invoker("getTopSectionForColumn")
int crystalline_sky$getTopSectionForColumn(long columnPos);
@Invoker("getMinSectionY")
int crystalline_sky$getMinSectionY();
}