diff --git a/build.gradle b/build.gradle
index 5b921c9d8..71de6ea8a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -132,6 +132,7 @@ minecraft {
"-Dcubicchunks.debug.window=false",
"-Dcubicchunks.debug.statusrenderer=false",
"-Dcubicchunks.debug.biomes=false",
+ "-ea"
]
runConfigs {
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
index 9dbcc9723..d7668838e 100644
--- a/config/checkstyle/suppressions.xml
+++ b/config/checkstyle/suppressions.xml
@@ -21,7 +21,7 @@
-
+
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/CubeMap.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/CubeMap.java
new file mode 100644
index 000000000..dc79692d5
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/CubeMap.java
@@ -0,0 +1,24 @@
+package io.github.opencubicchunks.cubicchunks.chunk;
+
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class CubeMap {
+ private final ConcurrentHashMap.KeySetView loadedCubes = ConcurrentHashMap.newKeySet();
+
+ public boolean isLoaded(int cubeY) {
+ return loadedCubes.contains(cubeY);
+ }
+
+ public void markLoaded(int cubeY) {
+ loadedCubes.add(cubeY);
+ }
+
+ public void markUnloaded(int cubeY) {
+ loadedCubes.remove(cubeY);
+ }
+
+ public Set getLoaded() {
+ return loadedCubes;
+ }
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/CubeMapGetter.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/CubeMapGetter.java
new file mode 100644
index 000000000..13db6dbe5
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/CubeMapGetter.java
@@ -0,0 +1,5 @@
+package io.github.opencubicchunks.cubicchunks.chunk;
+
+public interface CubeMapGetter {
+ CubeMap getCubeMap();
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IBigCube.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IBigCube.java
index 9018b9e87..4a98f5bf5 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IBigCube.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IBigCube.java
@@ -6,6 +6,7 @@
import javax.annotation.Nullable;
+import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerSection;
import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerSection;
import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
import io.github.opencubicchunks.cubicchunks.meta.EarlyConfig;
@@ -88,4 +89,7 @@ default void setCubeBlockEntity(CompoundTag nbt) {
default void loadHeightmapSection(SurfaceTrackerSection section, int localSectionX, int localSectionZZ) {
}
+
+ default void setLightHeightmapSection(LightSurfaceTrackerSection section, int localSectionX, int localSectionZZ) {
+ }
}
\ No newline at end of file
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunkManager.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunkManager.java
index 63f08ccec..3f13b6d4e 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunkManager.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunkManager.java
@@ -30,6 +30,7 @@ public interface IChunkManager {
@Nullable
ChunkHolder updateCubeScheduling(long cubePosIn, int newLevel, @Nullable ChunkHolder holder, int oldLevel);
+ void setServerChunkCache(ServerChunkCache cache);
LongSet getCubesToDrop();
@Nullable
@@ -121,6 +122,4 @@ static int getCubeDistanceXZ(CubePos cubePosIn, int x, int z) {
void releaseLightTicket(CubePos cubePos);
boolean noPlayersCloseForSpawning(CubePos cubePos);
-
- void setServerChunkCache(ServerChunkCache cache);
}
\ No newline at end of file
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/ICubeHolder.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/ICubeHolder.java
index e1c29e86d..723007991 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/ICubeHolder.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/ICubeHolder.java
@@ -34,10 +34,6 @@ static ChunkStatus getCubeStatusFromLevel(int cubeLevel) {
return cubeLevel < 33 ? ChunkStatus.FULL : CubeStatus.getStatus(cubeLevel - 33);
}
- void setChunkHolders(ChunkHolder[] chunkHolders);
-
- ChunkHolder[] getChunkHolders();
-
@Nullable
BigCube getCubeIfComplete();
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java
new file mode 100644
index 000000000..bb226a025
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java
@@ -0,0 +1,27 @@
+package io.github.opencubicchunks.cubicchunks.chunk;
+
+import io.github.opencubicchunks.cubicchunks.chunk.heightmap.ClientLightSurfaceTracker;
+import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper;
+import net.minecraft.world.level.levelgen.Heightmap;
+
+public interface LightHeightmapGetter {
+ Heightmap getLightHeightmap();
+
+ // Do not override this
+ default ClientLightSurfaceTracker getClientLightHeightmap() {
+ Heightmap lightHeightmap = this.getLightHeightmap();
+ if (!(lightHeightmap instanceof ClientLightSurfaceTracker)) {
+ throw new IllegalStateException("Attempted to get client light heightmap on server");
+ }
+ return (ClientLightSurfaceTracker) lightHeightmap;
+ }
+
+ // Do not override this
+ default LightSurfaceTrackerWrapper getServerLightHeightmap() {
+ Heightmap lightHeightmap = this.getLightHeightmap();
+ if (!(lightHeightmap instanceof LightSurfaceTrackerWrapper)) {
+ throw new IllegalStateException("Attempted to get server light heightmap on client");
+ }
+ return (LightSurfaceTrackerWrapper) lightHeightmap;
+ }
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/cube/BigCube.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/cube/BigCube.java
index 44a0ece07..ba6c3af41 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/cube/BigCube.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/cube/BigCube.java
@@ -20,8 +20,11 @@
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import io.github.opencubicchunks.cubicchunks.CubicChunks;
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter;
import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
import io.github.opencubicchunks.cubicchunks.chunk.ImposterChunkPos;
+import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter;
+import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerSection;
import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerSection;
import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerWrapper;
import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
@@ -110,6 +113,7 @@ public String getType() {
private final Map, LongSet> structuresRefences;
private final Map heightmaps;
+ private final LightSurfaceTrackerSection[] lightHeightmaps = new LightSurfaceTrackerSection[4];
private ChunkBiomeContainer cubeBiomeContainer;
@@ -218,10 +222,26 @@ public BigCube(Level worldIn, CubePrimer cubePrimer, @Nullable Consumer
this.setAllReferences(cubePrimer.getAllReferences());
// var4 = protoChunk.getHeightmaps().iterator();
+ LightSurfaceTrackerSection[] primerLightHeightmaps = cubePrimer.getLightHeightmaps();
+ for (int i = 0; i < IBigCube.DIAMETER_IN_SECTIONS * IBigCube.DIAMETER_IN_SECTIONS; i++) {
+ this.lightHeightmaps[i] = primerLightHeightmaps[i];
+ if (this.lightHeightmaps[i] == null) {
+ System.out.println("Got a null light heightmap while upgrading from CubePrimer at " + this.cubePos);
+ } else {
+ this.lightHeightmaps[i].upgradeCube(this);
+ }
+ }
+
this.setCubeLight(cubePrimer.hasCubeLight());
this.dirty = true;
}
+ @Override public void setLightHeightmapSection(LightSurfaceTrackerSection section, int localSectionX, int localSectionZ) {
+ int idx = localSectionX + localSectionZ * DIAMETER_IN_SECTIONS;
+
+ this.lightHeightmaps[idx] = section;
+ }
+
@Deprecated @Override public ChunkPos getPos() {
throw new UnsupportedOperationException("Not implemented");
}
@@ -983,14 +1003,20 @@ public void postLoad() {
ChunkPos pos = this.cubePos.asChunkPos();
for (int x = 0; x < IBigCube.DIAMETER_IN_SECTIONS; x++) {
for (int z = 0; z < IBigCube.DIAMETER_IN_SECTIONS; z++) {
- // TODO we really, *really* shouldn't be force-loading columns here.
- // probably the easiest approach until we get a "columns before cubes" invariant though.
+
+ // TODO force-loading columns is questionable, until we get load order
LevelChunk chunk = this.level.getChunk(pos.x + x, pos.z + z);
+ ((CubeMapGetter) chunk).getCubeMap().markLoaded(this.cubePos.getY());
for (Map.Entry entry : chunk.getHeightmaps()) {
Heightmap heightmap = entry.getValue();
SurfaceTrackerWrapper tracker = (SurfaceTrackerWrapper) heightmap;
tracker.loadCube(this);
}
+
+ if (!this.level.isClientSide) {
+ // TODO probably don't want to do this if the cube was already loaded as a CubePrimer
+ ((LightHeightmapGetter) chunk).getServerLightHeightmap().loadCube(this);
+ }
}
}
}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/cube/CubePrimer.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/cube/CubePrimer.java
index 5614c4178..3c6f75774 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/cube/CubePrimer.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/cube/CubePrimer.java
@@ -1,5 +1,3 @@
-
-
package io.github.opencubicchunks.cubicchunks.chunk.cube;
import static net.minecraft.world.level.chunk.LevelChunk.EMPTY_SECTION;
@@ -19,14 +17,20 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter;
import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
import io.github.opencubicchunks.cubicchunks.chunk.ImposterChunkPos;
+import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter;
import io.github.opencubicchunks.cubicchunks.chunk.biome.CubeBiomeContainer;
+import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerSection;
+import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper;
import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerSection;
import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
import io.github.opencubicchunks.cubicchunks.mixin.access.common.BiomeContainerAccess;
import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor;
import io.github.opencubicchunks.cubicchunks.utils.Coords;
+import io.github.opencubicchunks.cubicchunks.world.CubeWorldGenRegion;
+import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker;
import io.github.opencubicchunks.cubicchunks.world.storage.CubeProtoTickList;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
@@ -35,7 +39,9 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.nbt.CompoundTag;
+import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
+import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.block.Block;
@@ -44,6 +50,7 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkBiomeContainer;
+import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.ProtoChunk;
@@ -72,9 +79,10 @@ public class CubePrimer extends ProtoChunk implements IBigCube, CubicLevelHeight
@Nullable
private CubeBiomeContainer cubeBiomeContainer;
-
private final Map heightmaps;
+ private final LightSurfaceTrackerSection[] lightHeightmaps = new LightSurfaceTrackerSection[4];
+
private final List entities = Lists.newArrayList();
private final Map tileEntities = Maps.newHashMap();
@@ -121,6 +129,7 @@ public CubePrimer(CubePos cubePosIn, UpgradeData upgradeData, @Nullable LevelChu
this.carvingMasks = new Object2ObjectArrayMap<>();
this.structureStarts = Maps.newHashMap();
+
this.structuresRefences = new ConcurrentHashMap<>(); // Maps.newHashMap(); //TODO: This should NOT be a ConcurrentHashMap
this.cubePos = cubePosIn;
@@ -135,6 +144,7 @@ public CubePrimer(CubePos cubePosIn, UpgradeData upgradeData, @Nullable LevelChu
throw new IllegalStateException("Number of Sections must equal IBigCube.CUBESIZE | " + IBigCube.SECTION_COUNT);
}
}
+
isCubic = ((CubicLevelHeightAccessor) levelHeightAccessor).isCubic();
generates2DChunks = ((CubicLevelHeightAccessor) levelHeightAccessor).generates2DChunks();
worldStyle = ((CubicLevelHeightAccessor) levelHeightAccessor).worldStyle();
@@ -166,9 +176,67 @@ public void setHeightToCubeBounds(boolean cubeBounds) {
return this.sections;
}
+ private ChunkSource getChunkSource() {
+ if (this.levelHeightAccessor instanceof CubeWorldGenRegion) {
+ return ((CubeWorldGenRegion) this.levelHeightAccessor).getChunkSource();
+ } else {
+ return ((ServerLevel) this.levelHeightAccessor).getChunkSource();
+ }
+ }
+
//STATUS
public void setCubeStatus(ChunkStatus newStatus) {
this.status = newStatus;
+
+ if (this.status == ChunkStatus.FEATURES) {
+ ChunkSource chunkSource = getChunkSource();
+
+ for (int dx = 0; dx < IBigCube.DIAMETER_IN_SECTIONS; dx++) {
+ for (int dz = 0; dz < IBigCube.DIAMETER_IN_SECTIONS; dz++) {
+
+ // get the chunk for this section
+ ChunkPos chunkPos = this.cubePos.asChunkPos(dx, dz);
+ BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x, chunkPos.z);
+
+ // the load order guarantees the chunk being present
+ assert (chunk != null);
+
+ ((CubeMapGetter) chunk).getCubeMap().markLoaded(this.cubePos.getY());
+
+ LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap();
+
+ int[] beforeValues = new int[SECTION_DIAMETER * SECTION_DIAMETER];
+ for (int z = 0; z < SECTION_DIAMETER; z++) {
+ for (int x = 0; x < SECTION_DIAMETER; x++) {
+ beforeValues[z * SECTION_DIAMETER + x] = lightHeightmap.getFirstAvailable(x, z);
+ }
+ }
+
+ lightHeightmap.loadCube(this);
+
+ for (int z = 0; z < SECTION_DIAMETER; z++) {
+ for (int x = 0; x < SECTION_DIAMETER; x++) {
+ int beforeValue = beforeValues[z * SECTION_DIAMETER + x];
+ int afterValue = lightHeightmap.getFirstAvailable(x, z);
+ if (beforeValue != afterValue) {
+ ((ISkyLightColumnChecker) chunkSource.getLightEngine()).checkSkyLightColumn((CubeMapGetter) chunk,
+ chunkPos.getBlockX(x), chunkPos.getBlockZ(z), beforeValue, afterValue);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setLightHeightmapSection(LightSurfaceTrackerSection section, int localSectionX, int localSectionZ) {
+ int idx = localSectionX + localSectionZ * DIAMETER_IN_SECTIONS;
+ this.lightHeightmaps[idx] = section;
+ }
+
+ public LightSurfaceTrackerSection[] getLightHeightmaps() {
+ return lightHeightmaps;
}
@Override public ChunkStatus getCubeStatus() {
@@ -176,68 +244,112 @@ public void setCubeStatus(ChunkStatus newStatus) {
}
@Override @Nullable public BlockState setBlock(BlockPos pos, BlockState state, boolean isMoving) {
- int x = pos.getX() & 0xF;
- int y = pos.getY() & 0xF;
- int z = pos.getZ() & 0xF;
- int index = Coords.blockToIndex(pos.getX(), pos.getY(), pos.getZ());
+ int xSection = pos.getX() & 0xF;
+ int ySection = pos.getY() & 0xF;
+ int zSection = pos.getZ() & 0xF;
+ int sectionIdx = Coords.blockToIndex(pos.getX(), pos.getY(), pos.getZ());
- LevelChunkSection section = this.sections[index];
+ LevelChunkSection section = this.sections[sectionIdx];
if (section == EMPTY_SECTION && state == EMPTY_BLOCK) {
return state;
}
if (section == EMPTY_SECTION) {
- section = new LevelChunkSection(Coords.cubeToMinBlock(this.cubePos.getY() + Coords.sectionToMinBlock(Coords.indexToY(index))));
- this.sections[index] = section;
+ section = new LevelChunkSection(Coords.cubeToMinBlock(this.cubePos.getY() + Coords.sectionToMinBlock(Coords.indexToY(sectionIdx))));
+ this.sections[sectionIdx] = section;
}
if (state.getLightEmission() > 0) {
- SectionPos sectionPosAtIndex = Coords.sectionPosByIndex(this.cubePos, index);
+ SectionPos sectionPosAtIndex = Coords.sectionPosByIndex(this.cubePos, sectionIdx);
this.lightPositions.add(new BlockPos(
- x + Coords.sectionToMinBlock(sectionPosAtIndex.getX()),
- y + Coords.sectionToMinBlock(sectionPosAtIndex.getY()),
- z + Coords.sectionToMinBlock(sectionPosAtIndex.getZ()))
+ xSection + Coords.sectionToMinBlock(sectionPosAtIndex.getX()),
+ ySection + Coords.sectionToMinBlock(sectionPosAtIndex.getY()),
+ zSection + Coords.sectionToMinBlock(sectionPosAtIndex.getZ()))
);
}
- BlockState lastState = section.setBlockState(x, y, z, state, false);
- if (this.status.isOrAfter(ChunkStatus.FEATURES) && state != lastState && (state.getLightBlock(this, pos) != lastState.getLightBlock(this, pos)
- || state.getLightEmission() != lastState.getLightEmission() || state.useShapeForLightOcclusion() || lastState.useShapeForLightOcclusion())) {
+ BlockState lastState = section.setBlockState(xSection, ySection, zSection, state, false);
+ if (this.status.isOrAfter(ChunkStatus.LIGHT) && state != lastState && (state.getLightBlock(this, pos) != lastState.getLightBlock(this, pos)
+ || state.getLightEmission() != lastState.getLightEmission() || state.useShapeForLightOcclusion() || lastState.useShapeForLightOcclusion())) {
+
+ // get the chunk containing the updated block
+ ChunkSource chunkSource = getChunkSource();
+ ChunkPos chunkPos = Coords.chunkPosByIndex(this.cubePos, sectionIdx);
+ BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x, chunkPos.z);
+
+ // the load order guarantees the chunk being present
+ assert (chunk != null);
+
+ LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap();
+
+ int relX = pos.getX() & 15;
+ int relZ = pos.getZ() & 15;
+ int oldHeight = lightHeightmap.getFirstAvailable(relX, relZ);
+ // Light heightmap update needs to occur before the light engine update.
+ // Not sure if this is the right blockstate to pass in, but it doesn't actually matter since we don't use it
+ lightHeightmap.update(relX, pos.getY(), relZ, state);
+ int newHeight = lightHeightmap.getFirstAvailable(relX, relZ);
+ if (newHeight != oldHeight) {
+ ((ISkyLightColumnChecker) chunkSource.getLightEngine()).checkSkyLightColumn((CubeMapGetter) chunk, pos.getX(), pos.getZ(), oldHeight, newHeight);
+ }
lightManager.checkBlock(pos);
}
EnumSet heightMapsAfter = this.getStatus().heightmapsAfter();
- EnumSet toInitialize = null;
-
- for (Heightmap.Types type : heightMapsAfter) {
- SurfaceTrackerSection[] heightmapArray = this.heightmaps.get(type);
-
- if (heightmapArray == null) {
- if (toInitialize == null) {
- toInitialize = EnumSet.noneOf(Heightmap.Types.class);
- }
+// EnumSet toInitialize = null;
+//
+// for (Heightmap.Types type : heightMapsAfter) {
+// SurfaceTrackerSection[] heightmapArray = this.heightmaps.get(type);
+//
+// if (heightmapArray == null) {
+// if (toInitialize == null) {
+// toInitialize = EnumSet.noneOf(Heightmap.Types.class);
+// }
+//
+// toInitialize.add(type);
+// }
+// }
+//
+// if (toInitialize != null) {
+// primeHeightMaps(toInitialize);
+// }
+
+ int xChunk = Coords.blockToCubeLocalSection(pos.getX());
+ int zChunk = Coords.blockToCubeLocalSection(pos.getZ());
+ int chunkIdx = xChunk + zChunk * DIAMETER_IN_SECTIONS;
- toInitialize.add(type);
- }
+ for (Heightmap.Types types : heightMapsAfter) {
+ SurfaceTrackerSection surfaceTrackerSection = getHeightmapSections(types)[chunkIdx];
+ surfaceTrackerSection.onSetBlock(xSection, pos.getY(), zSection, state);
}
- if (toInitialize != null) {
- primeHeightMaps(toInitialize);
- }
+ return lastState;
+ }
- for (Heightmap.Types types : heightMapsAfter) {
+ /**
+ * Gets the SurfaceTrackerSections for the given Heightmap.Types for all chunks of this cube.
+ * Lazily initializes new SurfaceTrackerSections.
+ */
+ private SurfaceTrackerSection[] getHeightmapSections(Heightmap.Types type) {
+
+ SurfaceTrackerSection[] surfaceTrackerSections = heightmaps.get(type);
- int xSection = Coords.blockToCubeLocalSection(pos.getX());
- int zSection = Coords.blockToCubeLocalSection(pos.getZ());
+ if (surfaceTrackerSections == null) {
+ surfaceTrackerSections = new SurfaceTrackerSection[IBigCube.DIAMETER_IN_SECTIONS * IBigCube.DIAMETER_IN_SECTIONS];
- int idx = xSection + zSection * DIAMETER_IN_SECTIONS;
+ for (int dx = 0; dx < IBigCube.DIAMETER_IN_SECTIONS; dx++) {
+ for (int dz = 0; dz < IBigCube.DIAMETER_IN_SECTIONS; dz++) {
+ int idx = dx + dz * IBigCube.DIAMETER_IN_SECTIONS;
+ surfaceTrackerSections[idx] = new SurfaceTrackerSection(0, cubePos.getY(), null, this, type);
+ surfaceTrackerSections[idx].loadCube(dx, dz, this, true);
+ }
+ }
- SurfaceTrackerSection surfaceTrackerSection = this.heightmaps.get(types)[idx];
- surfaceTrackerSection.onSetBlock(x, pos.getY(), z, state);
+ heightmaps.put(type, surfaceTrackerSections);
}
- return lastState;
+ return surfaceTrackerSections;
}
private void primeHeightMaps(EnumSet toInitialize) {
@@ -383,7 +495,7 @@ public void setCubeLightManager(LevelLightEngine newLightEngine) {
}
@Override public int getCubeLocalHeight(Heightmap.Types type, int x, int z) {
- SurfaceTrackerSection[] surfaceTrackerSections = this.heightmaps.get(type);
+ SurfaceTrackerSection[] surfaceTrackerSections = getHeightmapSections(type);
if (surfaceTrackerSections == null) {
primeHeightMaps(EnumSet.of(type));
surfaceTrackerSections = this.heightmaps.get(type);
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/graph/CCTicketType.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/graph/CCTicketType.java
index 25de11d1a..cdaff358e 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/graph/CCTicketType.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/graph/CCTicketType.java
@@ -12,6 +12,8 @@ public class CCTicketType {
public static final TicketType CCLIGHT = create("light", Comparator.comparingLong(CubePos::asLong));
public static final TicketType CCUNKNOWN = create("unknown", Comparator.comparingLong(CubePos::asLong), 1);
+ public static final TicketType CCCOLUMN = create("column", Comparator.comparingLong(CubePos::asLong));
+
public static TicketType create(String nameIn, Comparator comparator) {
return TicketTypeAccess.createNew(nameIn, comparator, 0L);
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientLightSurfaceTracker.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientLightSurfaceTracker.java
new file mode 100644
index 000000000..90ec7f10f
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientLightSurfaceTracker.java
@@ -0,0 +1,59 @@
+package io.github.opencubicchunks.cubicchunks.chunk.heightmap;
+
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter;
+import io.github.opencubicchunks.cubicchunks.mixin.access.common.HeightmapAccess;
+import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker;
+import net.minecraft.client.Minecraft;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.util.BitStorage;
+import net.minecraft.util.Mth;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.LevelChunk;
+import net.minecraft.world.phys.shapes.Shapes;
+import net.minecraft.world.phys.shapes.VoxelShape;
+
+public class ClientLightSurfaceTracker extends ClientSurfaceTracker {
+ private final int bitsPerColumn;
+ private final int minHeight;
+ public ClientLightSurfaceTracker(ChunkAccess chunkAccess) {
+ // type shouldn't matter
+ super(chunkAccess, Types.WORLD_SURFACE);
+ bitsPerColumn = Mth.ceillog2(((HeightmapAccess) this).getChunk().getHeight() + 1);
+ minHeight = ((HeightmapAccess) this).getChunk().getMinBuildHeight();
+ }
+
+ @Override public boolean update(int x, int y, int z, BlockState blockState) {
+ throw new UnsupportedOperationException("ClientLightSurfaceTracker.update should never be called");
+ }
+
+ protected VoxelShape getShape(BlockState blockState, BlockPos pos, Direction facing) {
+ return blockState.canOcclude() && blockState.useShapeForLightOcclusion() ? blockState.getFaceOcclusionShape(((HeightmapAccess) this).getChunk(), pos, facing) : Shapes.empty();
+ }
+
+ private static int getIndex(int x, int z) {
+ return x + z * 16;
+ }
+
+ public void setRawData(long[] heightmap, LevelChunk chunk) {
+ // We need to compare the old and new data here, hence the inefficiencies with making a new bitstorage
+ // TODO can this be optimized to operate on long[]s directly instead of making an extra BitStorage?
+ BitStorage storage = ((HeightmapAccess) this).getData();
+ BitStorage oldStorage = new BitStorage(bitsPerColumn, 256, storage.getRaw().clone());
+ System.arraycopy(heightmap, 0, storage.getRaw(), 0, heightmap.length);
+// ChunkAccess chunk = ((HeightmapAccess) this).getChunk();
+ int baseX = chunk.getPos().getMinBlockX();
+ int baseZ = chunk.getPos().getMinBlockZ();
+ for (int z = 0; z < 16; z++) {
+ for (int x = 0; x < 16; x++) {
+ int index = getIndex(x, z);
+ int oldHeight = oldStorage.get(index) + minHeight;
+ int newHeight = storage.get(index) + minHeight;
+ if (oldHeight != newHeight) {
+ ((ISkyLightColumnChecker) Minecraft.getInstance().level.getLightEngine()).checkSkyLightColumn((CubeMapGetter) chunk, baseX + x, baseZ + z, oldHeight, newHeight);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientSurfaceTracker.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientSurfaceTracker.java
index b17e6ed0b..73f545b30 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientSurfaceTracker.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientSurfaceTracker.java
@@ -10,13 +10,18 @@
public class ClientSurfaceTracker extends Heightmap {
- private final Predicate isOpaque;
+ protected final Predicate isOpaque;
public ClientSurfaceTracker(ChunkAccess chunkAccess, Types types) {
super(chunkAccess, types);
this.isOpaque = ((HeightmapAccess) this).getIsOpaque();
}
+ /**
+ * @param x column-local x
+ * @param y global y
+ * @param z column-local z
+ */
@Override public boolean update(int x, int y, int z, BlockState blockState) {
int previous = getFirstAvailable(x, z);
if (y <= previous - 2) {
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java
new file mode 100644
index 000000000..badf550d5
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java
@@ -0,0 +1,168 @@
+package io.github.opencubicchunks.cubicchunks.chunk.heightmap;
+
+import java.util.Arrays;
+
+import javax.annotation.Nullable;
+
+import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
+import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.levelgen.Heightmap;
+import net.minecraft.world.phys.shapes.Shapes;
+import net.minecraft.world.phys.shapes.VoxelShape;
+
+public class LightSurfaceTrackerSection extends SurfaceTrackerSection {
+ public LightSurfaceTrackerSection() {
+ this(MAX_SCALE, 0, null);
+ }
+
+ public LightSurfaceTrackerSection(int scale, int scaledY, SurfaceTrackerSection parent) {
+ // type shouldn't actually matter here
+ super(scale, scaledY, parent, Heightmap.Types.WORLD_SURFACE);
+ }
+
+ public LightSurfaceTrackerSection(int scale, int scaledY, SurfaceTrackerSection parent, IBigCube cube) {
+ super(scale, scaledY, parent, cube, Heightmap.Types.WORLD_SURFACE);
+ }
+
+ private LightSurfaceTrackerSection getRoot() {
+ SurfaceTrackerSection section = this;
+ while (section.parent != null) {
+ section = section.parent;
+ }
+ return (LightSurfaceTrackerSection) section;
+ }
+
+ @Nullable
+ @Override
+ protected SurfaceTrackerSection loadNode(int newScaledY, int sectionScale, IBigCube newCube, boolean create) {
+ // TODO: loading from disk
+ if (!create) {
+ return null;
+ }
+ if (sectionScale == 0) {
+ return new LightSurfaceTrackerSection(sectionScale, newScaledY, this, newCube);
+ }
+ return new LightSurfaceTrackerSection(sectionScale, newScaledY, this);
+ }
+
+ @Nullable
+ private LightSurfaceTrackerSection getSectionAbove() {
+ if (scale != 0) {
+ throw new IllegalStateException("Attempted to get section above for a non-zero scale section");
+ }
+ // TODO this can be optimized - don't need to go to the root every time, just the lowest node that is a parent of both this node and the node above.
+ return (LightSurfaceTrackerSection) this.getRoot().getCubeNode(scaledY + 1);
+ }
+
+ @Override
+ public int getHeight(int x, int z) {
+ int idx = index(x, z);
+ if (!isDirty(idx)) {
+ int relativeY = heights.get(idx);
+ return relToAbsY(relativeY, scaledY, scale);
+ }
+
+ synchronized (this) {
+ int maxY = Integer.MIN_VALUE;
+ if (scale == 0) {
+ IBigCube cube = (IBigCube) cubeOrNodes;
+ CubePos cubePos = cube.getCubePos();
+
+ LightSurfaceTrackerSection sectionAbove = this.getSectionAbove();
+
+ int dy = IBigCube.DIAMETER_IN_BLOCKS - 1;
+
+ // TODO unknown behavior for occlusion on a loading boundary (i.e. sectionAbove == null)
+ BlockState above = sectionAbove == null ? Blocks.AIR.defaultBlockState() : ((IBigCube) sectionAbove.cubeOrNodes).getBlockState(x, 0, z);
+ BlockState state = cube.getBlockState(x, dy, z);
+
+ // note that this BlockPos relies on `cubePos.blockY` returning correct results when the local coord is not inside the cube
+ VoxelShape voxelShapeAbove = sectionAbove == null
+ ? Shapes.empty()
+ : this.getShape(above, new BlockPos(cubePos.blockX(x), cubePos.blockY(dy + 1), cubePos.blockZ(z)), Direction.DOWN);
+ VoxelShape voxelShape = this.getShape(state, new BlockPos(cubePos.blockX(x), cubePos.blockY(dy), cubePos.blockZ(z)), Direction.UP);
+
+ while (dy >= 0) {
+ int lightBlock = state.getLightBlock(cube, new BlockPos(cubePos.blockX(x), cubePos.blockY(dy), cubePos.blockZ(z)));
+ if (lightBlock > 0 || Shapes.faceShapeOccludes(voxelShapeAbove, voxelShape)) {
+ int minY = scaledY * IBigCube.DIAMETER_IN_BLOCKS;
+ maxY = minY + dy;
+ break;
+ }
+ dy--;
+ if (dy >= 0) {
+ above = state;
+ state = cube.getBlockState(x, dy, z);
+ voxelShapeAbove = this.getShape(above, new BlockPos(cubePos.blockX(x), cubePos.blockY(dy + 1), cubePos.blockZ(z)), Direction.DOWN);
+ voxelShape = this.getShape(state, new BlockPos(cubePos.blockX(x), cubePos.blockY(dy), cubePos.blockZ(z)), Direction.UP);
+ }
+ }
+ } else {
+ SurfaceTrackerSection[] nodes = (SurfaceTrackerSection[]) cubeOrNodes;
+ for (int i = nodes.length - 1; i >= 0; i--) {
+ SurfaceTrackerSection node = nodes[i];
+ if (node == null) {
+ continue;
+ }
+ int y = node.getHeight(x, z);
+ if (y != Integer.MIN_VALUE) {
+ maxY = y;
+ break;
+ }
+ }
+ }
+ heights.set(idx, absToRelY(maxY, scaledY, scale));
+ clearDirty(idx);
+ return maxY;
+ }
+ }
+
+ /**
+ * Used when upgrading CubePrimers to BigCubes; should never be used elsewhere.
+ */
+ public void upgradeCube(IBigCube cube) {
+ if (this.scale != 0) {
+ throw new IllegalStateException("Attempted to upgrade the cube on a non-zero scale section");
+ }
+ if (this.cubeOrNodes == null) {
+ throw new IllegalStateException("Attempting to upgrade cube " + cube.getCubePos() + " for an unloaded surface tracker section");
+ }
+ this.cubeOrNodes = cube;
+
+ }
+
+ @Override
+ public void loadCube(int sectionX, int sectionZ, IBigCube newCube, boolean markDirty) {
+ if (this.cubeOrNodes == null) {
+ throw new IllegalStateException("Attempting to load cube " + newCube.getCubePos() + " into an unloaded surface tracker section");
+ }
+ if (markDirty) {
+ Arrays.fill(dirtyPositions, -1);
+ }
+ if (this.scale == 0) {
+ // TODO merge loadHeightmapSection and loadLightHeightmapSection, and just use instanceof checks in the implementation to figure out if it's a light heightmap?
+ newCube.setLightHeightmapSection(this, sectionX, sectionZ);
+ return;
+ }
+ int idx = indexOfRawHeightNode(newCube.getCubePos().getY(), scale, scaledY);
+ SurfaceTrackerSection[] nodes = (SurfaceTrackerSection[]) cubeOrNodes;
+ for (int i = 0; i < nodes.length; i++) {
+ if (nodes[i] != null) {
+ continue;
+ }
+ int newScaledY = indexToScaledY(i, scale, scaledY);
+ SurfaceTrackerSection newMap = loadNode(newScaledY, scale - 1, newCube, i == idx);
+ nodes[i] = newMap;
+ }
+ assert nodes[idx] != null;
+ nodes[idx].loadCube(sectionX, sectionZ, newCube, markDirty);
+ }
+
+ protected VoxelShape getShape(BlockState blockState, BlockPos pos, Direction facing) {
+ return blockState.canOcclude() && blockState.useShapeForLightOcclusion() ? blockState.getFaceOcclusionShape((IBigCube) this.cubeOrNodes, pos, facing) : Shapes.empty();
+ }
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerWrapper.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerWrapper.java
new file mode 100644
index 000000000..ed6d954c5
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerWrapper.java
@@ -0,0 +1,35 @@
+package io.github.opencubicchunks.cubicchunks.chunk.heightmap;
+
+import static io.github.opencubicchunks.cubicchunks.utils.Coords.*;
+
+import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.chunk.ChunkAccess;
+
+public class LightSurfaceTrackerWrapper extends SurfaceTrackerWrapper {
+ public LightSurfaceTrackerWrapper(ChunkAccess chunkAccess) {
+ // type shouldn't matter
+ super(chunkAccess, Types.WORLD_SURFACE, new LightSurfaceTrackerSection());
+ }
+
+ @Override
+ public boolean update(int x, int y, int z, BlockState blockState) {
+ super.update(x, y, z, blockState);
+ int relY = blockToLocal(y);
+ // TODO how are we going to handle making sure that unloaded sections stay updated?
+ if (relY == 0) {
+ SurfaceTrackerSection section = surfaceTracker.getCubeNode(blockToCube(y - 1));
+ if (section != null) {
+ section.markDirty(x, z);
+ }
+ } else if (relY == IBigCube.DIAMETER_IN_BLOCKS - 1) {
+ SurfaceTrackerSection section = surfaceTracker.getCubeNode(blockToCube(y + 1));
+ if (section != null) {
+ section.markDirty(x, z);
+ }
+ }
+
+ // Return value is unused
+ return false;
+ }
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/SurfaceTrackerSection.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/SurfaceTrackerSection.java
index 0698c5ef9..de7f3392b 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/SurfaceTrackerSection.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/SurfaceTrackerSection.java
@@ -22,23 +22,23 @@ public class SurfaceTrackerSection {
/** Number of children nodes */
public static final int NODE_COUNT = 1 << NODE_COUNT_BITS;
+ // Use width of 16 to match columns.
+ public static final int WIDTH_BLOCKS = 16;
+
private static final Heightmap.Types[] HEIGHTMAP_TYPES = Heightmap.Types.values();
/** Number of bits needed to represent height (excluding null) at scale zero (i.e. log2(scale0 height)) */
private static final int BASE_SIZE_BITS = IBigCube.SIZE_BITS;
- // Use width of 16 to match columns.
- private static final int WIDTH_BLOCKS = 16;
-
- private final BitStorage heights;
- private final long[] dirtyPositions; // bitset has 100% memory usage overhead due to pointers and object headers
- private SurfaceTrackerSection parent;
- private Object cubeOrNodes;
+ protected final BitStorage heights;
+ protected final long[] dirtyPositions; // bitset has 100% memory usage overhead due to pointers and object headers
+ protected SurfaceTrackerSection parent;
+ protected Object cubeOrNodes;
/**
* Position of this section, within all sections of this size e.g. with 64-block sections, y=0-63 would be section 0, y=64-127 would be section 1, etc.
*/
- private final int scaledY;
- private final byte scale;
+ protected final int scaledY;
+ protected final byte scale;
private final byte heightmapType;
public SurfaceTrackerSection(Heightmap.Types types) {
@@ -61,7 +61,10 @@ public SurfaceTrackerSection(int scale, int scaledY, SurfaceTrackerSection paren
this.heightmapType = (byte) types.ordinal();
}
- /** Get the height for a given position. Recomputes the height if the column is marked dirty in this section. */
+ /**
+ * Get the height for a given position. Recomputes the height if the column is marked dirty in this section.
+ * x and z are global coordinates.
+ */
public int getHeight(int x, int z) {
int idx = index(x, z);
if (!isDirty(idx)) {
@@ -101,7 +104,7 @@ public int getHeight(int x, int z) {
}
}
- private void clearDirty(int idx) {
+ protected void clearDirty(int idx) {
dirtyPositions[idx >> 6] &= ~(1L << idx);
}
@@ -109,7 +112,7 @@ private void setDirty(int idx) {
dirtyPositions[idx >> 6] |= 1L << idx;
}
- private boolean isDirty(int idx) {
+ protected boolean isDirty(int idx) {
return (dirtyPositions[idx >> 6] & (1L << idx)) != 0;
}
@@ -241,7 +244,7 @@ public Heightmap.Types getType() {
}
@Nullable
- private SurfaceTrackerSection loadNode(int newScaledY, int sectionScale, IBigCube newCube, boolean create) {
+ protected SurfaceTrackerSection loadNode(int newScaledY, int sectionScale, IBigCube newCube, boolean create) {
// TODO: loading from disk
if (!create) {
return null;
@@ -252,7 +255,8 @@ private SurfaceTrackerSection loadNode(int newScaledY, int sectionScale, IBigCub
return new SurfaceTrackerSection(sectionScale, newScaledY, this, HEIGHTMAP_TYPES[this.heightmapType]);
}
- private int index(int x, int z) {
+ /** Get position x/z index within a column, from global/local pos */
+ protected int index(int x, int z) {
return (z & 0xF) * WIDTH_BLOCKS + (x & 0xF);
}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/SurfaceTrackerWrapper.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/SurfaceTrackerWrapper.java
index 0f0a5cd79..fd1b4074a 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/SurfaceTrackerWrapper.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/SurfaceTrackerWrapper.java
@@ -10,9 +10,11 @@
import net.minecraft.world.level.levelgen.Heightmap;
public class SurfaceTrackerWrapper extends Heightmap {
- private final SurfaceTrackerSection surfaceTracker;
- private final int dx;
- private final int dz;
+ protected final SurfaceTrackerSection surfaceTracker;
+ /** global x of min block in column */
+ protected final int dx;
+ /** global z of min block in column */
+ protected final int dz;
public SurfaceTrackerWrapper(ChunkAccess chunkAccess, Types types) {
super(chunkAccess, types);
@@ -22,14 +24,30 @@ public SurfaceTrackerWrapper(ChunkAccess chunkAccess, Types types) {
this.dz = sectionToMinBlock(chunkAccess.getPos().z);
}
+ protected SurfaceTrackerWrapper(ChunkAccess chunkAccess, Types types, SurfaceTrackerSection root) {
+ super(chunkAccess, types);
+ ((HeightmapAccess) this).setIsOpaque(null);
+ this.surfaceTracker = root;
+ this.dx = sectionToMinBlock(chunkAccess.getPos().x);
+ this.dz = sectionToMinBlock(chunkAccess.getPos().z);
+ }
+
+ /**
+ *
+ * @param x column-local x
+ * @param y global y
+ * @param z column-local z
+ * @param blockState unused.
+ * @return currently unused; always false
+ */
@Override
public boolean update(int x, int y, int z, BlockState blockState) {
- // TODO do we need to do anything else here?
surfaceTracker.getCubeNode(blockToCube(y)).markDirty(x + dx, z + dz);
- // TODO not sure if this is safe to do or if things depend on the result
+ // We always return false, because the result is never used anywhere anyway (by either vanilla or us)
return false;
}
+ /** x/z are column-local. */
@Override
public int getFirstAvailable(int x, int z) {
return surfaceTracker.getHeight(x + dx, z + dz) + 1;
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/ChunkManagerAccess.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/ChunkManagerAccess.java
index bdb0e4d09..084eb2edf 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/ChunkManagerAccess.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/ChunkManagerAccess.java
@@ -16,4 +16,6 @@ public interface ChunkManagerAccess {
@Invoker boolean invokePromoteChunkMap();
@Invoker void invokeOnFullChunkStatusChange(ChunkPos chunkPos, ChunkHolder.FullChunkStatus fullChunkStatus);
@Accessor int getViewDistance();
+
+ @Invoker void invokeReleaseLightTicket(ChunkPos pos);
}
\ No newline at end of file
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/SectionLightStorageAccess.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/LayerLightSectionStorageAccess.java
similarity index 53%
rename from src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/SectionLightStorageAccess.java
rename to src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/LayerLightSectionStorageAccess.java
index c9e10aa4c..2c86a1e28 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/SectionLightStorageAccess.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/LayerLightSectionStorageAccess.java
@@ -1,12 +1,19 @@
package io.github.opencubicchunks.cubicchunks.mixin.access.common;
+import net.minecraft.world.level.chunk.LightChunkGetter;
import net.minecraft.world.level.lighting.LayerLightSectionStorage;
import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(LayerLightSectionStorage.class)
-public interface SectionLightStorageAccess {
+public interface LayerLightSectionStorageAccess {
@Invoker("enableLightSources") void invokeSetColumnEnabled(long seed, boolean enable);
+ @Invoker boolean invokeStoringLightForSection(long sectionPos);
+
+ @Invoker void invokeRunAllUpdates();
+
+ @Accessor LightChunkGetter getChunkSource();
}
\ No newline at end of file
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/ThreadedLevelLightEngineAccess.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/ThreadedLevelLightEngineAccess.java
new file mode 100644
index 000000000..1e1129473
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/ThreadedLevelLightEngineAccess.java
@@ -0,0 +1,14 @@
+package io.github.opencubicchunks.cubicchunks.mixin.access.common;
+
+import net.minecraft.server.level.ChunkMap;
+import net.minecraft.server.level.ThreadedLevelLightEngine;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+@Mixin(ThreadedLevelLightEngine.class)
+public interface ThreadedLevelLightEngineAccess {
+ @Accessor ChunkMap getChunkMap();
+
+ @Invoker void invokeAddTask(int x, int z, ThreadedLevelLightEngine.TaskType stage, Runnable task);
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/TicketAccess.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/TicketAccess.java
index 57c76a5d3..de494ca2b 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/TicketAccess.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/TicketAccess.java
@@ -3,6 +3,7 @@
import net.minecraft.server.level.Ticket;
import net.minecraft.server.level.TicketType;
import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(Ticket.class)
@@ -12,4 +13,6 @@ public interface TicketAccess {
}
@Invoker boolean invokeTimedOut(long currentTime);
@Invoker void invokeSetCreatedTick(long time);
+
+ @Accessor T getKey();
}
\ No newline at end of file
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/TicketManagerAccess.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/TicketManagerAccess.java
index c1a7196c3..fd8efef53 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/TicketManagerAccess.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/TicketManagerAccess.java
@@ -2,6 +2,7 @@
import net.minecraft.server.level.DistanceManager;
import net.minecraft.server.level.Ticket;
+import net.minecraft.util.SortedArraySet;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@@ -10,4 +11,7 @@ public interface TicketManagerAccess {
@Invoker void invokeAddTicket(long chunkPosIn, Ticket> ticketIn);
@Invoker void invokeUpdatePlayerTickets(int viewDistance);
+
+ @Invoker SortedArraySet> invokeGetTickets(long position);
+ @Invoker void invokeRemoveTicket(long pos, Ticket> ticket);
}
\ No newline at end of file
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/debug/MixinDebugScreenOverlay.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/debug/MixinDebugScreenOverlay.java
new file mode 100644
index 000000000..3fa35497b
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/client/debug/MixinDebugScreenOverlay.java
@@ -0,0 +1,57 @@
+package io.github.opencubicchunks.cubicchunks.mixin.core.client.debug;
+
+import java.util.List;
+
+import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter;
+import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper;
+import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor;
+import it.unimi.dsi.fastutil.longs.LongSet;
+import net.minecraft.client.gui.components.DebugScreenOverlay;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.LightLayer;
+import net.minecraft.world.level.chunk.LevelChunk;
+import net.minecraft.world.level.lighting.LevelLightEngine;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+
+@Mixin(DebugScreenOverlay.class)
+public abstract class MixinDebugScreenOverlay {
+ @Shadow abstract LevelChunk getServerChunk();
+
+ @Inject(method = "getGameInformation",
+ at = @At(value = "INVOKE",
+ target = "Lnet/minecraft/client/multiplayer/ClientLevel;getBrightness(Lnet/minecraft/world/level/LightLayer;Lnet/minecraft/core/BlockPos;)I",
+ ordinal = 0),
+ locals = LocalCapture.CAPTURE_FAILHARD)
+ private void onGetGameInformation(CallbackInfoReturnable> cir, String string2, BlockPos pos, Entity entity, Direction direction,
+ String string7, Level level, LongSet longSet, List list, LevelChunk clientChunk, int i) {
+ LevelChunk serverChunk = this.getServerChunk();
+ if (((CubicLevelHeightAccessor) level).isCubic()) {
+ String serverHeight = "???";
+ if (serverChunk != null) {
+ LightSurfaceTrackerWrapper heightmap = ((LightHeightmapGetter) serverChunk).getServerLightHeightmap();
+ int height = heightmap.getFirstAvailable(pos.getX() & 0xF, pos.getZ() & 0xF);
+ serverHeight = "" + height;
+ }
+ list.add("Server light heightmap height: " + serverHeight);
+ int clientHeight = ((LightHeightmapGetter) clientChunk).getClientLightHeightmap().getFirstAvailable(pos.getX() & 0xF, pos.getZ() & 0xF);
+ list.add("Client light heightmap height: " + clientHeight);
+ }
+
+ // No cubic check here because it's a vanilla feature that was removed anyway
+ if (serverChunk != null) {
+ LevelLightEngine lightingProvider = level.getChunkSource().getLightEngine();
+ list.add("Server Light: (" + lightingProvider.getLayerListener(LightLayer.SKY).getLightValue(pos) + " sky, "
+ + lightingProvider.getLayerListener(LightLayer.BLOCK).getLightValue(pos) + " block)");
+ } else {
+ list.add("Server Light: (?? sky, ?? block)");
+ }
+ }
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/MixinMinecraftServer.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/MixinMinecraftServer.java
index 6d4f4dbd3..02c29b297 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/MixinMinecraftServer.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/MixinMinecraftServer.java
@@ -122,10 +122,10 @@ private void prepareLevels(ChunkProgressListener statusListener, CallbackInfo ci
int chunkDiameter = Coords.cubeToSection(radius, 0) * 2 + 1;
int d = radius * 2 + 1;
((IServerChunkProvider) serverchunkprovider).addCubeRegionTicket(TicketType.START, spawnPosCube, radius + 1, Unit.INSTANCE);
- serverchunkprovider.addRegionTicket(TicketType.START, spawnPosCube.asChunkPos(), Coords.cubeToSection(radius + 1, 0), Unit.INSTANCE);
+// serverchunkprovider.addRegionTicket(TicketType.START, spawnPosCube.asChunkPos(), Coords.cubeToSection(radius + 1, 0), Unit.INSTANCE);
- while (this.isRunning() && (serverchunkprovider.getTickingGenerated() < chunkDiameter * chunkDiameter
- || ((IServerChunkProvider) serverchunkprovider).getTickingGeneratedCubes() < d * d * d)) {
+ while (this.isRunning() && (/*serverchunkprovider.getTickingGenerated() < chunkDiameter * chunkDiameter
+ ||*/ ((IServerChunkProvider) serverchunkprovider).getTickingGeneratedCubes() < d * d * d)) {
// from CC
this.nextTickTime = Util.getMillis() + 10L;
this.waitUntilNextTick();
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/MixinServerChunkProvider.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/MixinServerChunkProvider.java
index 197653bd0..ed8bb7ca5 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/MixinServerChunkProvider.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/MixinServerChunkProvider.java
@@ -89,30 +89,7 @@ public abstract class MixinServerChunkProvider implements IServerChunkProvider,
@Shadow @org.jetbrains.annotations.Nullable protected abstract ChunkHolder getVisibleChunkIfPresent(long pos);
- @Inject(method = "", at = @At("RETURN"))
- private void onInit(ServerLevel serverLevel, LevelStorageSource.LevelStorageAccess levelStorageAccess, DataFixer dataFixer, StructureManager structureManager, Executor executor,
- ChunkGenerator chunkGenerator, int i, boolean bl, ChunkProgressListener chunkProgressListener, ChunkStatusUpdateListener chunkStatusUpdateListener,
- Supplier supplier, CallbackInfo ci) {
- ((IChunkManager) chunkMap).setServerChunkCache((ServerChunkCache) (Object) this);
- }
-
- @Override public ChunkHolder getChunkHolderForce(ChunkPos chunkPos, ChunkStatus requiredStatus) {
- long pos = chunkPos.toLong();
- ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(pos);
- int chunkLevel = 33 + ChunkStatus.getDistance(requiredStatus);
- this.distanceManager.addTicket(TicketType.UNKNOWN, chunkPos, chunkLevel, chunkPos);
- if (this.chunkAbsent(chunkHolder, chunkLevel)) {
- ProfilerFiller profilerFiller = this.level.getProfiler();
- profilerFiller.push("chunkLoad");
- this.runChunkDistanceManagerUpdates();
- chunkHolder = this.getVisibleChunkIfPresent(pos);
- profilerFiller.pop();
- if (this.chunkAbsent(chunkHolder, chunkLevel)) {
- throw Util.pauseInIde(new IllegalStateException("No chunk holder after ticket has been added"));
- }
- }
- return chunkHolder;
- }
+ @Shadow abstract boolean runDistanceManagerUpdates();
@Override
public void addCubeRegionTicket(TicketType type, CubePos pos, int distance, T value) {
@@ -208,6 +185,29 @@ public void forceCube(CubePos pos, boolean add) {
((ITicketManager) this.distanceManager).updateCubeForced(pos, add);
}
+
+ @Override public CompletableFuture> getColumnFutureForCube(CubePos cubepos, int chunkX, int chunkZ, ChunkStatus leastStatus,
+ boolean create) {
+ ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
+ long l = chunkPos.toLong();
+ int i = 33 + ChunkStatus.getDistance(leastStatus);
+ ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(l);
+ if (create) {
+ this.distanceManager.addTicket(CCTicketType.CCCOLUMN, chunkPos, i, cubepos);
+ if (this.chunkAbsent(chunkHolder, i)) {
+ ProfilerFiller profilerFiller = this.level.getProfiler();
+ profilerFiller.push("chunkLoad");
+ this.runDistanceManagerUpdates();
+ chunkHolder = this.getVisibleChunkIfPresent(l);
+ profilerFiller.pop();
+ if (this.chunkAbsent(chunkHolder, i)) {
+ throw Util.pauseInIde(new IllegalStateException("No chunk holder after ticket has been added"));
+ }
+ }
+ }
+ return this.chunkAbsent(chunkHolder, i) ? ChunkHolder.UNLOADED_CHUNK_FUTURE : chunkHolder.getOrScheduleFuture(leastStatus, this.chunkMap);
+ }
+
// func_217233_c, getChunkFutureMainThread
private CompletableFuture> getCubeFutureMainThread(int cubeX, int cubeY, int cubeZ,
ChunkStatus requiredStatus, boolean load) {
@@ -265,17 +265,6 @@ private void onRefreshAndInvalidate(CallbackInfoReturnable cir) {
this.clearCubeCache();
}
- private boolean runChunkDistanceManagerUpdates() {
- boolean flag = ((ITicketManager) this.distanceManager).runAllUpdatesForChunks(chunkMap);
- boolean flag1 = ((ChunkManagerAccess) this.chunkMap).invokePromoteChunkMap();
- if (!flag && !flag1) {
- return false;
- } else {
- this.clearCubeCache();
- return true;
- }
- }
-
// func_217235_l, runDistanceManagerUpdates
private boolean runCubeDistanceManagerUpdates() {
boolean flag = this.distanceManager.runAllUpdates(this.chunkMap);
@@ -320,6 +309,12 @@ public BlockGetter getCubeForLighting(int sectionX, int sectionY, int sectionZ)
}
}
+ @Inject(method = "", at = @At(value = "RETURN"))
+ private void setChunkManagerServerChunkCache(ServerLevel serverLevel, LevelStorageSource.LevelStorageAccess levelStorageAccess, DataFixer dataFixer, StructureManager structureManager,
+ Executor executor, ChunkGenerator chunkGenerator, int i, boolean bl, ChunkProgressListener chunkProgressListener,
+ ChunkStatusUpdateListener chunkStatusUpdateListener, Supplier supplier, CallbackInfo ci) {
+ ((IChunkManager) this.chunkMap).setServerChunkCache((ServerChunkCache) (Object) this);
+ }
/**
* @author Barteks2x
* @reason sections
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunk.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunk.java
index 0808a5f0e..a23c34ca5 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunk.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunk.java
@@ -4,18 +4,25 @@
import java.util.function.Consumer;
import io.github.opencubicchunks.cubicchunks.chunk.ChunkCubeGetter;
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMap;
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter;
import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
import io.github.opencubicchunks.cubicchunks.chunk.ICubeProvider;
+import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter;
import io.github.opencubicchunks.cubicchunks.chunk.biome.ColumnBiomeContainer;
import io.github.opencubicchunks.cubicchunks.chunk.cube.BigCube;
import io.github.opencubicchunks.cubicchunks.chunk.cube.EmptyCube;
+import io.github.opencubicchunks.cubicchunks.chunk.heightmap.ClientLightSurfaceTracker;
import io.github.opencubicchunks.cubicchunks.chunk.heightmap.ClientSurfaceTracker;
+import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper;
import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerWrapper;
import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor;
import io.github.opencubicchunks.cubicchunks.utils.Coords;
+import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
+import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.TickList;
@@ -27,6 +34,7 @@
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
+import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.material.Fluid;
@@ -39,9 +47,11 @@
import org.spongepowered.asm.mixin.injection.ModifyConstant;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
-@Mixin(value = LevelChunk.class, priority = 0) // Priority 0 to always ensure our redirects are on top. Should also prevent fabric api crashes that have occur(ed) here. See removeTileEntity
-public abstract class MixinChunk implements ChunkAccess, CubicLevelHeightAccessor, ChunkCubeGetter {
+@Mixin(value = LevelChunk.class, priority = 0) //Priority 0 to always ensure our redirects are on top. Should also prevent fabric api crashes that have occur(ed) here. See removeTileEntity
+
+public abstract class MixinChunk implements ChunkAccess, LightHeightmapGetter, CubeMapGetter, CubicLevelHeightAccessor, ChunkCubeGetter {
@Shadow @Final private Level level;
@Shadow @Final private ChunkPos chunkPos;
@@ -54,6 +64,9 @@ public abstract class MixinChunk implements ChunkAccess, CubicLevelHeightAccesso
private boolean generates2DChunks;
private WorldStyle worldStyle;
+ private Heightmap lightHeightmap;
+ private CubeMap cubeMap;
+
@Shadow public abstract ChunkStatus getStatus();
@Shadow protected abstract boolean isInLevel();
@@ -64,6 +77,19 @@ public abstract class MixinChunk implements ChunkAccess, CubicLevelHeightAccesso
return false;
}
+ @Override
+ public Heightmap getLightHeightmap() {
+ if (!isCubic) {
+ throw new UnsupportedOperationException("Attempted to get light heightmap on a non-cubic chunk");
+ }
+ return lightHeightmap;
+ }
+
+ @Override
+ public CubeMap getCubeMap() {
+ return cubeMap;
+ }
+
@Inject(
method = "(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/chunk/ChunkBiomeContainer;"
+ "Lnet/minecraft/world/level/chunk/UpgradeData;Lnet/minecraft/world/level/TickList;Lnet/minecraft/world/level/TickList;J[Lnet/minecraft/world/level/chunk/LevelChunkSection;"
@@ -84,6 +110,52 @@ private void onInit(Level levelIn, ChunkPos pos, ChunkBiomeContainer chunkBiomeC
if (!(biomes instanceof ColumnBiomeContainer)) {
this.biomes = new ColumnBiomeContainer(levelIn.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), levelIn, levelIn);
}
+
+ if (levelIn.isClientSide) {
+ lightHeightmap = new ClientLightSurfaceTracker(this);
+ } else {
+ lightHeightmap = new LightSurfaceTrackerWrapper(this);
+ }
+ // TODO might want 4 columns that share the same BigCubes to have a reference to the same CubeMap?
+ cubeMap = new CubeMap();
+ }
+
+ @Inject(
+ method = "(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/ProtoChunk;Ljava/util/function/Consumer;)V",
+ at = @At("RETURN")
+ )
+ private void onInitFromProtoChunk(ServerLevel serverLevel, ProtoChunk protoChunk, Consumer consumer, CallbackInfo ci) {
+ if (!this.isCubic()) {
+ return;
+ }
+ lightHeightmap = ((LightHeightmapGetter) protoChunk).getLightHeightmap();
+ cubeMap = ((CubeMapGetter) protoChunk).getCubeMap();
+ }
+
+ @Inject(
+ method = "setBlockState(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Z)Lnet/minecraft/world/level/block/state/BlockState;",
+ at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/Heightmap;update(IIILnet/minecraft/world/level/block/state/BlockState;)Z", ordinal = 0)
+ )
+ private void onSetBlock(BlockPos pos, BlockState state, boolean moved, CallbackInfoReturnable cir) {
+ if (!this.isCubic()) {
+ return;
+ }
+ // TODO client side light heightmap stuff
+ if (this.level.isClientSide) {
+ ClientLightSurfaceTracker clientLightHeightmap = ((LightHeightmapGetter) this).getClientLightHeightmap();
+ } else {
+ int relX = pos.getX() & 15;
+ int relZ = pos.getZ() & 15;
+ LightSurfaceTrackerWrapper serverLightHeightmap = ((LightHeightmapGetter) this).getServerLightHeightmap();
+ int oldHeight = serverLightHeightmap.getFirstAvailable(relX, relZ);
+ // Light heightmap update needs to occur before the light engine update.
+ // LevelChunk.setBlockState is called before the light engine is updated, so this works fine currently, but if this update call is ever moved, that must still be the case.
+ serverLightHeightmap.update(relX, pos.getY(), relZ, state);
+ int newHeight = serverLightHeightmap.getFirstAvailable(relX, relZ);
+ if (newHeight != oldHeight) {
+ ((ISkyLightColumnChecker) this.level.getChunkSource().getLightEngine()).checkSkyLightColumn(this, pos.getX(), pos.getZ(), oldHeight, newHeight);
+ }
+ }
}
@Redirect(
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkHolder.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkHolder.java
index 6f633f00b..4f0b6b42d 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkHolder.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkHolder.java
@@ -20,6 +20,7 @@
import io.github.opencubicchunks.cubicchunks.chunk.IChunkManager;
import io.github.opencubicchunks.cubicchunks.chunk.ICubeHolder;
import io.github.opencubicchunks.cubicchunks.chunk.ImposterChunkPos;
+import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter;
import io.github.opencubicchunks.cubicchunks.chunk.cube.BigCube;
import io.github.opencubicchunks.cubicchunks.chunk.cube.CubePrimer;
import io.github.opencubicchunks.cubicchunks.chunk.cube.CubePrimerWrapper;
@@ -78,7 +79,6 @@ public abstract class MixinChunkHolder implements ICubeHolder {
@Shadow private CompletableFuture pendingFullStateConfirmation;
@Shadow @Final private LevelHeightAccessor levelHeightAccessor;
- private ChunkHolder[] chunkHolders = null;
@Shadow private boolean hasChangedSections;
private CubePos cubePos; // set from ASM
@@ -311,39 +311,11 @@ private CompletableFuture> scheduleChunkOrCube(ChunkMap chunkManager, ChunkHol
}
}
- @Override
- public void setChunkHolders(ChunkHolder[] chunkHolders) {
- this.chunkHolders = chunkHolders;
- }
-
- @Override
- public ChunkHolder[] getChunkHolders() {
- return chunkHolders;
- }
-
// func_219276_a, getOrScheduleFuture
- @Override public CompletableFuture> getOrScheduleCubeFuture(ChunkStatus targetStatus, ChunkMap chunkStorage) {
- int i = targetStatus.getIndex();
- CompletableFuture> completableFuture = futures.get(i);
- if (completableFuture != null) {
- Either either = completableFuture.getNow(null);
- if (either == null || either.left().isPresent()) {
- return completableFuture;
- }
- }
-
- if (getStatus(this.ticketLevel).isOrAfter(targetStatus)) {
- CompletableFuture> completableFuture2 = ((IChunkManager) chunkStorage).scheduleCube((ChunkHolder) (Object) this,
- targetStatus);
- this.updateChunkToSave(completableFuture2, "schedule " + targetStatus);
- this.futures.set(i, completableFuture2);
- return completableFuture2;
- } else {
- return completableFuture == null ? UNLOADED_CUBE_FUTURE : completableFuture;
- }
+ @Override public CompletableFuture> getOrScheduleCubeFuture(ChunkStatus chunkStatus, ChunkMap chunkManager) {
+ return getOrScheduleFuture(chunkStatus, chunkManager);
}
- @Override
public void addCubeStageListener(ChunkStatus status, BiConsumer, Throwable> consumer, ChunkMap chunkManager) {
CompletableFuture> future = getOrScheduleFuture(status, chunkManager);
@@ -385,6 +357,9 @@ public void blockChanged(BlockPos blockPos, CallbackInfo ci) {
ci.cancel();
+ int localX = blockPos.getX() & 0xF;
+ int localZ = blockPos.getZ() & 0xF;
+
if (cubePos == null) {
ChunkAccess chunk = getTickingChunk();
if (chunk == null) {
@@ -407,6 +382,18 @@ public void blockChanged(BlockPos blockPos, CallbackInfo ci) {
changedLocalBlocks[sectionIDX].add(SectionPos.sectionRelativePos(blockPos));
}
}
+ int topY = ((LightHeightmapGetter) chunk).getLightHeightmap().getFirstAvailable(localX, localZ) - 1;
+ // if the block being changed is new top block - heightmap probably was updated
+ // if block being changed is above new top block - heightmap was probably decreased
+ // TODO: replace heuristics with proper tracking
+ if (blockPos.getY() >= topY) {
+ // TODO: don't use heightmap type as "height" for address
+
+ if (this.changedLocalBlocks[sectionIDX] == null) {
+ this.changedLocalBlocks[sectionIDX] = new ShortArraySet();
+ }
+ changedLocalBlocks[sectionIDX].add(SectionPos.sectionRelativePos(blockPos));
+ }
return;
}
@@ -435,6 +422,7 @@ private void broadcastCubeChanges(LevelChunk levelChunk, CallbackInfo ci) {
}
ci.cancel();
+
if (cubePos != null) {
throw new IllegalStateException("Why is this getting called?");
}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkManager.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkManager.java
index 40ce0a280..fb3a178f9 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkManager.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkManager.java
@@ -5,10 +5,8 @@
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
-import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -16,6 +14,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BooleanSupplier;
import java.util.function.IntFunction;
@@ -57,6 +56,8 @@
import io.github.opencubicchunks.cubicchunks.chunk.util.Utils;
import io.github.opencubicchunks.cubicchunks.mixin.access.common.EntityTrackerAccess;
import io.github.opencubicchunks.cubicchunks.mixin.access.common.IOWorkerAccess;
+import io.github.opencubicchunks.cubicchunks.mixin.access.common.TicketAccess;
+import io.github.opencubicchunks.cubicchunks.mixin.access.common.TicketManagerAccess;
import io.github.opencubicchunks.cubicchunks.network.PacketCubes;
import io.github.opencubicchunks.cubicchunks.network.PacketDispatcher;
import io.github.opencubicchunks.cubicchunks.network.PacketHeightmap;
@@ -97,6 +98,7 @@
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ThreadedLevelLightEngine;
+import net.minecraft.server.level.Ticket;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.Mth;
import net.minecraft.util.thread.BlockableEventLoop;
@@ -119,7 +121,6 @@
import net.minecraft.world.level.storage.DimensionDataStorage;
import net.minecraft.world.level.storage.LevelStorageSource;
import org.apache.commons.lang3.mutable.MutableBoolean;
-import org.spongepowered.asm.mixin.Dynamic;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -136,6 +137,8 @@ public abstract class MixinChunkManager implements IChunkManager, IChunkMapInter
private static final double TICK_UPDATE_DISTANCE = 128.0;
+ private static final Executor COLUMN_LOADING_EXECUTOR = Executors.newSingleThreadExecutor();
+
@Shadow @Final ServerLevel level;
@Shadow int viewDistance;
@@ -316,7 +319,7 @@ protected void save(boolean flush, CallbackInfo ci) {
}
- public void setServerChunkCache(ServerChunkCache cache) {
+ @Override public void setServerChunkCache(ServerChunkCache cache) {
serverChunkCache = cache;
}
@@ -468,7 +471,18 @@ private void scheduleCubeUnload(long cubePos, ChunkHolder chunkHolderIn) {
((IServerWorldLightManager) this.lightEngine).setCubeStatusEmpty(icube.getCubePos());
this.lightEngine.tryScheduleUpdate();
- ((ICubeStatusListener) this.progressListener).onCubeStatusChange(icube.getCubePos(), null);
+ CubePos pos = CubePos.from(cubePos);
+
+ for (int localX = 0; localX < IBigCube.DIAMETER_IN_SECTIONS; localX++) {
+ for (int localZ = 0; localZ < IBigCube.DIAMETER_IN_SECTIONS; localZ++) {
+ long chunkPos = pos.asChunkPos(localX, localZ).toLong();
+ Ticket>[] tickets = ((TicketManagerAccess) distanceManager).invokeGetTickets(chunkPos).stream().filter((ticket ->
+ ticket.getType() == CCTicketType.CCCOLUMN && ((TicketAccess) ticket).getKey().equals(pos))).toArray(Ticket[]::new);
+ for (Ticket> ticket : tickets) {
+ ((TicketManagerAccess) this.distanceManager).invokeRemoveTicket(chunkPos, ticket);
+ }
+ }
+ }
}
}
@@ -580,55 +594,24 @@ private void onPromoteChunkMap(CallbackInfoReturnable cir) {
this.visibleCubeMap = updatingCubeMap.clone();
}
- @Dynamic
- @Inject(method = "updateCubeScheduling", at = @At(value = "INVOKE", target = "Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;put(JLjava/lang/Object;)Ljava/lang/Object;"))
- private void addChunkHolders(long pos, int _level, ChunkHolder holder, int i, CallbackInfoReturnable cir) {
- ICubeHolder cubeHolder = (ICubeHolder) holder;
- if (cubeHolder.getChunkHolders() != null) {
- return;
- }
- CubePos cubePos = CubePos.from(pos);
- ChunkHolder[] chunkHolders = new ChunkHolder[IBigCube.DIAMETER_IN_SECTIONS * IBigCube.DIAMETER_IN_SECTIONS];
- for (int localX = 0; localX < IBigCube.DIAMETER_IN_SECTIONS; localX++) {
- for (int localZ = 0; localZ < IBigCube.DIAMETER_IN_SECTIONS; localZ++) {
- ChunkPos chunkPos = cubePos.asChunkPos(localX, localZ);
- ChunkHolder chunkHolder = ((IServerChunkProvider) serverChunkCache).getChunkHolderForce(chunkPos, ChunkStatus.EMPTY);
- chunkHolders[localX * IBigCube.DIAMETER_IN_SECTIONS + localZ] = chunkHolder;
- }
- }
- cubeHolder.setChunkHolders(chunkHolders);
- }
-
@Override
public Iterable getCubes() {
return Iterables.unmodifiableIterable(this.visibleCubeMap.values());
}
- //weird supplier to make sure the cube future is created after the chunk ones, just in case
- private CompletableFuture> chainFutures(
- Supplier>> cubeFutureSupplier, ChunkHolder[] chunkHolders, ChunkStatus chunkStatusIn) {
- Iterator iterator = Arrays.stream(chunkHolders).iterator();
- ChunkHolder chunkHolder = iterator.next(); //set first future
- CompletableFuture> chunkFutureChain = chunkHolder.getOrScheduleFuture(chunkStatusIn, (ChunkMap) (Object) this);
- while (iterator.hasNext()) { //chain all subsequent futures
- ChunkHolder next = iterator.next();
- chunkFutureChain = chunkFutureChain.thenComposeAsync((either) -> next.getOrScheduleFuture(chunkStatusIn, (ChunkMap) (Object) this));
- }
-
- CompletableFuture> cubeFuture = cubeFutureSupplier.get();
- return chunkFutureChain.thenComposeAsync((either) -> cubeFuture);
- }
-
// func_219244_a, schedule
@Override
public CompletableFuture> scheduleCube(ChunkHolder cubeHolder, ChunkStatus chunkStatusIn) {
CubePos cubePos = ((ICubeHolder) cubeHolder).getCubePos();
+ CompletableFuture> columnFutures = scheduleAndWaitForColumns(chunkStatusIn, cubePos);
if (chunkStatusIn == ChunkStatus.EMPTY) {
- return chainFutures(() -> scheduleCubeLoad(cubePos), ((ICubeHolder) cubeHolder).getChunkHolders(), chunkStatusIn);
+ CompletableFuture> cubeFuture = this.scheduleCubeLoad(cubePos);
+ return columnFutures.thenComposeAsync(columns -> cubeFuture);
} else {
- CompletableFuture> completablefuture = chainFutures(
- () -> ((ICubeHolder) cubeHolder).getOrScheduleCubeFuture(chunkStatusIn.getParent(), (ChunkMap) (Object) this), ((ICubeHolder) cubeHolder).getChunkHolders(), chunkStatusIn);
- return completablefuture.thenComposeAsync(
+ CompletableFuture> parentCubeFuture = Utils.unsafeCast(
+ ((ICubeHolder) cubeHolder).getOrScheduleCubeFuture(chunkStatusIn.getParent(), (ChunkMap) (Object) this)
+ );
+ return columnFutures.thenComposeAsync(columns -> parentCubeFuture).thenComposeAsync(
(Either inputSection) -> {
Optional optional = inputSection.left();
if (!optional.isPresent()) {
@@ -669,12 +652,8 @@ private ChunkStatus getCubeDependencyStatus(ChunkStatus status, int distance) {
private CompletableFuture> scheduleCubeGeneration(ChunkHolder chunkHolderIn, ChunkStatus chunkStatusIn) {
CubePos cubePos = ((ICubeHolder) chunkHolderIn).getCubePos();
CompletableFuture, ChunkHolder.ChunkLoadingFailure>> future =
- this.getCubeRangeFuture(cubePos, CubeStatus.getCubeTaskRange(chunkStatusIn), (count) -> {
- return this.getCubeDependencyStatus(chunkStatusIn, count);
- });
- this.level.getProfiler().incrementCounter(() -> {
- return "cubeGenerate " + chunkStatusIn.getName();
- });
+ this.getCubeRangeFuture(cubePos, CubeStatus.getCubeTaskRange(chunkStatusIn), (count) -> this.getCubeDependencyStatus(chunkStatusIn, count));
+ this.level.getProfiler().incrementCounter(() -> "cubeGenerate " + chunkStatusIn.getName());
Executor executor = (runnable) -> this.cubeWorldgenMailbox.tell(CubeTaskPriorityQueueSorter.createMsg(chunkHolderIn, runnable));
@@ -682,9 +661,8 @@ private CompletableFuture> sch
return sectionOrError.map((neighborSections) -> {
try {
CompletableFuture> finalFuture = Utils.unsafeCast(
- chunkStatusIn.generate(executor, this.level, this.generator, this.structureManager, this.lightEngine, (chunk) -> {
- return Utils.unsafeCast(this.protoCubeToFullCube(chunkHolderIn));
- }, Utils.unsafeCast(neighborSections)));
+ chunkStatusIn.generate(executor, this.level, this.generator, this.structureManager, this.lightEngine,
+ (chunk) -> Utils.unsafeCast(this.protoCubeToFullCube(chunkHolderIn)), Utils.unsafeCast(neighborSections)));
((ICubeStatusListener) this.progressListener).onCubeStatusChange(cubePos, chunkStatusIn);
return finalFuture;
} catch (Exception exception) {
@@ -695,13 +673,32 @@ private CompletableFuture> sch
crashreportcategory.setDetail("Generator", this.generator);
throw new ReportedException(crashreport);
}
- }, (p_219211_2_) -> {
+ }, (loadingFailure) -> {
this.releaseLightTicket(cubePos);
- return CompletableFuture.completedFuture(Either.right(p_219211_2_));
+ return CompletableFuture.completedFuture(Either.right(loadingFailure));
});
- }, (runnable) -> {
- this.cubeWorldgenMailbox.tell(CubeTaskPriorityQueueSorter.createMsg(chunkHolderIn, runnable));
- });
+ }, executor);
+ }
+
+ private CompletableFuture> scheduleAndWaitForColumns(ChunkStatus chunkStatusIn, CubePos cubePos) {
+
+ CompletableFuture>> nestedChainedFuture = CompletableFuture.supplyAsync(() -> {
+ CompletableFuture> chainedFutures = null;
+ for (int localX = 0; localX < IBigCube.DIAMETER_IN_SECTIONS; localX++) {
+ for (int localZ = 0; localZ < IBigCube.DIAMETER_IN_SECTIONS; localZ++) {
+ ChunkPos chunkPos = cubePos.asChunkPos(localX, localZ);
+ CompletableFuture> columnFutureForCube =
+ ((IServerChunkProvider) serverChunkCache).getColumnFutureForCube(cubePos, chunkPos.x, chunkPos.z, chunkStatusIn, true);
+ if (chainedFutures == null) {
+ chainedFutures = columnFutureForCube;
+ } else {
+ chainedFutures = chainedFutures.thenCompose((existingFuture) -> columnFutureForCube);
+ }
+ }
+ }
+ return chainedFutures;
+ }, mainThreadExecutor);
+ return nestedChainedFuture.thenComposeAsync((future) -> future, COLUMN_LOADING_EXECUTOR);
}
// func_219236_a, getChunkRangeFuture
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkStatus.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkStatus.java
index be8cb8fb6..0816a0f1a 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkStatus.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkStatus.java
@@ -19,7 +19,9 @@
import io.github.opencubicchunks.cubicchunks.config.ChunkGeneratorSettings;
import io.github.opencubicchunks.cubicchunks.config.reloadlisteners.ChunkGeneratorSettingsReloadListener;
import io.github.opencubicchunks.cubicchunks.mixin.access.common.ChunkGeneratorAccess;
+import io.github.opencubicchunks.cubicchunks.mixin.access.common.ChunkManagerAccess;
import io.github.opencubicchunks.cubicchunks.mixin.access.common.StructureFeatureManagerAccess;
+import io.github.opencubicchunks.cubicchunks.mixin.access.common.ThreadedLevelLightEngineAccess;
import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor;
import io.github.opencubicchunks.cubicchunks.utils.Coords;
import io.github.opencubicchunks.cubicchunks.world.CubeWorldGenRegion;
@@ -462,6 +464,10 @@ private static void lightChunkCC(ChunkStatus status, ThreadedLevelLightEngine li
}
if (!(chunk instanceof CubePrimer)) {
+ ChunkPos pos = chunk.getPos();
+ ((ThreadedLevelLightEngineAccess) lightManager).invokeAddTask(pos.x, pos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, () -> {
+ ((ChunkManagerAccess) ((ThreadedLevelLightEngineAccess) lightManager).getChunkMap()).invokeReleaseLightTicket(pos);
+ });
if (!chunk.getStatus().isOrAfter(status)) {
((ProtoChunk) chunk).setStatus(status);
}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinImposterProtoChunk.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinImposterProtoChunk.java
new file mode 100644
index 000000000..57ffcf388
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinImposterProtoChunk.java
@@ -0,0 +1,26 @@
+package io.github.opencubicchunks.cubicchunks.mixin.core.common.chunk;
+
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMap;
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter;
+import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter;
+import net.minecraft.world.level.chunk.ImposterProtoChunk;
+import net.minecraft.world.level.chunk.LevelChunk;
+import net.minecraft.world.level.levelgen.Heightmap;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+@Mixin(ImposterProtoChunk.class)
+public class MixinImposterProtoChunk implements CubeMapGetter, LightHeightmapGetter {
+
+
+ @Shadow @Final private LevelChunk wrapped;
+
+ @Override public CubeMap getCubeMap() {
+ return ((CubeMapGetter) this.wrapped).getCubeMap();
+ }
+
+ @Override public Heightmap getLightHeightmap() {
+ return ((LightHeightmapGetter) this.wrapped).getLightHeightmap();
+ }
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinProtoChunk.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinProtoChunk.java
index 768411f24..9b98cc719 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinProtoChunk.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinProtoChunk.java
@@ -1,18 +1,24 @@
package io.github.opencubicchunks.cubicchunks.mixin.core.common.chunk;
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMap;
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter;
import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
+import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter;
import io.github.opencubicchunks.cubicchunks.chunk.cube.CubePrimer;
+import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper;
import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.ProtoTickList;
import net.minecraft.world.level.chunk.UpgradeData;
+import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.material.Fluid;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -24,16 +30,36 @@
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ProtoChunk.class)
-public abstract class MixinProtoChunk implements LevelHeightAccessor, CubicLevelHeightAccessor {
+public abstract class MixinProtoChunk implements LightHeightmapGetter, LevelHeightAccessor, CubeMapGetter, CubicLevelHeightAccessor {
private boolean isCubic;
private boolean generates2DChunks;
private WorldStyle worldStyle;
+ private LightSurfaceTrackerWrapper lightHeightmap;
+ private CubeMap cubeMap;
+
@Shadow @Final private LevelHeightAccessor levelHeightAccessor;
@Shadow public abstract ChunkStatus getStatus();
+ @Override
+ public Heightmap getLightHeightmap() {
+ if (!isCubic) {
+ throw new UnsupportedOperationException("Attempted to get light heightmap on a non-cubic chunk");
+ }
+ return lightHeightmap;
+ }
+
+ @Override
+ public CubeMap getCubeMap() {
+ // TODO actually init this properly instead of doing lazy init here
+ if (cubeMap == null) {
+ cubeMap = new CubeMap();
+ }
+ return cubeMap;
+ }
+
@Inject(method = "(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/chunk/UpgradeData;[Lnet/minecraft/world/level/chunk/LevelChunkSection;"
+ "Lnet/minecraft/world/level/chunk/ProtoTickList;Lnet/minecraft/world/level/chunk/ProtoTickList;Lnet/minecraft/world/level/LevelHeightAccessor;)V", at = @At("RETURN"))
private void setCubic(ChunkPos chunkPos, UpgradeData upgradeData, LevelChunkSection[] levelChunkSections, ProtoTickList protoTickList, ProtoTickList protoTickList2,
@@ -104,4 +130,18 @@ private void setMinHeight(CallbackInfoReturnable cir) {
@Override public boolean generates2DChunks() {
return generates2DChunks;
}
+
+ @Inject(
+ method = "setStatus(Lnet/minecraft/world/level/chunk/ChunkStatus;)V",
+ at = @At("RETURN")
+ )
+ private void onSetStatus(ChunkStatus status, CallbackInfo ci) {
+ if (!this.isCubic()) {
+ return;
+ }
+ if (lightHeightmap == null && this.getStatus().isOrAfter(ChunkStatus.FEATURES)) {
+ // Lighting only starts happening after FEATURES, so we init here to avoid creating unnecessary heightmaps
+ lightHeightmap = new LightSurfaceTrackerWrapper((ChunkAccess) this);
+ }
+ }
}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/entity/MixinServerPlayerEntity.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/entity/MixinServerPlayerEntity.java
index 0a4a37f34..e12d4b507 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/entity/MixinServerPlayerEntity.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/entity/MixinServerPlayerEntity.java
@@ -1,17 +1,25 @@
package io.github.opencubicchunks.cubicchunks.mixin.core.common.entity;
+import com.mojang.authlib.GameProfile;
import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor;
+import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.Packet;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(ServerPlayer.class)
-public abstract class MixinServerPlayerEntity {
+public abstract class MixinServerPlayerEntity extends Player {
+ public MixinServerPlayerEntity(Level level, BlockPos blockPos, float f, GameProfile gameProfile) {
+ super(level, blockPos, f, gameProfile);
+ }
+
@Shadow public abstract ServerLevel getLevel();
@Redirect(method = "trackChunk",
@@ -21,4 +29,13 @@ public void onSendChunkLoad(ServerGamePacketListenerImpl serverPlayNetHandler, P
serverPlayNetHandler.send(packetIn);
}
}
+
+ // This debug code probably causes considerable lag and other issues; it should only be used while debugging lighting
+// @Inject(method = "tick",
+// at = @At("HEAD"))
+// private void onTick(CallbackInfo ci) {
+// if (((CubicLevelHeightAccessor) this.getLevel()).isCubic()) {
+// PacketDispatcher.sendTo(new PacketUpdateLight(CubePos.from(new BlockPos(this.position())), this.level.getLightEngine(), true), (ServerPlayer) (Object) this);
+// }
+// }
}
\ No newline at end of file
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/ticket/MixinTicketManager.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/ticket/MixinTicketManager.java
index 690c9b765..27b9d0e85 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/ticket/MixinTicketManager.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/ticket/MixinTicketManager.java
@@ -20,7 +20,6 @@
import io.github.opencubicchunks.cubicchunks.chunk.ticket.PlayerCubeTracker;
import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
import io.github.opencubicchunks.cubicchunks.mixin.access.common.ChunkHolderAccess;
-import io.github.opencubicchunks.cubicchunks.mixin.access.common.ChunkManagerAccess;
import io.github.opencubicchunks.cubicchunks.mixin.access.common.TicketAccess;
import io.github.opencubicchunks.cubicchunks.utils.Coords;
import io.github.opencubicchunks.cubicchunks.utils.MathUtil;
@@ -34,14 +33,13 @@
import it.unimi.dsi.fastutil.objects.ObjectSet;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap;
-import net.minecraft.server.level.ChunkTaskPriorityQueueSorter;
import net.minecraft.server.level.DistanceManager;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.Ticket;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.SortedArraySet;
import net.minecraft.util.thread.ProcessorHandle;
-import net.minecraft.world.level.chunk.LevelChunk;
+import net.minecraft.world.level.ChunkPos;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -53,6 +51,9 @@
@Mixin(DistanceManager.class)
public abstract class MixinTicketManager implements ITicketManager, IVerticalView {
+ @Final @Shadow private Executor mainThreadExecutor;
+ @Shadow private long ticketTickCounter;
+
private final Long2ObjectOpenHashMap>> cubeTickets = new Long2ObjectOpenHashMap<>();
private final Long2ObjectMap> playersPerCube = new Long2ObjectOpenHashMap<>();
@@ -68,27 +69,11 @@ public abstract class MixinTicketManager implements ITicketManager, IVerticalVie
private boolean isCubic;
- @Shadow @Final private DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter;
-
- @Shadow @Final private DistanceManager.PlayerTicketTracker playerTicketManager;
-
- @Shadow @Final private DistanceManager.ChunkTicketTracker ticketTracker;
-
- @Shadow @Final private Set chunksToUpdateFutures;
-
- @Shadow @Final private LongSet ticketsToRelease;
-
- @Shadow @Final private ProcessorHandle ticketThrottlerReleaser;
-
- @Final @Shadow private Executor mainThreadExecutor;
-
- @Shadow private long ticketTickCounter;
-
@Shadow private static int getTicketLevelAt(SortedArraySet> p_229844_0_) {
throw new Error("Mixin did not apply correctly");
}
- @Shadow protected abstract SortedArraySet> getTickets(long position);
+ @Shadow public abstract void addTicket(TicketType type, ChunkPos pos, int level, T argument);
@Inject(method = "", at = @At("RETURN"))
public void init(Executor executor, Executor executor2, CallbackInfo ci) {
@@ -103,6 +88,11 @@ public void init(Executor executor, Executor executor2, CallbackInfo ci) {
public void addCubeTicket(long cubePosIn, Ticket> ticketIn) {
SortedArraySet> sortedarrayset = this.getCubeTickets(cubePosIn);
int i = getTicketLevelAt(sortedarrayset);
+
+ // force a ticket on the cube's column
+ CubePos cubePos = CubePos.from(cubePosIn);
+ addTicket(CCTicketType.CCCOLUMN, cubePos.asChunkPos(), i, cubePos);
+
Ticket> ticket = sortedarrayset.addOrGet(ticketIn);
((TicketAccess) ticket).invokeSetCreatedTick(this.ticketTickCounter);
if (ticketIn.getTicketLevel() < i) {
@@ -129,45 +119,6 @@ private SortedArraySet> getCubeTickets(long cubePos) {
//BEGIN INJECT
- @Override public boolean runAllUpdatesForChunks(ChunkMap chunkMap) {
- this.naturalSpawnChunkCounter.runAllUpdates();
- this.playerTicketManager.runAllUpdates();
- int i = Integer.MAX_VALUE - this.ticketTracker.runDistanceUpdates(Integer.MAX_VALUE);
- boolean bl = i != 0;
-
- if (!this.chunksToUpdateFutures.isEmpty()) {
- this.chunksToUpdateFutures.forEach((chunkHolder) -> ((ChunkHolderAccess) chunkHolder).invokeUpdateFutures(chunkMap, this.mainThreadExecutor));
- this.chunksToUpdateFutures.clear();
- return true;
- } else {
- if (!this.ticketsToRelease.isEmpty()) {
- LongIterator longIterator = this.ticketsToRelease.iterator();
-
- while (longIterator.hasNext()) {
- long l = longIterator.nextLong();
- if (this.getTickets(l).stream().anyMatch((ticket) -> ticket.getType() == TicketType.PLAYER)) {
- ChunkHolder chunkHolder = ((ChunkManagerAccess) chunkMap).invokeGetUpdatingChunkIfPresent(l);
- if (chunkHolder == null) {
- throw new IllegalStateException();
- }
-
- CompletableFuture> completableFuture = chunkHolder.getEntityTickingChunkFuture();
- completableFuture.thenAccept((either) -> {
- this.mainThreadExecutor.execute(() -> {
- this.ticketThrottlerReleaser.tell(ChunkTaskPriorityQueueSorter.release(() -> {
- }, l, false));
- });
- });
- }
- }
-
- this.ticketsToRelease.clear();
- }
-
- return bl;
- }
- }
-
@Inject(method = "runAllUpdates", at = @At("RETURN"), cancellable = true)
public void processUpdates(ChunkMap chunkManager, CallbackInfoReturnable callbackInfoReturnable) {
if (!isCubic) {
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinBlockLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinBlockLightEngine.java
index 1498785dd..4b5a28cf2 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinBlockLightEngine.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinBlockLightEngine.java
@@ -13,7 +13,7 @@
@SuppressWarnings("rawtypes")
@Mixin(BlockLightEngine.class)
-public abstract class MixinBlockLightEngine extends MixinLightEngine {
+public abstract class MixinBlockLightEngine extends MixinLayerLightEngine {
/**
* @author NotStirred
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinDynamicGraphMinFixedPoint.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinDynamicGraphMinFixedPoint.java
new file mode 100644
index 000000000..adf46e6a1
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinDynamicGraphMinFixedPoint.java
@@ -0,0 +1,13 @@
+package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting;
+
+import net.minecraft.world.level.lighting.DynamicGraphMinFixedPoint;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+@Mixin(DynamicGraphMinFixedPoint.class)
+public abstract class MixinDynamicGraphMinFixedPoint {
+ @Shadow protected abstract void checkNeighbor(long sourceId, long targetId, int level, boolean decrease);
+
+ @Shadow
+ protected abstract void checkEdge(long sourceId, long id, int level, boolean decrease);
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLayerLightEngine.java
similarity index 61%
rename from src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLightEngine.java
rename to src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLayerLightEngine.java
index fd26b1e62..aec484fc5 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLightEngine.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLayerLightEngine.java
@@ -4,7 +4,7 @@
import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
-import io.github.opencubicchunks.cubicchunks.mixin.access.common.SectionLightStorageAccess;
+import io.github.opencubicchunks.cubicchunks.mixin.access.common.LayerLightSectionStorageAccess;
import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor;
import io.github.opencubicchunks.cubicchunks.world.lighting.ICubeLightProvider;
import io.github.opencubicchunks.cubicchunks.world.lighting.ILightEngine;
@@ -14,36 +14,36 @@
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LightLayer;
-import net.minecraft.world.level.block.Blocks;
-import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LightChunkGetter;
import net.minecraft.world.level.lighting.DataLayerStorageMap;
import net.minecraft.world.level.lighting.LayerLightEngine;
import net.minecraft.world.level.lighting.LayerLightSectionStorage;
-import org.apache.commons.lang3.mutable.MutableInt;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(LayerLightEngine.class)
-public abstract class MixinLightEngine, S extends LayerLightSectionStorage> implements ILightEngine {
+public abstract class MixinLayerLightEngine, S extends LayerLightSectionStorage> extends MixinDynamicGraphMinFixedPoint implements ILightEngine {
+
@Shadow @Final protected S storage;
@Shadow @Final protected BlockPos.MutableBlockPos pos;
@Shadow @Final protected LightChunkGetter chunkSource;
+ protected boolean isCubic;
+
@Shadow @Final private long[] lastChunkPos;
@Shadow @Final private BlockGetter[] lastChunk;
- private boolean isCubic;
- private boolean generates2DChunks;
- private CubicLevelHeightAccessor.WorldStyle worldStyle;
+ @Shadow protected void checkNode(long id) {
+ }
@Shadow @Nullable protected abstract BlockGetter getChunk(int chunkX, int chunkZ);
@@ -59,7 +59,7 @@ public void enableLightSources(CubePos cubePos, boolean enable) {
//TODO: implement invokeEnableLightSources for CubePos in SkyLightStorage
for (int x = 0; x < IBigCube.DIAMETER_IN_SECTIONS; x++) {
for (int z = 0; z < IBigCube.DIAMETER_IN_SECTIONS; z++) {
- ((SectionLightStorageAccess) this.storage).invokeSetColumnEnabled(new ChunkPos(chunkPos.x + x, chunkPos.z + z).toLong(), enable);
+ ((LayerLightSectionStorageAccess) this.storage).invokeSetColumnEnabled(new ChunkPos(chunkPos.x + x, chunkPos.z + z).toLong(), enable);
}
}
}
@@ -67,50 +67,20 @@ public void enableLightSources(CubePos cubePos, boolean enable) {
@Inject(method = "", at = @At("RETURN"))
private void setCubic(LightChunkGetter lightChunkGetter, LightLayer lightLayer, S layerLightSectionStorage, CallbackInfo ci) {
this.isCubic = ((CubicLevelHeightAccessor) this.chunkSource.getLevel()).isCubic();
- this.generates2DChunks = ((CubicLevelHeightAccessor) this.chunkSource.getLevel()).generates2DChunks();
- this.worldStyle = ((CubicLevelHeightAccessor) this.chunkSource.getLevel()).worldStyle();
+// this.generates2DChunks = ((CubicLevelHeightAccessor) this.chunkSource.getLevel()).generates2DChunks();
+// this.worldStyle = ((CubicLevelHeightAccessor) this.chunkSource.getLevel()).worldStyle();
}
- /**
- * @author NotStirred
- * @reason Vanilla lighting is gone
- */
- //TODO: make this into a redirect that calls getCubeReader taking arguments blockPosLong
- @Inject(method = "getStateAndOpacity", at = @At("HEAD"), cancellable = true)
- private void getStateAndOpacity(long blockPosLong, @Nullable MutableInt opacity, CallbackInfoReturnable cir) {
+ @Redirect(method = "getStateAndOpacity",
+ at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/lighting/LayerLightEngine;getChunk(II)Lnet/minecraft/world/level/BlockGetter;"))
+ private BlockGetter useCubicBlockGetter(LayerLightEngine layerLightEngine, int chunkX, int chunkZ, long blockPos) {
if (!this.isCubic) {
- return;
- }
- cir.cancel();
-
- if (blockPosLong == Long.MAX_VALUE) {
- if (opacity != null) {
- opacity.setValue(0);
- }
-
- cir.setReturnValue(Blocks.AIR.defaultBlockState());
- } else {
- int sectionX = SectionPos.blockToSectionCoord(BlockPos.getX(blockPosLong));
- int sectionY = SectionPos.blockToSectionCoord(BlockPos.getY(blockPosLong));
- int sectionZ = SectionPos.blockToSectionCoord(BlockPos.getZ(blockPosLong));
- BlockGetter iblockreader = this.getCubeReader(sectionX, sectionY, sectionZ);
- if (iblockreader == null) {
- if (opacity != null) {
- opacity.setValue(16);
- }
-
- cir.setReturnValue(Blocks.BEDROCK.defaultBlockState());
- } else {
- this.pos.set(blockPosLong);
- BlockState blockstate = iblockreader.getBlockState(this.pos);
- boolean flag = blockstate.canOcclude() && blockstate.useShapeForLightOcclusion();
- if (opacity != null) {
- opacity.setValue(blockstate.getLightBlock(this.chunkSource.getLevel(), this.pos));
- }
-
- cir.setReturnValue(flag ? blockstate : Blocks.AIR.defaultBlockState());
- }
+ return this.getChunk(chunkX, chunkZ);
}
+ int sectionX = SectionPos.blockToSectionCoord(BlockPos.getX(blockPos));
+ int sectionY = SectionPos.blockToSectionCoord(BlockPos.getY(blockPos));
+ int sectionZ = SectionPos.blockToSectionCoord(BlockPos.getZ(blockPos));
+ return this.getCubeReader(sectionX, sectionY, sectionZ);
}
@Nullable
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSectionLightStorage.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLayerLightSectionStorage.java
similarity index 90%
rename from src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSectionLightStorage.java
rename to src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLayerLightSectionStorage.java
index 01e273d09..82ff573f5 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSectionLightStorage.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLayerLightSectionStorage.java
@@ -1,6 +1,5 @@
package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting;
-import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
import io.github.opencubicchunks.cubicchunks.mixin.access.common.LevelBasedGraphAccess;
import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor;
import io.github.opencubicchunks.cubicchunks.world.lighting.ISectionLightStorage;
@@ -25,7 +24,7 @@
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(LayerLightSectionStorage.class)
-public abstract class MixinSectionLightStorage> extends SectionTracker implements ISectionLightStorage {
+public abstract class MixinLayerLightSectionStorage> extends SectionTracker implements ISectionLightStorage {
@Shadow @Final private static Direction[] DIRECTIONS;
@@ -38,7 +37,7 @@ public abstract class MixinSectionLightStorage>
private final LongSet cubesToRetain = new LongOpenHashSet();
- protected MixinSectionLightStorage(int p_i50706_1_, int p_i50706_2_, int p_i50706_3_) {
+ protected MixinLayerLightSectionStorage(int p_i50706_1_, int p_i50706_2_, int p_i50706_3_) {
super(p_i50706_1_, p_i50706_2_, p_i50706_3_);
}
@@ -78,13 +77,15 @@ protected void markNewInconsistenciesForCube(LayerLightEngine engine, bool
this.clearQueuedSectionBlocks(engine, noLightPos);
DataLayer nibblearray = this.queuedSections.remove(noLightPos);
DataLayer nibblearray1 = this.updatingSectionData.removeLayer(noLightPos);
- if (this.cubesToRetain.contains(CubePos.sectionToCubeSectionLong(noLightPos))) {
+ // FIXME this commented out check is probably important, but also breaks client-side lighting
+ // should investigate why it breaks things instead of just disabling it.
+// if (this.cubesToRetain.contains(CubePos.sectionToCubeSectionLong(noLightPos))) {
if (nibblearray != null) {
this.queuedSections.put(noLightPos, nibblearray);
} else if (nibblearray1 != null) {
this.queuedSections.put(noLightPos, nibblearray1);
}
- }
+// }
}
this.updatingSectionData.clearCache();
@@ -99,14 +100,16 @@ protected void markNewInconsistenciesForCube(LayerLightEngine engine, bool
for (Long2ObjectMap.Entry entry : this.queuedSections.long2ObjectEntrySet()) {
long entryPos = entry.getLongKey();
- if (this.storingLightForSection(entryPos)) {
+ // FIXME this commented out check is also probably important, but this one breaks *server-side* lighting
+ // should investigate why it breaks things instead of just disabling it.
+// if (this.storingLightForSection(entryPos)) {
DataLayer nibblearray2 = entry.getValue();
if (this.updatingSectionData.getLayer(entryPos) != nibblearray2) {
this.clearQueuedSectionBlocks(engine, entryPos);
this.updatingSectionData.setLayer(entryPos, nibblearray2);
this.changedSections.add(entryPos);
}
- }
+// }
}
LevelBasedGraphAccess engineAccess = ((LevelBasedGraphAccess) engine);
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinWorldLightManager.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLevelLightEngine.java
similarity index 72%
rename from src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinWorldLightManager.java
rename to src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLevelLightEngine.java
index 533733d0f..29b84249a 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinWorldLightManager.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLevelLightEngine.java
@@ -2,8 +2,12 @@
import javax.annotation.Nullable;
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter;
+import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
+import io.github.opencubicchunks.cubicchunks.world.lighting.ICubicSkyLightEngine;
import io.github.opencubicchunks.cubicchunks.world.lighting.ILightEngine;
+import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker;
import io.github.opencubicchunks.cubicchunks.world.lighting.IWorldLightManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
@@ -18,7 +22,7 @@
import org.spongepowered.asm.mixin.Shadow;
@Mixin(LevelLightEngine.class)
-public abstract class MixinWorldLightManager implements IWorldLightManager, LightEventListener {
+public abstract class MixinLevelLightEngine implements IWorldLightManager, LightEventListener, ISkyLightColumnChecker {
@Shadow @Final protected LevelHeightAccessor levelHeightAccessor;
@Shadow @Final @Nullable private LayerLightEngine, ?> blockEngine;
@@ -62,5 +66,16 @@ public void enableLightSources(CubePos cubePos, boolean retain) {
}
}
+ protected void doSkyLightForCube(IBigCube cube) {
+ if (this.skyEngine != null) {
+ ((ICubicSkyLightEngine) this.skyEngine).doSkyLightForCube(cube);
+ }
+ }
+ @Override
+ public void checkSkyLightColumn(CubeMapGetter chunk, int x, int z, int oldHeight, int newHeight) {
+ if (this.skyEngine != null) {
+ ((ISkyLightColumnChecker) skyEngine).checkSkyLightColumn(chunk, x, z, oldHeight, newHeight);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightEngine.java
new file mode 100644
index 000000000..672f34460
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightEngine.java
@@ -0,0 +1,223 @@
+package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting;
+
+
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMap;
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter;
+import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
+import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter;
+import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
+import io.github.opencubicchunks.cubicchunks.mixin.access.common.LayerLightSectionStorageAccess;
+import io.github.opencubicchunks.cubicchunks.utils.Coords;
+import io.github.opencubicchunks.cubicchunks.world.lighting.ICubeLightProvider;
+import io.github.opencubicchunks.cubicchunks.world.lighting.ICubicSkyLightEngine;
+import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.core.SectionPos;
+import net.minecraft.world.level.BlockGetter;
+import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.chunk.ChunkStatus;
+import net.minecraft.world.level.levelgen.Heightmap;
+import net.minecraft.world.level.lighting.SkyLightEngine;
+import net.minecraft.world.level.lighting.SkyLightSectionStorage;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+@Mixin(SkyLightEngine.class)
+public abstract class MixinSkyLightEngine extends MixinLayerLightEngine implements ISkyLightColumnChecker,
+ ICubicSkyLightEngine {
+ @Shadow @Final private static Direction[] DIRECTIONS;
+
+ /**
+ * @author CursedFlames
+ * @reason disable vanilla sky light logic
+ */
+ @Inject(method = "checkNode", at = @At("HEAD"), cancellable = true)
+ protected void checkNode(long id, CallbackInfo ci) {
+ if (!this.isCubic) {
+ return;
+ }
+ ci.cancel();
+ super.checkNode(id);
+ }
+
+ /** all parameters are global coordinates */
+ @Override public void checkSkyLightColumn(CubeMapGetter chunk, int x, int z, int oldHeight, int newHeight) {
+ ((LayerLightSectionStorageAccess) this.storage).invokeRunAllUpdates();
+ CubeMap cubeMap = chunk.getCubeMap();
+ int oldHeightCube = Coords.blockToCube(oldHeight - 1);
+ int newHeightCube = Coords.blockToCube(newHeight);
+ if (oldHeight > newHeight) {
+ // not sure if this is necessary - also maybe it should be done inside the loop? not sure if threaded stuff can result in storage becoming out of date inside the loop
+ ((LayerLightSectionStorageAccess) this.storage).invokeRunAllUpdates();
+
+ // TODO cube iteration order might still be important here
+ // (int y = oldHeight-1; y >= newHeight; y--)
+ for (int cubeY : cubeMap.getLoaded()) {
+ if (oldHeightCube <= cubeY && cubeY <= newHeightCube) {
+ for (int dy = IBigCube.DIAMETER_IN_BLOCKS - 1; dy >= 0; dy--) {
+ int y = cubeY * IBigCube.DIAMETER_IN_BLOCKS + dy;
+
+ if (y >= oldHeight) {
+ continue;
+ }
+ if (y < newHeight) {
+ break;
+ }
+
+ long pos = new BlockPos(x, y, z).asLong();
+ if (((LayerLightSectionStorageAccess) this.storage).invokeStoringLightForSection(SectionPos.blockToSection(pos))) {
+ addEmissionAtPos(pos);
+ }
+ }
+ }
+ }
+ } else {
+ // TODO cube iteration order might still be important here
+ // (int y = oldHeight; y < newHeight; y++)
+ for (int cubeY : cubeMap.getLoaded()) {
+ if (oldHeightCube <= cubeY && cubeY <= newHeightCube) {
+ for (int dy = 0; dy < IBigCube.DIAMETER_IN_BLOCKS; dy++) {
+ int y = cubeY * IBigCube.DIAMETER_IN_BLOCKS + dy;
+
+ if (y < oldHeight) {
+ continue;
+ }
+ if (y >= newHeight) {
+ break;
+ }
+
+ long pos = new BlockPos(x, y, z).asLong();
+ // Don't need to check storing light for pos here, since it's already handled by checkNode
+ this.checkNode(pos);
+ }
+ }
+ }
+ }
+ }
+
+ private void addEmissionAtPos(long pos) {
+ this.checkEdge(Long.MAX_VALUE, pos, 0, true);
+ }
+
+ /**
+ * @author CursedFlames
+ * @reason Prevent getComputedLevel from ignoring skylight sources and decreasing light level - similar to BlockLightEngine's light source check
+ */
+ @Inject(method = "getComputedLevel(JJI)I",
+ at = @At("HEAD"), cancellable = true)
+ private void onGetComputedLevel(long id, long excludedId, int maxLevel, CallbackInfoReturnable cir) {
+ // TODO do we want this mixin on client side too?
+ if (!this.isCubic /*|| this.chunkSource.getLevel() instanceof ClientLevel*/) {
+ return;
+ }
+ BlockPos pos = BlockPos.of(id);
+
+ BlockGetter cube = ((ICubeLightProvider) this.chunkSource).getCubeForLighting(
+ Coords.blockToSection(pos.getX()), Coords.blockToSection(pos.getY()), Coords.blockToSection(pos.getZ()));
+ if (cube == null || !((IBigCube) cube).getStatus().isOrAfter(ChunkStatus.LIGHT)) {
+ return;
+ }
+
+ BlockGetter chunk = this.chunkSource.getChunkForLighting(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()));
+
+ if (chunk == null) {
+ // ToDo Known bug: Cubes may be sent to the client ahead of their chunks. This is not fatal.
+ // see MixinSkyLightSectionStorage.onGetLightValue(...)
+// System.out.println("getComputedLevel: Missing chunk for lighting.");
+ return;
+ }
+
+ Heightmap heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap();
+
+ int height = heightmap.getFirstAvailable(pos.getX() & 0xF, pos.getZ() & 0xF);
+ if (height <= pos.getY()) {
+ cir.setReturnValue(0);
+ }
+ }
+
+ @Override
+ public void doSkyLightForCube(IBigCube cube) {
+ CubePos cubePos = cube.getCubePos();
+ ChunkPos chunkPos = cubePos.asChunkPos();
+ int minY = cubePos.minCubeY();
+ int maxY = cubePos.maxCubeY();
+ for (int sectionX = 0; sectionX < IBigCube.DIAMETER_IN_SECTIONS; sectionX++) {
+ for (int sectionZ = 0; sectionZ < IBigCube.DIAMETER_IN_SECTIONS; sectionZ++) {
+
+ BlockGetter chunk = this.chunkSource.getChunkForLighting(chunkPos.x + sectionX, chunkPos.z + sectionZ);
+
+ // the load order guarantees the chunk being present
+ assert (chunk != null);
+
+ CubeMap cubeMap = ((CubeMapGetter) chunk).getCubeMap();
+ if (!cubeMap.isLoaded(cubePos.getY())) {
+ // This is probably only happening because we don't have load order fixed yet
+ System.out.println(cube.getCubePos() + " : Cube not in cubemap during sky lighting");
+ }
+
+ Heightmap heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap();
+ if (heightmap == null) {
+ System.out.println("heightmap null");
+ return;
+ }
+ for (int z = 0; z < 16; z++) {
+ for (int x = 0; x < 16; x++) {
+ int height = heightmap.getFirstAvailable(x, z);
+ if (height <= maxY) {
+ height = Math.max(height, minY);
+ for (int y = maxY; y >= height; y--) {
+ long pos = new BlockPos((chunkPos.x + sectionX) * 16 + x, y, (chunkPos.z + sectionZ) * 16 + z).asLong();
+ // Not sure if this is necessary
+ ((LayerLightSectionStorageAccess) this.storage).invokeRunAllUpdates();
+
+ if (((LayerLightSectionStorageAccess) this.storage).invokeStoringLightForSection(SectionPos.blockToSection(pos))) {
+ addEmissionAtPos(pos);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @author CursedFlames
+ * @reason disable vanilla sky light logic
+ */
+ @Inject(method = "checkNeighborsAfterUpdate", at = @At("HEAD"), cancellable = true)
+ private void onCheckNeighborsAfterUpdate(long blockPos, int level, boolean decrease, CallbackInfo ci) {
+ if (!isCubic) {
+ return;
+ }
+ ci.cancel();
+
+ long sectionPos = SectionPos.blockToSection(blockPos);
+
+ for (Direction direction : DIRECTIONS) {
+ long offsetBlockPos = BlockPos.offset(blockPos, direction);
+ long offsetSectionPos = SectionPos.blockToSection(offsetBlockPos);
+ // Check all neighbors that are storing light
+ if (sectionPos == offsetSectionPos || (((LayerLightSectionStorageAccess) this.storage)).invokeStoringLightForSection(offsetSectionPos)) {
+ this.checkNeighbor(blockPos, offsetBlockPos, level, decrease);
+ }
+ }
+ }
+
+// /**
+// * @author CursedFlames
+// * @reason prevent infinite downwards skylight propagation
+// */
+// @Inject(method = "computeLevelFromNeighbor", at = @At("RETURN"), cancellable = true)
+// private void onComputeLevelFromNeighbor(long sourceId, long targetId, int level, CallbackInfoReturnable cir) {
+// if (isCubic && cir.getReturnValue() == 0) {
+// cir.setReturnValue(1);
+// }
+// }
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightSectionStorage.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightSectionStorage.java
new file mode 100644
index 000000000..7c68aeeb7
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightSectionStorage.java
@@ -0,0 +1,132 @@
+package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting;
+
+import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
+import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter;
+import io.github.opencubicchunks.cubicchunks.mixin.access.common.LayerLightSectionStorageAccess;
+import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor;
+import io.github.opencubicchunks.cubicchunks.utils.Coords;
+import io.github.opencubicchunks.cubicchunks.world.lighting.ICubeLightProvider;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.SectionPos;
+import net.minecraft.world.level.BlockGetter;
+import net.minecraft.world.level.LightLayer;
+import net.minecraft.world.level.chunk.ChunkStatus;
+import net.minecraft.world.level.chunk.DataLayer;
+import net.minecraft.world.level.chunk.LightChunkGetter;
+import net.minecraft.world.level.levelgen.Heightmap;
+import net.minecraft.world.level.lighting.LayerLightEngine;
+import net.minecraft.world.level.lighting.LayerLightSectionStorage;
+import net.minecraft.world.level.lighting.SkyLightSectionStorage;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+@Mixin(SkyLightSectionStorage.class)
+public abstract class MixinSkyLightSectionStorage extends LayerLightSectionStorage {
+ private boolean isCubic;
+
+ private MixinSkyLightSectionStorage(LightLayer lightLayer, LightChunkGetter lightChunkGetter,
+ SkyLightSectionStorage.SkyDataLayerStorageMap dataLayerStorageMap) {
+ super(lightLayer, lightChunkGetter, dataLayerStorageMap);
+ }
+
+ @Inject(method = "", at = @At("RETURN"))
+ private void onInit(LightChunkGetter lightChunkGetter, CallbackInfo ci) {
+ isCubic = ((CubicLevelHeightAccessor) lightChunkGetter.getLevel()).isCubic();
+ }
+
+ @Inject(method = "getLightValue(JZ)I", cancellable = true, at = @At("HEAD"))
+ private void onGetLightValue(long blockPos, boolean cached, CallbackInfoReturnable cir) {
+ if (!isCubic) {
+ return;
+ }
+
+ // Replace this method with an equivalent of BlockLightSectionStorage.getLightValue,
+ // since we don't need sky light logic
+ long l = SectionPos.blockToSection(blockPos);
+ DataLayer dataLayer = this.getDataLayer(l, cached);
+ int x = BlockPos.getX(blockPos);
+ int y = BlockPos.getY(blockPos);
+ int z = BlockPos.getZ(blockPos);
+ if (dataLayer == null) {
+
+ BlockGetter chunk = ((LayerLightSectionStorageAccess) this).getChunkSource().getChunkForLighting(Coords.blockToSection(x), Coords.blockToSection(z));
+
+ if (chunk == null) {
+ // ToDo Known bug: Cubes may be sent to the client ahead of their chunks. This is not fatal.
+ // see MixinSkyLightEngine.onGetComputedLevel(...)
+ System.out.println("getLightValue: Missing chunk for lighting.");
+ // Set return value to prevent vanilla behaviour from happening and causing weird effects
+ cir.setReturnValue(0);
+ return;
+ }
+
+ //TODO: Optimize
+ BlockGetter cube = ((ICubeLightProvider) ((LayerLightSectionStorageAccess) this).getChunkSource()).getCubeForLighting(
+ Coords.blockToSection(x), Coords.blockToSection(y), Coords.blockToSection(z));
+ if (cube == null || !((IBigCube) cube).getStatus().isOrAfter(ChunkStatus.LIGHT)) {
+ cir.setReturnValue(0);
+ return;
+ }
+
+ Heightmap lightHeightmap = ((LightHeightmapGetter) chunk).getLightHeightmap();
+ int height = lightHeightmap.getFirstAvailable(SectionPos.sectionRelative(x), SectionPos.sectionRelative(z));
+ cir.setReturnValue(height <= y ? 15 : 0);
+ } else {
+ cir.setReturnValue(dataLayer.get(
+ SectionPos.sectionRelative(x),
+ SectionPos.sectionRelative(y),
+ SectionPos.sectionRelative(z)));
+ }
+ }
+
+ @Inject(method = "onNodeAdded", cancellable = true, at = @At("HEAD"))
+ private void onOnNodeAdded(long sectionPos, CallbackInfo ci) {
+ if (!isCubic) return;
+ ci.cancel();
+ }
+
+ @Inject(method = "onNodeRemoved", cancellable = true, at = @At("HEAD"))
+ private void onOnNodeRemoved(long sectionPos, CallbackInfo ci) {
+ if (!isCubic) return;
+ ci.cancel();
+ }
+
+ @Inject(method = "enableLightSources", cancellable = true,
+ at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/world/level/lighting/SkyLightSectionStorage;runAllUpdates()V"))
+ private void onEnableLightSources(long columnPos, boolean enabled, CallbackInfo ci) {
+ if (!isCubic) return;
+ if (enabled) {
+ // We handle skylight emission differently anyway, so we don't need vanilla's sky light source system
+ ci.cancel();
+ }
+ }
+
+ @Inject(method = "createDataLayer", cancellable = true, at = @At("HEAD"))
+ private void onCreateDataLayer(long sectionPos, CallbackInfoReturnable cir) {
+ if (!isCubic) return;
+ cir.setReturnValue(super.createDataLayer(sectionPos));
+ }
+
+ @Inject(method = "markNewInconsistencies", cancellable = true, at = @At("HEAD"))
+ private void onMarkNewInconsistencies(LayerLightEngine lightProvider, boolean doSkylight, boolean skipEdgeLightPropagation,
+ CallbackInfo ci) {
+ if (!isCubic) return;
+ ci.cancel();
+ super.markNewInconsistencies(lightProvider, doSkylight, skipEdgeLightPropagation);
+ }
+
+ @Inject(method = "hasSectionsBelow", cancellable = true, at = @At("HEAD"))
+ private void onHasSectionsBelow(int sectionY, CallbackInfoReturnable cir) {
+ if (!isCubic) return;
+ cir.setReturnValue(true);
+ }
+
+ @Inject(method = "isAboveData", cancellable = true, at = @At("HEAD"))
+ private void onIsAboveData(long sectionPos, CallbackInfoReturnable cir) {
+ if (!isCubic) return;
+ cir.setReturnValue(false);
+ }
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/server/MixinServerWorldLightManager.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java
similarity index 87%
rename from src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/server/MixinServerWorldLightManager.java
rename to src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java
index 1ae1b5e53..f091660a7 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/server/MixinServerWorldLightManager.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java
@@ -1,4 +1,4 @@
-package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.server;
+package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting;
import java.util.concurrent.CompletableFuture;
import java.util.function.IntSupplier;
@@ -7,11 +7,11 @@
import com.mojang.datafixers.util.Pair;
import io.github.opencubicchunks.cubicchunks.CubicChunks;
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter;
import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
import io.github.opencubicchunks.cubicchunks.chunk.IChunkManager;
import io.github.opencubicchunks.cubicchunks.chunk.ticket.CubeTaskPriorityQueueSorter;
import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
-import io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting.MixinWorldLightManager;
import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor;
import io.github.opencubicchunks.cubicchunks.utils.Coords;
import io.github.opencubicchunks.cubicchunks.world.server.IServerWorldLightManager;
@@ -22,6 +22,7 @@
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.util.thread.ProcessorHandle;
+import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.chunk.DataLayer;
import net.minecraft.world.level.chunk.LevelChunkSection;
@@ -33,7 +34,7 @@
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ThreadedLevelLightEngine.class)
-public abstract class MixinServerWorldLightManager extends MixinWorldLightManager implements IServerWorldLightManager {
+public abstract class MixinThreadedLevelLightEngine extends MixinLevelLightEngine implements IServerWorldLightManager {
private ProcessorHandle> cubeSorterMailbox;
@@ -44,6 +45,8 @@ public abstract class MixinServerWorldLightManager extends MixinWorldLightManage
@Shadow private volatile int taskPerBatch;
@Shadow protected abstract void runUpdate();
+ @Shadow
+ protected abstract void addTask(int x, int z, ThreadedLevelLightEngine.TaskType stage, Runnable task);
@Override public void postConstructorSetup(CubeTaskPriorityQueueSorter sorter,
ProcessorHandle> taskExecutor) {
@@ -134,19 +137,36 @@ public CompletableFuture lightCube(IBigCube icube, boolean flagIn) {
super.onBlockEmissionIncrease(blockPos, icube.getLightEmission(blockPos));
}
});
+ // FIXME we probably want another flag for controlling skylight
+ super.doSkyLightForCube(icube);
}
- ((IChunkManager) this.chunkMap).releaseLightTicket(cubePos);
}, () -> "lightCube " + cubePos + " " + flagIn));
return CompletableFuture.supplyAsync(() -> {
icube.setCubeLight(true);
super.retainData(cubePos, false);
+ ((IChunkManager) this.chunkMap).releaseLightTicket(cubePos);
return icube;
}, (runnable) -> {
this.addTask(cubePos.getX(), cubePos.getY(), cubePos.getZ(), ThreadedLevelLightEngine.TaskType.POST_UPDATE, runnable);
});
}
+ @Override
+ public void checkSkyLightColumn(CubeMapGetter chunk, int x, int z, int oldHeight, int newHeight) {
+ // FIXME figure out when this should actually be scheduled instead of just hoping for the best
+ this.addTask(SectionPos.blockToSectionCoord(x), SectionPos.blockToSectionCoord(z), ThreadedLevelLightEngine.TaskType.POST_UPDATE, Util.name(() -> {
+ super.checkSkyLightColumn(chunk, x, z, oldHeight, newHeight);
+ }, () -> "checkSkyLightColumn " + x + " " + z));
+ }
+
+ @Inject(method = "updateChunkStatus", at = @At("HEAD"), cancellable = true)
+ private void cancelUpdateChunkStatus(ChunkPos pos, CallbackInfo ci) {
+ if (((CubicLevelHeightAccessor) this.levelHeightAccessor).isCubic()) {
+ ci.cancel();
+ }
+ }
+
/**
* @author NotStirred
* @reason Vanilla lighting is gone
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/client/MixinLevelRenderer.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/client/MixinLevelRenderer.java
index 4d92eab6b..869cab43b 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/client/MixinLevelRenderer.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/client/MixinLevelRenderer.java
@@ -11,14 +11,13 @@
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
-import io.github.opencubicchunks.cubicchunks.chunk.ICubeHolder;
import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
+import io.github.opencubicchunks.cubicchunks.client.CubicWorldLoadScreen;
import io.github.opencubicchunks.cubicchunks.utils.Coords;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.screens.LevelLoadingScreen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture;
@@ -61,7 +60,7 @@ public void render(PoseStack matrices, float tickDelta, long limitTime, boolean
bufferBuilder.begin(VertexFormat.Mode.TRIANGLE_STRIP, DefaultVertexFormat.POSITION_COLOR);
Object2IntMap colors = getField(
- LevelLoadingScreen.class, null, "COLORS" // TODO: intermediary name
+ CubicWorldLoadScreen.class, null, "STATUS_COLORS" // TODO: intermediary name
);
int renderRadius = 5;
@@ -85,7 +84,7 @@ public void render(PoseStack matrices, float tickDelta, long limitTime, boolean
if (holder == null) {
continue;
}
- ChunkStatus status = ICubeHolder.getCubeStatusFromLevel(holder.getTicketLevel());
+ ChunkStatus status = holder.getLastAvailableStatus();
int color = colors.getOrDefault(status, 0);
@@ -122,7 +121,7 @@ public void render(PoseStack matrices, float tickDelta, long limitTime, boolean
if (holder == null) {
continue;
}
- ChunkStatus status = ICubeHolder.getCubeStatusFromLevel(holder.getTicketLevel());
+ ChunkStatus status = holder.getLastAvailableStatus();
int color = colors.getOrDefault(status, 0);
@@ -131,14 +130,18 @@ public void render(PoseStack matrices, float tickDelta, long limitTime, boolean
int xPos = Coords.cubeToMinBlock(cubeX);
int yPos = Coords.cubeToMinBlock(cubeY);
int zPos = Coords.cubeToMinBlock(cubeZ);
- LevelRenderer.addChainedFilledBoxVertices(bufferBuilder, xPos + 4.25F - cameraX, yPos - 4.25F - cameraY, zPos + 4.25F - cameraZ,
- xPos + 11.75F - cameraX, yPos + 4.25F - cameraY, zPos + 11.75F - cameraZ, vector3f.x(), vector3f.y(), vector3f.z(), 1.0F);
+ drawBox(bufferBuilder, cameraX, cameraY, cameraZ, xPos + 16, yPos + 16, zPos + 16, 4, vector3f);
}
tesselator.end();
RenderSystem.enableTexture();
}
+ private void drawBox(BufferBuilder bufferBuilder, double cameraX, double cameraY, double cameraZ, float x, float y, float z, float radius, Vector3f color) {
+ LevelRenderer.addChainedFilledBoxVertices(bufferBuilder, x - radius - cameraX, y - radius - cameraY, z - radius - cameraZ,
+ x + radius - cameraX, y + radius - cameraY, z + radius - cameraZ, color.x(), color.y(), color.z(), 1.0F);
+ }
+
private static T getField(Class> cl, Object obj, String name) {
try {
Field f = cl.getDeclaredField(name);
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/common/MixinDistanceManager.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/common/MixinDistanceManager.java
index 59eb7ec8d..5e4a21d58 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/common/MixinDistanceManager.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/common/MixinDistanceManager.java
@@ -1,5 +1,6 @@
package io.github.opencubicchunks.cubicchunks.mixin.debug.common;
+import io.github.opencubicchunks.cubicchunks.chunk.graph.CCTicketType;
import net.minecraft.server.level.DistanceManager;
import net.minecraft.server.level.Ticket;
import net.minecraft.server.level.TicketType;
@@ -17,7 +18,7 @@ private void cancelPlayerTickets(long position, Ticket> ticket, CallbackInfo c
if (!DEBUG_LOAD_ORDER_ENABLED) {
return;
}
- if (ticket.getType() == TicketType.PLAYER) {
+ if (ticket.getType() == TicketType.PLAYER || ticket.getType() == CCTicketType.CCPLAYER) {
ci.cancel();
}
}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/common/MixinMinecraftServer.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/common/MixinMinecraftServer.java
index 54a449eaf..7b8cd1a4c 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/common/MixinMinecraftServer.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/common/MixinMinecraftServer.java
@@ -91,11 +91,11 @@ private void prepareLevels(ChunkProgressListener worldGenerationProgressListener
this.waitUntilNextTick();
}
- try {
- Thread.sleep(10000);
- } catch (InterruptedException e) {
- int ignored = 0;
- }
+// try {
+// Thread.sleep(10000);
+// } catch (InterruptedException e) {
+// int ignored = 0;
+// }
this.nextTickTime = Util.getMillis() + 10L;
this.waitUntilNextTick();
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketHeightmap.java b/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketHeightmap.java
index 1771244e7..c5df2d33e 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketHeightmap.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketHeightmap.java
@@ -2,6 +2,9 @@
import java.util.Map;
+import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter;
+import io.github.opencubicchunks.cubicchunks.chunk.heightmap.ClientLightSurfaceTracker;
+import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.LongArrayTag;
import net.minecraft.network.FriendlyByteBuf;
@@ -33,6 +36,8 @@ public static PacketHeightmap forChunk(LevelChunk chunk) {
heightmaps.put(entry.getKey().getSerializationKey(), new LongArrayTag(entry.getValue().getRawData()));
}
}
+ LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap();
+ heightmaps.put("light", new LongArrayTag(lightHeightmap.getRawData()));
return new PacketHeightmap(chunk.getPos(), heightmaps);
}
@@ -57,6 +62,12 @@ public static void handle(PacketHeightmap packet, Level worldIn) {
long[] longArray = packet.heightmaps.getLongArray(value.getSerializationKey());
chunk.setHeightmap(value, longArray);
}
+ if (packet.heightmaps.contains("light")) {
+ // TODO is this safe on dedicated server?
+ long[] data = packet.heightmaps.getLongArray("light");
+ ClientLightSurfaceTracker heightmap = ((LightHeightmapGetter) chunk).getClientLightHeightmap();
+ heightmap.setRawData(data, chunk);
+ }
}
}
}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketHeightmapChanges.java b/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketHeightmapChanges.java
index 9a2f9e35c..cc21005d3 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketHeightmapChanges.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketHeightmapChanges.java
@@ -1,6 +1,7 @@
package io.github.opencubicchunks.cubicchunks.network;
import io.github.opencubicchunks.cubicchunks.CubicChunks;
+import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter;
import io.github.opencubicchunks.cubicchunks.mixin.access.common.HeightmapAccess;
import io.github.opencubicchunks.cubicchunks.utils.AddressTools;
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
@@ -26,8 +27,13 @@ public PacketHeightmapChanges(ChunkAccess chunk, ShortArrayList changed) {
for (int i = 0; i < this.positionsAndTypes.length; i++) {
int x = AddressTools.getLocalX(positionsAndTypes[i]);
int z = AddressTools.getLocalZ(positionsAndTypes[i]);
- Heightmap.Types type = Heightmap.Types.values()[AddressTools.getLocalY(positionsAndTypes[i])];
- heights[i] = chunk.getHeight(type, x + dx, z + dz) + 1;
+ int index = AddressTools.getLocalY(positionsAndTypes[i]);
+ if (index == 0xF) { // Light heightmap
+ heights[i] = ((LightHeightmapGetter) chunk).getLightHeightmap().getFirstAvailable(x, z);
+ } else { // Normal heightmaps
+ Heightmap.Types type = Heightmap.Types.values()[AddressTools.getLocalY(positionsAndTypes[i])];
+ heights[i] = chunk.getHeight(type, x + dx, z + dz) + 1;
+ }
}
}
@@ -61,8 +67,13 @@ public static void handle(PacketHeightmapChanges packet, Level worldIn) {
short posType = packet.positionsAndTypes[i];
int x = AddressTools.getLocalX(posType);
int z = AddressTools.getLocalZ(posType);
- Heightmap.Types type = Heightmap.Types.values()[AddressTools.getLocalY(posType)];
- ((HeightmapAccess) chunk.getOrCreateHeightmapUnprimed(type)).invokeSetHeight(x & 0xF, z & 0xF, packet.heights[i]);
+ int index = AddressTools.getLocalY(posType);
+ if (index == 0xF) {
+ ((HeightmapAccess) ((LightHeightmapGetter) chunk).getLightHeightmap()).invokeSetHeight(x & 0xF, z & 0xF, packet.heights[i]);
+ } else {
+ Heightmap.Types type = Heightmap.Types.values()[index];
+ ((HeightmapAccess) chunk.getOrCreateHeightmapUnprimed(type)).invokeSetHeight(x & 0xF, z & 0xF, packet.heights[i]);
+ }
}
}
}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketUpdateLight.java b/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketUpdateLight.java
index bc4b85b6d..71ad251a4 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketUpdateLight.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketUpdateLight.java
@@ -110,11 +110,7 @@ public static void handle(PacketUpdateLight packet, Level worldIn) {
Iterator blockIterator = packet.blockLightData.iterator();
for (int i = 0; i < IBigCube.SECTION_COUNT; ++i) {
- SectionPos sectionPos = SectionPos.of(
- packet.cubePos.getX() + Coords.indexToX(i),
- packet.cubePos.getY() + Coords.indexToY(i),
- packet.cubePos.getZ() + Coords.indexToZ(i)
- );
+ SectionPos sectionPos = Coords.sectionPosByIndex(packet.cubePos, i);
if (packet.dataExists.get(i * 2)) {
worldlightmanager.queueSectionData(LightLayer.SKY, sectionPos, new DataLayer(skyIterator.next()), packet.lightFlag);
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/server/IServerChunkProvider.java b/src/main/java/io/github/opencubicchunks/cubicchunks/server/IServerChunkProvider.java
index a32e4a0ff..c4fe8ff38 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/server/IServerChunkProvider.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/server/IServerChunkProvider.java
@@ -9,11 +9,12 @@
import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.TicketType;
-import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
public interface IServerChunkProvider extends ICubeProvider {
- ChunkHolder getChunkHolderForce(ChunkPos chunkPos, ChunkStatus requiredStatus);
+ // TODO check whether this is still needed
+ // ChunkHolder getChunkHolderForce(ChunkPos chunkPos, ChunkStatus requiredStatus);
void addCubeRegionTicket(TicketType type, CubePos pos, int distance, T value);
@@ -21,5 +22,9 @@ public interface IServerChunkProvider extends ICubeProvider {
void forceCube(CubePos pos, boolean add);
+ CompletableFuture> getColumnFutureForCube(CubePos cubePos, int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create);
+ // TODO check whether this is still needed
+ // boolean isEntityTickingCube(CubePos pos);
+
boolean checkCubeFuture(long cubePosLong, Function>> futureFunction);
}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/utils/Coords.java b/src/main/java/io/github/opencubicchunks/cubicchunks/utils/Coords.java
index 07ddd14bd..e6a53cfb0 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/utils/Coords.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/utils/Coords.java
@@ -32,6 +32,7 @@
import net.minecraft.core.SectionPos;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
+import net.minecraft.world.level.ChunkPos;
/**
* A class that contains helper-methods for many CubicChunks related things.
@@ -377,6 +378,16 @@ public static SectionPos sectionPosByIndex(CubePos cubePos, int i) {
indexToZ(i)));
}
+ /**
+ * @param cubePos The {@link CubePos}
+ * @param i The index of the {@link ChunkSection} inside the {@link CubePos}
+ *
+ * @return The {@link ChunkPos} of the column containing the {@link ChunkSection} at index i
+ */
+ public static ChunkPos chunkPosByIndex(CubePos cubePos, int i) {
+ return new ChunkPos(cubeToSection(cubePos.getX(), indexToX(i)), cubeToSection(cubePos.getZ(), indexToZ(i)));
+ }
+
public static int blockToCubeLocalSection(int x) {
return (x >> 4) & (IBigCube.DIAMETER_IN_SECTIONS - 1);
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ICubeLightProvider.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ICubeLightProvider.java
index 58601221d..2bd1ae4ed 100644
--- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ICubeLightProvider.java
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ICubeLightProvider.java
@@ -6,5 +6,6 @@
public interface ICubeLightProvider {
+ //TODO: FIX THIS NAME AHHHHHHHHHHHHH
@Nullable BlockGetter getCubeForLighting(int sectionX, int sectionY, int sectionZ);
}
\ No newline at end of file
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ICubicSkyLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ICubicSkyLightEngine.java
new file mode 100644
index 000000000..2bb44bd70
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ICubicSkyLightEngine.java
@@ -0,0 +1,7 @@
+package io.github.opencubicchunks.cubicchunks.world.lighting;
+
+import io.github.opencubicchunks.cubicchunks.chunk.IBigCube;
+
+public interface ICubicSkyLightEngine {
+ void doSkyLightForCube(IBigCube cube);
+}
diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ISkyLightColumnChecker.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ISkyLightColumnChecker.java
new file mode 100644
index 000000000..d8fb46d60
--- /dev/null
+++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ISkyLightColumnChecker.java
@@ -0,0 +1,8 @@
+package io.github.opencubicchunks.cubicchunks.world.lighting;
+
+import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter;
+
+public interface ISkyLightColumnChecker {
+ /** all parameters are global coordinates */
+ void checkSkyLightColumn(CubeMapGetter chunk, int x, int z, int oldHeight, int newHeight);
+}
diff --git a/src/main/resources/cubicchunks.accesswidener b/src/main/resources/cubicchunks.accesswidener
index a5fd3ba14..db3d7e2c0 100644
--- a/src/main/resources/cubicchunks.accesswidener
+++ b/src/main/resources/cubicchunks.accesswidener
@@ -10,5 +10,6 @@ accessible class net/minecraft/server/level/ThreadedLevelLightEngine$TaskType
accessible class net/minecraft/world/level/levelgen/VerticalAnchor$BelowTop
accessible class net/minecraft/world/level/levelgen/VerticalAnchor$AboveBottom
accessible class net/minecraft/world/level/levelgen/VerticalAnchor$Absolute
+accessible class net/minecraft/world/level/lighting/SkyLightSectionStorage$SkyDataLayerStorageMap
extendable class net/minecraft/server/level/Ticket
accessible method net/minecraft/server/level/ChunkMap$DistanceManager (Lnet/minecraft/server/level/ChunkMap;Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)V
diff --git a/src/main/resources/cubicchunks.mixins.access.json b/src/main/resources/cubicchunks.mixins.access.json
index cecb13f8f..c9f4e577e 100644
--- a/src/main/resources/cubicchunks.mixins.access.json
+++ b/src/main/resources/cubicchunks.mixins.access.json
@@ -21,6 +21,7 @@
"common.EntityTrackerAccess",
"common.HeightmapAccess",
"common.IOWorkerAccess",
+ "common.LayerLightSectionStorageAccess",
"common.LevelBasedGraphAccess",
"common.Matrix4fAccess",
"common.NaturalSpawnerAccess",
@@ -30,9 +31,9 @@
"common.PlayerTicketTrackerFactoryAccess",
"common.PoiSectionAccess",
"common.ProtoTickListAccess",
- "common.SectionLightStorageAccess",
"common.SpawnStateAccess",
"common.StructureFeatureManagerAccess",
+ "common.ThreadedLevelLightEngineAccess",
"common.TicketAccess",
"common.TicketManagerAccess",
"common.TicketTypeAccess",
diff --git a/src/main/resources/cubicchunks.mixins.core.json b/src/main/resources/cubicchunks.mixins.core.json
index adfadb490..47fd7c3ec 100644
--- a/src/main/resources/cubicchunks.mixins.core.json
+++ b/src/main/resources/cubicchunks.mixins.core.json
@@ -23,6 +23,7 @@
"common.chunk.MixinChunkSerializer",
"common.chunk.MixinChunkStatus",
"common.chunk.MixinDepthBasedReplacingBaseStoneSource",
+ "common.chunk.MixinImposterProtoChunk",
"common.chunk.MixinISelectiveWorker",
"common.chunk.MixinNoiseBasedChunkGenerator",
"common.chunk.MixinNoiseSampler",
@@ -61,9 +62,13 @@
"common.world.feature.nether.MixinTwistyVinesFeature",
"common.world.feature.range.MixinRandomPatchFeature",
"common.world.lighting.MixinBlockLightEngine",
- "common.world.lighting.MixinLightEngine",
- "common.world.lighting.MixinSectionLightStorage",
- "common.world.lighting.MixinWorldLightManager",
+ "common.world.lighting.MixinDynamicGraphMinFixedPoint",
+ "common.world.lighting.MixinLayerLightEngine",
+ "common.world.lighting.MixinLayerLightSectionStorage",
+ "common.world.lighting.MixinLevelLightEngine",
+ "common.world.lighting.MixinSkyLightEngine",
+ "common.world.lighting.MixinSkyLightSectionStorage",
+ "common.world.lighting.MixinThreadedLevelLightEngine",
"common.world.MixinAbstractChunkProvider",
"common.world.MixinConfiguredSurfaceBuilder",
"common.world.MixinFuzzyOffsetConstantColumnBiomeZoomer",
@@ -88,7 +93,6 @@
"common.world.placement.MixinVerticalDecorator",
"common.world.placement.verticalanchor.MixinVerticalAnchorAboveBottom",
"common.world.placement.verticalanchor.MixinVerticalAnchorBelowTop",
- "common.world.server.MixinServerWorldLightManager",
"common.world.structure.MixinConfiguredStructureFeature",
"common.world.structure.MixinLocateCommand",
"common.world.structure.MixinStructureFeature",
@@ -105,6 +109,7 @@
"client.chunk.MixinRenderChunkRegion",
"client.debug.MixinChunkBorderRenderer",
"client.debug.MixinClientWorld",
+ "client.debug.MixinDebugScreenOverlay",
"client.debug.MixinGameRenderer",
"client.debug.MixinMinecraft",
"client.debug.MixinMinecraftServer",