Replace ChunkWrapper light hash maps with 1D arrays

This commit is contained in:
James Seibel
2023-08-13 17:02:45 -05:00
parent fe973d27b9
commit 9020d5bbe6
@@ -44,10 +44,7 @@ import net.minecraft.world.level.levelgen.Heightmap;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.WeakHashMap;
import java.util.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;
#if POST_MC_1_17_1
@@ -68,8 +65,9 @@ public class ChunkWrapper implements IChunkWrapper
private final ILevelWrapper wrappedLevel;
private boolean isDhLightCorrect = false;
private final HashMap<DhBlockPos, Integer> blockLightAtRelBlockPos = new HashMap<>(LodUtil.CHUNK_WIDTH * LodUtil.CHUNK_WIDTH * 256);
private final HashMap<DhBlockPos, Integer> skyLightAtRelBlockPos = new HashMap<>(LodUtil.CHUNK_WIDTH * LodUtil.CHUNK_WIDTH * 256);
private final byte[] blockLightArray;
private final byte[] skyLightArray;
private LinkedList<DhBlockPos> blockLightPosList = null;
@@ -106,6 +104,10 @@ public class ChunkWrapper implements IChunkWrapper
boolean isDhGeneratedChunk = (this.lightSource.getClass() == DhLitWorldGenRegion.class);
this.useDhLighting = isDhGeneratedChunk && (Config.Client.Advanced.WorldGenerator.worldGenLightingEngine.get() == ELightGenerationMode.DISTANT_HORIZONS);
// FIXME +2 is to handle the fact that LodDataBuilder adds +1 to all block lighting calculations, also done in the relative position validator
this.blockLightArray = new byte[LodUtil.CHUNK_WIDTH * LodUtil.CHUNK_WIDTH * (this.getHeight() + 2)];
this.skyLightArray = new byte[LodUtil.CHUNK_WIDTH * LodUtil.CHUNK_WIDTH * (this.getHeight() + 2)];
weakMapLock.writeLock().lock();
chunksToUpdateClientLightReady.put(chunk, false);
weakMapLock.writeLock().unlock();
@@ -229,67 +231,77 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public int getDhBlockLight(int relX, int relY, int relZ)
public int getDhBlockLight(int relX, int y, int relZ)
{
throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
return this.blockLightAtRelBlockPos.getOrDefault(new DhBlockPos(relX, relY, relZ), 0);
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
int index = this.relativeBlockPosToIndex(relX, y, relZ);
return this.blockLightArray[index];
}
@Override
public void setDhBlockLight(int relX, int relY, int relZ, int lightValue)
public void setDhBlockLight(int relX, int y, int relZ, int lightValue)
{
throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
this.blockLightAtRelBlockPos.put(new DhBlockPos(relX, relY, relZ), lightValue);
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
int index = this.relativeBlockPosToIndex(relX, y, relZ);
this.blockLightArray[index] = (byte) lightValue;
}
@Override
public int getDhSkyLight(int relX, int relY, int relZ)
public int getDhSkyLight(int relX, int y, int relZ)
{
throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
return this.skyLightAtRelBlockPos.getOrDefault(new DhBlockPos(relX, relY, relZ), 0);
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
int index = this.relativeBlockPosToIndex(relX, y, relZ);
return this.skyLightArray[index];
}
@Override
public void setDhSkyLight(int relX, int relY, int relZ, int lightValue)
public void setDhSkyLight(int relX, int y, int relZ, int lightValue)
{
throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
this.skyLightAtRelBlockPos.put(new DhBlockPos(relX, relY, relZ), lightValue);
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
int index = this.relativeBlockPosToIndex(relX, y, relZ);
this.skyLightArray[index] = (byte) lightValue;
}
@Override
public int getBlockLight(int relX, int relY, int relZ)
public int getBlockLight(int relX, int y, int relZ)
{
throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
// use the full lighting engine when the chunks are within render distance or the config requests it
if (this.useDhLighting)
{
// DH lighting method
return this.blockLightAtRelBlockPos.getOrDefault(new DhBlockPos(relX, relY, relZ), 0);
int index = this.relativeBlockPosToIndex(relX, y, relZ);
return this.blockLightArray[index];
}
else
{
// note: this returns 0 if the chunk is unload
// MC lighting method
return this.lightSource.getBrightness(LightLayer.BLOCK, new BlockPos(relX +this.getMinBlockX(), relY, relZ +this.getMinBlockZ()));
return this.lightSource.getBrightness(LightLayer.BLOCK, new BlockPos(relX +this.getMinBlockX(), y, relZ +this.getMinBlockZ()));
}
}
@Override
public int getSkyLight(int relX, int relY, int relZ)
public int getSkyLight(int relX, int y, int relZ)
{
throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
// use the full lighting engine when the chunks are within render distance or the config requests it
if (this.useDhLighting)
{
// DH lighting method
return this.skyLightAtRelBlockPos.getOrDefault(new DhBlockPos(relX, relY, relZ), 0);
int index = this.relativeBlockPosToIndex(relX, y, relZ);
return this.skyLightArray[index];
}
else
{
// MC lighting method
return this.lightSource.getBrightness(LightLayer.SKY, new BlockPos(relX +this.getMinBlockX(), relY, relZ +this.getMinBlockZ()));
return this.lightSource.getBrightness(LightLayer.SKY, new BlockPos(relX +this.getMinBlockX(), y, relZ +this.getMinBlockZ()));
}
}
@@ -421,13 +433,53 @@ public class ChunkWrapper implements IChunkWrapper
//================//
/** used to prevent accidentally attempting to get/set values outside this chunk's boundaries */
private static void throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(int x, int y, int z) throws IndexOutOfBoundsException
private void throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(int x, int y, int z) throws IndexOutOfBoundsException
{
// FIXME +/-1 is to handle the fact that LodDataBuilder adds +1 to all block lighting calculations, also done in the relative position validator
int minHeight = this.getMinBuildHeight()-1;
int maxHeight = this.getMaxBuildHeight()+1;
if (x < 0 || x >= LodUtil.CHUNK_WIDTH
|| z < 0 || z >= LodUtil.CHUNK_WIDTH)
|| z < 0 || z >= LodUtil.CHUNK_WIDTH
|| y < minHeight || y > maxHeight)
{
throw new IndexOutOfBoundsException("Indices are relative and must be between 0 and 15 (inclusive), X:"+x+", Y:"+y+" Z:"+z);
String errorMessage = "Relative position ["+x+","+y+","+z+"] out of bounds. \n" +
"X/Z must be between 0 and 15 (inclusive) \n" +
"Y must be between ["+minHeight+"] and ["+maxHeight+"] (inclusive).";
throw new IndexOutOfBoundsException(errorMessage);
}
}
/**
* Converts a 3D position into a 1D array index. <br><br>
*
* Source: <br>
* <a href="https://stackoverflow.com/questions/7367770/how-to-flatten-or-index-3d-array-in-1d-array">stackoverflow</a>
*/
public int relativeBlockPosToIndex(int xRel, int y, int zRel)
{
int yRel = y - this.getMinBuildHeight();
return (zRel * LodUtil.CHUNK_WIDTH * this.getHeight()) + (yRel * LodUtil.CHUNK_WIDTH) + xRel;
}
/**
* Converts a 3D position into a 1D array index. <br><br>
*
* Source: <br>
* <a href="https://stackoverflow.com/questions/7367770/how-to-flatten-or-index-3d-array-in-1d-array">stackoverflow</a>
*/
public DhBlockPos indexToRelativeBlockPos(int index)
{
final int zRel = index / (LodUtil.CHUNK_WIDTH * this.getHeight());
index -= (zRel * LodUtil.CHUNK_WIDTH * this.getHeight());
final int y = index / LodUtil.CHUNK_WIDTH;
final int yRel = y + this.getMinBuildHeight();
final int xRel = index % LodUtil.CHUNK_WIDTH;
return new DhBlockPos(xRel, yRel, zRel);
}
}