Add BuilderB0y's getBlockState optimization

This commit is contained in:
James Seibel
2024-09-05 07:50:18 -05:00
parent 847cfa3ca9
commit d03a887620
4 changed files with 61 additions and 11 deletions
@@ -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);
@@ -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)
@@ -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;
}
@@ -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
{
}