From a00dcd77722f469d3e520f3fe8a319d62674e309 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Tue, 8 Dec 2020 15:16:24 +1300 Subject: [PATCH 01/39] Begin to implement a skylight heightmap. Doesn't handle any client-side stuff yet. --- .../cubicchunks/chunk/IChunk.java | 7 + .../cubicchunks/chunk/cube/BigCube.java | 2 + .../heightmap/LightSurfaceTrackerSection.java | 122 +++++++++++++ .../heightmap/LightSurfaceTrackerWrapper.java | 10 ++ .../heightmap/SurfaceTrackerSection.java | 18 +- .../heightmap/SurfaceTrackerWrapper.java | 10 +- .../mixin/core/common/chunk/MixinChunk.java | 36 +++- .../resources/cubicchunks.mixins.core.json | 168 +++++++++--------- 8 files changed, 278 insertions(+), 95 deletions(-) create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunk.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerWrapper.java diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunk.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunk.java new file mode 100644 index 000000000..b65e3e13f --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunk.java @@ -0,0 +1,7 @@ +package io.github.opencubicchunks.cubicchunks.chunk; + +import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper; + +public interface IChunk { + LightSurfaceTrackerWrapper getLightHeightmap(); +} 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 f7930bba7..b8805a3c3 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,6 +20,7 @@ import com.google.common.collect.Sets; import io.github.opencubicchunks.cubicchunks.CubicChunks; import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; +import io.github.opencubicchunks.cubicchunks.chunk.IChunk; import io.github.opencubicchunks.cubicchunks.chunk.biome.CubeBiomeContainer; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerSection; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerWrapper; @@ -886,6 +887,7 @@ public void postLoad() { SurfaceTrackerWrapper tracker = (SurfaceTrackerWrapper) heightmap; tracker.loadCube(this); } + ((IChunk) chunk).getLightHeightmap().loadCube(this); } } } 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..f42b148c1 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java @@ -0,0 +1,122 @@ +package io.github.opencubicchunks.cubicchunks.chunk.heightmap; + +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; + +import javax.annotation.Nullable; + +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 IllegalArgumentException("TODO put an actual error message here - also this probably shouldn't be an IllegalArgumentException"); + } + 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; + } + } + + 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..eb0343acb --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerWrapper.java @@ -0,0 +1,10 @@ +package io.github.opencubicchunks.cubicchunks.chunk.heightmap; + +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()); + } +} 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 3b520c404..918e8b42a 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 @@ -29,15 +29,15 @@ public class SurfaceTrackerSection { // Use width of 16 to match columns. private static final int WIDTH_BLOCKS = 16; - private final BitStorage heights; + protected 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 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) { @@ -100,7 +100,7 @@ public int getHeight(int x, int z) { } } - private void clearDirty(int idx) { + protected void clearDirty(int idx) { dirtyPositions[idx >> 6] &= ~(1L << idx); } @@ -108,7 +108,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; } @@ -210,7 +210,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; @@ -221,7 +221,7 @@ 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) { + 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 df6072083..087118a88 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,7 +10,7 @@ import net.minecraft.world.level.levelgen.Heightmap; public class SurfaceTrackerWrapper extends Heightmap { - private final SurfaceTrackerSection surfaceTracker; + protected final SurfaceTrackerSection surfaceTracker; private final int dx; private final int dz; @@ -22,6 +22,14 @@ 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); + } + @Override public boolean update(int x, int y, int z, BlockState blockState) { // TODO do we need to do anything else here? 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 271e5ff07..5b484b702 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 @@ -7,16 +7,20 @@ import javax.annotation.Nullable; import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; +import io.github.opencubicchunks.cubicchunks.chunk.IChunk; import io.github.opencubicchunks.cubicchunks.chunk.ICubeProvider; 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.ClientSurfaceTracker; +import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerSection; +import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerWrapper; import io.github.opencubicchunks.cubicchunks.utils.Coords; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.TickList; @@ -28,6 +32,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; @@ -40,9 +45,10 @@ 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(LevelChunk.class) -public abstract class MixinChunk implements ChunkAccess { +public abstract class MixinChunk implements ChunkAccess, IChunk { @Shadow @Final private Level level; @Shadow @Final private ChunkPos chunkPos; @@ -57,6 +63,13 @@ public abstract class MixinChunk implements ChunkAccess { return false; } + private LightSurfaceTrackerWrapper lightHeightmap; + + @Override + public LightSurfaceTrackerWrapper getLightHeightmap() { + return lightHeightmap; + } + @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;" @@ -69,6 +82,27 @@ 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); } + + lightHeightmap = new LightSurfaceTrackerWrapper(this); + } + + @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) { + lightHeightmap = new LightSurfaceTrackerWrapper(this); + } + + @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/chunk/LevelChunkSection;isEmpty()Z") + ) + private void onSetBlock(BlockPos pos, BlockState state, boolean moved, CallbackInfoReturnable cir) { + // TODO client side light heightmap stuff + if (!this.level.isClientSide) { + ((IChunk) this).getLightHeightmap().update(pos.getX() & 15, pos.getY(), pos.getZ() & 15, state); + } } @Redirect( diff --git a/src/main/resources/cubicchunks.mixins.core.json b/src/main/resources/cubicchunks.mixins.core.json index cd4760f49..6de710928 100644 --- a/src/main/resources/cubicchunks.mixins.core.json +++ b/src/main/resources/cubicchunks.mixins.core.json @@ -1,86 +1,86 @@ { - "required": true, - "package": "io.github.opencubicchunks.cubicchunks.mixin.core", - "refmap": "CubicChunks-refmap.json", - "compatibilityLevel": "JAVA_8", - "minVersion": "0.8", - "injectors": { - "defaultRequire": 1 - }, - "overwrites": { - "conformVisibility": true - }, - "mixins": [ - "common.MixinBlockPos", - "common.MixinMinecraftServer", - "common.MixinServerChunkProvider", - "common.chunk.MixinChunk", - "common.chunk.MixinChunkGenerator", - "common.chunk.MixinChunkHolder", - "common.chunk.MixinChunkHolderListener", - "common.chunk.MixinChunkManager", - "common.chunk.MixinChunkSerializer", - "common.chunk.MixinChunkStatus", - "common.chunk.MixinISelectiveWorker", - "common.chunk.MixinProtoChunk", - "common.chunk.MixinProtoTickList", - "common.entity.MixinBoatEntity", - "common.entity.MixinServerPlayerEntity", - "common.network.MixinClientboundLevelChunkPacket", - "common.progress.MixinLoggingChunkStatusListener", - "common.ticket.MixinProxyTicketManager", - "common.ticket.MixinTicketManager", - "common.tileentity.MixinBeaconTileEntity", - "common.tileentity.MixinConduitTileEntity", - "common.world.MixinAbstractChunkProvider", - "common.world.MixinFuzzyOffsetConstantColumnBiomeZoomer", - "common.world.MixinIWorldReader", - "common.world.MixinLevelHeightAccessor", - "common.world.MixinNaturalSpawner", - "common.world.MixinServerWorld", - "common.world.MixinSpawnLocationHelper", - "common.world.MixinWorld", - "common.world.biome.MixinBiome", - "common.world.biome.MixinBiomeDefaultFeatures", - "common.world.feature.MixinBlockBlobFeature", - "common.world.feature.MixinIcebergFeature", - "common.world.feature.MixinLakeFeature", - "common.world.feature.MixinOreFeature", - "common.world.feature.MixinSpringFeature", - "common.world.feature.MixinVineFeature", - "common.world.lighting.MixinBlockLightEngine", - "common.world.lighting.MixinLightEngine", - "common.world.lighting.MixinSectionLightStorage", - "common.world.lighting.MixinWorldLightManager", - "common.world.placement.MixinDarkOakTreePlacementDecorator", - "common.world.placement.MixinDepthAverageDecorator", - "common.world.placement.MixinEmeraldPlacementDecorator", - "common.world.placement.MixinFireDecorator", - "common.world.placement.MixinHeightMapDoubleDecorator", - "common.world.placement.MixinRangeDecorator", - "common.world.placement.MixinSimpleFeatureDecorator", - "common.world.placement.MixinSpread32Decorator", - "common.world.server.MixinServerWorldLightManager", - "common.world.structure.MixinStructureFeature", - "common.world.structure.MixinStructureFeatureManager", - "common.world.structure.MixinStructurePiece", - "common.world.structure.MixinStructureStart", - "common.world.structure.pieces.MixinOceanRuinPieces" - ], - "client": [ - "client.MixinClientPacketListener", - "client.MixinDebugOverlayGui", - "client.MixinRenderChunk", - "client.MixinViewFrustum", - "client.debug.MixinClientWorld", - "client.debug.MixinGameRenderer", - "client.debug.MixinMinecraft", - "client.debug.MixinMinecraftServer", - "client.progress.MixinChainedChunkStatusListener", - "client.progress.MixinTrackingChunkStatusListener", - "client.progress.MixinWorldLoadProgressScreen", - "client.world.MixinClientChunkProvider", - "client.world.MixinClientWorld" - ], - "server": [] + "required": true, + "package": "io.github.opencubicchunks.cubicchunks.mixin.core", + "refmap": "CubicChunks-refmap.json", + "compatibilityLevel": "JAVA_8", + "minVersion": "0.8", + "injectors": { + "defaultRequire": 1 + }, + "overwrites": { + "conformVisibility": true + }, + "mixins": [ + "common.MixinBlockPos", + "common.MixinMinecraftServer", + "common.MixinServerChunkProvider", + "common.chunk.MixinChunk", + "common.chunk.MixinChunkGenerator", + "common.chunk.MixinChunkHolder", + "common.chunk.MixinChunkHolderListener", + "common.chunk.MixinChunkManager", + "common.chunk.MixinChunkSerializer", + "common.chunk.MixinChunkStatus", + "common.chunk.MixinISelectiveWorker", + "common.chunk.MixinProtoChunk", + "common.chunk.MixinProtoTickList", + "common.entity.MixinBoatEntity", + "common.entity.MixinServerPlayerEntity", + "common.network.MixinClientboundLevelChunkPacket", + "common.progress.MixinLoggingChunkStatusListener", + "common.ticket.MixinProxyTicketManager", + "common.ticket.MixinTicketManager", + "common.tileentity.MixinBeaconTileEntity", + "common.tileentity.MixinConduitTileEntity", + "common.world.MixinAbstractChunkProvider", + "common.world.MixinFuzzyOffsetConstantColumnBiomeZoomer", + "common.world.MixinIWorldReader", + "common.world.MixinLevelHeightAccessor", + "common.world.MixinNaturalSpawner", + "common.world.MixinServerWorld", + "common.world.MixinSpawnLocationHelper", + "common.world.MixinWorld", + "common.world.biome.MixinBiome", + "common.world.biome.MixinBiomeDefaultFeatures", + "common.world.feature.MixinBlockBlobFeature", + "common.world.feature.MixinIcebergFeature", + "common.world.feature.MixinLakeFeature", + "common.world.feature.MixinOreFeature", + "common.world.feature.MixinSpringFeature", + "common.world.feature.MixinVineFeature", + "common.world.lighting.MixinBlockLightEngine", + "common.world.lighting.MixinLightEngine", + "common.world.lighting.MixinSectionLightStorage", + "common.world.lighting.MixinWorldLightManager", + "common.world.placement.MixinDarkOakTreePlacementDecorator", + "common.world.placement.MixinDepthAverageDecorator", + "common.world.placement.MixinEmeraldPlacementDecorator", + "common.world.placement.MixinFireDecorator", + "common.world.placement.MixinHeightMapDoubleDecorator", + "common.world.placement.MixinRangeDecorator", + "common.world.placement.MixinSimpleFeatureDecorator", + "common.world.placement.MixinSpread32Decorator", + "common.world.server.MixinServerWorldLightManager", + "common.world.structure.MixinStructureFeature", + "common.world.structure.MixinStructureFeatureManager", + "common.world.structure.MixinStructurePiece", + "common.world.structure.MixinStructureStart", + "common.world.structure.pieces.MixinOceanRuinPieces" + ], + "client": [ + "client.MixinClientPacketListener", + "client.MixinDebugOverlayGui", + "client.MixinRenderChunk", + "client.MixinViewFrustum", + "client.debug.MixinClientWorld", + "client.debug.MixinGameRenderer", + "client.debug.MixinMinecraft", + "client.debug.MixinMinecraftServer", + "client.progress.MixinChainedChunkStatusListener", + "client.progress.MixinTrackingChunkStatusListener", + "client.progress.MixinWorldLoadProgressScreen", + "client.world.MixinClientChunkProvider", + "client.world.MixinClientWorld" + ], + "server": [] } \ No newline at end of file From fcec43a8224bfd6c797556c362f8970b5f358a7a Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Thu, 10 Dec 2020 12:28:01 +1300 Subject: [PATCH 02/39] misc cleanup, and make light heightmap update mark neighboring section as dirty when necessary --- ...{IChunk.java => LightHeightmapGetter.java} | 4 +- .../cubicchunks/chunk/cube/BigCube.java | 4 +- .../heightmap/LightSurfaceTrackerSection.java | 213 +++++++++--------- .../heightmap/LightSurfaceTrackerWrapper.java | 32 ++- .../heightmap/SurfaceTrackerWrapper.java | 4 +- .../mixin/core/common/chunk/MixinChunk.java | 7 +- .../resources/cubicchunks.mixins.core.json | 168 +++++++------- 7 files changed, 228 insertions(+), 204 deletions(-) rename src/main/java/io/github/opencubicchunks/cubicchunks/chunk/{IChunk.java => LightHeightmapGetter.java} (61%) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunk.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java similarity index 61% rename from src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunk.java rename to src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java index b65e3e13f..4eb250788 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunk.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java @@ -2,6 +2,6 @@ import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper; -public interface IChunk { - LightSurfaceTrackerWrapper getLightHeightmap(); +public interface LightHeightmapGetter { + LightSurfaceTrackerWrapper getLightHeightmap(); } 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 b8805a3c3..2d8efaffb 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,7 +20,7 @@ import com.google.common.collect.Sets; import io.github.opencubicchunks.cubicchunks.CubicChunks; import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; -import io.github.opencubicchunks.cubicchunks.chunk.IChunk; +import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; import io.github.opencubicchunks.cubicchunks.chunk.biome.CubeBiomeContainer; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerSection; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerWrapper; @@ -887,7 +887,7 @@ public void postLoad() { SurfaceTrackerWrapper tracker = (SurfaceTrackerWrapper) heightmap; tracker.loadCube(this); } - ((IChunk) chunk).getLightHeightmap().loadCube(this); + ((LightHeightmapGetter) chunk).getLightHeightmap().loadCube(this); } } } 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 index f42b148c1..ce8754864 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java @@ -13,110 +13,111 @@ import javax.annotation.Nullable; 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 IllegalArgumentException("TODO put an actual error message here - also this probably shouldn't be an IllegalArgumentException"); - } - 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; - } - } - - protected VoxelShape getShape(BlockState blockState, BlockPos pos, Direction facing) { - return blockState.canOcclude() && blockState.useShapeForLightOcclusion() ? blockState.getFaceOcclusionShape((IBigCube) this.cubeOrNodes, pos, facing) : Shapes.empty(); - } + 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 IllegalArgumentException("TODO put an actual error message here - also this probably shouldn't be an IllegalArgumentException"); + } + // 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; + } + } + + 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 index eb0343acb..14a7b3a2d 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerWrapper.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerWrapper.java @@ -1,10 +1,34 @@ 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()); - } + 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 + dx, z + dz); + } + } else if (relY == IBigCube.DIAMETER_IN_BLOCKS - 1) { + SurfaceTrackerSection section = surfaceTracker.getCubeNode(blockToCube(y + 1)); + if (section != null) { + section.markDirty(x + dx, z + dz); + } + } + + return false; + } } 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 087118a88..b40d2c1b5 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 @@ -11,8 +11,8 @@ public class SurfaceTrackerWrapper extends Heightmap { protected final SurfaceTrackerSection surfaceTracker; - private final int dx; - private final int dz; + protected final int dx; + protected final int dz; public SurfaceTrackerWrapper(ChunkAccess chunkAccess, Types types) { super(chunkAccess, types); 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 5b484b702..8525cfa50 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 @@ -7,13 +7,12 @@ import javax.annotation.Nullable; import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; -import io.github.opencubicchunks.cubicchunks.chunk.IChunk; +import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; import io.github.opencubicchunks.cubicchunks.chunk.ICubeProvider; 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.ClientSurfaceTracker; -import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerSection; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerWrapper; import io.github.opencubicchunks.cubicchunks.utils.Coords; @@ -48,7 +47,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(LevelChunk.class) -public abstract class MixinChunk implements ChunkAccess, IChunk { +public abstract class MixinChunk implements ChunkAccess, LightHeightmapGetter { @Shadow @Final private Level level; @Shadow @Final private ChunkPos chunkPos; @@ -101,7 +100,7 @@ private void onInitFromProtoChunk(ServerLevel serverLevel, ProtoChunk protoChunk private void onSetBlock(BlockPos pos, BlockState state, boolean moved, CallbackInfoReturnable cir) { // TODO client side light heightmap stuff if (!this.level.isClientSide) { - ((IChunk) this).getLightHeightmap().update(pos.getX() & 15, pos.getY(), pos.getZ() & 15, state); + ((LightHeightmapGetter) this).getLightHeightmap().update(pos.getX() & 15, pos.getY(), pos.getZ() & 15, state); } } diff --git a/src/main/resources/cubicchunks.mixins.core.json b/src/main/resources/cubicchunks.mixins.core.json index 6de710928..7c3d107ba 100644 --- a/src/main/resources/cubicchunks.mixins.core.json +++ b/src/main/resources/cubicchunks.mixins.core.json @@ -1,86 +1,86 @@ { - "required": true, - "package": "io.github.opencubicchunks.cubicchunks.mixin.core", - "refmap": "CubicChunks-refmap.json", - "compatibilityLevel": "JAVA_8", - "minVersion": "0.8", - "injectors": { - "defaultRequire": 1 - }, - "overwrites": { - "conformVisibility": true - }, - "mixins": [ - "common.MixinBlockPos", - "common.MixinMinecraftServer", - "common.MixinServerChunkProvider", - "common.chunk.MixinChunk", - "common.chunk.MixinChunkGenerator", - "common.chunk.MixinChunkHolder", - "common.chunk.MixinChunkHolderListener", - "common.chunk.MixinChunkManager", - "common.chunk.MixinChunkSerializer", - "common.chunk.MixinChunkStatus", - "common.chunk.MixinISelectiveWorker", - "common.chunk.MixinProtoChunk", - "common.chunk.MixinProtoTickList", - "common.entity.MixinBoatEntity", - "common.entity.MixinServerPlayerEntity", - "common.network.MixinClientboundLevelChunkPacket", - "common.progress.MixinLoggingChunkStatusListener", - "common.ticket.MixinProxyTicketManager", - "common.ticket.MixinTicketManager", - "common.tileentity.MixinBeaconTileEntity", - "common.tileentity.MixinConduitTileEntity", - "common.world.MixinAbstractChunkProvider", - "common.world.MixinFuzzyOffsetConstantColumnBiomeZoomer", - "common.world.MixinIWorldReader", - "common.world.MixinLevelHeightAccessor", - "common.world.MixinNaturalSpawner", - "common.world.MixinServerWorld", - "common.world.MixinSpawnLocationHelper", - "common.world.MixinWorld", - "common.world.biome.MixinBiome", - "common.world.biome.MixinBiomeDefaultFeatures", - "common.world.feature.MixinBlockBlobFeature", - "common.world.feature.MixinIcebergFeature", - "common.world.feature.MixinLakeFeature", - "common.world.feature.MixinOreFeature", - "common.world.feature.MixinSpringFeature", - "common.world.feature.MixinVineFeature", - "common.world.lighting.MixinBlockLightEngine", - "common.world.lighting.MixinLightEngine", - "common.world.lighting.MixinSectionLightStorage", - "common.world.lighting.MixinWorldLightManager", - "common.world.placement.MixinDarkOakTreePlacementDecorator", - "common.world.placement.MixinDepthAverageDecorator", - "common.world.placement.MixinEmeraldPlacementDecorator", - "common.world.placement.MixinFireDecorator", - "common.world.placement.MixinHeightMapDoubleDecorator", - "common.world.placement.MixinRangeDecorator", - "common.world.placement.MixinSimpleFeatureDecorator", - "common.world.placement.MixinSpread32Decorator", - "common.world.server.MixinServerWorldLightManager", - "common.world.structure.MixinStructureFeature", - "common.world.structure.MixinStructureFeatureManager", - "common.world.structure.MixinStructurePiece", - "common.world.structure.MixinStructureStart", - "common.world.structure.pieces.MixinOceanRuinPieces" - ], - "client": [ - "client.MixinClientPacketListener", - "client.MixinDebugOverlayGui", - "client.MixinRenderChunk", - "client.MixinViewFrustum", - "client.debug.MixinClientWorld", - "client.debug.MixinGameRenderer", - "client.debug.MixinMinecraft", - "client.debug.MixinMinecraftServer", - "client.progress.MixinChainedChunkStatusListener", - "client.progress.MixinTrackingChunkStatusListener", - "client.progress.MixinWorldLoadProgressScreen", - "client.world.MixinClientChunkProvider", - "client.world.MixinClientWorld" - ], - "server": [] + "required": true, + "package": "io.github.opencubicchunks.cubicchunks.mixin.core", + "refmap": "CubicChunks-refmap.json", + "compatibilityLevel": "JAVA_8", + "minVersion": "0.8", + "injectors": { + "defaultRequire": 1 + }, + "overwrites": { + "conformVisibility": true + }, + "mixins": [ + "common.chunk.MixinChunk", + "common.chunk.MixinChunkGenerator", + "common.chunk.MixinChunkHolder", + "common.chunk.MixinChunkHolderListener", + "common.chunk.MixinChunkManager", + "common.chunk.MixinChunkSerializer", + "common.chunk.MixinChunkStatus", + "common.chunk.MixinISelectiveWorker", + "common.chunk.MixinProtoChunk", + "common.chunk.MixinProtoTickList", + "common.entity.MixinBoatEntity", + "common.entity.MixinServerPlayerEntity", + "common.MixinBlockPos", + "common.MixinMinecraftServer", + "common.MixinServerChunkProvider", + "common.network.MixinClientboundLevelChunkPacket", + "common.progress.MixinLoggingChunkStatusListener", + "common.ticket.MixinProxyTicketManager", + "common.ticket.MixinTicketManager", + "common.tileentity.MixinBeaconTileEntity", + "common.tileentity.MixinConduitTileEntity", + "common.world.biome.MixinBiome", + "common.world.biome.MixinBiomeDefaultFeatures", + "common.world.feature.MixinBlockBlobFeature", + "common.world.feature.MixinIcebergFeature", + "common.world.feature.MixinLakeFeature", + "common.world.feature.MixinOreFeature", + "common.world.feature.MixinSpringFeature", + "common.world.feature.MixinVineFeature", + "common.world.lighting.MixinBlockLightEngine", + "common.world.lighting.MixinLightEngine", + "common.world.lighting.MixinSectionLightStorage", + "common.world.lighting.MixinWorldLightManager", + "common.world.MixinAbstractChunkProvider", + "common.world.MixinFuzzyOffsetConstantColumnBiomeZoomer", + "common.world.MixinIWorldReader", + "common.world.MixinLevelHeightAccessor", + "common.world.MixinNaturalSpawner", + "common.world.MixinServerWorld", + "common.world.MixinSpawnLocationHelper", + "common.world.MixinWorld", + "common.world.placement.MixinDarkOakTreePlacementDecorator", + "common.world.placement.MixinDepthAverageDecorator", + "common.world.placement.MixinEmeraldPlacementDecorator", + "common.world.placement.MixinFireDecorator", + "common.world.placement.MixinHeightMapDoubleDecorator", + "common.world.placement.MixinRangeDecorator", + "common.world.placement.MixinSimpleFeatureDecorator", + "common.world.placement.MixinSpread32Decorator", + "common.world.server.MixinServerWorldLightManager", + "common.world.structure.MixinStructureFeature", + "common.world.structure.MixinStructureFeatureManager", + "common.world.structure.MixinStructurePiece", + "common.world.structure.MixinStructureStart", + "common.world.structure.pieces.MixinOceanRuinPieces" + ], + "client": [ + "client.debug.MixinClientWorld", + "client.debug.MixinGameRenderer", + "client.debug.MixinMinecraft", + "client.debug.MixinMinecraftServer", + "client.MixinClientPacketListener", + "client.MixinDebugOverlayGui", + "client.MixinRenderChunk", + "client.MixinViewFrustum", + "client.progress.MixinChainedChunkStatusListener", + "client.progress.MixinTrackingChunkStatusListener", + "client.progress.MixinWorldLoadProgressScreen", + "client.world.MixinClientChunkProvider", + "client.world.MixinClientWorld" + ], + "server": [] } \ No newline at end of file From 753cbf79430085fe0d97d43020eeca8e305a0240 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Sat, 12 Dec 2020 15:37:31 +1300 Subject: [PATCH 03/39] create and update light heightmap during worldgen. Currently awful for performance; needs optimization --- .../cubicchunks/chunk/cube/BigCube.java | 1 + .../cubicchunks/chunk/cube/CubePrimer.java | 40 ++++++++++++++++++- .../heightmap/LightSurfaceTrackerWrapper.java | 4 +- .../mixin/core/common/chunk/MixinChunk.java | 6 ++- .../core/common/chunk/MixinProtoChunk.java | 28 ++++++++++++- 5 files changed, 72 insertions(+), 7 deletions(-) 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 2d8efaffb..7786e4af1 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 @@ -887,6 +887,7 @@ public void postLoad() { SurfaceTrackerWrapper tracker = (SurfaceTrackerWrapper) heightmap; tracker.loadCube(this); } + // TODO probably don't want to do this if the cube was already loaded as a CubePrimer ((LightHeightmapGetter) chunk).getLightHeightmap().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 1bdb3e62c..93d64c023 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 @@ -17,10 +17,13 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; +import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; import io.github.opencubicchunks.cubicchunks.chunk.biome.CubeBiomeContainer; +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.utils.Coords; +import io.github.opencubicchunks.cubicchunks.world.CubeWorldGenRegion; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; @@ -31,7 +34,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.TickList; @@ -41,6 +46,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.ProtoTickList; @@ -88,6 +94,8 @@ public class CubePrimer implements IBigCube, ChunkAccess { private long inhabitedTime; + private boolean[] lightHeightmapLoaded; + public CubePrimer(CubePos cubePos, UpgradeData upgradeData, LevelHeightAccessor levelHeightAccessor) { // this(cubePos, upgradeData, (ChunkSection[])null, new ChunkPrimerTickList<>((p_205332_0_) -> { // return p_205332_0_ == null || p_205332_0_.defaultBlockState().isAir(); @@ -121,6 +129,8 @@ public CubePrimer(CubePos cubePosIn, UpgradeData p_i49941_2_, @Nullable LevelChu throw new IllegalStateException("Number of Sections must equal BigCube.CUBESIZE"); } } + + this.lightHeightmapLoaded = new boolean[IBigCube.CHUNK_COUNT]; } @Deprecated @Override public ChunkPos getPos() { @@ -182,7 +192,35 @@ public CubePrimer(CubePos cubePosIn, UpgradeData p_i49941_2_, @Nullable LevelChu LevelChunkSection chunksection = this.sections[index]; BlockState blockstate = chunksection.setBlockState(x, y, z, state, false); if (this.status.isOrAfter(ChunkStatus.FEATURES) && state != blockstate && (state.getLightBlock(this, pos) != blockstate.getLightBlock(this, pos) - || state.getLightEmission() != blockstate.getLightEmission() || state.useShapeForLightOcclusion() || blockstate.useShapeForLightOcclusion())) { + || state.getLightEmission() != blockstate.getLightEmission() || state.useShapeForLightOcclusion() || blockstate.useShapeForLightOcclusion())) { + ChunkSource chunkSource; + if (this.levelHeightAccessor instanceof CubeWorldGenRegion) { + chunkSource = ((CubeWorldGenRegion) this.levelHeightAccessor).getChunkSource(); + } else { + chunkSource = ((ServerLevel) this.levelHeightAccessor).getChunkSource(); + } + + ChunkPos chunkPos = this.cubePos.asChunkPos(); + for (int dx = 0; dx < IBigCube.DIAMETER_IN_SECTIONS; dx++) { + for (int dz = 0; dz < IBigCube.DIAMETER_IN_SECTIONS; dz++) { + // TODO this can return null, leading to incorrect light heightmap values -> incorrect sky lighting on worldgen. + // not really feasible to fix until we get a "columns before cubes" invariant. + BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x + dx, chunkPos.z + dz); + if (chunk instanceof LightHeightmapGetter) { + LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); + if (lightHeightmap != null) { + // TODO this stuff is awful for performance; need to optimize it + // probably want to do the thing we do for other scale0 sections and store a reference to it + if (!lightHeightmapLoaded[dx + dz * IBigCube.DIAMETER_IN_SECTIONS]) { + lightHeightmapLoaded[dx + dz * IBigCube.DIAMETER_IN_SECTIONS] = true; + lightHeightmap.loadCube(this); + } + // 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(x, pos.getY(), z, state); + } + } + } + } lightManager.checkBlock(pos); } 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 index 14a7b3a2d..23c80a0d3 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerWrapper.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerWrapper.java @@ -20,12 +20,12 @@ public boolean update(int x, int y, int z, BlockState blockState) { if (relY == 0) { SurfaceTrackerSection section = surfaceTracker.getCubeNode(blockToCube(y - 1)); if (section != null) { - section.markDirty(x + dx, z + dz); + 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 + dx, z + dz); + section.markDirty(x, z); } } 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 8525cfa50..e161dcbe6 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 @@ -90,16 +90,18 @@ private void onInit(Level levelIn, ChunkPos pos, ChunkBiomeContainer chunkBiomeC at = @At("RETURN") ) private void onInitFromProtoChunk(ServerLevel serverLevel, ProtoChunk protoChunk, Consumer consumer, CallbackInfo ci) { - lightHeightmap = new LightSurfaceTrackerWrapper(this); + lightHeightmap = ((LightHeightmapGetter) protoChunk).getLightHeightmap(); } @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/chunk/LevelChunkSection;isEmpty()Z") + 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) { // TODO client side light heightmap stuff if (!this.level.isClientSide) { + // 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. ((LightHeightmapGetter) this).getLightHeightmap().update(pos.getX() & 15, pos.getY(), pos.getZ() & 15, state); } } 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 0606c96c1..0bfe32b68 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,16 +1,29 @@ package io.github.opencubicchunks.cubicchunks.mixin.core.common.chunk; +import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; +import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper; import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ProtoChunk; 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; @Mixin(ProtoChunk.class) -public abstract class MixinProtoChunk { - @Shadow public abstract ChunkStatus getStatus(); +public abstract class MixinProtoChunk implements LightHeightmapGetter { + @Shadow + public abstract ChunkStatus getStatus(); + + private LightSurfaceTrackerWrapper lightHeightmap; + + @Override + public LightSurfaceTrackerWrapper getLightHeightmap() { + return lightHeightmap; + } @Redirect( method = "(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/chunk/UpgradeData;[Lnet/minecraft/world/level/chunk/LevelChunkSection;" @@ -19,4 +32,15 @@ public abstract class MixinProtoChunk { private int getFakeSectionCount(LevelHeightAccessor accessor) { return 16; // TODO: properly handle ProtoChunk } + + @Inject( + method = "setStatus(Lnet/minecraft/world/level/chunk/ChunkStatus;)V", + at = @At("RETURN") + ) + private void onSetStatus(ChunkStatus status, CallbackInfo ci) { + 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); + } + } } From ae6d2386b70695b92c496f6d17b576643fd1529a Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Tue, 29 Dec 2020 17:49:00 +1300 Subject: [PATCH 04/39] disable vanilla skylight source handling --- .../lighting/MixinSkyLightSectionStorage.java | 27 +++++++++++++++++++ .../resources/cubicchunks.mixins.core.json | 1 + 2 files changed, 28 insertions(+) create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightSectionStorage.java 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..c8f37f98e --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightSectionStorage.java @@ -0,0 +1,27 @@ +package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting; + +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.chunk.LightChunkGetter; +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; + +@Mixin(SkyLightSectionStorage.class) +public abstract class MixinSkyLightSectionStorage extends LayerLightSectionStorage { + private MixinSkyLightSectionStorage(LightLayer lightLayer, LightChunkGetter lightChunkGetter, + SkyLightSectionStorage.SkyDataLayerStorageMap dataLayerStorageMap) { + super(lightLayer, lightChunkGetter, dataLayerStorageMap); + } + + @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 (enabled) { + // We handle skylight emission differently anyway, so we don't need vanilla's sky light source system + ci.cancel(); + } + } +} diff --git a/src/main/resources/cubicchunks.mixins.core.json b/src/main/resources/cubicchunks.mixins.core.json index 7c3d107ba..79a5a1a3b 100644 --- a/src/main/resources/cubicchunks.mixins.core.json +++ b/src/main/resources/cubicchunks.mixins.core.json @@ -43,6 +43,7 @@ "common.world.lighting.MixinBlockLightEngine", "common.world.lighting.MixinLightEngine", "common.world.lighting.MixinSectionLightStorage", + "common.world.lighting.MixinSkyLightSectionStorage", "common.world.lighting.MixinWorldLightManager", "common.world.MixinAbstractChunkProvider", "common.world.MixinFuzzyOffsetConstantColumnBiomeZoomer", From af43403bbae497d9a294b57c2f587f1947c69155 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Tue, 12 Jan 2021 09:10:57 +1300 Subject: [PATCH 05/39] begin implementing server-side sky light --- .../common/SectionLightStorageAccess.java | 3 + .../mixin/core/common/chunk/MixinChunk.java | 13 ++- .../world/lighting/MixinBlockLightEngine.java | 2 +- .../MixinDynamicGraphMinFixedPoint.java | 11 ++ ...anager.java => MixinLevelLightEngine.java} | 16 ++- .../world/lighting/MixinLightEngine.java | 4 +- .../world/lighting/MixinSkyLightEngine.java | 107 ++++++++++++++++++ .../MixinThreadedLevelLightEngine.java} | 17 ++- .../world/lighting/ICubicSkyLightEngine.java | 7 ++ .../lighting/ISkyLightColumnChecker.java | 5 + .../resources/cubicchunks.mixins.core.json | 8 +- 11 files changed, 183 insertions(+), 10 deletions(-) create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinDynamicGraphMinFixedPoint.java rename src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/{MixinWorldLightManager.java => MixinLevelLightEngine.java} (73%) create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightEngine.java rename src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/{server/MixinServerWorldLightManager.java => lighting/MixinThreadedLevelLightEngine.java} (89%) create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ICubicSkyLightEngine.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ISkyLightColumnChecker.java 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/SectionLightStorageAccess.java index c9e10aa4c..794306e9e 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/SectionLightStorageAccess.java @@ -9,4 +9,7 @@ public interface SectionLightStorageAccess { @Invoker("enableLightSources") void invokeSetColumnEnabled(long seed, boolean enable); + @Invoker boolean invokeStoringLightForSection(long sectionPos); + + @Invoker void invokeRunAllUpdates(); } \ No newline at end of file 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 e161dcbe6..69c1b07aa 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 @@ -7,8 +7,8 @@ import javax.annotation.Nullable; import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; -import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; 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; @@ -16,6 +16,7 @@ import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerWrapper; 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.nbt.CompoundTag; @@ -100,9 +101,17 @@ private void onInitFromProtoChunk(ServerLevel serverLevel, ProtoChunk protoChunk private void onSetBlock(BlockPos pos, BlockState state, boolean moved, CallbackInfoReturnable cir) { // TODO client side light heightmap stuff if (!this.level.isClientSide) { + int relX = pos.getX() & 15; + int relZ = pos.getZ() & 15; + LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) this).getLightHeightmap(); + int oldHeight = lightHeightmap.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. - ((LightHeightmapGetter) this).getLightHeightmap().update(pos.getX() & 15, pos.getY(), pos.getZ() & 15, state); + lightHeightmap.update(relX, pos.getY(), relZ, state); + int newHeight = lightHeightmap.getFirstAvailable(relX, relZ); + if (newHeight != oldHeight) { + ((ISkyLightColumnChecker) this.level.getChunkSource().getLightEngine()).checkSkyLightColumn(pos.getX(), pos.getZ(), oldHeight, newHeight); + } } } 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 f0769cf2d..cafb98121 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 @@ -10,7 +10,7 @@ import org.spongepowered.asm.mixin.Overwrite; @Mixin(BlockLightEngine.class) -public class MixinBlockLightEngine extends MixinLightEngine { +public abstract class MixinBlockLightEngine extends MixinLightEngine { /** * @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..975448e33 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinDynamicGraphMinFixedPoint.java @@ -0,0 +1,11 @@ +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 checkEdge(long sourceId, long id, int level, boolean decrease); +} 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 73% 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 ca3e3e8ee..e0e53ef57 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,11 @@ import javax.annotation.Nullable; +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; @@ -17,7 +20,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 @Nullable private LayerLightEngine blockEngine; @@ -59,5 +62,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(int x, int z, int oldHeight, int newHeight) { + if (this.skyEngine != null) { + ((ISkyLightColumnChecker) skyEngine).checkSkyLightColumn(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/MixinLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLightEngine.java index 910298768..3f050b680 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/MixinLightEngine.java @@ -25,7 +25,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(LayerLightEngine.class) -public class MixinLightEngine, S extends LayerLightSectionStorage> implements ILightEngine { +public abstract class MixinLightEngine, S extends LayerLightSectionStorage> extends MixinDynamicGraphMinFixedPoint implements ILightEngine { @Shadow @Final protected S storage; @@ -37,6 +37,8 @@ public class MixinLightEngine, S extends LayerL @Shadow @Final private BlockGetter[] lastChunk; + @Shadow protected void checkNode(long id) {} + @Override public void retainCubeData(CubePos posIn, boolean retain) { long i = posIn.asSectionPos().asLong(); 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..8868a623a --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightEngine.java @@ -0,0 +1,107 @@ +package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting; + +import io.github.opencubicchunks.cubicchunks.CubicChunks; +import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; +import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; +import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper; +import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; +import io.github.opencubicchunks.cubicchunks.mixin.access.common.SectionLightStorageAccess; +import io.github.opencubicchunks.cubicchunks.world.lighting.ICubicSkyLightEngine; +import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.lighting.SkyLightEngine; +import net.minecraft.world.level.lighting.SkyLightSectionStorage; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(SkyLightEngine.class) +public abstract class MixinSkyLightEngine extends MixinLightEngine implements ISkyLightColumnChecker, + ICubicSkyLightEngine { + /** + * @author CursedFlames + * @reason disable vanilla sky light logic + */ + @Overwrite + protected void checkNode(long id) { + super.checkNode(id); + } + + @Override public void checkSkyLightColumn(int x, int z, int oldHeight, int newHeight) { + ((SectionLightStorageAccess) this.storage).invokeRunAllUpdates(); + 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 + ((SectionLightStorageAccess) this.storage).invokeRunAllUpdates(); + + for (int y = oldHeight-1; y >= newHeight; y--) { + long pos = new BlockPos(x, y, z).asLong(); + if (((SectionLightStorageAccess) this.storage).invokeStoringLightForSection(SectionPos.blockToSection(pos))) { + addEmissionAtPos(pos); + } + } + } else { + for (int y = oldHeight; y < newHeight; y++) { + 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); + } + + @Inject(method = "getComputedLevel(JJI)I", + at = @At("HEAD"), cancellable = true) + private void onGetComputedLevel(long id, long excludedId, int maxLevel, CallbackInfoReturnable cir) { + if (this.chunkSource.getLevel() instanceof ClientLevel) return; + BlockPos pos = BlockPos.of(id); + // FIXME this may or may not be a horrendously unsafe way of getting the light heightmap. I'm not sure. + BlockGetter chunk = this.chunkSource.getChunkForLighting(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); + if (chunk == null) return; + LightSurfaceTrackerWrapper heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); + int height = heightmap.getFirstAvailable(pos.getX(), pos.getZ()); + 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++) { + // FIXME possibly unsafe light heightmap access here too + BlockGetter chunk = this.chunkSource.getChunkForLighting(chunkPos.x + sectionX, chunkPos.z + sectionZ); + LightSurfaceTrackerWrapper heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); + 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 + ((SectionLightStorageAccess) this.storage).invokeRunAllUpdates(); + + if (((SectionLightStorageAccess) this.storage).invokeStoringLightForSection(SectionPos.blockToSection(pos))) { + addEmissionAtPos(pos); + } + } + } + } + } + } + } + } +} 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 89% 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 a72319af0..eed3c984b 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; @@ -10,7 +10,6 @@ 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.utils.Coords; import io.github.opencubicchunks.cubicchunks.world.server.IServerWorldLightManager; import it.unimi.dsi.fastutil.objects.ObjectList; @@ -29,7 +28,7 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(ThreadedLevelLightEngine.class) -public abstract class MixinServerWorldLightManager extends MixinWorldLightManager implements IServerWorldLightManager { +public abstract class MixinThreadedLevelLightEngine extends MixinLevelLightEngine implements IServerWorldLightManager { private ProcessorHandle> cubeSorterMailbox; @@ -40,6 +39,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) { @@ -120,6 +121,8 @@ public CompletableFuture lightCube(IBigCube icube, boolean flagIn) { icube.getCubeLightSources().forEach((blockPos) -> { super.onBlockEmissionIncrease(blockPos, icube.getLightEmission(blockPos)); }); + // FIXME we probably want another flag for controlling skylight + super.doSkyLightForCube(icube); } ((IChunkManager) this.chunkMap).releaseLightTicket(cubePos); @@ -133,6 +136,14 @@ public CompletableFuture lightCube(IBigCube icube, boolean flagIn) { }); } + @Override + public void checkSkyLightColumn(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(x, z, oldHeight, newHeight); + }, () -> "checkSkyLightColumn " + x + " " + z)); + } + /** * @author NotStirred * @reason Vanilla lighting is gone 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..269322055 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ISkyLightColumnChecker.java @@ -0,0 +1,5 @@ +package io.github.opencubicchunks.cubicchunks.world.lighting; + +public interface ISkyLightColumnChecker { + void checkSkyLightColumn(int x, int z, int oldHeight, int newHeight); +} diff --git a/src/main/resources/cubicchunks.mixins.core.json b/src/main/resources/cubicchunks.mixins.core.json index 79a5a1a3b..7a8d06026 100644 --- a/src/main/resources/cubicchunks.mixins.core.json +++ b/src/main/resources/cubicchunks.mixins.core.json @@ -41,10 +41,14 @@ "common.world.feature.MixinSpringFeature", "common.world.feature.MixinVineFeature", "common.world.lighting.MixinBlockLightEngine", + "common.world.lighting.MixinDynamicGraphMinFixedPoint", + "common.world.lighting.MixinLevelLightEngine", "common.world.lighting.MixinLightEngine", "common.world.lighting.MixinSectionLightStorage", + "common.world.lighting.MixinSkyLightEngine", "common.world.lighting.MixinSkyLightSectionStorage", - "common.world.lighting.MixinWorldLightManager", + "common.world.lighting.MixinThreadedLevelLightEngine", + "common.world.lighting.MixinLevelLightEngine", "common.world.MixinAbstractChunkProvider", "common.world.MixinFuzzyOffsetConstantColumnBiomeZoomer", "common.world.MixinIWorldReader", @@ -61,7 +65,7 @@ "common.world.placement.MixinRangeDecorator", "common.world.placement.MixinSimpleFeatureDecorator", "common.world.placement.MixinSpread32Decorator", - "common.world.server.MixinServerWorldLightManager", + "common.world.lighting.MixinThreadedLevelLightEngine", "common.world.structure.MixinStructureFeature", "common.world.structure.MixinStructureFeatureManager", "common.world.structure.MixinStructurePiece", From 40581b4a1c3da6a695eb74eac22d484e221d29fe Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Mon, 15 Feb 2021 11:23:41 +1300 Subject: [PATCH 06/39] more WIP lighting stuff; still mostly non-functional --- .../cubicchunks/chunk/CubeMap.java | 24 +++++ .../cubicchunks/chunk/CubeMapGetter.java | 5 + .../chunk/LightHeightmapGetter.java | 19 +++- .../cubicchunks/chunk/cube/BigCube.java | 7 +- .../cubicchunks/chunk/cube/CubePrimer.java | 2 +- .../heightmap/ClientLightSurfaceTracker.java | 91 +++++++++++++++++++ .../chunk/heightmap/ClientSurfaceTracker.java | 2 +- .../mixin/core/common/chunk/MixinChunk.java | 30 ++++-- .../core/common/chunk/MixinProtoChunk.java | 4 +- .../world/lighting/MixinSkyLightEngine.java | 77 +++++++++++++--- .../cubicchunks/network/PacketHeightmap.java | 11 +++ 11 files changed, 250 insertions(+), 22 deletions(-) create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/chunk/CubeMap.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/chunk/CubeMapGetter.java create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientLightSurfaceTracker.java 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..16bc9d97d --- /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..a38bf4136 --- /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/LightHeightmapGetter.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java index 4eb250788..4cd641424 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java @@ -1,7 +1,24 @@ 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 { - LightSurfaceTrackerWrapper getLightHeightmap(); + Heightmap getLightHeightmap(); + default ClientLightSurfaceTracker getClientLightHeightmap() { + Heightmap lightHeightmap = this.getLightHeightmap(); + if (!(lightHeightmap instanceof ClientLightSurfaceTracker)) { + throw new Error("Kurst is dumb"); + } + return (ClientLightSurfaceTracker) lightHeightmap; + } + + default LightSurfaceTrackerWrapper getServerLightHeightmap() { + Heightmap lightHeightmap = this.getLightHeightmap(); + if (!(lightHeightmap instanceof LightSurfaceTrackerWrapper)) { + throw new Error("Kurst is dumb"); + } + 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 7786e4af1..4cfca876b 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 @@ -19,6 +19,7 @@ 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.LightHeightmapGetter; import io.github.opencubicchunks.cubicchunks.chunk.biome.CubeBiomeContainer; @@ -882,13 +883,17 @@ public void postLoad() { // TODO we really, *really* shouldn't be force-loading columns here. // probably the easiest approach until we get a "columns before cubes" invariant though. 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); } // TODO probably don't want to do this if the cube was already loaded as a CubePrimer - ((LightHeightmapGetter) chunk).getLightHeightmap().loadCube(this); + // TODO what should we do on the client here? + if (!this.level.isClientSide) { + ((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 93d64c023..9b608f85b 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 @@ -207,7 +207,7 @@ public CubePrimer(CubePos cubePosIn, UpgradeData p_i49941_2_, @Nullable LevelChu // not really feasible to fix until we get a "columns before cubes" invariant. BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x + dx, chunkPos.z + dz); if (chunk instanceof LightHeightmapGetter) { - LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); + LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); if (lightHeightmap != null) { // TODO this stuff is awful for performance; need to optimize it // probably want to do the thing we do for other scale0 sections and store a reference to it 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..14ce73f30 --- /dev/null +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientLightSurfaceTracker.java @@ -0,0 +1,91 @@ +package io.github.opencubicchunks.cubicchunks.chunk.heightmap; + +import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; +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.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) { + return false;/* + // TODO is it safe to do this or are we risking causing cube loading, etc? + int previous = getFirstAvailable(x, z); + if (y <= previous - 2) { + return false; + } + ChunkAccess chunk = ((HeightmapAccess) this).getChunk(); + BlockPos blockPos = new BlockPos(x, y, z); + BlockPos abovePos = new BlockPos(x, y+1, z); + BlockState above = chunk.getBlockState(abovePos); + int lightBlock = blockState.getLightBlock(chunk, blockPos); + if (lightBlock > 0 || (above != null && Shapes.faceShapeOccludes(getShape(above, abovePos, Direction.DOWN), getShape(blockState, blockPos, Direction.UP)))) { + if (y >= previous) { + ((HeightmapAccess) this).invokeSetHeight(x, z, y + 1); + return true; + } + return true; + } + if (previous - 1 == y) { + BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); + + int currentY; + for (currentY = y - 1; currentY >= y - 64; --currentY) { + pos.set(x, currentY, z); + // TODO copy the face shape occlusion logic here too - I'm too lazy for now. + if (blockState.getLightBlock(chunk, pos) > 0) { + ((HeightmapAccess) this).invokeSetHeight(x, z, currentY + 1); + return true; + } + } + ((HeightmapAccess) this).invokeSetHeight(x, z, currentY); + return true; + } + return false;*/ + } + + 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; + } + + @Override + public void setRawData(long[] heightmap) { + // We need to compare the old and new data here, hence the inefficiencies with making a new 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(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..1719ca965 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,7 +10,7 @@ public class ClientSurfaceTracker extends Heightmap { - private final Predicate isOpaque; + protected final Predicate isOpaque; public ClientSurfaceTracker(ChunkAccess chunkAccess, Types types) { super(chunkAccess, types); 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 69c1b07aa..acb97bbd6 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 @@ -6,15 +6,19 @@ import javax.annotation.Nullable; +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.utils.Coords; import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker; import net.minecraft.core.BlockPos; @@ -48,7 +52,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(LevelChunk.class) -public abstract class MixinChunk implements ChunkAccess, LightHeightmapGetter { +public abstract class MixinChunk implements ChunkAccess, LightHeightmapGetter, CubeMapGetter { @Shadow @Final private Level level; @Shadow @Final private ChunkPos chunkPos; @@ -63,13 +67,19 @@ public abstract class MixinChunk implements ChunkAccess, LightHeightmapGetter { return false; } - private LightSurfaceTrackerWrapper lightHeightmap; + private Heightmap lightHeightmap; + private CubeMap cubeMap; @Override - public LightSurfaceTrackerWrapper getLightHeightmap() { + public Heightmap getLightHeightmap() { 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;" @@ -83,7 +93,13 @@ private void onInit(Level levelIn, ChunkPos pos, ChunkBiomeContainer chunkBiomeC this.biomes = new ColumnBiomeContainer(levelIn.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), levelIn, levelIn); } - lightHeightmap = new LightSurfaceTrackerWrapper(this); + 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( @@ -100,10 +116,12 @@ private void onInitFromProtoChunk(ServerLevel serverLevel, ProtoChunk protoChunk ) private void onSetBlock(BlockPos pos, BlockState state, boolean moved, CallbackInfoReturnable cir) { // TODO client side light heightmap stuff - if (!this.level.isClientSide) { + if (this.level.isClientSide) { + ClientLightSurfaceTracker lightHeightmap = ((LightHeightmapGetter) this).getClientLightHeightmap(); + } else { int relX = pos.getX() & 15; int relZ = pos.getZ() & 15; - LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) this).getLightHeightmap(); + LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) this).getServerLightHeightmap(); int oldHeight = lightHeightmap.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. 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 0bfe32b68..1f24fc003 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 @@ -6,6 +6,7 @@ import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.levelgen.Heightmap; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -21,7 +22,7 @@ public abstract class MixinProtoChunk implements LightHeightmapGetter { private LightSurfaceTrackerWrapper lightHeightmap; @Override - public LightSurfaceTrackerWrapper getLightHeightmap() { + public Heightmap getLightHeightmap() { return lightHeightmap; } @@ -38,6 +39,7 @@ private int getFakeSectionCount(LevelHeightAccessor accessor) { at = @At("RETURN") ) private void onSetStatus(ChunkStatus status, CallbackInfo ci) { + // TODO can this run on the client? Will break things if so. 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/world/lighting/MixinSkyLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightEngine.java index 8868a623a..d344bbe3a 100644 --- 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 @@ -1,11 +1,14 @@ package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting; import io.github.opencubicchunks.cubicchunks.CubicChunks; +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.heightmap.LightSurfaceTrackerWrapper; import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; import io.github.opencubicchunks.cubicchunks.mixin.access.common.SectionLightStorageAccess; +import io.github.opencubicchunks.cubicchunks.utils.Coords; import io.github.opencubicchunks.cubicchunks.world.lighting.ICubicSkyLightEngine; import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker; import net.minecraft.client.multiplayer.ClientLevel; @@ -13,6 +16,8 @@ import net.minecraft.core.SectionPos; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.LevelChunk; +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.Mixin; @@ -35,21 +40,60 @@ protected void checkNode(long id) { @Override public void checkSkyLightColumn(int x, int z, int oldHeight, int newHeight) { ((SectionLightStorageAccess) this.storage).invokeRunAllUpdates(); + // FIXME another probably-unsafe chunk get + // this should probably be in a helper method anyway + BlockGetter blockGetter = this.chunkSource.getChunkForLighting(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); + LevelChunk chunk = (LevelChunk) blockGetter; + CubeMap cubeMap = ((CubeMapGetter) 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 ((SectionLightStorageAccess) this.storage).invokeRunAllUpdates(); - for (int y = oldHeight-1; y >= newHeight; y--) { - long pos = new BlockPos(x, y, z).asLong(); - if (((SectionLightStorageAccess) this.storage).invokeStoringLightForSection(SectionPos.blockToSection(pos))) { - addEmissionAtPos(pos); +// for (int y = oldHeight-1; y >= newHeight; y--) { +// } + // TODO cube iteration order might still be important here + 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 (((SectionLightStorageAccess) this.storage).invokeStoringLightForSection(SectionPos.blockToSection(pos))) { + addEmissionAtPos(pos); + } + } } } } else { - for (int y = oldHeight; y < newHeight; y++) { - 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); +// for (int y = oldHeight; y < newHeight; y++) { +// } + // TODO cube iteration order might still be important here + 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); + } + } } } } @@ -64,9 +108,14 @@ private void onGetComputedLevel(long id, long excludedId, int maxLevel, Callback if (this.chunkSource.getLevel() instanceof ClientLevel) return; BlockPos pos = BlockPos.of(id); // FIXME this may or may not be a horrendously unsafe way of getting the light heightmap. I'm not sure. + // okay it is unsafe - it sometimes but rarely NPEs and I'm not sure where. BlockGetter chunk = this.chunkSource.getChunkForLighting(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); if (chunk == null) return; - LightSurfaceTrackerWrapper heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); + Heightmap heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); + if (heightmap == null) { + System.out.println("onGetComputedLevel heightmap was null"); + return; + } int height = heightmap.getFirstAvailable(pos.getX(), pos.getZ()); if (height <= pos.getY()) { cir.setReturnValue(0); @@ -81,9 +130,15 @@ public void doSkyLightForCube(IBigCube cube) { int maxY = cubePos.maxCubeY(); for (int sectionX = 0; sectionX < IBigCube.DIAMETER_IN_SECTIONS; sectionX++) { for (int sectionZ = 0; sectionZ < IBigCube.DIAMETER_IN_SECTIONS; sectionZ++) { - // FIXME possibly unsafe light heightmap access here too + // FIXME possibly unsafe light heightmap access here too - rarely NPEs somewhere BlockGetter chunk = this.chunkSource.getChunkForLighting(chunkPos.x + sectionX, chunkPos.z + sectionZ); - LightSurfaceTrackerWrapper heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); + if (chunk == null) { + System.out.println("chunk null"); + } + Heightmap heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); + if (heightmap == null) { + System.out.println("heightmap null"); + } for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { int height = heightmap.getFirstAvailable(x, z); 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..197d46ece 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); + } } } } From 27c65857432df90bc0ff69139dede41e7f58905c Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Mon, 15 Feb 2021 23:53:43 +1300 Subject: [PATCH 07/39] fix CubePrimers not being added to light heightmaps properly --- .../cubicchunks/chunk/cube/CubePrimer.java | 56 ++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) 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 750bdf076..081fa39ed 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 @@ -96,8 +96,6 @@ public class CubePrimer implements IBigCube, ChunkAccess, CubicLevelHeightAccess private long inhabitedTime; - private boolean[] lightHeightmapLoaded; - private final boolean isCubic; private final boolean generates2DChunks; private final WorldStyle worldStyle; @@ -137,8 +135,6 @@ public CubePrimer(CubePos cubePosIn, UpgradeData p_i49941_2_, @Nullable LevelChu } } - this.lightHeightmapLoaded = new boolean[IBigCube.CHUNK_COUNT]; - isCubic = ((CubicLevelHeightAccessor) levelHeightAccessor).isCubic(); generates2DChunks = ((CubicLevelHeightAccessor) levelHeightAccessor).generates2DChunks(); worldStyle = ((CubicLevelHeightAccessor) levelHeightAccessor).worldStyle(); @@ -160,9 +156,32 @@ public CubePrimer(CubePos cubePosIn, UpgradeData p_i49941_2_, @Nullable LevelChu return this.sections; } + private ChunkSource getChunkSource() { + if (this.levelHeightAccessor instanceof CubeWorldGenRegion) { + return ((CubeWorldGenRegion) this.levelHeightAccessor).getChunkSource(); + } else { + return ((ServerLevel) this.levelHeightAccessor).getChunkSource(); + } + } + //STATUS @Override public void setCubeStatus(ChunkStatus newStatus) { this.status = newStatus; + + if (this.status == ChunkStatus.LIGHT) { + ChunkSource chunkSource = getChunkSource(); + + ChunkPos chunkPos = this.cubePos.asChunkPos(); + for (int dx = 0; dx < IBigCube.DIAMETER_IN_SECTIONS; dx++) { + for (int dz = 0; dz < IBigCube.DIAMETER_IN_SECTIONS; dz++) { + // TODO do we want to force-load chunks here? if not the chunk can be null, at least until we get the column->cube invariant + BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x + dx, chunkPos.z + dz); + LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); + // TODO want to optimize this - probably want to do the thing we do for other scale0 sections and store a reference to it + lightHeightmap.loadCube(this); + } + } + } } @Deprecated @Override public ChunkStatus getStatus() { @@ -202,34 +221,19 @@ public CubePrimer(CubePos cubePosIn, UpgradeData p_i49941_2_, @Nullable LevelChu LevelChunkSection chunksection = this.sections[index]; BlockState blockstate = chunksection.setBlockState(x, y, z, state, false); - if (this.status.isOrAfter(ChunkStatus.FEATURES) && state != blockstate && (state.getLightBlock(this, pos) != blockstate.getLightBlock(this, pos) + if (this.status.isOrAfter(ChunkStatus.LIGHT) && state != blockstate && (state.getLightBlock(this, pos) != blockstate.getLightBlock(this, pos) || state.getLightEmission() != blockstate.getLightEmission() || state.useShapeForLightOcclusion() || blockstate.useShapeForLightOcclusion())) { - ChunkSource chunkSource; - if (this.levelHeightAccessor instanceof CubeWorldGenRegion) { - chunkSource = ((CubeWorldGenRegion) this.levelHeightAccessor).getChunkSource(); - } else { - chunkSource = ((ServerLevel) this.levelHeightAccessor).getChunkSource(); - } + ChunkSource chunkSource = getChunkSource(); ChunkPos chunkPos = this.cubePos.asChunkPos(); for (int dx = 0; dx < IBigCube.DIAMETER_IN_SECTIONS; dx++) { for (int dz = 0; dz < IBigCube.DIAMETER_IN_SECTIONS; dz++) { - // TODO this can return null, leading to incorrect light heightmap values -> incorrect sky lighting on worldgen. - // not really feasible to fix until we get a "columns before cubes" invariant. + // TODO do we want to force-load chunks here? if not the chunk can be null, at least until we get the column->cube invariant BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x + dx, chunkPos.z + dz); - if (chunk instanceof LightHeightmapGetter) { - LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); - if (lightHeightmap != null) { - // TODO this stuff is awful for performance; need to optimize it - // probably want to do the thing we do for other scale0 sections and store a reference to it - if (!lightHeightmapLoaded[dx + dz * IBigCube.DIAMETER_IN_SECTIONS]) { - lightHeightmapLoaded[dx + dz * IBigCube.DIAMETER_IN_SECTIONS] = true; - lightHeightmap.loadCube(this); - } - // 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(x, pos.getY(), z, state); - } - } + LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); + + // 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(x, pos.getY(), z, state); } } From 989cb2bfd2b961d5af9bb4e316fabeeef084cbaa Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Tue, 16 Feb 2021 12:33:09 +1300 Subject: [PATCH 08/39] slight code cleanup and isCubic checks --- .../cubicchunks/chunk/cube/CubePrimer.java | 1 + .../mixin/core/common/chunk/MixinChunk.java | 33 +++++++------ .../core/common/chunk/MixinProtoChunk.java | 40 +++++++++------- .../world/lighting/MixinLightEngine.java | 2 +- .../world/lighting/MixinSkyLightEngine.java | 48 +++++++++---------- 5 files changed, 66 insertions(+), 58 deletions(-) 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 081fa39ed..c552b2215 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 @@ -176,6 +176,7 @@ private ChunkSource getChunkSource() { for (int dz = 0; dz < IBigCube.DIAMETER_IN_SECTIONS; dz++) { // TODO do we want to force-load chunks here? if not the chunk can be null, at least until we get the column->cube invariant BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x + dx, chunkPos.z + dz); +// BlockGetter chunk = chunkSource.getChunk(chunkPos.x + dx, chunkPos.z + dz, ChunkStatus.EMPTY, true); LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); // TODO want to optimize this - probably want to do the thing we do for other scale0 sections and store a reference to it lightHeightmap.loadCube(this); 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 eebacd743..81ed8c11f 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 @@ -87,15 +87,18 @@ public abstract class MixinChunk implements ChunkAccess, LightHeightmapGetter, C @Override public Heightmap getLightHeightmap() { - // FIXME remove debug - if (lightHeightmap == null) { - System.out.println("late creation of light heightmap in MixinChunk"); - if (level.isClientSide) { - lightHeightmap = new ClientLightSurfaceTracker(this); - } else { - lightHeightmap = new LightSurfaceTrackerWrapper(this); - } - } + if (!isCubic) { + throw new UnsupportedOperationException("Attempted to get light heightmap on a non-cubic chunk"); + } + // FIXME remove debug + if (lightHeightmap == null) { + System.out.println("late creation of light heightmap in MixinChunk"); + if (level.isClientSide) { + lightHeightmap = new ClientLightSurfaceTracker(this); + } else { + lightHeightmap = new LightSurfaceTrackerWrapper(this); + } + } return lightHeightmap; } @@ -139,9 +142,9 @@ private void onInit(Level levelIn, ChunkPos pos, ChunkBiomeContainer chunkBiomeC at = @At("RETURN") ) private void onInitFromProtoChunk(ServerLevel serverLevel, ProtoChunk protoChunk, Consumer consumer, CallbackInfo ci) { - if (!this.isCubic()) { - return; - } + if (!this.isCubic()) { + return; + } lightHeightmap = ((LightHeightmapGetter) protoChunk).getLightHeightmap(); } @@ -150,9 +153,9 @@ private void onInitFromProtoChunk(ServerLevel serverLevel, ProtoChunk protoChunk 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; - } + if (!this.isCubic()) { + return; + } // TODO client side light heightmap stuff if (this.level.isClientSide) { ClientLightSurfaceTracker lightHeightmap = ((LightHeightmapGetter) this).getClientLightHeightmap(); 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 ac3aadda8..03ad6dec0 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 @@ -38,21 +38,25 @@ public abstract class MixinProtoChunk implements LightHeightmapGetter, LevelHeig @Shadow public abstract ChunkStatus getStatus(); - private LightSurfaceTrackerWrapper lightHeightmap; - - @Override - public Heightmap getLightHeightmap() { - // FIXME remove debug - if (lightHeightmap == null) { - System.out.println("late creation of light heightmap in MixinProtoChunk"); -// if (level.isClientSide) { -// lightHeightmap = new ClientLightSurfaceTracker(this); -// } else { - lightHeightmap = new LightSurfaceTrackerWrapper((ChunkAccess) this); -// } - } - return lightHeightmap; - } + private LightSurfaceTrackerWrapper lightHeightmap; + + @Override + public Heightmap getLightHeightmap() { + if (!isCubic) { + throw new UnsupportedOperationException("Attempted to get light heightmap on a non-cubic chunk"); + } + // FIXME remove debug + if (lightHeightmap == null) { + System.out.println("late creation of light heightmap in MixinProtoChunk"); + // TODO figure out how to make sure this only happens on server side - do ProtoChunks exist on client? +// if (level.isClientSide) { +// lightHeightmap = new ClientLightSurfaceTracker(this); +// } else { + lightHeightmap = new LightSurfaceTrackerWrapper((ChunkAccess) this); +// } + } + return lightHeightmap; + } @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")) @@ -125,9 +129,9 @@ private void setMinHeight(CallbackInfoReturnable cir) { at = @At("RETURN") ) private void onSetStatus(ChunkStatus status, CallbackInfo ci) { - if (!this.isCubic()) { - return; - } + if (!this.isCubic()) { + return; + } // TODO can this run on the client? Will break things if so. if (lightHeightmap == null && this.getStatus().isOrAfter(ChunkStatus.FEATURES)) { // Lighting only starts happening after FEATURES, so we init here to avoid creating unnecessary heightmaps 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/MixinLightEngine.java index eebbb1bae..18dac6ba2 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/MixinLightEngine.java @@ -42,7 +42,7 @@ public abstract class MixinLightEngine, S exten @Shadow @Final private BlockGetter[] lastChunk; - private boolean isCubic; + protected boolean isCubic; private boolean generates2DChunks; private CubicLevelHeightAccessor.WorldStyle worldStyle; 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 index fb0086624..695f46fcc 100644 --- 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 @@ -1,11 +1,9 @@ package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting; -import io.github.opencubicchunks.cubicchunks.CubicChunks; 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.heightmap.LightSurfaceTrackerWrapper; import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; import io.github.opencubicchunks.cubicchunks.mixin.access.common.SectionLightStorageAccess; import io.github.opencubicchunks.cubicchunks.utils.Coords; @@ -21,9 +19,9 @@ import net.minecraft.world.level.lighting.SkyLightEngine; import net.minecraft.world.level.lighting.SkyLightSectionStorage; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; 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) @@ -33,21 +31,18 @@ public abstract class MixinSkyLightEngine extends MixinLightEngine= newHeight; y--) { -// } // 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--) { @@ -78,9 +72,8 @@ protected void checkNode(long id) { } } } else { -// for (int y = oldHeight; y < newHeight; y++) { -// } // 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++) { @@ -106,18 +99,25 @@ 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) { - if (this.chunkSource.getLevel() instanceof ClientLevel) return; + // TODO do we want this mixin on client side too? + if (!this.isCubic || this.chunkSource.getLevel() instanceof ClientLevel) return; BlockPos pos = BlockPos.of(id); - // FIXME this may or may not be a horrendously unsafe way of getting the light heightmap. I'm not sure. - // okay it is unsafe - it sometimes but rarely NPEs and I'm not sure where. + // TODO chunk is sometimes null BlockGetter chunk = this.chunkSource.getChunkForLighting(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); - if (chunk == null) return; + if (chunk == null) { + System.out.println("onGetComputedLevel chunk was null " + (this.chunkSource.getLevel() instanceof ClientLevel ? "client" : "server")); + return; + } Heightmap heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); if (heightmap == null) { - System.out.println("onGetComputedLevel heightmap was null"); + System.out.println("onGetComputedLevel heightmap was null " + (this.chunkSource.getLevel() instanceof ClientLevel ? "client" : "server")); return; } int height = heightmap.getFirstAvailable(pos.getX(), pos.getZ()); @@ -134,10 +134,10 @@ public void doSkyLightForCube(IBigCube cube) { int maxY = cubePos.maxCubeY(); for (int sectionX = 0; sectionX < IBigCube.DIAMETER_IN_SECTIONS; sectionX++) { for (int sectionZ = 0; sectionZ < IBigCube.DIAMETER_IN_SECTIONS; sectionZ++) { - // FIXME possibly unsafe light heightmap access here too - rarely NPEs somewhere + // TODO this chunk is sometimes null BlockGetter chunk = this.chunkSource.getChunkForLighting(chunkPos.x + sectionX, chunkPos.z + sectionZ); if (chunk == null) { - System.out.println("chunk null"); + System.out.println("null chunk in MixinSkyLightEngine.doSkyLightForCube"); return; } Heightmap heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); From c36f8e5e381663c99a99fac86929bd83b9ea8e07 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Wed, 17 Feb 2021 20:56:10 +1300 Subject: [PATCH 09/39] add light heightmap data to F3 menu --- .../client/debug/MixinDebugScreenOverlay.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) 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 index 37b3a0bba..71d574528 100644 --- 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 @@ -1,5 +1,8 @@ package io.github.opencubicchunks.cubicchunks.mixin.core.client.debug; +import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; +import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper; +import io.github.opencubicchunks.cubicchunks.utils.Coords; import it.unimi.dsi.fastutil.longs.LongSet; import net.minecraft.client.gui.components.DebugScreenOverlay; import net.minecraft.core.BlockPos; @@ -25,12 +28,22 @@ public abstract class MixinDebugScreenOverlay { @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 blockPos, Entity entity, Direction direction, String string7, Level level, LongSet longSet, List list, LevelChunk levelChunk, int i) { - LevelChunk worldChunk2 = this.getServerChunk(); - if (worldChunk2 != null) { + 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(); + 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); + + if (serverChunk != null) { LevelLightEngine lightingProvider = level.getChunkSource().getLightEngine(); - list.add("Server Light: (" + lightingProvider.getLayerListener(LightLayer.SKY).getLightValue(blockPos) + " sky, " - + lightingProvider.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) + " block)"); + 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)"); } From bd90f5712ee0509c8538184067a589bc4e44844f Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Wed, 17 Feb 2021 21:53:13 +1300 Subject: [PATCH 10/39] sync light heightmap updates to the client --- .../core/common/chunk/MixinChunkHolder.java | 10 ++++++++- .../network/PacketHeightmapChanges.java | 21 +++++++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) 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 3723f1150..769a10a07 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 @@ -18,6 +18,7 @@ import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; import io.github.opencubicchunks.cubicchunks.chunk.IChunkManager; import io.github.opencubicchunks.cubicchunks.chunk.ICubeHolder; +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; @@ -365,9 +366,16 @@ public void blockChanged(BlockPos blockPos, CallbackInfo ci) { // TODO: replace heuristics with proper tracking if (blockPos.getY() >= topY) { // TODO: don't use heightmap type as "height" for address - changedLocalBlocks.add((short) AddressTools.getLocalAddress(blockPos.getX() & 0xF, value.ordinal() & 0xF, blockPos.getZ())); + changedLocalBlocks.add((short) AddressTools.getLocalAddress(blockPos.getX() & 0xF, value.ordinal() & 0xF, blockPos.getZ() & 0xF)); } } + int topY = ((LightHeightmapGetter) chunk).getLightHeightmap().getFirstAvailable(blockPos.getX(), blockPos.getZ()) - 1; + // Same logic as above for heightmap updates + // TODO: replace heuristics with proper tracking + if (blockPos.getY() >= topY) { + // TODO: don't use heightmap type as "height" for address + changedLocalBlocks.add((short) AddressTools.getLocalAddress(blockPos.getX() & 0xF, 0xF, blockPos.getZ() & 0xF)); + } return; } 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..eec659666 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,8 @@ package io.github.opencubicchunks.cubicchunks.network; import io.github.opencubicchunks.cubicchunks.CubicChunks; +import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; +import io.github.opencubicchunks.cubicchunks.chunk.heightmap.ClientSurfaceTracker; import io.github.opencubicchunks.cubicchunks.mixin.access.common.HeightmapAccess; import io.github.opencubicchunks.cubicchunks.utils.AddressTools; import it.unimi.dsi.fastutil.shorts.ShortArrayList; @@ -9,6 +11,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; +import net.minecraft.world.level.chunk.EmptyLevelChunk; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.levelgen.Heightmap; @@ -26,8 +29,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 +69,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]); + } } } } From bcc7955731d71910f81277635730c589f649a327 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Fri, 19 Feb 2021 20:10:12 +1300 Subject: [PATCH 11/39] add comments to distinguish local/global positions, and fix global positions being used in a few places that should use locals --- .../cubicchunks/chunk/cube/CubePrimer.java | 9 ++++++++- .../chunk/heightmap/ClientSurfaceTracker.java | 5 +++++ .../chunk/heightmap/SurfaceTrackerSection.java | 6 +++++- .../chunk/heightmap/SurfaceTrackerWrapper.java | 11 +++++++++++ .../mixin/core/common/chunk/MixinChunkHolder.java | 9 ++++++--- .../common/world/lighting/MixinSkyLightEngine.java | 3 ++- .../world/lighting/ISkyLightColumnChecker.java | 1 + 7 files changed, 38 insertions(+), 6 deletions(-) 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 c552b2215..0b2b4cb0b 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 @@ -17,6 +17,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import io.github.opencubicchunks.cubicchunks.CubicChunks; import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; import io.github.opencubicchunks.cubicchunks.chunk.biome.CubeBiomeContainer; @@ -174,9 +175,15 @@ private ChunkSource getChunkSource() { ChunkPos chunkPos = this.cubePos.asChunkPos(); for (int dx = 0; dx < IBigCube.DIAMETER_IN_SECTIONS; dx++) { for (int dz = 0; dz < IBigCube.DIAMETER_IN_SECTIONS; dz++) { - // TODO do we want to force-load chunks here? if not the chunk can be null, at least until we get the column->cube invariant + // TODO chunk can be null, at least until we get the column->cube invariant BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x + dx, chunkPos.z + dz); + // force-loading like this causes lighting to init incorrectly for some reason // BlockGetter chunk = chunkSource.getChunk(chunkPos.x + dx, chunkPos.z + dz, ChunkStatus.EMPTY, true); + if (chunk == null) { + CubicChunks.LOGGER.warn("Got a null column at " + (chunkPos.x + dx) + ", " + (chunkPos.z + dz) + + " while adding cube to light heightmap; lighting will not be initialized correctly"); + return; + } LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); // TODO want to optimize this - probably want to do the thing we do for other scale0 sections and store a reference to it lightHeightmap.loadCube(this); 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 1719ca965..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 @@ -17,6 +17,11 @@ public ClientSurfaceTracker(ChunkAccess chunkAccess, Types 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/SurfaceTrackerSection.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/SurfaceTrackerSection.java index 918e8b42a..3a7324729 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 @@ -60,7 +60,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)) { @@ -221,6 +224,7 @@ protected SurfaceTrackerSection loadNode(int newScaledY, int sectionScale, IBigC return new SurfaceTrackerSection(sectionScale, newScaledY, this, HEIGHTMAP_TYPES[this.heightmapType]); } + /** 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 d33b17dba..41a78cda8 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 @@ -11,7 +11,9 @@ public class SurfaceTrackerWrapper extends Heightmap { 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) { @@ -30,6 +32,14 @@ protected SurfaceTrackerWrapper(ChunkAccess chunkAccess, Types types, SurfaceTra 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? @@ -46,6 +56,7 @@ public boolean update(int x, int y, int z, BlockState blockState) { 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/core/common/chunk/MixinChunkHolder.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkHolder.java index 769a10a07..1891cd747 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 @@ -351,6 +351,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) { @@ -366,15 +369,15 @@ public void blockChanged(BlockPos blockPos, CallbackInfo ci) { // TODO: replace heuristics with proper tracking if (blockPos.getY() >= topY) { // TODO: don't use heightmap type as "height" for address - changedLocalBlocks.add((short) AddressTools.getLocalAddress(blockPos.getX() & 0xF, value.ordinal() & 0xF, blockPos.getZ() & 0xF)); + changedLocalBlocks.add((short) AddressTools.getLocalAddress(localX, value.ordinal() & 0xF, localZ)); } } - int topY = ((LightHeightmapGetter) chunk).getLightHeightmap().getFirstAvailable(blockPos.getX(), blockPos.getZ()) - 1; + int topY = ((LightHeightmapGetter) chunk).getLightHeightmap().getFirstAvailable(localX, localZ) - 1; // Same logic as above for heightmap updates // TODO: replace heuristics with proper tracking if (blockPos.getY() >= topY) { // TODO: don't use heightmap type as "height" for address - changedLocalBlocks.add((short) AddressTools.getLocalAddress(blockPos.getX() & 0xF, 0xF, blockPos.getZ() & 0xF)); + changedLocalBlocks.add((short) AddressTools.getLocalAddress(localX, 0xF, localZ)); } return; } 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 index 695f46fcc..18800db9a 100644 --- 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 @@ -40,6 +40,7 @@ protected void checkNode(long id, CallbackInfo ci) { super.checkNode(id); } + /** all parameters are global coordinates */ @Override public void checkSkyLightColumn(LevelChunk chunk, int x, int z, int oldHeight, int newHeight) { ((SectionLightStorageAccess) this.storage).invokeRunAllUpdates(); // TODO pass CubeMap into method instead? @@ -120,7 +121,7 @@ private void onGetComputedLevel(long id, long excludedId, int maxLevel, Callback System.out.println("onGetComputedLevel heightmap was null " + (this.chunkSource.getLevel() instanceof ClientLevel ? "client" : "server")); return; } - int height = heightmap.getFirstAvailable(pos.getX(), pos.getZ()); + int height = heightmap.getFirstAvailable(pos.getX() & 0xF, pos.getZ() & 0xF); if (height <= pos.getY()) { cir.setReturnValue(0); } 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 index 072d1fa72..985774e0c 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ISkyLightColumnChecker.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ISkyLightColumnChecker.java @@ -3,5 +3,6 @@ import net.minecraft.world.level.chunk.LevelChunk; public interface ISkyLightColumnChecker { + /** all parameters are global coordinates */ void checkSkyLightColumn(LevelChunk chunk, int x, int z, int oldHeight, int newHeight); } From 9257cfa1a0a92725402b8c01f9cbaa3aa6cc7527 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Sat, 3 Apr 2021 11:24:56 +1300 Subject: [PATCH 12/39] Several lighting fixes. Lighting should be mostly functional now. --- .../entity/MixinServerPlayerEntity.java | 22 ++++++++- .../lighting/MixinSectionLightStorage.java | 12 +++-- .../lighting/MixinSkyLightSectionStorage.java | 49 +++++++++++++++++++ .../network/PacketUpdateLight.java | 6 +-- 4 files changed, 79 insertions(+), 10 deletions(-) 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..b1571ad9d 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,30 @@ package io.github.opencubicchunks.cubicchunks.mixin.core.common.entity; +import com.mojang.authlib.GameProfile; +import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; +import io.github.opencubicchunks.cubicchunks.network.PacketDispatcher; +import io.github.opencubicchunks.cubicchunks.network.PacketUpdateLight; 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.Inject; import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @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 +34,11 @@ 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) { +// 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/world/lighting/MixinSectionLightStorage.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSectionLightStorage.java index 01e273d09..ee435e010 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/MixinSectionLightStorage.java @@ -78,13 +78,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 +101,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/MixinSkyLightSectionStorage.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightSectionStorage.java index c8f37f98e..c892dbe7e 100644 --- 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 @@ -1,14 +1,20 @@ package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.LightChunkGetter; +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; +// FIXME cubic checks for everything in this class @Mixin(SkyLightSectionStorage.class) public abstract class MixinSkyLightSectionStorage extends LayerLightSectionStorage { private MixinSkyLightSectionStorage(LightLayer lightLayer, LightChunkGetter lightChunkGetter, @@ -16,6 +22,28 @@ private MixinSkyLightSectionStorage(LightLayer lightLayer, LightChunkGetter ligh super(lightLayer, lightChunkGetter, dataLayerStorageMap); } + @Inject(method = "getLightValue(JZ)I", cancellable = true, at = @At("HEAD")) + private void onGetLightValue(long blockPos, boolean cached, CallbackInfoReturnable cir) { + // 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); + cir.setReturnValue(dataLayer == null ? 0 : dataLayer.get( + SectionPos.sectionRelative(BlockPos.getX(blockPos)), + SectionPos.sectionRelative(BlockPos.getY(blockPos)), + SectionPos.sectionRelative(BlockPos.getZ(blockPos)))); + } + + @Inject(method = "onNodeAdded", cancellable = true, at = @At("HEAD")) + private void onOnNodeAdded(long sectionPos, CallbackInfo ci) { + ci.cancel(); + } + + @Inject(method = "onNodeRemoved", cancellable = true, at = @At("HEAD")) + private void onOnNodeRemoved(long sectionPos, CallbackInfo ci) { + 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) { @@ -24,4 +52,25 @@ private void onEnableLightSources(long columnPos, boolean enabled, CallbackInfo ci.cancel(); } } + + @Inject(method = "createDataLayer", cancellable = true, at = @At("HEAD")) + private void onCreateDataLayer(long sectionPos, CallbackInfoReturnable cir) { + cir.setReturnValue(super.createDataLayer(sectionPos)); + } + + @Inject(method = "markNewInconsistencies", cancellable = true, at = @At("HEAD")) + private void onMarkNewInconsistencies(LayerLightEngine lightProvider, boolean doSkylight, boolean skipEdgeLightPropagation, CallbackInfo ci) { + ci.cancel(); + super.markNewInconsistencies(lightProvider, doSkylight, skipEdgeLightPropagation); + } + + @Inject(method = "hasSectionsBelow", cancellable = true, at = @At("HEAD")) + private void onHasSectionsBelow(int sectionY, CallbackInfoReturnable cir) { + cir.setReturnValue(true); + } + + @Inject(method = "isAboveData", cancellable = true, at = @At("HEAD")) + private void onIsAboveData(long sectionPos, CallbackInfoReturnable cir) { + cir.setReturnValue(false); + } } 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); From d02559e427babd6ee1feff675065b7f8c403ef4f Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Sat, 10 Apr 2021 14:20:01 +1200 Subject: [PATCH 13/39] isCubic checks --- .../client/debug/MixinDebugScreenOverlay.java | 24 +++++++++++-------- .../core/common/chunk/MixinProtoChunk.java | 8 +------ .../entity/MixinServerPlayerEntity.java | 4 +++- .../lighting/MixinSkyLightSectionStorage.java | 17 ++++++++++++- 4 files changed, 34 insertions(+), 19 deletions(-) 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 index 71d574528..4c81b55d9 100644 --- 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 @@ -2,7 +2,7 @@ import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper; -import io.github.opencubicchunks.cubicchunks.utils.Coords; +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; @@ -28,18 +28,22 @@ public abstract class MixinDebugScreenOverlay { @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) { + 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(); - String serverHeight = "???"; - if (serverChunk != null) { - LightSurfaceTrackerWrapper heightmap = ((LightHeightmapGetter) serverChunk).getServerLightHeightmap(); - int height = heightmap.getFirstAvailable(pos.getX() & 0xF, pos.getZ() & 0xF); - serverHeight = "" + height; + 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); } - 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, " 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 5e2b33b64..0901dc832 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 @@ -49,12 +49,7 @@ public Heightmap getLightHeightmap() { // FIXME remove debug if (lightHeightmap == null) { System.out.println("late creation of light heightmap in MixinProtoChunk"); - // TODO figure out how to make sure this only happens on server side - do ProtoChunks exist on client? -// if (level.isClientSide) { -// lightHeightmap = new ClientLightSurfaceTracker(this); -// } else { - lightHeightmap = new LightSurfaceTrackerWrapper((ChunkAccess) this); -// } + lightHeightmap = new LightSurfaceTrackerWrapper((ChunkAccess) this); } return lightHeightmap; } @@ -138,7 +133,6 @@ private void onSetStatus(ChunkStatus status, CallbackInfo ci) { if (!this.isCubic()) { return; } - // TODO can this run on the client? Will break things if so. 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 b1571ad9d..6a38f00cc 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 @@ -39,6 +39,8 @@ public void onSendChunkLoad(ServerGamePacketListenerImpl serverPlayNetHandler, P // @Inject(method = "tick", // at = @At("HEAD")) // private void onTick(CallbackInfo ci) { -// PacketDispatcher.sendTo(new PacketUpdateLight(CubePos.from(new BlockPos(this.position())), this.level.getLightEngine(), true), (ServerPlayer) (Object) this); +// 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/world/lighting/MixinSkyLightSectionStorage.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightSectionStorage.java index c892dbe7e..c2fc377be 100644 --- 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 @@ -1,5 +1,6 @@ package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting; +import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.world.level.LightLayer; @@ -14,16 +15,23 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -// FIXME cubic checks for everything in this class @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); @@ -36,17 +44,20 @@ private void onGetLightValue(long blockPos, boolean cached, CallbackInfoReturnab @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(); @@ -55,22 +66,26 @@ private void onEnableLightSources(long columnPos, boolean enabled, CallbackInfo @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); } } From dba3658a93d887d48dd98bc3103d1614d9b722d9 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Sun, 18 Apr 2021 12:11:58 +1200 Subject: [PATCH 14/39] Fix skylight updates during cube generation. Still broken somehow though --- .../cubicchunks/chunk/cube/CubePrimer.java | 54 ++++++++++++++----- .../heightmap/ClientLightSurfaceTracker.java | 3 +- .../heightmap/LightSurfaceTrackerSection.java | 26 +++++++++ .../heightmap/SurfaceTrackerSection.java | 4 +- .../mixin/core/common/chunk/MixinChunk.java | 3 +- .../core/common/chunk/MixinProtoChunk.java | 16 ++++-- .../world/lighting/MixinLevelLightEngine.java | 4 +- .../world/lighting/MixinSkyLightEngine.java | 6 +-- .../MixinThreadedLevelLightEngine.java | 4 +- .../cubicchunks/utils/Coords.java | 11 ++++ .../lighting/ISkyLightColumnChecker.java | 4 +- 11 files changed, 104 insertions(+), 31 deletions(-) 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 115f1d499..add7d462b 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 @@ -18,6 +18,7 @@ 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.LightHeightmapGetter; import io.github.opencubicchunks.cubicchunks.chunk.ImposterChunkPos; @@ -30,6 +31,7 @@ import io.github.opencubicchunks.cubicchunks.utils.Coords; import io.github.opencubicchunks.cubicchunks.world.CubeWorldGenRegion; import io.github.opencubicchunks.cubicchunks.world.storage.CubeProtoTickList; +import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; @@ -187,21 +189,40 @@ private ChunkSource getChunkSource() { if (this.status == ChunkStatus.LIGHT) { ChunkSource chunkSource = getChunkSource(); - ChunkPos chunkPos = this.cubePos.asChunkPos(); for (int dx = 0; dx < IBigCube.DIAMETER_IN_SECTIONS; dx++) { for (int dz = 0; dz < IBigCube.DIAMETER_IN_SECTIONS; dz++) { + ChunkPos chunkPos = this.cubePos.asChunkPos(dx, dz); // TODO chunk can be null, at least until we get the column->cube invariant - BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x + dx, chunkPos.z + dz); + BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x, chunkPos.z); // force-loading like this causes lighting to init incorrectly for some reason -// BlockGetter chunk = chunkSource.getChunk(chunkPos.x + dx, chunkPos.z + dz, ChunkStatus.EMPTY, true); +// BlockGetter chunk = chunkSource.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.EMPTY, true); if (chunk == null) { - CubicChunks.LOGGER.warn("Got a null column at " + (chunkPos.x + dx) + ", " + (chunkPos.z + dz) + CubicChunks.LOGGER.warn("Got a null column at " + (chunkPos.x) + ", " + (chunkPos.z) + " while adding cube to light heightmap; lighting will not be initialized correctly"); return; } 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); + } + } + // TODO want to optimize this - probably want to do the thing we do for other scale0 sections and store a reference to it 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); + } + } + } } } } @@ -242,16 +263,21 @@ private ChunkSource getChunkSource() { || state.getLightEmission() != lastState.getLightEmission() || state.useShapeForLightOcclusion() || lastState.useShapeForLightOcclusion())) { ChunkSource chunkSource = getChunkSource(); - ChunkPos chunkPos = this.cubePos.asChunkPos(); - for (int dx = 0; dx < IBigCube.DIAMETER_IN_SECTIONS; dx++) { - for (int dz = 0; dz < IBigCube.DIAMETER_IN_SECTIONS; dz++) { - // TODO do we want to force-load chunks here? if not the chunk can be null, at least until we get the column->cube invariant - BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x + dx, chunkPos.z + dz); - LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); - - // 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(x, pos.getY(), z, state); - } + ChunkPos chunkPos = Coords.chunkPosByIndex(this.cubePos, index); + + // TODO do we want to force-load chunks here? if not the chunk can be null, at least until we get the column->cube invariant + BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x, chunkPos.z); + 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); 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 index 9b0acbbd6..383842924 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientLightSurfaceTracker.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientLightSurfaceTracker.java @@ -1,5 +1,6 @@ package io.github.opencubicchunks.cubicchunks.chunk.heightmap; +import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter; import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; import io.github.opencubicchunks.cubicchunks.mixin.access.common.HeightmapAccess; import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker; @@ -87,7 +88,7 @@ public void setRawData(long[] heightmap, LevelChunk chunk) { int oldHeight = oldStorage.get(index) + minHeight; int newHeight = storage.get(index) + minHeight; if (oldHeight != newHeight) { - ((ISkyLightColumnChecker) Minecraft.getInstance().level.getLightEngine()).checkSkyLightColumn(chunk, baseX + x, baseZ + z, 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/LightSurfaceTrackerSection.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java index ce8754864..0027a0dba 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java @@ -11,6 +11,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; import javax.annotation.Nullable; +import java.util.Arrays; public class LightSurfaceTrackerSection extends SurfaceTrackerSection { public LightSurfaceTrackerSection() { @@ -117,6 +118,31 @@ public int getHeight(int x, int z) { } } + @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) { + 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/SurfaceTrackerSection.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/SurfaceTrackerSection.java index ebc5f4e86..fc2cd028f 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 @@ -27,10 +27,10 @@ public class SurfaceTrackerSection { private static final int BASE_SIZE_BITS = IBigCube.SIZE_BITS; // Use width of 16 to match columns. - private static final int WIDTH_BLOCKS = 16; + public static final int WIDTH_BLOCKS = 16; protected final BitStorage heights; - private final long[] dirtyPositions; // bitset has 100% memory usage overhead due to pointers and object headers + protected final long[] dirtyPositions; // bitset has 100% memory usage overhead due to pointers and object headers protected SurfaceTrackerSection parent; protected Object cubeOrNodes; /** 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 81ed8c11f..29cc9987f 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 @@ -146,6 +146,7 @@ private void onInitFromProtoChunk(ServerLevel serverLevel, ProtoChunk protoChunk return; } lightHeightmap = ((LightHeightmapGetter) protoChunk).getLightHeightmap(); + cubeMap = ((CubeMapGetter) protoChunk).getCubeMap(); } @Inject( @@ -169,7 +170,7 @@ private void onSetBlock(BlockPos pos, BlockState state, boolean moved, CallbackI lightHeightmap.update(relX, pos.getY(), relZ, state); int newHeight = lightHeightmap.getFirstAvailable(relX, relZ); if (newHeight != oldHeight) { - ((ISkyLightColumnChecker) this.level.getChunkSource().getLightEngine()).checkSkyLightColumn((LevelChunk) (Object) this, pos.getX(), pos.getZ(), oldHeight, newHeight); + ((ISkyLightColumnChecker) this.level.getChunkSource().getLightEngine()).checkSkyLightColumn(this, pos.getX(), pos.getZ(), oldHeight, newHeight); } } } 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 0901dc832..40cfa3ff8 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,7 +1,8 @@ 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 io.github.opencubicchunks.cubicchunks.chunk.heightmap.ClientLightSurfaceTracker; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.chunk.ChunkAccess; @@ -11,7 +12,6 @@ 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.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -30,7 +30,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(ProtoChunk.class) -public abstract class MixinProtoChunk implements LightHeightmapGetter, LevelHeightAccessor, CubicLevelHeightAccessor { +public abstract class MixinProtoChunk implements LightHeightmapGetter, LevelHeightAccessor, CubeMapGetter, CubicLevelHeightAccessor { @Shadow @Final private LevelHeightAccessor levelHeightAccessor; private boolean isCubic; @@ -40,6 +40,7 @@ public abstract class MixinProtoChunk implements LightHeightmapGetter, LevelHeig @Shadow public abstract ChunkStatus getStatus(); private LightSurfaceTrackerWrapper lightHeightmap; + private CubeMap cubeMap; @Override public Heightmap getLightHeightmap() { @@ -54,6 +55,15 @@ public Heightmap getLightHeightmap() { 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, diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLevelLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLevelLightEngine.java index 7eb58444a..29b84249a 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLevelLightEngine.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLevelLightEngine.java @@ -2,6 +2,7 @@ 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; @@ -13,7 +14,6 @@ import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.lighting.LayerLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LightEventListener; @@ -73,7 +73,7 @@ protected void doSkyLightForCube(IBigCube cube) { } @Override - public void checkSkyLightColumn(LevelChunk chunk, int x, int z, int oldHeight, int newHeight) { + 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); } 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 index 18800db9a..900163bfb 100644 --- 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 @@ -14,7 +14,6 @@ import net.minecraft.core.SectionPos; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.SkyLightEngine; import net.minecraft.world.level.lighting.SkyLightSectionStorage; @@ -41,10 +40,9 @@ protected void checkNode(long id, CallbackInfo ci) { } /** all parameters are global coordinates */ - @Override public void checkSkyLightColumn(LevelChunk chunk, int x, int z, int oldHeight, int newHeight) { + @Override public void checkSkyLightColumn(CubeMapGetter chunk, int x, int z, int oldHeight, int newHeight) { ((SectionLightStorageAccess) this.storage).invokeRunAllUpdates(); - // TODO pass CubeMap into method instead? - CubeMap cubeMap = ((CubeMapGetter) chunk).getCubeMap(); + CubeMap cubeMap = chunk.getCubeMap(); int oldHeightCube = Coords.blockToCube(oldHeight-1); int newHeightCube = Coords.blockToCube(newHeight); if (oldHeight > newHeight) { diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java index 636d2ed3c..ba9d80a1b 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java @@ -6,6 +6,7 @@ import javax.annotation.Nullable; import com.mojang.datafixers.util.Pair; +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; @@ -22,7 +23,6 @@ import net.minecraft.util.thread.ProcessorHandle; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -146,7 +146,7 @@ public CompletableFuture lightCube(IBigCube icube, boolean flagIn) { } @Override - public void checkSkyLightColumn(LevelChunk chunk, int x, int z, int oldHeight, int newHeight) { + 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); 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 f68a8c3dc..786534577 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. @@ -374,6 +375,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/ISkyLightColumnChecker.java b/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ISkyLightColumnChecker.java index 985774e0c..d8fb46d60 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ISkyLightColumnChecker.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/world/lighting/ISkyLightColumnChecker.java @@ -1,8 +1,8 @@ package io.github.opencubicchunks.cubicchunks.world.lighting; -import net.minecraft.world.level.chunk.LevelChunk; +import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter; public interface ISkyLightColumnChecker { /** all parameters are global coordinates */ - void checkSkyLightColumn(LevelChunk chunk, int x, int z, int oldHeight, int newHeight); + void checkSkyLightColumn(CubeMapGetter chunk, int x, int z, int oldHeight, int newHeight); } From abda8221beb288531d8f15357527750f9eb2a098 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Sun, 18 Apr 2021 17:34:25 +1200 Subject: [PATCH 15/39] add CubePrimers to CubeMap during lighting stage --- .../opencubicchunks/cubicchunks/chunk/cube/CubePrimer.java | 3 +++ .../core/common/world/lighting/MixinSkyLightEngine.java | 7 +++++++ 2 files changed, 10 insertions(+) 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 add7d462b..218f0d943 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 @@ -201,6 +201,9 @@ private ChunkSource getChunkSource() { + " while adding cube to light heightmap; lighting will not be initialized correctly"); return; } + + ((CubeMapGetter) chunk).getCubeMap().markLoaded(this.cubePos.getY()); + LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); int[] beforeValues = new int[SECTION_DIAMETER*SECTION_DIAMETER]; 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 index 900163bfb..8cd8977c5 100644 --- 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 @@ -12,6 +12,7 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; +import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.levelgen.Heightmap; @@ -139,6 +140,12 @@ public void doSkyLightForCube(IBigCube cube) { System.out.println("null chunk in MixinSkyLightEngine.doSkyLightForCube"); return; } + 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 not in cubemap during sky lighting"); + cubeMap.markLoaded(cubePos.getY()); + } Heightmap heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); if (heightmap == null) { System.out.println("heightmap null"); From 90f19d8acbc35a77f141d8befad73820a6b85f8f Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Sun, 18 Apr 2021 20:33:49 +1200 Subject: [PATCH 16/39] pass checkstyle --- config/checkstyle/suppressions.xml | 2 +- .../cubicchunks/chunk/CubeMap.java | 26 ++++---- .../cubicchunks/chunk/CubeMapGetter.java | 2 +- .../chunk/LightHeightmapGetter.java | 6 +- .../cubicchunks/chunk/cube/BigCube.java | 3 +- .../cubicchunks/chunk/cube/CubePrimer.java | 52 ++++++++-------- .../heightmap/ClientLightSurfaceTracker.java | 7 +-- .../heightmap/LightSurfaceTrackerSection.java | 11 ++-- .../heightmap/SurfaceTrackerSection.java | 6 +- .../heightmap/SurfaceTrackerWrapper.java | 12 ++-- .../client/debug/MixinDebugScreenOverlay.java | 60 ++++++++++--------- .../mixin/core/common/chunk/MixinChunk.java | 20 +++---- .../core/common/chunk/MixinChunkHolder.java | 4 +- .../core/common/chunk/MixinProtoChunk.java | 14 ++--- .../entity/MixinServerPlayerEntity.java | 5 -- .../world/lighting/MixinLightEngine.java | 12 ++-- .../lighting/MixinSectionLightStorage.java | 1 - .../world/lighting/MixinSkyLightEngine.java | 7 +-- .../lighting/MixinSkyLightSectionStorage.java | 5 +- .../network/PacketHeightmapChanges.java | 2 - 20 files changed, 125 insertions(+), 132 deletions(-) diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml index b1efac2e6..af837323b 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 index 16bc9d97d..dc79692d5 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/CubeMap.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/CubeMap.java @@ -4,21 +4,21 @@ import java.util.concurrent.ConcurrentHashMap; public class CubeMap { - private final ConcurrentHashMap.KeySetView loadedCubes = ConcurrentHashMap.newKeySet(); + private final ConcurrentHashMap.KeySetView loadedCubes = ConcurrentHashMap.newKeySet(); - public boolean isLoaded(int cubeY) { - return loadedCubes.contains(cubeY); - } + public boolean isLoaded(int cubeY) { + return loadedCubes.contains(cubeY); + } - public void markLoaded(int cubeY) { - loadedCubes.add(cubeY); - } + public void markLoaded(int cubeY) { + loadedCubes.add(cubeY); + } - public void markUnloaded(int cubeY) { - loadedCubes.remove(cubeY); - } + public void markUnloaded(int cubeY) { + loadedCubes.remove(cubeY); + } - public Set getLoaded() { - return loadedCubes; - } + 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 index a38bf4136..13db6dbe5 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/CubeMapGetter.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/CubeMapGetter.java @@ -1,5 +1,5 @@ package io.github.opencubicchunks.cubicchunks.chunk; public interface CubeMapGetter { - CubeMap getCubeMap(); + CubeMap getCubeMap(); } diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java index 5a8b1b0f1..d26c84eb3 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java @@ -6,10 +6,11 @@ public interface LightHeightmapGetter { Heightmap getLightHeightmap(); + default ClientLightSurfaceTracker getClientLightHeightmap() { Heightmap lightHeightmap = this.getLightHeightmap(); if (!(lightHeightmap instanceof ClientLightSurfaceTracker)) { - throw new Error("Kurst is dumb"); + throw new IllegalStateException("Attempted to get client light heightmap on server"); } return (ClientLightSurfaceTracker) lightHeightmap; } @@ -17,8 +18,7 @@ default ClientLightSurfaceTracker getClientLightHeightmap() { default LightSurfaceTrackerWrapper getServerLightHeightmap() { Heightmap lightHeightmap = this.getLightHeightmap(); if (!(lightHeightmap instanceof LightSurfaceTrackerWrapper)) { - System.out.println(lightHeightmap); - throw new Error("Kurst is dumb"); + 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 235ff2c0b..c2ec7d098 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 @@ -22,9 +22,8 @@ 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.LightHeightmapGetter; -import io.github.opencubicchunks.cubicchunks.chunk.biome.CubeBiomeContainer; import io.github.opencubicchunks.cubicchunks.chunk.ImposterChunkPos; +import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerSection; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerWrapper; import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; 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 218f0d943..dbb44e1eb 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 @@ -20,8 +20,8 @@ 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.LightHeightmapGetter; 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.LightSurfaceTrackerWrapper; import io.github.opencubicchunks.cubicchunks.chunk.heightmap.SurfaceTrackerSection; @@ -30,8 +30,8 @@ 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.storage.CubeProtoTickList; 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; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; @@ -175,27 +175,27 @@ public void setHeightToCubeBounds(boolean cubeBounds) { } private ChunkSource getChunkSource() { - if (this.levelHeightAccessor instanceof CubeWorldGenRegion) { - return ((CubeWorldGenRegion) this.levelHeightAccessor).getChunkSource(); - } else { - return ((ServerLevel) this.levelHeightAccessor).getChunkSource(); - } - } + if (this.levelHeightAccessor instanceof CubeWorldGenRegion) { + return ((CubeWorldGenRegion) this.levelHeightAccessor).getChunkSource(); + } else { + return ((ServerLevel) this.levelHeightAccessor).getChunkSource(); + } + } //STATUS @Override public void setCubeStatus(ChunkStatus newStatus) { this.status = newStatus; if (this.status == ChunkStatus.LIGHT) { - ChunkSource chunkSource = getChunkSource(); - - for (int dx = 0; dx < IBigCube.DIAMETER_IN_SECTIONS; dx++) { - for (int dz = 0; dz < IBigCube.DIAMETER_IN_SECTIONS; dz++) { - ChunkPos chunkPos = this.cubePos.asChunkPos(dx, dz); - // TODO chunk can be null, at least until we get the column->cube invariant - BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x, chunkPos.z); - // force-loading like this causes lighting to init incorrectly for some reason -// BlockGetter chunk = chunkSource.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.EMPTY, true); + ChunkSource chunkSource = getChunkSource(); + + for (int dx = 0; dx < IBigCube.DIAMETER_IN_SECTIONS; dx++) { + for (int dz = 0; dz < IBigCube.DIAMETER_IN_SECTIONS; dz++) { + ChunkPos chunkPos = this.cubePos.asChunkPos(dx, dz); + // TODO chunk can be null, at least until we get the column->cube invariant + BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x, chunkPos.z); + // force-loading like this causes lighting to init incorrectly for some reason +// BlockGetter chunk = chunkSource.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.EMPTY, true); if (chunk == null) { CubicChunks.LOGGER.warn("Got a null column at " + (chunkPos.x) + ", " + (chunkPos.z) + " while adding cube to light heightmap; lighting will not be initialized correctly"); @@ -204,21 +204,21 @@ private ChunkSource getChunkSource() { ((CubeMapGetter) chunk).getCubeMap().markLoaded(this.cubePos.getY()); - LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); + LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); - int[] beforeValues = new int[SECTION_DIAMETER*SECTION_DIAMETER]; + 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); + beforeValues[z * SECTION_DIAMETER + x] = lightHeightmap.getFirstAvailable(x, z); } } - // TODO want to optimize this - probably want to do the thing we do for other scale0 sections and store a reference to it - lightHeightmap.loadCube(this); + // TODO want to optimize this - probably want to do the thing we do for other scale0 sections and store a reference to it + 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 beforeValue = beforeValues[z * SECTION_DIAMETER + x]; int afterValue = lightHeightmap.getFirstAvailable(x, z); if (beforeValue != afterValue) { ((ISkyLightColumnChecker) chunkSource.getLightEngine()).checkSkyLightColumn((CubeMapGetter) chunk, @@ -226,9 +226,9 @@ private ChunkSource getChunkSource() { } } } - } - } - } + } + } + } } @Override public ChunkStatus getCubeStatus() { 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 index 383842924..4b8a6cea0 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientLightSurfaceTracker.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientLightSurfaceTracker.java @@ -1,7 +1,6 @@ package io.github.opencubicchunks.cubicchunks.chunk.heightmap; import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter; -import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; import io.github.opencubicchunks.cubicchunks.mixin.access.common.HeightmapAccess; import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker; import net.minecraft.client.Minecraft; @@ -26,7 +25,7 @@ public ClientLightSurfaceTracker(ChunkAccess chunkAccess) { } @Override public boolean update(int x, int y, int z, BlockState blockState) { - return false;/* + return false; /* // TODO is it safe to do this or are we risking causing cube loading, etc? int previous = getFirstAvailable(x, z); if (y <= previous - 2) { @@ -72,8 +71,8 @@ private static int getIndex(int x, int z) { @Override public void setRawData(long[] heightmap) { - throw new UnsupportedOperationException("this shouldn't be called"); - } + throw new UnsupportedOperationException("this shouldn't be called"); + } 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 BitStorage storage = ((HeightmapAccess) this).getData(); 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 index 0027a0dba..8d96fe437 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java @@ -1,5 +1,9 @@ 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; @@ -10,9 +14,6 @@ import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; -import javax.annotation.Nullable; -import java.util.Arrays; - public class LightSurfaceTrackerSection extends SurfaceTrackerSection { public LightSurfaceTrackerSection() { this(MAX_SCALE, 0, null); @@ -80,7 +81,9 @@ public int getHeight(int x, int 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 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) { 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 fc2cd028f..9757be00b 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 @@ -21,14 +21,14 @@ 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. - public static final int WIDTH_BLOCKS = 16; - protected final BitStorage heights; protected final long[] dirtyPositions; // bitset has 100% memory usage overhead due to pointers and object headers protected SurfaceTrackerSection parent; 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 41a78cda8..b0048620a 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 @@ -46,12 +46,12 @@ public boolean update(int x, int y, int z, BlockState blockState) { // 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 // return false; - // FIXME soft fail for debugging - SurfaceTrackerSection node = surfaceTracker.getCubeNode(blockToCube(y)); - if (node == null) { - System.out.println("warning: null node in surface tracker " + this); - return false; - } + // FIXME soft fail for debugging + SurfaceTrackerSection node = surfaceTracker.getCubeNode(blockToCube(y)); + if (node == null) { + System.out.println("warning: null node in surface tracker " + this); + return false; + } node.markDirty(x + dx, z + dz); return false; } 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 index 4c81b55d9..3fa35497b 100644 --- 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 @@ -1,5 +1,7 @@ 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; @@ -19,37 +21,37 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import java.util.List; - @Mixin(DebugScreenOverlay.class) public abstract class MixinDebugScreenOverlay { - @Shadow abstract LevelChunk getServerChunk(); + @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); - } + @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)"); - } - } + // 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/chunk/MixinChunk.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunk.java index 29cc9987f..a76900162 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 @@ -18,11 +18,9 @@ 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.utils.Coords; -import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker; import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor; import io.github.opencubicchunks.cubicchunks.utils.Coords; +import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerBlockEntityEvents; import net.minecraft.client.multiplayer.ClientLevel; @@ -72,6 +70,9 @@ public abstract class MixinChunk implements ChunkAccess, LightHeightmapGetter, C private boolean generates2DChunks; private WorldStyle worldStyle; + private Heightmap lightHeightmap; + private CubeMap cubeMap; + @Shadow public abstract ChunkStatus getStatus(); @Shadow protected abstract boolean isInLevel(); @@ -82,9 +83,6 @@ public abstract class MixinChunk implements ChunkAccess, LightHeightmapGetter, C return false; } - private Heightmap lightHeightmap; - private CubeMap cubeMap; - @Override public Heightmap getLightHeightmap() { if (!isCubic) { @@ -159,16 +157,16 @@ private void onSetBlock(BlockPos pos, BlockState state, boolean moved, CallbackI } // TODO client side light heightmap stuff if (this.level.isClientSide) { - ClientLightSurfaceTracker lightHeightmap = ((LightHeightmapGetter) this).getClientLightHeightmap(); + ClientLightSurfaceTracker clientLightHeightmap = ((LightHeightmapGetter) this).getClientLightHeightmap(); } else { int relX = pos.getX() & 15; int relZ = pos.getZ() & 15; - LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) this).getServerLightHeightmap(); - int oldHeight = lightHeightmap.getFirstAvailable(relX, relZ); + 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. - lightHeightmap.update(relX, pos.getY(), relZ, state); - int newHeight = lightHeightmap.getFirstAvailable(relX, relZ); + 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); } 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 9fbc3ff19..95808302f 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 @@ -1,6 +1,6 @@ package io.github.opencubicchunks.cubicchunks.mixin.core.common.chunk; -import static io.github.opencubicchunks.cubicchunks.chunk.util.Utils.*; +import static io.github.opencubicchunks.cubicchunks.chunk.util.Utils.unsafeCast; import java.util.ArrayList; import java.util.BitSet; @@ -18,8 +18,8 @@ import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; import io.github.opencubicchunks.cubicchunks.chunk.IChunkManager; import io.github.opencubicchunks.cubicchunks.chunk.ICubeHolder; -import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; 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; 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 40cfa3ff8..342906e11 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 @@ -2,23 +2,23 @@ import io.github.opencubicchunks.cubicchunks.chunk.CubeMap; import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter; -import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; -import io.github.opencubicchunks.cubicchunks.chunk.heightmap.LightSurfaceTrackerWrapper; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.chunk.ChunkAccess; 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.levelgen.Heightmap; 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; @@ -37,11 +37,11 @@ public abstract class MixinProtoChunk implements LightHeightmapGetter, LevelHeig private boolean generates2DChunks; private WorldStyle worldStyle; - @Shadow public abstract ChunkStatus getStatus(); - private LightSurfaceTrackerWrapper lightHeightmap; private CubeMap cubeMap; + @Shadow public abstract ChunkStatus getStatus(); + @Override public Heightmap getLightHeightmap() { if (!isCubic) { 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 6a38f00cc..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,9 +1,6 @@ package io.github.opencubicchunks.cubicchunks.mixin.core.common.entity; import com.mojang.authlib.GameProfile; -import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; -import io.github.opencubicchunks.cubicchunks.network.PacketDispatcher; -import io.github.opencubicchunks.cubicchunks.network.PacketUpdateLight; import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor; import net.minecraft.core.BlockPos; import net.minecraft.network.protocol.Packet; @@ -15,9 +12,7 @@ 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; @Mixin(ServerPlayer.class) public abstract class MixinServerPlayerEntity extends Player { 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/MixinLightEngine.java index 18dac6ba2..d55c6cd32 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/MixinLightEngine.java @@ -38,15 +38,15 @@ public abstract class MixinLightEngine, S exten @Shadow @Final protected LightChunkGetter chunkSource; + protected boolean isCubic; + @Shadow @Final private long[] lastChunkPos; @Shadow @Final private BlockGetter[] lastChunk; - protected boolean isCubic; - private boolean generates2DChunks; - private CubicLevelHeightAccessor.WorldStyle worldStyle; + @Shadow protected void checkNode(long id) { + } - @Shadow protected void checkNode(long id) {} @Shadow @Nullable protected abstract BlockGetter getChunk(int chunkX, int chunkZ); @Override @@ -69,8 +69,8 @@ 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(); } /** 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/MixinSectionLightStorage.java index ee435e010..a1aae6561 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/MixinSectionLightStorage.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; 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 index 8cd8977c5..79e00d48e 100644 --- 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 @@ -12,7 +12,6 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.levelgen.Heightmap; @@ -44,7 +43,7 @@ protected void checkNode(long id, CallbackInfo ci) { @Override public void checkSkyLightColumn(CubeMapGetter chunk, int x, int z, int oldHeight, int newHeight) { ((SectionLightStorageAccess) this.storage).invokeRunAllUpdates(); CubeMap cubeMap = chunk.getCubeMap(); - int oldHeightCube = Coords.blockToCube(oldHeight-1); + 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 @@ -54,7 +53,7 @@ protected void checkNode(long id, CallbackInfo ci) { // (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--) { + for (int dy = IBigCube.DIAMETER_IN_BLOCKS - 1; dy >= 0; dy--) { int y = cubeY * IBigCube.DIAMETER_IN_BLOCKS + dy; if (y >= oldHeight) { @@ -157,7 +156,7 @@ public void doSkyLightForCube(IBigCube cube) { 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(); + long pos = new BlockPos((chunkPos.x + sectionX) * 16 + x, y, (chunkPos.z + sectionZ) * 16 + z).asLong(); // Not sure if this is necessary ((SectionLightStorageAccess) this.storage).invokeRunAllUpdates(); 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 index c2fc377be..dea0f3342 100644 --- 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 @@ -55,7 +55,7 @@ private void onOnNodeRemoved(long sectionPos, CallbackInfo ci) { } @Inject(method = "enableLightSources", cancellable = true, - at = @At(value = "INVOKE", shift= At.Shift.AFTER, target="Lnet/minecraft/world/level/lighting/SkyLightSectionStorage;runAllUpdates()V")) + 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) { @@ -71,7 +71,8 @@ private void onCreateDataLayer(long sectionPos, CallbackInfoReturnable lightProvider, boolean doSkylight, boolean skipEdgeLightPropagation, CallbackInfo ci) { + private void onMarkNewInconsistencies(LayerLightEngine lightProvider, boolean doSkylight, boolean skipEdgeLightPropagation, + CallbackInfo ci) { if (!isCubic) return; ci.cancel(); super.markNewInconsistencies(lightProvider, doSkylight, skipEdgeLightPropagation); 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 eec659666..cc21005d3 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketHeightmapChanges.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/network/PacketHeightmapChanges.java @@ -2,7 +2,6 @@ import io.github.opencubicchunks.cubicchunks.CubicChunks; import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; -import io.github.opencubicchunks.cubicchunks.chunk.heightmap.ClientSurfaceTracker; import io.github.opencubicchunks.cubicchunks.mixin.access.common.HeightmapAccess; import io.github.opencubicchunks.cubicchunks.utils.AddressTools; import it.unimi.dsi.fastutil.shorts.ShortArrayList; @@ -11,7 +10,6 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; -import net.minecraft.world.level.chunk.EmptyLevelChunk; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.levelgen.Heightmap; From 34f91fdd4862e9959ea9c954c547cff75dcfc16a Mon Sep 17 00:00:00 2001 From: Barteks2x Date: Mon, 19 Apr 2021 05:16:46 +0200 Subject: [PATCH 17/39] Fix full skylight in random places --- .../core/common/world/lighting/MixinSkyLightEngine.java | 9 +++++++++ 1 file changed, 9 insertions(+) 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 index 79e00d48e..4bb803835 100644 --- 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 @@ -7,6 +7,7 @@ import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; import io.github.opencubicchunks.cubicchunks.mixin.access.common.SectionLightStorageAccess; 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.client.multiplayer.ClientLevel; @@ -14,6 +15,7 @@ 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; @@ -108,6 +110,13 @@ private void onGetComputedLevel(long id, long excludedId, int maxLevel, Callback // 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; + } + // TODO chunk is sometimes null BlockGetter chunk = this.chunkSource.getChunkForLighting(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); if (chunk == null) { From b8795f29d1db2612bd0c3e439f8bcfbc4c222a12 Mon Sep 17 00:00:00 2001 From: Corgi Taco <66983020+CorgiTaco@users.noreply.github.com> Date: Sun, 18 Apr 2021 20:39:00 -0700 Subject: [PATCH 18/39] -Make ImposterProtoChunk use LevelChunk's CubeMap and LightHeightmap --- .../chunk/LightHeightmapGetter.java | 2 ++ .../common/chunk/MixinImposterProtoChunk.java | 26 +++++++++++++++++++ .../world/lighting/MixinSkyLightEngine.java | 3 +-- .../world/lighting/ICubeLightProvider.java | 1 + .../resources/cubicchunks.mixins.core.json | 1 + 5 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinImposterProtoChunk.java diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java index d26c84eb3..bb226a025 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/LightHeightmapGetter.java @@ -7,6 +7,7 @@ public interface LightHeightmapGetter { Heightmap getLightHeightmap(); + // Do not override this default ClientLightSurfaceTracker getClientLightHeightmap() { Heightmap lightHeightmap = this.getLightHeightmap(); if (!(lightHeightmap instanceof ClientLightSurfaceTracker)) { @@ -15,6 +16,7 @@ default ClientLightSurfaceTracker getClientLightHeightmap() { return (ClientLightSurfaceTracker) lightHeightmap; } + // Do not override this default LightSurfaceTrackerWrapper getServerLightHeightmap() { Heightmap lightHeightmap = this.getLightHeightmap(); if (!(lightHeightmap instanceof LightSurfaceTrackerWrapper)) { 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/world/lighting/MixinSkyLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightEngine.java index 4bb803835..86e9a31d0 100644 --- 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 @@ -151,8 +151,7 @@ public void doSkyLightForCube(IBigCube cube) { 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 not in cubemap during sky lighting"); - cubeMap.markLoaded(cubePos.getY()); + System.out.println(cube.getCubePos() + " : Cube not in cubemap during sky lighting"); } Heightmap heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); if (heightmap == null) { 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/resources/cubicchunks.mixins.core.json b/src/main/resources/cubicchunks.mixins.core.json index 721ced532..aac7c7e31 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", From 0d87143cbcc8d0623802abb67875c8a886073b90 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Mon, 19 Apr 2021 16:48:06 +1200 Subject: [PATCH 19/39] misc cleanup --- .../cubicchunks/chunk/cube/BigCube.java | 6 +-- .../cubicchunks/chunk/cube/CubePrimer.java | 5 +-- .../heightmap/ClientLightSurfaceTracker.java | 38 ++----------------- .../heightmap/LightSurfaceTrackerSection.java | 2 +- .../heightmap/LightSurfaceTrackerWrapper.java | 1 + .../heightmap/SurfaceTrackerWrapper.java | 13 +------ .../world/lighting/MixinSkyLightEngine.java | 4 +- 7 files changed, 13 insertions(+), 56 deletions(-) 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 c2ec7d098..7750cb3fb 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 @@ -991,8 +991,7 @@ 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()) { @@ -1000,9 +999,8 @@ public void postLoad() { SurfaceTrackerWrapper tracker = (SurfaceTrackerWrapper) heightmap; tracker.loadCube(this); } - // TODO probably don't want to do this if the cube was already loaded as a CubePrimer - // TODO what should we do on the client here? 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 dbb44e1eb..a5946b202 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 @@ -192,7 +192,7 @@ private ChunkSource getChunkSource() { for (int dx = 0; dx < IBigCube.DIAMETER_IN_SECTIONS; dx++) { for (int dz = 0; dz < IBigCube.DIAMETER_IN_SECTIONS; dz++) { ChunkPos chunkPos = this.cubePos.asChunkPos(dx, dz); - // TODO chunk can be null, at least until we get the column->cube invariant + // TODO chunk can be null until load order is fixed BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x, chunkPos.z); // force-loading like this causes lighting to init incorrectly for some reason // BlockGetter chunk = chunkSource.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.EMPTY, true); @@ -261,14 +261,13 @@ private ChunkSource getChunkSource() { } BlockState lastState = section.setBlockState(x, y, z, state, false); - // TODO should this be isOrAfter LIGHT, or isOrAfter FEATURES? if (this.status.isOrAfter(ChunkStatus.LIGHT) && state != lastState && (state.getLightBlock(this, pos) != lastState.getLightBlock(this, pos) || state.getLightEmission() != lastState.getLightEmission() || state.useShapeForLightOcclusion() || lastState.useShapeForLightOcclusion())) { ChunkSource chunkSource = getChunkSource(); ChunkPos chunkPos = Coords.chunkPosByIndex(this.cubePos, index); - // TODO do we want to force-load chunks here? if not the chunk can be null, at least until we get the column->cube invariant + // TODO chunk can be null until load order is fixed BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x, chunkPos.z); LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); 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 index 4b8a6cea0..abd73801a 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientLightSurfaceTracker.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/ClientLightSurfaceTracker.java @@ -25,40 +25,7 @@ public ClientLightSurfaceTracker(ChunkAccess chunkAccess) { } @Override public boolean update(int x, int y, int z, BlockState blockState) { - return false; /* - // TODO is it safe to do this or are we risking causing cube loading, etc? - int previous = getFirstAvailable(x, z); - if (y <= previous - 2) { - return false; - } - ChunkAccess chunk = ((HeightmapAccess) this).getChunk(); - BlockPos blockPos = new BlockPos(x, y, z); - BlockPos abovePos = new BlockPos(x, y+1, z); - BlockState above = chunk.getBlockState(abovePos); - int lightBlock = blockState.getLightBlock(chunk, blockPos); - if (lightBlock > 0 || (above != null && Shapes.faceShapeOccludes(getShape(above, abovePos, Direction.DOWN), getShape(blockState, blockPos, Direction.UP)))) { - if (y >= previous) { - ((HeightmapAccess) this).invokeSetHeight(x, z, y + 1); - return true; - } - return true; - } - if (previous - 1 == y) { - BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); - - int currentY; - for (currentY = y - 1; currentY >= y - 64; --currentY) { - pos.set(x, currentY, z); - // TODO copy the face shape occlusion logic here too - I'm too lazy for now. - if (blockState.getLightBlock(chunk, pos) > 0) { - ((HeightmapAccess) this).invokeSetHeight(x, z, currentY + 1); - return true; - } - } - ((HeightmapAccess) this).invokeSetHeight(x, z, currentY); - return true; - } - return false;*/ + throw new UnsupportedOperationException("ClientLightSurfaceTracker.update should never be called"); } protected VoxelShape getShape(BlockState blockState, BlockPos pos, Direction facing) { @@ -71,10 +38,11 @@ private static int getIndex(int x, int z) { @Override public void setRawData(long[] heightmap) { - throw new UnsupportedOperationException("this shouldn't be called"); + throw new UnsupportedOperationException("ClientLightSurfaceTracker.setRawData(heightmap) shouldn't be called"); } 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); 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 index 8d96fe437..404693bf8 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java @@ -52,7 +52,7 @@ protected SurfaceTrackerSection loadNode(int newScaledY, int sectionScale, IBigC @Nullable private LightSurfaceTrackerSection getSectionAbove() { if (scale != 0) { - throw new IllegalArgumentException("TODO put an actual error message here - also this probably shouldn't be an IllegalArgumentException"); + 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); 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 index 23c80a0d3..ed6d954c5 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerWrapper.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerWrapper.java @@ -29,6 +29,7 @@ public boolean update(int x, int y, int z, BlockState blockState) { } } + // Return value is unused return false; } } 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 b0048620a..8b71706b6 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 @@ -42,17 +42,8 @@ protected SurfaceTrackerWrapper(ChunkAccess chunkAccess, Types types, SurfaceTra */ @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 -// return false; - // FIXME soft fail for debugging - SurfaceTrackerSection node = surfaceTracker.getCubeNode(blockToCube(y)); - if (node == null) { - System.out.println("warning: null node in surface tracker " + this); - return false; - } - node.markDirty(x + dx, z + dz); + surfaceTracker.getCubeNode(blockToCube(y)).markDirty(x + dx, z + dz); + // We always return false, because the result is never used anywhere anyway (by either vanilla or us) return false; } 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 index 86e9a31d0..ccc809023 100644 --- 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 @@ -117,7 +117,7 @@ private void onGetComputedLevel(long id, long excludedId, int maxLevel, Callback return; } - // TODO chunk is sometimes null + // TODO chunk can be null until load order is fixed BlockGetter chunk = this.chunkSource.getChunkForLighting(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); if (chunk == null) { System.out.println("onGetComputedLevel chunk was null " + (this.chunkSource.getLevel() instanceof ClientLevel ? "client" : "server")); @@ -142,7 +142,7 @@ public void doSkyLightForCube(IBigCube cube) { int maxY = cubePos.maxCubeY(); for (int sectionX = 0; sectionX < IBigCube.DIAMETER_IN_SECTIONS; sectionX++) { for (int sectionZ = 0; sectionZ < IBigCube.DIAMETER_IN_SECTIONS; sectionZ++) { - // TODO this chunk is sometimes null + // TODO chunk can be null until load order is fixed BlockGetter chunk = this.chunkSource.getChunkForLighting(chunkPos.x + sectionX, chunkPos.z + sectionZ); if (chunk == null) { System.out.println("null chunk in MixinSkyLightEngine.doSkyLightForCube"); From a9128edbf103498184726f72e5d5242beebd41d0 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Mon, 19 Apr 2021 23:45:32 +1200 Subject: [PATCH 20/39] replace LayerLightEngine.getStateAndOpacity inject with a redirect --- .../world/lighting/MixinLightEngine.java | 50 ++++--------------- 1 file changed, 9 insertions(+), 41 deletions(-) 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/MixinLightEngine.java index d55c6cd32..8769a220c 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/MixinLightEngine.java @@ -14,18 +14,16 @@ 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; @@ -73,46 +71,16 @@ private void setCubic(LightChunkGetter lightChunkGetter, LightLayer lightLayer, // 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 From b58077c287a46c415db1162aa80a22d7c445d4f6 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Tue, 20 Apr 2021 16:39:36 +1200 Subject: [PATCH 21/39] mixin to remove unnecessary skylight logic --- .../MixinDynamicGraphMinFixedPoint.java | 2 + .../world/lighting/MixinSkyLightEngine.java | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+) 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 index 975448e33..adf46e6a1 100644 --- 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 @@ -6,6 +6,8 @@ @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/MixinSkyLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightEngine.java index ccc809023..673f1ba7f 100644 --- 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 @@ -1,5 +1,7 @@ package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting; +import static net.minecraft.client.renderer.LevelRenderer.DIRECTIONS; + import io.github.opencubicchunks.cubicchunks.chunk.CubeMap; import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter; import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; @@ -12,6 +14,7 @@ import io.github.opencubicchunks.cubicchunks.world.lighting.ISkyLightColumnChecker; import net.minecraft.client.multiplayer.ClientLevel; 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; @@ -178,4 +181,38 @@ public void doSkyLightForCube(IBigCube cube) { } } } + + /** + * @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 || (((SectionLightStorageAccess) 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); + } + } } From fe61e37f8dc9066a9af3075d570a6cf2be7b56da Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Wed, 21 Apr 2021 12:57:07 +1200 Subject: [PATCH 22/39] fix no skylight in sections without skylight storage --- .../common/SectionLightStorageAccess.java | 4 +++ .../lighting/MixinSkyLightSectionStorage.java | 30 ++++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) 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/SectionLightStorageAccess.java index 794306e9e..c6d1c6742 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/SectionLightStorageAccess.java @@ -1,7 +1,9 @@ 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) @@ -12,4 +14,6 @@ public interface SectionLightStorageAccess { @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/core/common/world/lighting/MixinSkyLightSectionStorage.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinSkyLightSectionStorage.java index dea0f3342..d1ac54422 100644 --- 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 @@ -1,11 +1,16 @@ package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting; +import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; +import io.github.opencubicchunks.cubicchunks.mixin.access.common.SectionLightStorageAccess; import io.github.opencubicchunks.cubicchunks.server.CubicLevelHeightAccessor; +import io.github.opencubicchunks.cubicchunks.utils.Coords; 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.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; @@ -36,10 +41,27 @@ private void onGetLightValue(long blockPos, boolean cached, CallbackInfoReturnab // since we don't need sky light logic long l = SectionPos.blockToSection(blockPos); DataLayer dataLayer = this.getDataLayer(l, cached); - cir.setReturnValue(dataLayer == null ? 0 : dataLayer.get( - SectionPos.sectionRelative(BlockPos.getX(blockPos)), - SectionPos.sectionRelative(BlockPos.getY(blockPos)), - SectionPos.sectionRelative(BlockPos.getZ(blockPos)))); + int x = BlockPos.getX(blockPos); + int y = BlockPos.getY(blockPos); + int z = BlockPos.getZ(blockPos); + if (dataLayer == null) { + BlockGetter chunk = ((SectionLightStorageAccess) this).getChunkSource().getChunkForLighting(Coords.blockToSection(x), Coords.blockToSection(z)); + if (chunk == null) { + // TODO This currently gets called a lot; not sure if it's due to broken load order or this method being called before the lighting stage or in unloaded chunks/cubes +// System.out.println("Null chunk (" + Coords.blockToSection(x) + ", " + Coords.blockToSection(z) + ") in MixinSkyLightSectionStorage.onGetLightValue " +// + ((SectionLightStorageAccess) this).getChunkSource().getLevel()); + 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")) From c10223174abb0d7c3b6c9d10709edd8c32767c11 Mon Sep 17 00:00:00 2001 From: Corgi Taco <66983020+CorgiTaco@users.noreply.github.com> Date: Tue, 20 Apr 2021 18:04:57 -0700 Subject: [PATCH 23/39] -Allow getComputedLevel to run on the client -CHeck if a cube is either null or before light status --- .../world/lighting/MixinSkyLightEngine.java | 24 ++++++++++--------- .../lighting/MixinSkyLightSectionStorage.java | 19 +++++++++++++-- 2 files changed, 30 insertions(+), 13 deletions(-) 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 index 673f1ba7f..6e0bea471 100644 --- 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 @@ -111,7 +111,9 @@ private void addEmissionAtPos(long pos) { 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; + if (!this.isCubic /*|| this.chunkSource.getLevel() instanceof ClientLevel*/) { + return; + } BlockPos pos = BlockPos.of(id); BlockGetter cube = ((ICubeLightProvider) this.chunkSource).getCubeForLighting( @@ -205,14 +207,14 @@ private void onCheckNeighborsAfterUpdate(long blockPos, int level, boolean decre } } - /** - * @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); - } - } +// /** +// * @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 index d1ac54422..ba4666fe3 100644 --- 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 @@ -1,13 +1,16 @@ 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.SectionLightStorageAccess; 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; @@ -25,7 +28,7 @@ public abstract class MixinSkyLightSectionStorage extends LayerLightSectionStora private boolean isCubic; private MixinSkyLightSectionStorage(LightLayer lightLayer, LightChunkGetter lightChunkGetter, - SkyLightSectionStorage.SkyDataLayerStorageMap dataLayerStorageMap) { + SkyLightSectionStorage.SkyDataLayerStorageMap dataLayerStorageMap) { super(lightLayer, lightChunkGetter, dataLayerStorageMap); } @@ -36,7 +39,10 @@ private void onInit(LightChunkGetter lightChunkGetter, CallbackInfo ci) { @Inject(method = "getLightValue(JZ)I", cancellable = true, at = @At("HEAD")) private void onGetLightValue(long blockPos, boolean cached, CallbackInfoReturnable cir) { - if (!isCubic) return; + 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); @@ -53,6 +59,15 @@ private void onGetLightValue(long blockPos, boolean cached, CallbackInfoReturnab cir.setReturnValue(0); return; } + + //TODO: Optimize + BlockGetter cube = ((ICubeLightProvider) ((SectionLightStorageAccess) 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); From 3d43648a039842d5bce596d553e38269071f7065 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Wed, 21 Apr 2021 14:32:00 +1200 Subject: [PATCH 24/39] rename some lighting mixins to match mojang mappings --- ....java => LayerLightSectionStorageAccess.java} | 2 +- .../world/lighting/MixinBlockLightEngine.java | 2 +- ...ghtEngine.java => MixinLayerLightEngine.java} | 6 +++--- ...e.java => MixinLayerLightSectionStorage.java} | 4 ++-- .../world/lighting/MixinSkyLightEngine.java | 16 ++++++++-------- .../lighting/MixinSkyLightSectionStorage.java | 6 +++--- .../resources/cubicchunks.mixins.access.json | 2 +- src/main/resources/cubicchunks.mixins.core.json | 4 ++-- 8 files changed, 21 insertions(+), 21 deletions(-) rename src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/{SectionLightStorageAccess.java => LayerLightSectionStorageAccess.java} (92%) rename src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/{MixinLightEngine.java => MixinLayerLightEngine.java} (93%) rename src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/{MixinSectionLightStorage.java => MixinLayerLightSectionStorage.java} (97%) 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 92% 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 c6d1c6742..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 @@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(LayerLightSectionStorage.class) -public interface SectionLightStorageAccess { +public interface LayerLightSectionStorageAccess { @Invoker("enableLightSources") void invokeSetColumnEnabled(long seed, boolean enable); 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 d7f60d30a..20ffc5885 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 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @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/MixinLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinLayerLightEngine.java similarity index 93% 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 8769a220c..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; @@ -28,7 +28,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(LayerLightEngine.class) -public abstract class MixinLightEngine, S extends LayerLightSectionStorage> extends MixinDynamicGraphMinFixedPoint implements ILightEngine { +public abstract class MixinLayerLightEngine, S extends LayerLightSectionStorage> extends MixinDynamicGraphMinFixedPoint implements ILightEngine { @Shadow @Final protected S storage; @@ -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); } } } 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 97% 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 a1aae6561..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 @@ -24,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; @@ -37,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_); } 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 index 6e0bea471..b872494f2 100644 --- 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 @@ -7,7 +7,7 @@ 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.SectionLightStorageAccess; +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; @@ -29,7 +29,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(SkyLightEngine.class) -public abstract class MixinSkyLightEngine extends MixinLightEngine implements ISkyLightColumnChecker, +public abstract class MixinSkyLightEngine extends MixinLayerLightEngine implements ISkyLightColumnChecker, ICubicSkyLightEngine { /** * @author CursedFlames @@ -46,13 +46,13 @@ protected void checkNode(long id, CallbackInfo ci) { /** all parameters are global coordinates */ @Override public void checkSkyLightColumn(CubeMapGetter chunk, int x, int z, int oldHeight, int newHeight) { - ((SectionLightStorageAccess) this.storage).invokeRunAllUpdates(); + ((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 - ((SectionLightStorageAccess) this.storage).invokeRunAllUpdates(); + ((LayerLightSectionStorageAccess) this.storage).invokeRunAllUpdates(); // TODO cube iteration order might still be important here // (int y = oldHeight-1; y >= newHeight; y--) @@ -69,7 +69,7 @@ protected void checkNode(long id, CallbackInfo ci) { } long pos = new BlockPos(x, y, z).asLong(); - if (((SectionLightStorageAccess) this.storage).invokeStoringLightForSection(SectionPos.blockToSection(pos))) { + if (((LayerLightSectionStorageAccess) this.storage).invokeStoringLightForSection(SectionPos.blockToSection(pos))) { addEmissionAtPos(pos); } } @@ -171,9 +171,9 @@ public void doSkyLightForCube(IBigCube cube) { 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 - ((SectionLightStorageAccess) this.storage).invokeRunAllUpdates(); + ((LayerLightSectionStorageAccess) this.storage).invokeRunAllUpdates(); - if (((SectionLightStorageAccess) this.storage).invokeStoringLightForSection(SectionPos.blockToSection(pos))) { + if (((LayerLightSectionStorageAccess) this.storage).invokeStoringLightForSection(SectionPos.blockToSection(pos))) { addEmissionAtPos(pos); } } @@ -201,7 +201,7 @@ private void onCheckNeighborsAfterUpdate(long blockPos, int level, boolean decre long offsetBlockPos = BlockPos.offset(blockPos, direction); long offsetSectionPos = SectionPos.blockToSection(offsetBlockPos); // Check all neighbors that are storing light - if (sectionPos == offsetSectionPos || (((SectionLightStorageAccess) this.storage)).invokeStoringLightForSection(offsetSectionPos)) { + if (sectionPos == offsetSectionPos || (((LayerLightSectionStorageAccess) this.storage)).invokeStoringLightForSection(offsetSectionPos)) { this.checkNeighbor(blockPos, offsetBlockPos, level, decrease); } } 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 index ba4666fe3..63960a0dd 100644 --- 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 @@ -2,7 +2,7 @@ import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; import io.github.opencubicchunks.cubicchunks.chunk.LightHeightmapGetter; -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.utils.Coords; import io.github.opencubicchunks.cubicchunks.world.lighting.ICubeLightProvider; @@ -51,7 +51,7 @@ private void onGetLightValue(long blockPos, boolean cached, CallbackInfoReturnab int y = BlockPos.getY(blockPos); int z = BlockPos.getZ(blockPos); if (dataLayer == null) { - BlockGetter chunk = ((SectionLightStorageAccess) this).getChunkSource().getChunkForLighting(Coords.blockToSection(x), Coords.blockToSection(z)); + BlockGetter chunk = ((LayerLightSectionStorageAccess) this).getChunkSource().getChunkForLighting(Coords.blockToSection(x), Coords.blockToSection(z)); if (chunk == null) { // TODO This currently gets called a lot; not sure if it's due to broken load order or this method being called before the lighting stage or in unloaded chunks/cubes // System.out.println("Null chunk (" + Coords.blockToSection(x) + ", " + Coords.blockToSection(z) + ") in MixinSkyLightSectionStorage.onGetLightValue " @@ -61,7 +61,7 @@ private void onGetLightValue(long blockPos, boolean cached, CallbackInfoReturnab } //TODO: Optimize - BlockGetter cube = ((ICubeLightProvider) ((SectionLightStorageAccess) this).getChunkSource()).getCubeForLighting( + 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); diff --git a/src/main/resources/cubicchunks.mixins.access.json b/src/main/resources/cubicchunks.mixins.access.json index 1302f606f..eb74f63da 100644 --- a/src/main/resources/cubicchunks.mixins.access.json +++ b/src/main/resources/cubicchunks.mixins.access.json @@ -17,6 +17,7 @@ "common.DecorationContextAccess", "common.EntityTrackerAccess", "common.HeightmapAccess", + "common.LayerLightSectionStorageAccess", "common.LevelBasedGraphAccess", "common.Matrix4fAccess", "common.NaturalSpawnerAccess", @@ -25,7 +26,6 @@ "common.PlayerChunkTrackerFactoryAccess", "common.PlayerTicketTrackerFactoryAccess", "common.ProtoTickListAccess", - "common.SectionLightStorageAccess", "common.SpawnStateAccess", "common.StructureFeatureManagerAccess", "common.TicketAccess", diff --git a/src/main/resources/cubicchunks.mixins.core.json b/src/main/resources/cubicchunks.mixins.core.json index f9916cf81..0165b7196 100644 --- a/src/main/resources/cubicchunks.mixins.core.json +++ b/src/main/resources/cubicchunks.mixins.core.json @@ -56,9 +56,9 @@ "common.world.feature.range.MixinRandomPatchFeature", "common.world.lighting.MixinBlockLightEngine", "common.world.lighting.MixinDynamicGraphMinFixedPoint", + "common.world.lighting.MixinLayerLightEngine", + "common.world.lighting.MixinLayerLightSectionStorage", "common.world.lighting.MixinLevelLightEngine", - "common.world.lighting.MixinLightEngine", - "common.world.lighting.MixinSectionLightStorage", "common.world.lighting.MixinSkyLightEngine", "common.world.lighting.MixinSkyLightSectionStorage", "common.world.lighting.MixinThreadedLevelLightEngine", From 126db8ac87b3c4467113a7de76349a9966ea5fc9 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Fri, 23 Apr 2021 18:00:27 +1200 Subject: [PATCH 25/39] store light heightmap sections on CubePrimer and BigCube, and make light heightmap handle upgrade from CubePrimer to BigCube --- .../cubicchunks/chunk/IBigCube.java | 4 ++++ .../cubicchunks/chunk/cube/BigCube.java | 12 ++++++++++++ .../cubicchunks/chunk/cube/CubePrimer.java | 14 +++++++++++++- .../heightmap/LightSurfaceTrackerSection.java | 16 ++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) 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..8f20c6bfb 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 loadLightHeightmapSection(LightSurfaceTrackerSection section, int localSectionX, int localSectionZZ) { + } } \ No newline at end of file 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 aac391075..dc02a873e 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 @@ -24,6 +24,7 @@ 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; @@ -112,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; @@ -220,6 +222,16 @@ 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; } 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 6a7b98f8b..c0a2cb3f8 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 @@ -23,6 +23,7 @@ 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; @@ -81,6 +82,8 @@ public class CubePrimer extends ProtoChunk implements IBigCube, CubicLevelHeight private final Map heightmaps; + private final LightSurfaceTrackerSection[] lightHeightmaps = new LightSurfaceTrackerSection[4]; + private final List entities = Lists.newArrayList(); private final Map tileEntities = Maps.newHashMap(); @@ -213,7 +216,6 @@ public void setCubeStatus(ChunkStatus newStatus) { } } - // TODO want to optimize this - probably want to do the thing we do for other scale0 sections and store a reference to it lightHeightmap.loadCube(this); for (int z = 0; z < SECTION_DIAMETER; z++) { @@ -231,6 +233,16 @@ public void setCubeStatus(ChunkStatus newStatus) { } } + @Override public void loadLightHeightmapSection(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() { return this.status; } 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 index 404693bf8..33f9e009b 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java @@ -121,6 +121,20 @@ public int getHeight(int x, int z) { } } + /** + * 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) { @@ -130,6 +144,8 @@ public void loadCube(int sectionX, int sectionZ, IBigCube newCube, boolean markD 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.loadLightHeightmapSection(this, sectionX, sectionZ); return; } int idx = indexOfRawHeightNode(newCube.getCubePos().getY(), scale, scaledY); From 4e2f802b664baae9ecb65b7ff976715e37360b02 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Fri, 23 Apr 2021 18:11:46 +1200 Subject: [PATCH 26/39] implement loadLightHeightmapSection on BigCube too --- .../opencubicchunks/cubicchunks/chunk/cube/BigCube.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 dc02a873e..9011caf36 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 @@ -236,6 +236,12 @@ public BigCube(Level worldIn, CubePrimer cubePrimer, @Nullable Consumer this.dirty = true; } + @Override public void loadLightHeightmapSection(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"); } From 5e6659d48717c0f2d8c1c744111ca87e39076709 Mon Sep 17 00:00:00 2001 From: Corgi Taco <66983020+CorgiTaco@users.noreply.github.com> Date: Thu, 13 May 2021 20:12:12 -0700 Subject: [PATCH 27/39] -Fix client and server siding --- .../common/world/lighting/MixinSkyLightEngine.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) 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 index b872494f2..5ce821f1c 100644 --- 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 @@ -1,6 +1,5 @@ package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.lighting; -import static net.minecraft.client.renderer.LevelRenderer.DIRECTIONS; import io.github.opencubicchunks.cubicchunks.chunk.CubeMap; import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter; @@ -12,17 +11,19 @@ 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.client.multiplayer.ClientLevel; 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.Level; 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; @@ -31,6 +32,8 @@ @Mixin(SkyLightEngine.class) public abstract class MixinSkyLightEngine extends MixinLayerLightEngine implements ISkyLightColumnChecker, ICubicSkyLightEngine { + @Shadow @Final private static Direction[] HORIZONTALS; + /** * @author CursedFlames * @reason disable vanilla sky light logic @@ -125,12 +128,12 @@ private void onGetComputedLevel(long id, long excludedId, int maxLevel, Callback // TODO chunk can be null until load order is fixed BlockGetter chunk = this.chunkSource.getChunkForLighting(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); if (chunk == null) { - System.out.println("onGetComputedLevel chunk was null " + (this.chunkSource.getLevel() instanceof ClientLevel ? "client" : "server")); + System.out.println("onGetComputedLevel chunk was null " + (((Level) this.chunkSource.getLevel()).isClientSide ? "client" : "server")); return; } Heightmap heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); if (heightmap == null) { - System.out.println("onGetComputedLevel heightmap was null " + (this.chunkSource.getLevel() instanceof ClientLevel ? "client" : "server")); + System.out.println("onGetComputedLevel heightmap was null " + (((Level) this.chunkSource.getLevel()).isClientSide ? "client" : "server")); return; } int height = heightmap.getFirstAvailable(pos.getX() & 0xF, pos.getZ() & 0xF); @@ -197,7 +200,7 @@ private void onCheckNeighborsAfterUpdate(long blockPos, int level, boolean decre long sectionPos = SectionPos.blockToSection(blockPos); - for (Direction direction : DIRECTIONS) { + for (Direction direction : HORIZONTALS) { long offsetBlockPos = BlockPos.offset(blockPos, direction); long offsetSectionPos = SectionPos.blockToSection(offsetBlockPos); // Check all neighbors that are storing light From 949e7e9f0c9ad63ac56215c2bdba499ff0fa9372 Mon Sep 17 00:00:00 2001 From: Corgi Taco <66983020+CorgiTaco@users.noreply.github.com> Date: Thu, 13 May 2021 21:13:52 -0700 Subject: [PATCH 28/39] -Make SkyDataLayerStorageMap non protected --- src/main/resources/cubicchunks.accesswidener | 1 + 1 file changed, 1 insertion(+) 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 From 6dde09dbc03a4b18cd4ec497fe5128a94ec957c7 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Thu, 20 May 2021 04:28:50 +0100 Subject: [PATCH 29/39] Revert "[1.17] Columns before cubes load order (#671)" --- .../cubicchunks/chunk/IChunkManager.java | 3 - .../cubicchunks/chunk/ICubeHolder.java | 4 -- .../core/common/MixinServerChunkProvider.java | 48 -------------- .../core/common/chunk/MixinChunkHolder.java | 33 +--------- .../core/common/chunk/MixinChunkManager.java | 41 ++---------- .../common/ticket/MixinTicketManager.java | 63 +------------------ .../server/IServerChunkProvider.java | 4 -- 7 files changed, 9 insertions(+), 187 deletions(-) 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..42f106a4b 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunkManager.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunkManager.java @@ -15,7 +15,6 @@ import it.unimi.dsi.fastutil.longs.LongSet; import net.minecraft.core.SectionPos; import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.chunk.ChunkStatus; @@ -121,6 +120,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/mixin/core/common/MixinServerChunkProvider.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/MixinServerChunkProvider.java index bb5872678..5950c5a0b 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 @@ -6,14 +6,11 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.Supplier; import javax.annotation.Nullable; -import com.mojang.datafixers.DataFixer; import com.mojang.datafixers.util.Either; import io.github.opencubicchunks.cubicchunks.CubicChunks; import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; @@ -41,20 +38,13 @@ import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.TicketType; -import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.NaturalSpawner; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.entity.ChunkStatusUpdateListener; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; -import net.minecraft.world.level.storage.DimensionDataStorage; import net.minecraft.world.level.storage.LevelData; -import net.minecraft.world.level.storage.LevelStorageSource; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -85,33 +75,6 @@ public abstract class MixinServerChunkProvider implements IServerChunkProvider, @Shadow public abstract int getLoadedChunksCount(); - @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; - } - @Override public void addCubeRegionTicket(TicketType type, CubePos pos, int distance, T value) { ((ITicketManager) this.distanceManager).addCubeRegionTicket(type, pos, distance, value); @@ -263,17 +226,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); 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 484fc6f68..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 @@ -79,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 @@ -312,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); 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 d8b94fcf4..e90aac8d9 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 @@ -582,54 +582,21 @@ 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(); if (chunkStatusIn == ChunkStatus.EMPTY) { - return chainFutures(() -> scheduleCubeLoad(cubePos), ((ICubeHolder) cubeHolder).getChunkHolders(), chunkStatusIn); + return this.scheduleCubeLoad(cubePos); } else { - CompletableFuture> completablefuture = chainFutures( - () -> ((ICubeHolder) cubeHolder).getOrScheduleCubeFuture(chunkStatusIn.getParent(), (ChunkMap) (Object) this), ((ICubeHolder) cubeHolder).getChunkHolders(), chunkStatusIn); + CompletableFuture> completablefuture = Utils.unsafeCast( + ((ICubeHolder) cubeHolder).getOrScheduleCubeFuture(chunkStatusIn.getParent(), (ChunkMap) (Object) this) + ); return completablefuture.thenComposeAsync( (Either inputSection) -> { Optional optional = inputSection.left(); 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..1b7b998d4 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,12 @@ 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 org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -53,6 +50,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,28 +68,10 @@ 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); - @Inject(method = "", at = @At("RETURN")) public void init(Executor executor, Executor executor2, CallbackInfo ci) { ProcessorHandle itaskexecutor = ProcessorHandle.of("player ticket throttler", executor2::execute); @@ -129,45 +111,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/server/IServerChunkProvider.java b/src/main/java/io/github/opencubicchunks/cubicchunks/server/IServerChunkProvider.java index ee3bbffbe..63d4d2ed8 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/server/IServerChunkProvider.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/server/IServerChunkProvider.java @@ -9,12 +9,8 @@ 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.ChunkStatus; public interface IServerChunkProvider extends ICubeProvider { - ChunkHolder getChunkHolderForce(ChunkPos chunkPos, ChunkStatus requiredStatus); - void addCubeRegionTicket(TicketType type, CubePos pos, int distance, T value); int getTickingGeneratedCubes(); From 57c1c88a3031491c4c967f0e5389e7597f651015 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Fri, 21 May 2021 02:37:16 +0100 Subject: [PATCH 30/39] base load order + unload order --- .../cubicchunks/chunk/IChunkManager.java | 2 + .../cubicchunks/chunk/graph/CCTicketType.java | 3 + .../access/common/ChunkManagerAccess.java | 2 + .../ThreadedLevelLightEngineAccess.java | 14 ++++ .../mixin/access/common/TicketAccess.java | 3 + .../access/common/TicketManagerAccess.java | 4 ++ .../core/common/MixinMinecraftServer.java | 6 +- .../core/common/MixinServerChunkProvider.java | 43 ++++++++++++ .../core/common/chunk/MixinChunkManager.java | 70 +++++++++++++------ .../core/common/chunk/MixinChunkStatus.java | 7 ++ .../debug/client/MixinLevelRenderer.java | 4 +- .../server/IServerChunkProvider.java | 3 + .../resources/cubicchunks.mixins.access.json | 3 +- 13 files changed, 138 insertions(+), 26 deletions(-) create mode 100644 src/main/java/io/github/opencubicchunks/cubicchunks/mixin/access/common/ThreadedLevelLightEngineAccess.java 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 42f106a4b..3f13b6d4e 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunkManager.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IChunkManager.java @@ -15,6 +15,7 @@ import it.unimi.dsi.fastutil.longs.LongSet; import net.minecraft.core.SectionPos; import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.chunk.ChunkStatus; @@ -29,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 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..d08ca6949 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 @@ -5,6 +5,7 @@ import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; import io.github.opencubicchunks.cubicchunks.mixin.access.common.TicketTypeAccess; import net.minecraft.server.level.TicketType; +import net.minecraft.world.level.ChunkPos; public class CCTicketType { public static final TicketType CCPLAYER = create("player", Comparator.comparingLong(CubePos::asLong)); @@ -12,6 +13,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/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/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/common/MixinMinecraftServer.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/MixinMinecraftServer.java index b755a5c0b..b9fab275f 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 @@ -68,10 +68,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 5950c5a0b..4281debd3 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 @@ -6,11 +6,14 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; import javax.annotation.Nullable; +import com.mojang.datafixers.DataFixer; import com.mojang.datafixers.util.Either; import io.github.opencubicchunks.cubicchunks.CubicChunks; import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; @@ -38,13 +41,20 @@ import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.TicketType; +import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.NaturalSpawner; import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.entity.ChunkStatusUpdateListener; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; +import net.minecraft.world.level.storage.DimensionDataStorage; import net.minecraft.world.level.storage.LevelData; +import net.minecraft.world.level.storage.LevelStorageSource; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -75,6 +85,10 @@ public abstract class MixinServerChunkProvider implements IServerChunkProvider, @Shadow public abstract int getLoadedChunksCount(); + @Shadow @org.jetbrains.annotations.Nullable protected abstract ChunkHolder getVisibleChunkIfPresent(long pos); + + @Shadow abstract boolean runDistanceManagerUpdates(); + @Override public void addCubeRegionTicket(TicketType type, CubePos pos, int distance, T value) { ((ITicketManager) this.distanceManager).addCubeRegionTicket(type, pos, distance, value); @@ -169,6 +183,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) { @@ -270,6 +307,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/MixinChunkManager.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/chunk/MixinChunkManager.java index e90aac8d9..6534a7d1b 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; @@ -17,6 +15,7 @@ import java.util.concurrent.CompletionStage; 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; @@ -58,6 +57,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; @@ -98,6 +99,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; @@ -120,7 +122,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; @@ -150,6 +151,8 @@ public abstract class MixinChunkManager implements IChunkManager, IChunkMapInter private final LongSet cubeEntitiesInLevel = new LongOpenHashSet(); private final Long2ObjectLinkedOpenHashMap pendingCubeUnloads = new Long2ObjectLinkedOpenHashMap<>(); + private static final Executor columnLoadingExecutor = Executors.newSingleThreadExecutor(); + // field_219264_r, worldgenMailbox private ProcessorHandle> cubeWorldgenMailbox; // field_219265_s, mainThreadMailbox @@ -318,7 +321,7 @@ protected void save(boolean flush, CallbackInfo ci) { } - public void setServerChunkCache(ServerChunkCache cache) { + @Override public void setServerChunkCache(ServerChunkCache cache) { serverChunkCache = cache; } @@ -470,7 +473,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); + } + } + } } } @@ -597,7 +611,10 @@ public CompletableFuture> sche CompletableFuture> completablefuture = Utils.unsafeCast( ((ICubeHolder) cubeHolder).getOrScheduleCubeFuture(chunkStatusIn.getParent(), (ChunkMap) (Object) this) ); - return completablefuture.thenComposeAsync( + return completablefuture.thenApplyAsync((either) -> { + scheduleAndWaitForColumns(chunkStatusIn, cubePos); + return either; + }, columnLoadingExecutor).thenComposeAsync( (Either inputSection) -> { Optional optional = inputSection.left(); if (!optional.isPresent()) { @@ -638,12 +655,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)); @@ -651,9 +664,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) { @@ -664,13 +676,31 @@ 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 void scheduleAndWaitForColumns(ChunkStatus chunkStatusIn, CubePos cubePos) { + 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).join().join(); } // 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 d68bd7597..6db427654 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 @@ -15,7 +15,9 @@ import io.github.opencubicchunks.cubicchunks.chunk.biome.ColumnBiomeContainer; import io.github.opencubicchunks.cubicchunks.chunk.cube.CubePrimer; import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; +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.world.CubeWorldGenRegion; import io.github.opencubicchunks.cubicchunks.world.server.IServerWorldLightManager; @@ -23,6 +25,7 @@ import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.StructureFeatureManager; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkGenerator; @@ -394,6 +397,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/debug/client/MixinLevelRenderer.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/debug/client/MixinLevelRenderer.java index 4d92eab6b..0be108756 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 @@ -64,8 +64,8 @@ public void render(PoseStack matrices, float tickDelta, long limitTime, boolean LevelLoadingScreen.class, null, "COLORS" // TODO: intermediary name ); - int renderRadius = 5; - int chunkRenderRadius = renderRadius * IBigCube.DIAMETER_IN_SECTIONS; + int renderRadius = 1; + int chunkRenderRadius = 100; //renderRadius * IBigCube.DIAMETER_IN_SECTIONS; Long2ObjectLinkedOpenHashMap loadedColumns = getField(ChunkMap.class, levelAccessor.getChunkSource().chunkMap, "updatingChunkMap"); Object[] data = getField(Long2ObjectLinkedOpenHashMap.class, loadedColumns, "value"); 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 63d4d2ed8..6405c1502 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/server/IServerChunkProvider.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/server/IServerChunkProvider.java @@ -9,6 +9,8 @@ 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.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; public interface IServerChunkProvider extends ICubeProvider { void addCubeRegionTicket(TicketType type, CubePos pos, int distance, T value); @@ -17,6 +19,7 @@ public interface IServerChunkProvider extends ICubeProvider { void forceCube(CubePos pos, boolean add); + CompletableFuture> getColumnFutureForCube(CubePos cubePos, int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create); boolean isEntityTickingCube(CubePos pos); boolean checkCubeFuture(long cubePosLong, Function>> futureFunction); diff --git a/src/main/resources/cubicchunks.mixins.access.json b/src/main/resources/cubicchunks.mixins.access.json index fecb13a60..b5ac5534c 100644 --- a/src/main/resources/cubicchunks.mixins.access.json +++ b/src/main/resources/cubicchunks.mixins.access.json @@ -32,7 +32,8 @@ "common.TicketAccess", "common.TicketManagerAccess", "common.TicketTypeAccess", - "common.VerticalAnchorAccess" + "common.VerticalAnchorAccess", + "common.ThreadedLevelLightEngineAccess" ], "client": [ "client.ChunkRenderDispatcherAccess", From 4b9f2559a19d6c933ed0f5466c6618820b366376 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Fri, 21 May 2021 05:07:14 +0100 Subject: [PATCH 31/39] Fix future chain order --- .../cubicchunks/chunk/graph/CCTicketType.java | 1 - .../core/common/chunk/MixinChunkManager.java | 26 +++++++++---------- .../MixinThreadedLevelLightEngine.java | 8 ++++++ .../debug/client/MixinLevelRenderer.java | 15 ++++++----- .../debug/common/MixinDistanceManager.java | 3 ++- .../debug/common/MixinMinecraftServer.java | 10 +++---- 6 files changed, 37 insertions(+), 26 deletions(-) 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 d08ca6949..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 @@ -5,7 +5,6 @@ import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; import io.github.opencubicchunks.cubicchunks.mixin.access.common.TicketTypeAccess; import net.minecraft.server.level.TicketType; -import net.minecraft.world.level.ChunkPos; public class CCTicketType { public static final TicketType CCPLAYER = create("player", Comparator.comparingLong(CubePos::asLong)); 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 6534a7d1b..c616b6f12 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 @@ -139,6 +139,8 @@ public abstract class MixinChunkManager implements IChunkManager, IChunkMapInter private static final double TICK_UPDATE_DISTANCE = 128.0; private static final boolean USE_ASYNC_SERIALIZATION = true; + private static final Executor COLUMN_LOADING_EXECUTOR = Executors.newSingleThreadExecutor(); + @Shadow @Final ServerLevel level; @Shadow int viewDistance; @@ -151,8 +153,6 @@ public abstract class MixinChunkManager implements IChunkManager, IChunkMapInter private final LongSet cubeEntitiesInLevel = new LongOpenHashSet(); private final Long2ObjectLinkedOpenHashMap pendingCubeUnloads = new Long2ObjectLinkedOpenHashMap<>(); - private static final Executor columnLoadingExecutor = Executors.newSingleThreadExecutor(); - // field_219264_r, worldgenMailbox private ProcessorHandle> cubeWorldgenMailbox; // field_219265_s, mainThreadMailbox @@ -605,16 +605,15 @@ public Iterable getCubes() { @Override public CompletableFuture> scheduleCube(ChunkHolder cubeHolder, ChunkStatus chunkStatusIn) { CubePos cubePos = ((ICubeHolder) cubeHolder).getCubePos(); + CompletableFuture> columnFutures = scheduleAndWaitForColumns(chunkStatusIn, cubePos); if (chunkStatusIn == ChunkStatus.EMPTY) { - return this.scheduleCubeLoad(cubePos); + CompletableFuture> cubeFuture = this.scheduleCubeLoad(cubePos); + return columnFutures.thenComposeAsync(columns -> cubeFuture); } else { - CompletableFuture> completablefuture = Utils.unsafeCast( + CompletableFuture> parentCubeFuture = Utils.unsafeCast( ((ICubeHolder) cubeHolder).getOrScheduleCubeFuture(chunkStatusIn.getParent(), (ChunkMap) (Object) this) ); - return completablefuture.thenApplyAsync((either) -> { - scheduleAndWaitForColumns(chunkStatusIn, cubePos); - return either; - }, columnLoadingExecutor).thenComposeAsync( + return columnFutures.thenComposeAsync(columns -> parentCubeFuture).thenComposeAsync( (Either inputSection) -> { Optional optional = inputSection.left(); if (!optional.isPresent()) { @@ -683,16 +682,16 @@ private CompletableFuture> sch }, executor); } - private void scheduleAndWaitForColumns(ChunkStatus chunkStatusIn, CubePos cubePos) { - CompletableFuture.supplyAsync(() -> { - CompletableFuture> chainedFutures = null; + 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) { + if (chainedFutures == null) { chainedFutures = columnFutureForCube; } else { chainedFutures = chainedFutures.thenCompose((existingFuture) -> columnFutureForCube); @@ -700,7 +699,8 @@ private void scheduleAndWaitForColumns(ChunkStatus chunkStatusIn, CubePos cubePo } } return chainedFutures; - }, mainThreadExecutor).join().join(); + }, 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/world/lighting/MixinThreadedLevelLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java index ba9d80a1b..86e760b8b 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java @@ -21,6 +21,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; @@ -153,6 +154,13 @@ public void checkSkyLightColumn(CubeMapGetter chunk, int x, int z, int oldHeight }, () -> "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 0be108756..c31c07432 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 @@ -10,15 +10,14 @@ import com.mojang.blaze3d.vertex.VertexFormat; 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,10 +60,10 @@ 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 = 1; + int renderRadius = 25; int chunkRenderRadius = 100; //renderRadius * IBigCube.DIAMETER_IN_SECTIONS; Long2ObjectLinkedOpenHashMap loadedColumns = getField(ChunkMap.class, levelAccessor.getChunkSource().chunkMap, "updatingChunkMap"); @@ -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 451523c58..6b2143e3f 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 @@ -90,11 +90,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(); From 0b654a403762c88aeb659ee5b50994cdc887692c Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Thu, 3 Jun 2021 16:58:02 +0100 Subject: [PATCH 32/39] Fix debug status renderer displaying incorrect statuses for cubes & columns - was previously displaying target status, which were always invalid for chunks for load order --- .../mixin/debug/client/MixinLevelRenderer.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 c31c07432..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 @@ -10,7 +10,7 @@ import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.math.Matrix4f; import com.mojang.math.Vector3f; -import io.github.opencubicchunks.cubicchunks.chunk.ICubeHolder; +import io.github.opencubicchunks.cubicchunks.chunk.IBigCube; import io.github.opencubicchunks.cubicchunks.chunk.util.CubePos; import io.github.opencubicchunks.cubicchunks.client.CubicWorldLoadScreen; import io.github.opencubicchunks.cubicchunks.utils.Coords; @@ -63,8 +63,8 @@ public void render(PoseStack matrices, float tickDelta, long limitTime, boolean CubicWorldLoadScreen.class, null, "STATUS_COLORS" // TODO: intermediary name ); - int renderRadius = 25; - int chunkRenderRadius = 100; //renderRadius * IBigCube.DIAMETER_IN_SECTIONS; + int renderRadius = 5; + int chunkRenderRadius = renderRadius * IBigCube.DIAMETER_IN_SECTIONS; Long2ObjectLinkedOpenHashMap loadedColumns = getField(ChunkMap.class, levelAccessor.getChunkSource().chunkMap, "updatingChunkMap"); Object[] data = getField(Long2ObjectLinkedOpenHashMap.class, loadedColumns, "value"); @@ -84,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); @@ -121,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); From ea6d954babd3dcd0f9129426ba17a8de0c535313 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Thu, 3 Jun 2021 16:58:43 +0100 Subject: [PATCH 33/39] attempted fix for https://bugs.mojang.com/browse/MC-224894 in CC code --- .../common/world/lighting/MixinThreadedLevelLightEngine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java index 86e760b8b..1e356f2c2 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java @@ -135,11 +135,11 @@ public CompletableFuture lightCube(IBigCube icube, boolean flagIn) { 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); From 6e4691b5db9be87a1f7228e456228bb3dc280d45 Mon Sep 17 00:00:00 2001 From: Christopher Cyclonit Klinge Date: Sun, 6 Jun 2021 09:53:14 +0200 Subject: [PATCH 34/39] - Replaced warnings/error handling on accessing missing chunks with assertions. Load order should guarantee chunks being present. - Renamed CubePrimer.loadLightHeightmapSection to CubePrimer.setLightHeightmapSection as that is what it does. --- .../cubicchunks/chunk/IBigCube.java | 2 +- .../cubicchunks/chunk/cube/BigCube.java | 4 +- .../cubicchunks/chunk/cube/CubePrimer.java | 64 +++++++++---------- .../heightmap/LightSurfaceTrackerSection.java | 2 +- .../world/lighting/MixinSkyLightEngine.java | 17 +++-- .../lighting/MixinSkyLightSectionStorage.java | 11 ++-- 6 files changed, 51 insertions(+), 49 deletions(-) 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 8f20c6bfb..4a98f5bf5 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IBigCube.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/IBigCube.java @@ -90,6 +90,6 @@ default void setCubeBlockEntity(CompoundTag nbt) { default void loadHeightmapSection(SurfaceTrackerSection section, int localSectionX, int localSectionZZ) { } - default void loadLightHeightmapSection(LightSurfaceTrackerSection 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/cube/BigCube.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/cube/BigCube.java index 6bf0b09fc..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 @@ -236,7 +236,7 @@ public BigCube(Level worldIn, CubePrimer cubePrimer, @Nullable Consumer this.dirty = true; } - @Override public void loadLightHeightmapSection(LightSurfaceTrackerSection section, int localSectionX, int localSectionZ) { + @Override public void setLightHeightmapSection(LightSurfaceTrackerSection section, int localSectionX, int localSectionZ) { int idx = localSectionX + localSectionZ * DIAMETER_IN_SECTIONS; this.lightHeightmaps[idx] = section; @@ -1003,6 +1003,7 @@ 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 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()); @@ -1011,6 +1012,7 @@ public void postLoad() { 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 2f4f35a1d..b76a8d197 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 @@ -194,16 +194,13 @@ public void setCubeStatus(ChunkStatus newStatus) { 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); - // TODO chunk can be null until load order is fixed BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x, chunkPos.z); - // force-loading like this causes lighting to init incorrectly for some reason -// BlockGetter chunk = chunkSource.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.EMPTY, true); - if (chunk == null) { - CubicChunks.LOGGER.warn("Got a null column at " + (chunkPos.x) + ", " + (chunkPos.z) - + " while adding cube to light heightmap; lighting will not be initialized correctly"); - return; - } + + // the load order guarantees the chunk being present + assert(chunk != null); ((CubeMapGetter) chunk).getCubeMap().markLoaded(this.cubePos.getY()); @@ -233,9 +230,9 @@ public void setCubeStatus(ChunkStatus newStatus) { } } - @Override public void loadLightHeightmapSection(LightSurfaceTrackerSection section, int localSectionX, int localSectionZ) { + @Override + public void setLightHeightmapSection(LightSurfaceTrackerSection section, int localSectionX, int localSectionZ) { int idx = localSectionX + localSectionZ * DIAMETER_IN_SECTIONS; - this.lightHeightmaps[idx] = section; } @@ -248,39 +245,42 @@ public LightSurfaceTrackerSection[] getLightHeightmaps() { } @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); + 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); - ChunkPos chunkPos = Coords.chunkPosByIndex(this.cubePos, index); + // the load order guarantees the chunk being present + assert(chunk != null); - // TODO chunk can be null until load order is fixed - BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x, chunkPos.z); LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); int relX = pos.getX() & 15; @@ -316,15 +316,13 @@ public LightSurfaceTrackerSection[] getLightHeightmaps() { primeHeightMaps(toInitialize); } - for (Heightmap.Types types : heightMapsAfter) { - - int xSection = Coords.blockToCubeLocalSection(pos.getX()); - int zSection = Coords.blockToCubeLocalSection(pos.getZ()); - - int idx = xSection + zSection * DIAMETER_IN_SECTIONS; + int xChunk = Coords.blockToCubeLocalSection(pos.getX()); + int zChunk = Coords.blockToCubeLocalSection(pos.getZ()); + int chunkIdx = xChunk + zChunk * DIAMETER_IN_SECTIONS; - SurfaceTrackerSection surfaceTrackerSection = this.heightmaps.get(types)[idx]; - surfaceTrackerSection.onSetBlock(x, pos.getY(), z, state); + for (Heightmap.Types types : heightMapsAfter) { + SurfaceTrackerSection surfaceTrackerSection = this.heightmaps.get(types)[chunkIdx]; + surfaceTrackerSection.onSetBlock(xSection, pos.getY(), zSection, state); } return lastState; 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 index 33f9e009b..badf550d5 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/heightmap/LightSurfaceTrackerSection.java @@ -145,7 +145,7 @@ public void loadCube(int sectionX, int sectionZ, IBigCube newCube, boolean markD } 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.loadLightHeightmapSection(this, sectionX, sectionZ); + newCube.setLightHeightmapSection(this, sectionX, sectionZ); return; } int idx = indexOfRawHeightNode(newCube.getCubePos().getY(), scale, scaledY); 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 index 5ce821f1c..d65a997a0 100644 --- 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 @@ -125,12 +125,16 @@ private void onGetComputedLevel(long id, long excludedId, int maxLevel, Callback return; } - // TODO chunk can be null until load order is fixed BlockGetter chunk = this.chunkSource.getChunkForLighting(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); + + // the load order guarantees the chunk being present + assert(chunk != null); + if (chunk == null) { System.out.println("onGetComputedLevel chunk was null " + (((Level) this.chunkSource.getLevel()).isClientSide ? "client" : "server")); return; } + Heightmap heightmap = ((LightHeightmapGetter) chunk).getLightHeightmap(); if (heightmap == null) { System.out.println("onGetComputedLevel heightmap was null " + (((Level) this.chunkSource.getLevel()).isClientSide ? "client" : "server")); @@ -150,17 +154,18 @@ public void doSkyLightForCube(IBigCube cube) { int maxY = cubePos.maxCubeY(); for (int sectionX = 0; sectionX < IBigCube.DIAMETER_IN_SECTIONS; sectionX++) { for (int sectionZ = 0; sectionZ < IBigCube.DIAMETER_IN_SECTIONS; sectionZ++) { - // TODO chunk can be null until load order is fixed + BlockGetter chunk = this.chunkSource.getChunkForLighting(chunkPos.x + sectionX, chunkPos.z + sectionZ); - if (chunk == null) { - System.out.println("null chunk in MixinSkyLightEngine.doSkyLightForCube"); - return; - } + + // 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"); 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 index 63960a0dd..e72c5134f 100644 --- 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 @@ -51,14 +51,11 @@ private void onGetLightValue(long blockPos, boolean cached, CallbackInfoReturnab 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 This currently gets called a lot; not sure if it's due to broken load order or this method being called before the lighting stage or in unloaded chunks/cubes -// System.out.println("Null chunk (" + Coords.blockToSection(x) + ", " + Coords.blockToSection(z) + ") in MixinSkyLightSectionStorage.onGetLightValue " -// + ((SectionLightStorageAccess) this).getChunkSource().getLevel()); - cir.setReturnValue(0); - return; - } + + // load order guarantees the chunk being present + assert(chunk != null); //TODO: Optimize BlockGetter cube = ((ICubeLightProvider) ((LayerLightSectionStorageAccess) this).getChunkSource()).getCubeForLighting( From a4d0456e64aa7ae01249a02aa2b80c091052ed65 Mon Sep 17 00:00:00 2001 From: Christopher Cyclonit Klinge Date: Mon, 7 Jun 2021 17:35:25 +0200 Subject: [PATCH 35/39] - Introduce proper lazy loading for heightmaps in CubePrimer.getHeightmapSections. --- build.gradle | 1 + .../cubicchunks/chunk/cube/CubePrimer.java | 64 +++++++++++++------ 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/build.gradle b/build.gradle index e30ee3e8a..b3ed7f6a3 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/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/cube/CubePrimer.java b/src/main/java/io/github/opencubicchunks/cubicchunks/chunk/cube/CubePrimer.java index b76a8d197..a2cfded5a 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 @@ -12,6 +12,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.google.common.collect.Lists; @@ -298,36 +299,61 @@ public LightSurfaceTrackerSection[] getLightHeightmaps() { } 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); - } - - toInitialize.add(type); - } - } - - if (toInitialize != null) { - primeHeightMaps(toInitialize); - } +// 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; for (Heightmap.Types types : heightMapsAfter) { - SurfaceTrackerSection surfaceTrackerSection = this.heightmaps.get(types)[chunkIdx]; + SurfaceTrackerSection surfaceTrackerSection = getHeightmapSections(types)[chunkIdx]; surfaceTrackerSection.onSetBlock(xSection, pos.getY(), zSection, state); } return lastState; } + /** + * 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[] sections = heightmaps.get(type); + + if (sections == null) { + sections = new SurfaceTrackerSection[IBigCube.DIAMETER_IN_SECTIONS * IBigCube.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; + sections[idx] = new SurfaceTrackerSection(0, cubePos.getY(), null, this, type); + sections[idx].loadCube(dx, dz, this, true); + } + } + + heightmaps.put(type, sections); + } + + return sections; + } + private void primeHeightMaps(EnumSet toInitialize) { for (Heightmap.Types type : toInitialize) { SurfaceTrackerSection[] surfaceTrackerSections = new SurfaceTrackerSection[IBigCube.DIAMETER_IN_SECTIONS * IBigCube.DIAMETER_IN_SECTIONS]; @@ -471,7 +497,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); From c30572e00318803e5f1e5499cd0f01957beaf5a3 Mon Sep 17 00:00:00 2001 From: Christopher Cyclonit Klinge Date: Fri, 11 Jun 2021 11:24:25 +0200 Subject: [PATCH 36/39] - Fixed light heightmaps being initialized in LIGHTING instead of FEATURES, resulting in missing heightmaps on the server. - Removed assertions for missing chunks until client load order is fixed. - Added forcing CCColumn tickets for every cube ticket to fix missing chunks. - Removed unnecessary debugging code for lazily initialing light heightmaps. --- .../cubicchunks/chunk/cube/CubePrimer.java | 2 +- .../mixin/core/common/chunk/MixinChunk.java | 9 --------- .../mixin/core/common/chunk/MixinProtoChunk.java | 5 ----- .../mixin/core/common/ticket/MixinTicketManager.java | 8 ++++++++ .../common/world/lighting/MixinSkyLightEngine.java | 12 ++++-------- .../world/lighting/MixinSkyLightSectionStorage.java | 9 +++++++-- 6 files changed, 20 insertions(+), 25 deletions(-) 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 a2cfded5a..e6be76c15 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 @@ -190,7 +190,7 @@ private ChunkSource getChunkSource() { public void setCubeStatus(ChunkStatus newStatus) { this.status = newStatus; - if (this.status == ChunkStatus.LIGHT) { + if (this.status == ChunkStatus.FEATURES) { ChunkSource chunkSource = getChunkSource(); for (int dx = 0; dx < IBigCube.DIAMETER_IN_SECTIONS; dx++) { 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 b967a50d8..2cb03fe8b 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 @@ -81,15 +81,6 @@ public Heightmap getLightHeightmap() { if (!isCubic) { throw new UnsupportedOperationException("Attempted to get light heightmap on a non-cubic chunk"); } - // FIXME remove debug - if (lightHeightmap == null) { - System.out.println("late creation of light heightmap in MixinChunk"); - if (level.isClientSide) { - lightHeightmap = new ClientLightSurfaceTracker(this); - } else { - lightHeightmap = new LightSurfaceTrackerWrapper(this); - } - } return lightHeightmap; } 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 dc827d0b1..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 @@ -48,11 +48,6 @@ public Heightmap getLightHeightmap() { if (!isCubic) { throw new UnsupportedOperationException("Attempted to get light heightmap on a non-cubic chunk"); } - // FIXME remove debug - if (lightHeightmap == null) { - System.out.println("late creation of light heightmap in MixinProtoChunk"); - lightHeightmap = new LightSurfaceTrackerWrapper((ChunkAccess) this); - } return lightHeightmap; } 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 1b7b998d4..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 @@ -39,6 +39,7 @@ import net.minecraft.server.level.TicketType; import net.minecraft.util.SortedArraySet; import net.minecraft.util.thread.ProcessorHandle; +import net.minecraft.world.level.ChunkPos; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -72,6 +73,8 @@ public abstract class MixinTicketManager implements ITicketManager, IVerticalVie throw new Error("Mixin did not apply correctly"); } + @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) { ProcessorHandle itaskexecutor = ProcessorHandle.of("player ticket throttler", executor2::execute); @@ -85,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) { 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 index d65a997a0..d789e74e9 100644 --- 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 @@ -127,19 +127,15 @@ private void onGetComputedLevel(long id, long excludedId, int maxLevel, Callback BlockGetter chunk = this.chunkSource.getChunkForLighting(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); - // the load order guarantees the chunk being present - assert(chunk != null); - if (chunk == null) { - System.out.println("onGetComputedLevel chunk was null " + (((Level) this.chunkSource.getLevel()).isClientSide ? "client" : "server")); + // 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(); - if (heightmap == null) { - System.out.println("onGetComputedLevel heightmap was null " + (((Level) this.chunkSource.getLevel()).isClientSide ? "client" : "server")); - return; - } + int height = heightmap.getFirstAvailable(pos.getX() & 0xF, pos.getZ() & 0xF); if (height <= pos.getY()) { cir.setReturnValue(0); 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 index e72c5134f..84fe328c5 100644 --- 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 @@ -10,6 +10,7 @@ import net.minecraft.core.SectionPos; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.LightChunkGetter; @@ -54,8 +55,12 @@ private void onGetLightValue(long blockPos, boolean cached, CallbackInfoReturnab BlockGetter chunk = ((LayerLightSectionStorageAccess) this).getChunkSource().getChunkForLighting(Coords.blockToSection(x), Coords.blockToSection(z)); - // load order guarantees the chunk being present - assert(chunk != null); + 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."); + return; + } //TODO: Optimize BlockGetter cube = ((ICubeLightProvider) ((LayerLightSectionStorageAccess) this).getChunkSource()).getCubeForLighting( From 3249dd6f6e46c6af17152fe4e0fcb602b8e6f8e6 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Sat, 12 Jun 2021 17:08:06 +1200 Subject: [PATCH 37/39] fix skylight propagation only using horizontal directions --- .../core/common/world/lighting/MixinSkyLightEngine.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 index d789e74e9..e8aae6512 100644 --- 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 @@ -16,7 +16,6 @@ import net.minecraft.core.SectionPos; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.lighting.SkyLightEngine; @@ -32,7 +31,7 @@ @Mixin(SkyLightEngine.class) public abstract class MixinSkyLightEngine extends MixinLayerLightEngine implements ISkyLightColumnChecker, ICubicSkyLightEngine { - @Shadow @Final private static Direction[] HORIZONTALS; + @Shadow @Final private static Direction[] DIRECTIONS; /** * @author CursedFlames @@ -201,7 +200,7 @@ private void onCheckNeighborsAfterUpdate(long blockPos, int level, boolean decre long sectionPos = SectionPos.blockToSection(blockPos); - for (Direction direction : HORIZONTALS) { + for (Direction direction : DIRECTIONS) { long offsetBlockPos = BlockPos.offset(blockPos, direction); long offsetSectionPos = SectionPos.blockToSection(offsetBlockPos); // Check all neighbors that are storing light From bb68954bf008292f1f8d93918cb4ea17a22674ca Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Sat, 12 Jun 2021 17:11:30 +1200 Subject: [PATCH 38/39] prevent vanilla behaviour in SkyLightSectionStorage.getLightValue on client --- .../core/common/world/lighting/MixinSkyLightSectionStorage.java | 2 ++ 1 file changed, 2 insertions(+) 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 index 84fe328c5..d704967bb 100644 --- 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 @@ -59,6 +59,8 @@ private void onGetLightValue(long blockPos, boolean cached, CallbackInfoReturnab // 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; } From c9575d54a1147bc25d8b2b82592e7fd7c0af53a2 Mon Sep 17 00:00:00 2001 From: CursedFlames <18627001+CursedFlames@users.noreply.github.com> Date: Sat, 12 Jun 2021 17:50:08 +1200 Subject: [PATCH 39/39] pass checkstyle --- .../cubicchunks/chunk/cube/CubePrimer.java | 20 +++++++++---------- .../world/lighting/MixinSkyLightEngine.java | 2 +- .../lighting/MixinSkyLightSectionStorage.java | 1 - .../MixinThreadedLevelLightEngine.java | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) 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 e6be76c15..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 @@ -12,13 +12,11 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.google.common.collect.Lists; 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; @@ -201,7 +199,7 @@ public void setCubeStatus(ChunkStatus newStatus) { BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x, chunkPos.z); // the load order guarantees the chunk being present - assert(chunk != null); + assert (chunk != null); ((CubeMapGetter) chunk).getCubeMap().markLoaded(this.cubePos.getY()); @@ -280,7 +278,7 @@ public LightSurfaceTrackerSection[] getLightHeightmaps() { BlockGetter chunk = chunkSource.getChunkForLighting(chunkPos.x, chunkPos.z); // the load order guarantees the chunk being present - assert(chunk != null); + assert (chunk != null); LightSurfaceTrackerWrapper lightHeightmap = ((LightHeightmapGetter) chunk).getServerLightHeightmap(); @@ -335,23 +333,23 @@ public LightSurfaceTrackerSection[] getLightHeightmaps() { */ private SurfaceTrackerSection[] getHeightmapSections(Heightmap.Types type) { - SurfaceTrackerSection[] sections = heightmaps.get(type); + SurfaceTrackerSection[] surfaceTrackerSections = heightmaps.get(type); - if (sections == null) { - sections = new SurfaceTrackerSection[IBigCube.DIAMETER_IN_SECTIONS * IBigCube.DIAMETER_IN_SECTIONS]; + if (surfaceTrackerSections == null) { + surfaceTrackerSections = new SurfaceTrackerSection[IBigCube.DIAMETER_IN_SECTIONS * IBigCube.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; - sections[idx] = new SurfaceTrackerSection(0, cubePos.getY(), null, this, type); - sections[idx].loadCube(dx, dz, this, true); + surfaceTrackerSections[idx] = new SurfaceTrackerSection(0, cubePos.getY(), null, this, type); + surfaceTrackerSections[idx].loadCube(dx, dz, this, true); } } - heightmaps.put(type, sections); + heightmaps.put(type, surfaceTrackerSections); } - return sections; + return surfaceTrackerSections; } private void primeHeightMaps(EnumSet toInitialize) { 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 index e8aae6512..a11982403 100644 --- 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 @@ -153,7 +153,7 @@ public void doSkyLightForCube(IBigCube cube) { BlockGetter chunk = this.chunkSource.getChunkForLighting(chunkPos.x + sectionX, chunkPos.z + sectionZ); // the load order guarantees the chunk being present - assert(chunk != null); + assert (chunk != null); CubeMap cubeMap = ((CubeMapGetter) chunk).getCubeMap(); if (!cubeMap.isLoaded(cubePos.getY())) { 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 index d704967bb..7c68aeeb7 100644 --- 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 @@ -10,7 +10,6 @@ import net.minecraft.core.SectionPos; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.LightChunkGetter; diff --git a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java index e2c7df15c..f091660a7 100644 --- a/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java +++ b/src/main/java/io/github/opencubicchunks/cubicchunks/mixin/core/common/world/lighting/MixinThreadedLevelLightEngine.java @@ -6,8 +6,8 @@ import javax.annotation.Nullable; import com.mojang.datafixers.util.Pair; -import io.github.opencubicchunks.cubicchunks.chunk.CubeMapGetter; 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;