diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/LodDataBuilder.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/LodDataBuilder.java index 8d8d94f5f..97c76104b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/LodDataBuilder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/transformers/LodDataBuilder.java @@ -40,6 +40,7 @@ import com.seibel.distanthorizons.core.util.RenderDataPointUtil; import com.seibel.distanthorizons.core.util.objects.DataCorruptedException; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IMutableBlockPosWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory; import it.unimi.dsi.fastutil.longs.LongArrayList; @@ -132,6 +133,9 @@ public class LodDataBuilder try { + IMutableBlockPosWrapper mcBlockPos = chunkWrapper.getMutableBlockPosWrapper(); + IBlockStateWrapper previousBlockState = null; + int minBuildHeight = chunkWrapper.getMinNonEmptyHeight(); for (int relBlockX = 0; relBlockX < LodUtil.CHUNK_WIDTH; relBlockX++) { @@ -163,7 +167,7 @@ public class LodDataBuilder // determine the starting Y Pos int y = chunkWrapper.getLightBlockingHeightMapValue(relBlockX, relBlockZ); // go up until we reach open air or the world limit - IBlockStateWrapper topBlockState = chunkWrapper.getBlockState(relBlockX, y, relBlockZ); + IBlockStateWrapper topBlockState = previousBlockState = chunkWrapper.getBlockState(relBlockX, y, relBlockZ, mcBlockPos, previousBlockState); while (!topBlockState.isAir() && y < chunkWrapper.getMaxBuildHeight()) { try @@ -171,7 +175,7 @@ public class LodDataBuilder // This is necessary in some edge cases with snow layers and some other blocks that may not appear in the height map but do block light. // Interestingly this doesn't appear to be the case in the DhLightingEngine, if this same logic is added there the lighting breaks for the affected blocks. y++; - topBlockState = chunkWrapper.getBlockState(relBlockX, y, relBlockZ); + topBlockState = previousBlockState = chunkWrapper.getBlockState(relBlockX, y, relBlockZ, mcBlockPos, previousBlockState); } catch (Exception e) { @@ -190,7 +194,7 @@ public class LodDataBuilder for (; y >= minBuildHeight; y--) { IBiomeWrapper newBiome = chunkWrapper.getBiome(relBlockX, y, relBlockZ); - IBlockStateWrapper newBlockState = chunkWrapper.getBlockState(relBlockX, y, relBlockZ); + IBlockStateWrapper newBlockState = previousBlockState = chunkWrapper.getBlockState(relBlockX, y, relBlockZ, mcBlockPos, previousBlockState); byte newBlockLight = (byte) chunkWrapper.getBlockLight(relBlockX, y + 1, relBlockZ); byte newSkyLight = (byte) chunkWrapper.getSkyLight(relBlockX, y + 1, relBlockZ); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java index fbcc68168..e17e58710 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/DhLightingEngine.java @@ -29,6 +29,7 @@ import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IMutableBlockPosWrapper; import org.apache.logging.log4j.Logger; import java.awt.*; @@ -163,6 +164,9 @@ public class DhLightingEngine // if the dimension has skylights if (maxSkyLight > 0) { + IMutableBlockPosWrapper mcBlockPos = chunk.getMutableBlockPosWrapper(); + IBlockStateWrapper previousBlockState = null; + int maxY = chunk.getMaxNonEmptyHeight(); int minY = chunk.getMinBuildHeight(); @@ -174,7 +178,7 @@ public class DhLightingEngine // set each pos' sky light all the way down until an opaque block is hit for (int y = maxY; y >= minY; y--) { - IBlockStateWrapper block = chunk.getBlockState(relX, y, relZ); + IBlockStateWrapper block = previousBlockState = chunk.getBlockState(relX, y, relZ, mcBlockPos, previousBlockState); if (block != null && block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT) { // keep moving down until we find a non-transparent block @@ -247,6 +251,8 @@ public class DhLightingEngine final DhBlockPosMutable neighbourBlockPos = PRIMARY_BLOCK_POS_REF.get(); final DhBlockPosMutable relNeighbourBlockPos = SECONDARY_BLOCK_POS_REF.get(); + IMutableBlockPosWrapper mcBlockPos = null; + IBlockStateWrapper previousBlockState = null; // update each light position while (!lightPosQueue.isEmpty()) @@ -290,7 +296,15 @@ public class DhLightingEngine } - IBlockStateWrapper neighbourBlockState = neighbourChunk.getBlockState(relNeighbourBlockPos); + if (mcBlockPos == null) + { + // it doesn't matter what chunk we get the position object from + // TODO move this getter logic out of ChunkWrapper + mcBlockPos = neighbourChunk.getMutableBlockPosWrapper(); + } + + + IBlockStateWrapper neighbourBlockState = previousBlockState = neighbourChunk.getBlockState(relNeighbourBlockPos, mcBlockPos, previousBlockState); // Math.max(1, ...) is used so that the propagated light level always drops by at least 1, preventing infinite cycles. int targetLevel = lightValue - Math.max(1, neighbourBlockState.getOpacity()); if (targetLevel > currentBlockLight) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java index 3bcc287eb..440e6b47d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/chunk/IChunkWrapper.java @@ -20,15 +20,13 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.chunk; import com.seibel.distanthorizons.core.generation.AdjacentChunkHolder; -import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable; import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; -import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; -import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IMutableBlockPosWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable; @@ -117,6 +115,15 @@ public interface IChunkWrapper extends IBindable default IBlockStateWrapper getBlockState(DhBlockPos pos) { return this.getBlockState(pos.getX(), pos.getY(), pos.getZ()); } IBlockStateWrapper getBlockState(int relX, int relY, int relZ); + /** @see IChunkWrapper#getBlockState(int, int, int, IMutableBlockPosWrapper, IBlockStateWrapper) */ + default IBlockStateWrapper getBlockState(DhBlockPos pos, IMutableBlockPosWrapper mcBlockPos, IBlockStateWrapper guess) { return this.getBlockState(pos.getX(), pos.getY(), pos.getZ(), mcBlockPos, guess); } + /** + * Can be faster than {@link IChunkWrapper#getBlockState} in some cases + * due to directly passing in several shared objects. + */ + IBlockStateWrapper getBlockState(int relX, int relY, int relZ, IMutableBlockPosWrapper mcBlockPos, IBlockStateWrapper guess); + + IMutableBlockPosWrapper getMutableBlockPosWrapper(); IBiomeWrapper getBiome(int relX, int relY, int relZ); @@ -290,6 +297,9 @@ public interface IChunkWrapper extends IBindable int minBuildHeight = this.getMinNonEmptyHeight(); int maxBuildHeight = this.getMaxNonEmptyHeight(); + IMutableBlockPosWrapper mcBlockPos = this.getMutableBlockPosWrapper(); + IBlockStateWrapper previousBlockState = null; + // most blocks (only some blocks are sampled since checking every block is a very slow operation) for (int x = 0; x < LodUtil.CHUNK_WIDTH; x+=2) @@ -298,7 +308,9 @@ public interface IChunkWrapper extends IBindable { for (int y = minBuildHeight; y < maxBuildHeight; y+=2) { - hash = (hash * primeBlockMultiplier) + this.getBlockState(x, y, z).hashCode(); + previousBlockState = this.getBlockState(x, y, z, mcBlockPos, previousBlockState); + + hash = (hash * primeBlockMultiplier) + previousBlockState.hashCode(); hash = (hash * primeBiomeMultiplier) + this.getBiome(x, y, z).hashCode(); hash = (hash * primeHeightMultiplier) + y; } @@ -311,14 +323,18 @@ public interface IChunkWrapper extends IBindable for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++) { int lightBlockingY = this.getLightBlockingHeightMapValue(x, z); - hash = (hash * primeBlockMultiplier) + this.getBlockState(x, lightBlockingY, z).hashCode(); + previousBlockState = this.getBlockState(x, lightBlockingY, z, mcBlockPos, previousBlockState); + + hash = (hash * primeBlockMultiplier) + previousBlockState.hashCode(); hash = (hash * primeBiomeMultiplier) + this.getBiome(x, lightBlockingY, z).hashCode(); hash = (hash * primeHeightMultiplier) + lightBlockingY; int solidY = this.getSolidHeightMapValue(x, z); if (solidY != lightBlockingY) { - hash = (hash * primeBlockMultiplier) + this.getBlockState(x, solidY, z).hashCode(); + previousBlockState = this.getBlockState(x, lightBlockingY, z, mcBlockPos, previousBlockState); + + hash = (hash * primeBlockMultiplier) + previousBlockState.hashCode(); hash = (hash * primeBiomeMultiplier) + this.getBiome(x, solidY, z).hashCode(); hash = (hash * primeHeightMultiplier) + solidY; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/misc/IMutableBlockPosWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/misc/IMutableBlockPosWrapper.java new file mode 100644 index 000000000..8922cdf49 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/misc/IMutableBlockPosWrapper.java @@ -0,0 +1,16 @@ +package com.seibel.distanthorizons.core.wrapperInterfaces.misc; + +import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; + +/** + * Currently this wrapper is just used to prevent + * accidentally passing in the wrong object to + * {@link IChunkWrapper#getBlockState(int, int, int, IMutableBlockPosWrapper, IBlockStateWrapper)} + */ +public interface IMutableBlockPosWrapper extends IDhApiUnsafeWrapper +{ + + +}