Tune memory use on generic chunks, lighting lookup performance

This commit is contained in:
Mike Primm 2021-12-28 22:14:19 -06:00
parent adcfedd68e
commit 0166895a7f
14 changed files with 300 additions and 37 deletions

View File

@ -9,6 +9,7 @@ import org.dynmap.common.BiomeMap;
public class GenericChunk {
public final int cx, cz; // Chunk coord (world coord / 16)
public final GenericChunkSection[] sections;
public final int sectionCnt;
public final int cy_min; // CY value of first section in sections list (index = (Y >> 4) - cy_min
public final long inhabitedTicks;
public final int dataVersion; // Version of chunk data loaded
@ -31,15 +32,16 @@ public class GenericChunk {
empty = empty && sections[off].isEmpty;
}
}
this.sectionCnt = sections.length;
this.isEmpty = empty;
}
// Get section for given block Y coord
public final GenericChunkSection getSection(int y) {
try {
return this.sections[(y >> 4) - cy_min];
} catch (IndexOutOfBoundsException ioobx) { // Builder and padding should be avoiding this, but be safe
int idx = (y >> 4) - this.cy_min;
if ((idx < 0) || (idx >= sectionCnt)) {
return GenericChunkSection.EMPTY;
}
return this.sections[idx];
}
public final DynmapBlockState getBlockType(int x, int y, int z) {

View File

@ -31,6 +31,21 @@ public class GenericChunkSection {
return blocks[pos.soffset];
}
}
private static class BlockStateAccess3DPalette implements BlockStateAccess {
private final DynmapBlockState palette[];
private final short[] blocks; // YZX order
// Array given to us by builder
BlockStateAccess3DPalette(DynmapBlockState pal[], short[] blks) {
blocks = blks;
palette = pal;
}
public final DynmapBlockState getBlock(int x, int y, int z) {
return palette[blocks[(256 * (y & 0xF)) + (16 * (z & 0xF)) + (x & 0xF)]];
}
public final DynmapBlockState getBlock(GenericChunkPos pos) {
return palette[blocks[pos.soffset]];
}
}
private static class BlockStateAccessSingle implements BlockStateAccess {
private final DynmapBlockState block;
BlockStateAccessSingle(DynmapBlockState bs) {
@ -157,6 +172,8 @@ public class GenericChunkSection {
private LightingAccess em;
private DynmapBlockState bsaccumsing; // Used for single
private DynmapBlockState bsaccum[]; // Use for incremental setting of 3D - YZX order
private short[] bsblks; // Use for incremental setting of 3D palette - XZY order
private DynmapBlockState[] bspal; // Palette for bsblks
private BiomeMap baaccumsingle; // Use for single
private BiomeMap baaccum[]; // Use for incremental setting of 3D biome - YZX order or 2D biome (ZX order) length used to control which
private boolean empty;
@ -170,6 +187,8 @@ public class GenericChunkSection {
bsaccum = null;
baaccumsingle = BiomeMap.NULL;
baaccum = null;
bsblks = null;
bspal = null;
sk = defaultLight;
em = defaultLight;
empty = true;
@ -224,6 +243,8 @@ public class GenericChunkSection {
public Builder singleBlockState(DynmapBlockState block) {
bsaccumsing = block;
bsaccum = null;
bsblks = null;
bspal = null;
empty = block.isAir();
return this;
}
@ -238,6 +259,23 @@ public class GenericChunkSection {
empty = false;
return this;
}
// Set block state palette (states will be indexes vs this
public Builder xyzBlockStatePalette(DynmapBlockState[] bspalette) {
if (bsblks == null) {
bsblks = new short[4096];
}
bspal = Arrays.copyOf(bspalette, bspalette.length);
return this;
}
// Set block state using palette
public Builder xyzBlockStateInPalette(int x, int y, int z, short palidx) {
if (bsblks == null) {
bsblks = new short[4096];
}
bsblks[((y & 0xF) << 8) + ((z & 0xF) << 4) + (x & 0xF)] = palidx;
empty = false;
return this;
}
// Build copy from existing section with new skylight (YZX nibble array)
public GenericChunkSection buildFrom(GenericChunkSection s, byte[] sky) {
LightingAccess skyA = new LightingAccess3D(sky);
@ -272,6 +310,17 @@ public class GenericChunkSection {
bsaccum = null;
empty = false;
}
else if (bspal != null) { // 3D palette
// Only one state in palette?
if (bspal.length == 1) {
bs = new BlockStateAccessSingle(bspal[0]); // Just single
}
else {
bs = new BlockStateAccess3DPalette(bspal, bsblks);
}
bspal = null;
bsblks = null;
}
else if (bsaccumsing == DynmapBlockState.AIR) { // Just air?
bs = defaultBlockState;
empty = true;

View File

@ -101,7 +101,32 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
return 0;
}
}
@Override
/**
* Get block sky and emitted light, relative to current coordinate
* @return (emitted light * 256) + sky light
*/
public final int getBlockLight(BlockStep step) {
int emit = 0, sky = 15;
GenericChunkSection sect;
if (step.yoff != 0) { // Y coord - snap is valid already
int ny = y + step.yoff;
sect = snap.getSection(ny);
emit = sect.emitted.getLight(x, ny, z);
sky = sect.sky.getLight(x, ny, z);
}
else {
int nx = x + step.xoff;
int nz = z + step.zoff;
int nchunkindex = ((nx >> 4) - x_min) + (((nz >> 4) - z_min) * x_dim);
if ((nchunkindex < snapcnt) && (nchunkindex >= 0)) {
sect = snaparray[nchunkindex].getSection(y);
emit = sect.emitted.getLight(nx, y, nz);
sky = sect.sky.getLight(nx, y, nz);
}
}
return (emit << 8) + sky;
}
@Override
public final BiomeMap getBiome() {
try {
@ -1007,11 +1032,11 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
}
}
else {
for (int j = 0; j < 4096; j++) {
int v = (dbp != null) ? dbp.getAt(j) : db.get(j);
DynmapBlockState bs = (v < palette.length) ? palette[v] : DynmapBlockState.AIR;
sbld.xyzBlockState(j & 0xF, (j & 0xF00) >> 8, (j & 0xF0) >> 4, bs);
}
sbld.xyzBlockStatePalette(palette); // Set palette
for (int j = 0; j < 4096; j++) {
int v = db != null ? db.get(j) : dbp.getAt(j);
sbld.xyzBlockStateInPalette(j & 0xF, (j & 0xF00) >> 8, (j & 0xF0) >> 4, (short)v);
}
}
}
else if (sec.contains("block_states", GenericNBTCompound.TAG_COMPOUND)) { // 1.18
@ -1059,10 +1084,10 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
}
}
else {
sbld.xyzBlockStatePalette(palette); // Set palette
for (int j = 0; j < 4096; j++) {
int v = db != null ? db.get(j) : dbp.getAt(j);
DynmapBlockState bs = (v < palette.length) ? palette[v] : DynmapBlockState.AIR;
sbld.xyzBlockState(j & 0xF, (j & 0xF00) >> 8, (j & 0xF0) >> 4, bs);
sbld.xyzBlockStateInPalette(j & 0xF, (j & 0xF00) >> 8, (j & 0xF0) >> 4, (short)v);
}
}
}

View File

@ -149,8 +149,8 @@ public class IsoHDPerspective implements HDPerspective {
llcache = new LightLevels[4];
for(int i = 0; i < llcache.length; i++)
llcache[i] = new LightLevels();
custom_meshes = new DynLongHashMap();
custom_fluid_meshes = new DynLongHashMap();
custom_meshes = new DynLongHashMap(4096);
custom_fluid_meshes = new DynLongHashMap(4096);
modscale = basemodscale << scaled;
scalemodels = HDBlockModels.getModelsForScale(basemodscale << scaled);
}
@ -158,13 +158,9 @@ public class IsoHDPerspective implements HDPerspective {
private final void updateSemitransparentLight(LightLevels ll) {
int emitted = 0, sky = 0;
for(int i = 0; i < semi_steps.length; i++) {
BlockStep s = semi_steps[i];
mapiter.stepPosition(s);
int v = mapiter.getBlockEmittedLight();
if(v > emitted) emitted = v;
v = mapiter.getBlockSkyLight();
if(v > sky) sky = v;
mapiter.unstepPosition(s);
int emit_sky_light = mapiter.getBlockLight(semi_steps[i]);
if ((emit_sky_light >> 8) > emitted) emitted = (emit_sky_light >> 8);
if ((emit_sky_light & 0xF) > sky) sky = (emit_sky_light & 0xF);
}
ll.sky = sky;
ll.emitted = emitted;
@ -181,16 +177,10 @@ public class IsoHDPerspective implements HDPerspective {
ll.emitted = mapiter.getBlockEmittedLight();
break;
case OPAQUE:
if(HDBlockStateTextureMap.getTransparency(lastblocktype) != BlockTransparency.SEMITRANSPARENT) {
mapiter.unstepPosition(laststep); /* Back up to block we entered on */
if(mapiter.getY() < worldheight) {
ll.sky = mapiter.getBlockSkyLight();
ll.emitted = mapiter.getBlockEmittedLight();
} else {
ll.sky = 15;
ll.emitted = 0;
}
mapiter.stepPosition(laststep);
if (HDBlockStateTextureMap.getTransparency(lastblocktype) != BlockTransparency.SEMITRANSPARENT) {
int emit_sky_light = mapiter.getBlockLight(laststep.opposite());
ll.sky = emit_sky_light & 0xF;
ll.emitted = emit_sky_light >> 8;
}
else {
mapiter.unstepPosition(laststep); /* Back up to block we entered on */

View File

@ -236,6 +236,9 @@ public class DynLongHashMap
return getEntry(key) != null;
}
private static final int toHash(long key) {
return (int)((key >>> 32) ^ key);
}
/**
* Returns the entry associated with the specified key in the
* HashMap. Returns null if the HashMap contains no mapping
@ -243,7 +246,7 @@ public class DynLongHashMap
*/
Entry getEntry(long key) {
Entry tab[] = table;
int hash = (int) key;
int hash = toHash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index]; e != null; e = e.next)
@ -293,7 +296,7 @@ public class DynLongHashMap
*/
public Object put(long key, Object value) {
Entry tab[] = table;
int hash = (int) key;
int hash = toHash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
// Look for entry in hash table
@ -340,7 +343,7 @@ public class DynLongHashMap
*/
Entry removeEntryForKey(long key) {
Entry tab[] = table;
int hash = (int) key;
int hash = toHash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index], prev = null; e != null;

View File

@ -26,6 +26,11 @@ public interface MapIterator extends MapDataContext {
* @return emitted light level
*/
int getBlockEmittedLight();
/**
* Get block sky and emitted light, relative to current coordinate
* @return (emitted light * 256) + sky light
*/
int getBlockLight(BlockStep step);
/**
* Get biome at coordinates
* @return biome

View File

@ -158,6 +158,30 @@ public abstract class AbstractMapChunkCache extends MapChunkCache {
}
return 0;
}
@Override
/**
* Get block sky and emitted light, relative to current coordinate
* @return (emitted light * 256) + sky light
*/
public final int getBlockLight(BlockStep step) {
int emit = 0, sky = 15;
if (step.yoff != 0) { // Y coord - snap is valid already
int ny = y + step.yoff;
emit = snap.getBlockEmittedLight(x, ny, z);
sky = snap.getBlockSkyLight(x, ny, z);
}
else {
int nx = x + step.xoff;
int nz = z + step.zoff;
int nchunkindex = ((nx >> 4) - x_min) + (((nz >> 4) - z_min) * x_dim);
if ((nchunkindex < snapcnt) && (nchunkindex >= 0)) {
emit = snaparray[nchunkindex].getBlockEmittedLight(nx, y, nz);
sky = snaparray[nchunkindex].getBlockSkyLight(nx, y, nz);
}
}
return (emit << 8) + sky;
}
private void biomePrep() {
if(sameneighborbiomecnt != null)
return;

View File

@ -132,6 +132,29 @@ public class FabricMapChunkCache extends MapChunkCache {
return 0;
}
}
@Override
/**
* Get block sky and emitted light, relative to current coordinate
* @return (emitted light * 256) + sky light
*/
public final int getBlockLight(BlockStep step) {
int emit = 0, sky = 15;
if (step.yoff != 0) { // Y coord - snap is valid already
int ny = y + step.yoff;
emit = snap.getBlockEmittedLight(x, ny, z);
sky = snap.getBlockSkyLight(x, ny, z);
}
else {
int nx = x + step.xoff;
int nz = z + step.zoff;
int nchunkindex = ((nx >> 4) - x_min) + (((nz >> 4) - z_min) * x_dim);
if ((nchunkindex < snapcnt) && (nchunkindex >= 0)) {
emit = snaparray[nchunkindex].getBlockEmittedLight(nx, y, nz);
sky = snaparray[nchunkindex].getBlockSkyLight(nx, y, nz);
}
}
return (emit << 8) + sky;
}
private void biomePrep() {
if (sameneighborbiomecnt != null) {

View File

@ -132,6 +132,29 @@ public class FabricMapChunkCache extends MapChunkCache {
return 0;
}
}
@Override
/**
* Get block sky and emitted light, relative to current coordinate
* @return (emitted light * 256) + sky light
*/
public final int getBlockLight(BlockStep step) {
int emit = 0, sky = 15;
if (step.yoff != 0) { // Y coord - snap is valid already
int ny = y + step.yoff;
emit = snap.getBlockEmittedLight(x, ny, z);
sky = snap.getBlockSkyLight(x, ny, z);
}
else {
int nx = x + step.xoff;
int nz = z + step.zoff;
int nchunkindex = ((nx >> 4) - x_min) + (((nz >> 4) - z_min) * x_dim);
if ((nchunkindex < snapcnt) && (nchunkindex >= 0)) {
emit = snaparray[nchunkindex].getBlockEmittedLight(nx, y, nz);
sky = snaparray[nchunkindex].getBlockSkyLight(nx, y, nz);
}
}
return (emit << 8) + sky;
}
private void biomePrep() {
if (sameneighborbiomecnt != null) {

View File

@ -177,6 +177,29 @@ public class ForgeMapChunkCache extends MapChunkCache
return 0;
}
}
@Override
/**
* Get block sky and emitted light, relative to current coordinate
* @return (emitted light * 256) + sky light
*/
public final int getBlockLight(BlockStep step) {
int emit = 0, sky = 15;
if (step.yoff != 0) { // Y coord - snap is valid already
int ny = y + step.yoff;
emit = snap.getBlockEmittedLight(x, ny, z);
sky = snap.getBlockSkyLight(x, ny, z);
}
else {
int nx = x + step.xoff;
int nz = z + step.zoff;
int nchunkindex = ((nx >> 4) - x_min) + (((nz >> 4) - z_min) * x_dim);
if ((nchunkindex < snapcnt) && (nchunkindex >= 0)) {
emit = snaparray[nchunkindex].getBlockEmittedLight(nx, y, nz);
sky = snaparray[nchunkindex].getBlockSkyLight(nx, y, nz);
}
}
return (emit << 8) + sky;
}
private void biomePrep()
{
if (sameneighborbiomecnt != null)

View File

@ -177,7 +177,31 @@ public class ForgeMapChunkCache extends MapChunkCache
return 0;
}
}
private void biomePrep()
@Override
/**
* Get block sky and emitted light, relative to current coordinate
* @return (emitted light * 256) + sky light
*/
public final int getBlockLight(BlockStep step) {
int emit = 0, sky = 15;
if (step.yoff != 0) { // Y coord - snap is valid already
int ny = y + step.yoff;
emit = snap.getBlockEmittedLight(x, ny, z);
sky = snap.getBlockSkyLight(x, ny, z);
}
else {
int nx = x + step.xoff;
int nz = z + step.zoff;
int nchunkindex = ((nx >> 4) - x_min) + (((nz >> 4) - z_min) * x_dim);
if ((nchunkindex < snapcnt) && (nchunkindex >= 0)) {
emit = snaparray[nchunkindex].getBlockEmittedLight(nx, y, nz);
sky = snaparray[nchunkindex].getBlockSkyLight(nx, y, nz);
}
}
return (emit << 8) + sky;
}
private void biomePrep()
{
if (sameneighborbiomecnt != null)
{

View File

@ -178,7 +178,31 @@ public class ForgeMapChunkCache extends MapChunkCache
return 0;
}
}
private void biomePrep()
@Override
/**
* Get block sky and emitted light, relative to current coordinate
* @return (emitted light * 256) + sky light
*/
public final int getBlockLight(BlockStep step) {
int emit = 0, sky = 15;
if (step.yoff != 0) { // Y coord - snap is valid already
int ny = y + step.yoff;
emit = snap.getBlockEmittedLight(x, ny, z);
sky = snap.getBlockSkyLight(x, ny, z);
}
else {
int nx = x + step.xoff;
int nz = z + step.zoff;
int nchunkindex = ((nx >> 4) - x_min) + (((nz >> 4) - z_min) * x_dim);
if ((nchunkindex < snapcnt) && (nchunkindex >= 0)) {
emit = snaparray[nchunkindex].getBlockEmittedLight(nx, y, nz);
sky = snaparray[nchunkindex].getBlockSkyLight(nx, y, nz);
}
}
return (emit << 8) + sky;
}
private void biomePrep()
{
if (sameneighborbiomecnt != null)
{

View File

@ -174,7 +174,31 @@ public class ForgeMapChunkCache extends MapChunkCache
return 0;
}
}
private void biomePrep()
@Override
/**
* Get block sky and emitted light, relative to current coordinate
* @return (emitted light * 256) + sky light
*/
public final int getBlockLight(BlockStep step) {
int emit = 0, sky = 15;
if (step.yoff != 0) { // Y coord - snap is valid already
int ny = y + step.yoff;
emit = snap.getBlockEmittedLight(x, ny, z);
sky = snap.getBlockSkyLight(x, ny, z);
}
else {
int nx = x + step.xoff;
int nz = z + step.zoff;
int nchunkindex = ((nx >> 4) - x_min) + (((nz >> 4) - z_min) * x_dim);
if ((nchunkindex < snapcnt) && (nchunkindex >= 0)) {
emit = snaparray[nchunkindex].getBlockEmittedLight(nx, y, nz);
sky = snaparray[nchunkindex].getBlockSkyLight(nx, y, nz);
}
}
return (emit << 8) + sky;
}
private void biomePrep()
{
if (sameneighborbiomecnt != null)
{

View File

@ -174,7 +174,31 @@ public class ForgeMapChunkCache extends MapChunkCache
return 0;
}
}
private void biomePrep()
@Override
/**
* Get block sky and emitted light, relative to current coordinate
* @return (emitted light * 256) + sky light
*/
public final int getBlockLight(BlockStep step) {
int emit = 0, sky = 15;
if (step.yoff != 0) { // Y coord - snap is valid already
int ny = y + step.yoff;
emit = snap.getBlockEmittedLight(x, ny, z);
sky = snap.getBlockSkyLight(x, ny, z);
}
else {
int nx = x + step.xoff;
int nz = z + step.zoff;
int nchunkindex = ((nx >> 4) - x_min) + (((nz >> 4) - z_min) * x_dim);
if ((nchunkindex < snapcnt) && (nchunkindex >= 0)) {
emit = snaparray[nchunkindex].getBlockEmittedLight(nx, y, nz);
sky = snaparray[nchunkindex].getBlockSkyLight(nx, y, nz);
}
}
return (emit << 8) + sky;
}
private void biomePrep()
{
if (sameneighborbiomecnt != null)
{