diff --git a/src/main/java/com/seibel/lod/Main.java b/src/main/java/com/seibel/lod/Main.java index e51463c7b..05c00a423 100644 --- a/src/main/java/com/seibel/lod/Main.java +++ b/src/main/java/com/seibel/lod/Main.java @@ -11,14 +11,13 @@ public class Main { public static void main(String[] args) { - /* try { long[][] dataToMerge = new long[][]{ - {DataPointUtil.createDataPoint(10, 5, 0, 0, 0)}, - {DataPointUtil.createDataPoint(15, 5, 0, 0, 0)}, - {DataPointUtil.createDataPoint(40, 20, 0, 0, 0)}, - {DataPointUtil.createDataPoint(1, 0, 0, 0, 0)}}; + {DataPointUtil.createDataPoint(10, 5, 0, 0, 0, 0)}, + {DataPointUtil.createDataPoint(15, 5, 0, 0, 0, 0)}, + {DataPointUtil.createDataPoint(40, 20, 0, 0, 0, 0)}, + {DataPointUtil.createDataPoint(1, 0, 0, 0, 0, 0)}}; long[] data = DataPointUtil.mergeVerticalData(dataToMerge); for (long dataPoint : data) { @@ -27,6 +26,6 @@ public class Main } }catch (Exception e){ e.printStackTrace(); - }*/ + } } } diff --git a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java index 7e502783d..0ee8d2be6 100644 --- a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java @@ -26,6 +26,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.locks.ReentrantLock; +import com.seibel.lod.enums.LodQualityMode; +import com.seibel.lod.util.*; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL15C; @@ -40,10 +42,6 @@ import com.seibel.lod.proxy.ClientProxy; import com.seibel.lod.proxy.GlProxy; import com.seibel.lod.proxy.GlProxy.GlProxyContext; import com.seibel.lod.render.LodRenderer; -import com.seibel.lod.util.DataPointUtil; -import com.seibel.lod.util.LevelPosUtil; -import com.seibel.lod.util.LodThreadFactory; -import com.seibel.lod.util.LodUtil; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.LightTexture; @@ -67,72 +65,70 @@ public class LodBufferBuilder * This holds the threads used to generate buffers. */ public static ExecutorService bufferBuilderThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfBufferBuilderThreads.get(), new LodThreadFactory(LodBufferBuilder.class.getSimpleName() + " - builder")); - + /** * The buffers that are used to create LODs using far fog */ public volatile BufferBuilder[][] buildableBuffers; - + /** * Used when building new VBOs */ public volatile VertexBuffer[][] buildableVbos; - + /** * VBOs that are sent over to the LodNodeRenderer */ public volatile VertexBuffer[][] drawableVbos; - + /** * if this is true the LOD buffers are currently being * regenerated. */ public boolean generatingBuffers = false; - + /** * if this is true new LOD buffers have been generated * and are waiting to be swapped with the drawable buffers */ private boolean switchVbos = false; - + /** * Size of the buffer builders in bytes last time we created them */ public int previousBufferSize = 0; - + /** * Width of the dimension in regions last time we created the buffers */ public int previousRegionWidth = 0; - + /** * this is used to prevent multiple threads creating, destroying, or using the buffers at the same time */ private ReentrantLock bufferLock = new ReentrantLock(); - + private static final int NUMBER_OF_DIRECTION = 4; //in order -x, +x, -z, +z - private static final int[][] ADJ_DIRECTION = new int[][] { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; - + private static final int[][] ADJ_DIRECTION = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; + private volatile Box[][] boxCache; private volatile PosToRenderContainer[][] setsToRender; private volatile RegionPos center; - + /** * This is the ChunkPos the player was at the last time the buffers were built. * IE the center of the buffers last time they were built */ private volatile ChunkPos drawableCenterChunkPos = new ChunkPos(0, 0); private volatile ChunkPos buildableCenterChunkPos = new ChunkPos(0, 0); - - - - + + public LodBufferBuilder() { - + } - + /** * Create a thread to asynchronously generate LOD buffers * centered around the given camera X and Z. @@ -143,10 +139,10 @@ public class LodBufferBuilder * swapped with the drawable buffers in the LodRenderer to be drawn. */ public void generateLodBuffersAsync(LodRenderer renderer, LodDimension lodDim, - BlockPos playerBlockPos, boolean fullRegen) + BlockPos playerBlockPos, boolean fullRegen) { - +/* for(int i = 0; i<16; i++) { for(int j = 0; j<16; j++) @@ -156,61 +152,61 @@ public class LodBufferBuilder System.out.print(Integer.toHexString(lightTint) + " "); } System.out.println(); - } + }*/ // only allow one generation process to happen at a time if (generatingBuffers) return; - + if (buildableBuffers == null) // setupBuffers hasn't been called yet return; - + generatingBuffers = true; - + // round the player's block position down to the nearest chunk BlockPos ChunkPos playerChunkPos = new ChunkPos(playerBlockPos); BlockPos playerBlockPosRounded = playerChunkPos.getWorldPosition(); - + Thread thread = new Thread(() -> { bufferLock.lock(); - + try { long treeStart = System.currentTimeMillis(); long treeEnd = System.currentTimeMillis(); - + long startTime = System.currentTimeMillis(); - + ArrayList> nodeToRenderThreads = new ArrayList<>(lodDim.regions.length * lodDim.regions.length); - + startBuffers(fullRegen, lodDim); - + // =====================// // RENDERING PART // // =====================// - + RegionPos playerRegionPos = new RegionPos(playerChunkPos); if (center == null) center = playerRegionPos; - + if (setsToRender == null) setsToRender = new PosToRenderContainer[lodDim.regions.length][lodDim.regions.length]; - + if (setsToRender.length != lodDim.regions.length) setsToRender = new PosToRenderContainer[lodDim.regions.length][lodDim.regions.length]; - + if (boxCache == null) boxCache = new Box[lodDim.regions.length][lodDim.regions.length]; - + if (boxCache.length != lodDim.regions.length) boxCache = new Box[lodDim.regions.length][lodDim.regions.length]; - + // this will be the center of the VBOs once they have been built buildableCenterChunkPos = playerChunkPos; - + for (int xRegion = 0; xRegion < lodDim.regions.length; xRegion++) { for (int zRegion = 0; zRegion < lodDim.regions.length; zRegion++) @@ -220,7 +216,7 @@ public class LodBufferBuilder RegionPos regionPos = new RegionPos( xRegion + lodDim.getCenterX() - Math.floorDiv(lodDim.getWidth(), 2), zRegion + lodDim.getCenterZ() - Math.floorDiv(lodDim.getWidth(), 2)); - + // local position in the vbo and bufferBuilder arrays BufferBuilder currentBuffer = buildableBuffers[xRegion][zRegion]; LodRegion region = lodDim.getRegion(regionPos.x, regionPos.z); @@ -235,26 +231,26 @@ public class LodBufferBuilder final int zR = zRegion; Callable dataToRenderThread = () -> { - + //previous setToRender chache if (setsToRender[xR][zR] == null) { setsToRender[xR][zR] = new PosToRenderContainer(minDetail, regionPos.x, regionPos.z); } - + if (boxCache[xR][zR] == null) { boxCache[xR][zR] = new Box(); } PosToRenderContainer posToRender = setsToRender[xR][zR]; posToRender.clear(minDetail, regionPos.x, regionPos.z); - + lodDim.getDataToRender( posToRender, regionPos, playerBlockPosRounded.getX(), playerBlockPosRounded.getZ()); - + byte detailLevel; int posX; int posZ; @@ -275,62 +271,77 @@ public class LodBufferBuilder chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkPos.x; chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkPos.z; if (gameChunkRenderDistance >= Math.abs(chunkXdist) - && gameChunkRenderDistance >= Math.abs(chunkZdist) - && detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL - && renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]) + && gameChunkRenderDistance >= Math.abs(chunkZdist) + && detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL + && renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]) { continue; } // skip any chunks that Minecraft is going to render try { - //dataPoint = lodDim.getData(detailLevel, posX, posZ)[0]; - for(long dataPoint : lodDim.getData(detailLevel, posX, posZ)) - { - if (!DataPointUtil.isItVoid(dataPoint) && DataPointUtil.doesItExist(dataPoint)) + if (region.getLodQualityMode() == LodQualityMode.HEIGHTMAP) { - /* - for (int direction = 0; direction < NUMBER_OF_DIRECTION; direction++) + //dataPoint = lodDim.getData(detailLevel, posX, posZ)[0]; + long dataPoint = lodDim.getSingleData(detailLevel, posX, posZ); + if (!DataPointUtil.isItVoid(dataPoint) && DataPointUtil.doesItExist(dataPoint)) { - xAdj = posX + ADJ_DIRECTION[direction][0]; - zAdj = posZ + ADJ_DIRECTION[direction][1]; - chunkXdist = LevelPosUtil.getChunkPos(detailLevel, xAdj) - playerChunkPos.x; - chunkZdist = LevelPosUtil.getChunkPos(detailLevel, zAdj) - playerChunkPos.z; - - if (gameChunkRenderDistance >= Math.abs(chunkXdist) && gameChunkRenderDistance >= Math.abs(chunkZdist)) + dataPoint = lodDim.getSingleData(detailLevel, posX, posZ); + if(DataPointUtil.getHeight(dataPoint) == LodBuilder.DEFAULT_HEIGHT && DataPointUtil.getDepth(dataPoint) == LodBuilder.DEFAULT_DEPTH) + continue; + for (int direction = 0; direction < NUMBER_OF_DIRECTION; direction++) { - if (!renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1] - && posToRender.contains(detailLevel, xAdj, zAdj)) + + xAdj = posX + ADJ_DIRECTION[direction][0]; + zAdj = posZ + ADJ_DIRECTION[direction][1]; + chunkXdist = LevelPosUtil.getChunkPos(detailLevel,xAdj) - playerChunkPos.x; + chunkZdist = LevelPosUtil.getChunkPos(detailLevel,zAdj) - playerChunkPos.z; + + if (gameChunkRenderDistance >= Math.abs(chunkXdist) && gameChunkRenderDistance >= Math.abs(chunkZdist)) { - adjData[direction] = lodDim.getData(detailLevel, xAdj, zAdj)[0]; - } else + if (!renderer.vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1] + && posToRender.contains(detailLevel, xAdj, zAdj)) { - adjData[direction] = 0; - } + adjData[direction]= lodDim.getSingleData(detailLevel, xAdj, zAdj); + }else{ + adjData[direction]= 0; + } } else - { - if (posToRender.contains(detailLevel, xAdj, zAdj)) { - adjData[direction] = lodDim.getData(detailLevel, xAdj, zAdj)[0]; - } else + if (posToRender.contains(detailLevel, xAdj, zAdj)) { - adjData[direction] = 0; + adjData[direction] = lodDim.getSingleData(detailLevel, xAdj, zAdj); + }else{ + adjData[direction]= 0; + } } } - }*/ - LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, dataPoint, adjData, - detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode); - } + LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, dataPoint, adjData, + detailLevel, posX, posZ, boxCache[xR][zR],renderer.previousDebugMode); + } + + } else if (region.getLodQualityMode() == LodQualityMode.MULTI_LOD) + { + //dataPoint = lodDim.getData(detailLevel, posX, posZ)[0]; + for (long dataPoint : lodDim.getData(detailLevel, posX, posZ)) + { + if (!DataPointUtil.isItVoid(dataPoint) && DataPointUtil.doesItExist(dataPoint)) + { + LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, dataPoint, adjData, + detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode); + } + } } + } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); return false; } - + } // for pos to in list to render - // the thread executed successfully + // the thread executed successfully return true; }; nodeToRenderThreads.add(dataToRenderThread); @@ -351,7 +362,7 @@ public class LodBufferBuilder } } long renderEnd = System.currentTimeMillis(); - + long endTime = System.currentTimeMillis(); @SuppressWarnings("unused") long buildTime = endTime - startTime; @@ -366,38 +377,36 @@ public class LodBufferBuilder // mark that the buildable buffers as ready to swap switchVbos = true; - } - catch (Exception e) + } catch (Exception e) { ClientProxy.LOGGER.warn("\"LodNodeBufferBuilder.generateLodBuffersAsync\" ran into trouble: "); e.printStackTrace(); - } - finally + } finally { // regardless of if we successfully created the buffers // we are done generating. generatingBuffers = false; - + // clean up any potentially open resources if (buildableBuffers != null) closeBuffers(fullRegen, lodDim); - + // upload the new buffers uploadBuffers(fullRegen, lodDim); bufferLock.unlock(); } - + }); - + mainGenThread.execute(thread); - + return; } - + //===============================// // BufferBuilder related methods // //===============================// - + /** * Called from the LodRenderer to create the * BufferBuilders.

@@ -407,30 +416,30 @@ public class LodBufferBuilder public void setupBuffers(int numbRegionsWide, int bufferMaxCapacity) { bufferLock.lock(); - + previousRegionWidth = numbRegionsWide; previousBufferSize = bufferMaxCapacity; - + buildableBuffers = new BufferBuilder[numbRegionsWide][numbRegionsWide]; - + buildableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide]; drawableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide]; - - + + for (int x = 0; x < numbRegionsWide; x++) { for (int z = 0; z < numbRegionsWide; z++) { buildableBuffers[x][z] = new BufferBuilder(bufferMaxCapacity); - + buildableVbos[x][z] = new VertexBuffer(LodRenderer.LOD_VERTEX_FORMAT); drawableVbos[x][z] = new VertexBuffer(LodRenderer.LOD_VERTEX_FORMAT); } } - + bufferLock.unlock(); } - + /** * sets the buffers and Vbos to null, forcing them to be recreated.

*

@@ -439,14 +448,14 @@ public class LodBufferBuilder public void destroyBuffers() { bufferLock.lock(); - + buildableBuffers = null; buildableVbos = null; drawableVbos = null; - + bufferLock.unlock(); } - + /** * Calls begin on each of the buildable BufferBuilders. */ @@ -463,7 +472,7 @@ public class LodBufferBuilder } } } - + /** * Calls end on each of the buildable BufferBuilders. */ @@ -472,9 +481,9 @@ public class LodBufferBuilder for (int x = 0; x < buildableBuffers.length; x++) for (int z = 0; z < buildableBuffers.length; z++) if (buildableBuffers[x][z] != null && buildableBuffers[x][z].building() && (fullRegen || lodDim.regen[x][z])) - buildableBuffers[x][z].end(); + buildableBuffers[x][z].end(); } - + /** * Upload all buildableBuffers to the GPU. */ @@ -486,8 +495,8 @@ public class LodBufferBuilder glProxy.setGlContext(GlProxyContext.LOD_BUILDER); // only print console debugging for vboUpload once per upload cycle boolean bufferMapFail = false; - - + + for (int x = 0; x < buildableVbos.length; x++) { for (int z = 0; z < buildableVbos.length; z++) @@ -500,14 +509,14 @@ public class LodBufferBuilder } } } - - + + // make sure all the buffers have been uploaded. // this probably is necessary, but it makes me feel good :) GL11.glFlush(); glProxy.setGlContext(GlProxyContext.NONE); } - + /** * Uploads the uploadBuffer into the VBO in GPU memory. */ @@ -517,47 +526,46 @@ public class LodBufferBuilder if (vbo.id != -1) { vbo.vertexCount = uploadBuffer.remaining() / vbo.format.getVertexSize(); - - + + GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo.id); - - + + // make sure enough space is allocated to fit the builderBuffer GL15C.glBufferData(GL15.GL_ARRAY_BUFFER, uploadBuffer.capacity(), GL15C.GL_DYNAMIC_DRAW); // try to get a pointer to the VBO's byteBuffer in GPU memory ByteBuffer vboBuffer = GL15C.glMapBuffer(GL15.GL_ARRAY_BUFFER, GL15.GL_WRITE_ONLY); - + // upload the builderBuffer to the GPU if (vboBuffer != null) { // This is the best way to upload lots of data, since writes directly to GPU // memory, and doesn't pause OpenGL. vboBuffer.put(uploadBuffer); - } - else + } else { // Sometimes the vboBuffer is null (I think it may be due to buffer sizes // changing or a setup process that didn't complete), so in that case // we have to use this method which is slower and pauses OpenGL, // but always succeeds. GL15C.glBufferData(GL15.GL_ARRAY_BUFFER, uploadBuffer, GL15C.GL_DYNAMIC_DRAW); - + // only print to console once per upload cycle if (!bufferMapFail) ClientProxy.LOGGER.debug("LOD buffer upload: glMapBuffer failed, used slower glBufferData."); bufferMapFail = true; } - - + + GL15C.glUnmapBuffer(GL15.GL_ARRAY_BUFFER); GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); } - - + + // just used to improve debug printing return bufferMapFail; } - + /** * Get the newly created VBOs */ @@ -570,17 +578,17 @@ public class LodBufferBuilder VertexBuffer[][] tmpVbo = drawableVbos; drawableVbos = buildableVbos; buildableVbos = tmpVbo; - + drawableCenterChunkPos = buildableCenterChunkPos; - + // the vbos have been swapped switchVbos = false; bufferLock.unlock(); } - + return new VertexBuffersAndOffset(drawableVbos, drawableCenterChunkPos); } - + /** * A simple container to pass multiple objects back in the getVertexBuffers method. */ @@ -588,14 +596,14 @@ public class LodBufferBuilder { public VertexBuffer[][] vbos; public ChunkPos drawableCenterChunkPos; - + public VertexBuffersAndOffset(VertexBuffer[][] newVbos, ChunkPos newDrawableCenterChunkPos) { vbos = newVbos; drawableCenterChunkPos = newDrawableCenterChunkPos; } } - + /** * If this is true the buildable near and far * buffers have been generated and are ready to be @@ -605,5 +613,5 @@ public class LodBufferBuilder { return switchVbos; } - + } diff --git a/src/main/java/com/seibel/lod/builders/LodBuilder.java b/src/main/java/com/seibel/lod/builders/LodBuilder.java index d78d7be81..66af45eff 100644 --- a/src/main/java/com/seibel/lod/builders/LodBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBuilder.java @@ -190,32 +190,39 @@ public class LodBuilder posX = LevelPosUtil.convert((byte) 0, chunk.getPos().x * 16 + startX, detail.detailLevel); posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().z * 16 + startZ, detail.detailLevel); - long[] data = null - ; + long singleData = 0; + long[] data = null; + boolean isServer = config.distanceGenerationMode == DistanceGenerationMode.SERVER; + switch (lodQualityMode){ + default: case HEIGHTMAP: - data = ThreadMapUtil.getSingleAddDataArray(); long[] dataToMergeSingle; dataToMergeSingle = createSingleDataToMerge(detail, chunk, config, startX, startZ, endX, endZ); - data[0] = DataPointUtil.mergeSingleData(dataToMergeSingle); + singleData = DataPointUtil.mergeSingleData(dataToMergeSingle); + lodDim.addSingleData(detailLevel, + posX, + posZ, + singleData, + false, + isServer); break; case MULTI_LOD: long[][] dataToMergeVertical; dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ, endX, endZ); data = DataPointUtil.mergeVerticalData(dataToMergeVertical); + if (data.length == 0 || data == null) + data = new long[]{DataPointUtil.EMPTY_DATA}; + lodDim.addData(detailLevel, + posX, + posZ, + data, + false, + isServer); break; } - if (data.length == 0 || data == null) - data = new long[]{DataPointUtil.EMPTY_DATA}; - boolean isServer = config.distanceGenerationMode == DistanceGenerationMode.SERVER; - lodDim.addData(detailLevel, - posX, - posZ, - data, - false, - isServer); } lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z); @@ -382,6 +389,9 @@ public class LodBuilder int xAbs; int yAbs; int zAbs; + int lightBlock; + int lightSky; + BlockPos.Mutable blockPos = new BlockPos.Mutable(0, 0, 0); int index = 0; @@ -414,8 +424,9 @@ public class LodBuilder blockPos.set(xAbs, yAbs + 1, zAbs); light = getLightValue(chunk, blockPos); - - dataToMerge[index] = DataPointUtil.createDataPoint(height, depth, color, (light >> 4) & 0b1111, light & 0b1111, generation); + lightBlock = light & 0b1111; + lightSky = (light >> 4) & 0b1111; + dataToMerge[index] = DataPointUtil.createDataPoint(height, depth, color, lightSky, lightBlock, generation); } return dataToMerge; } @@ -440,6 +451,7 @@ public class LodBuilder { for (int yRel = 0; yRel < CHUNK_DATA_WIDTH; yRel++) { + blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel, chunk.getPos().getMinBlockZ() + zRel); if (isLayerValidLodPoint(chunk, blockPos)) { depth = (short) (sectionIndex * CHUNK_DATA_WIDTH + yRel); @@ -474,6 +486,7 @@ public class LodBuilder { for (int yRel = CHUNK_DATA_WIDTH - 1; yRel >= 0; yRel--) { + blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel, chunk.getPos().getMinBlockZ() + zRel); if (isLayerValidLodPoint(chunk, blockPos)) { height = (short) (sectionIndex * CHUNK_DATA_WIDTH + yRel + 1); @@ -537,6 +550,7 @@ public class LodBuilder light += MinecraftWrapper.INSTANCE.getPlayer().level.getBrightness(LightType.SKY, blockPos) << 4; //BlockState blockState = chunk.getBlockState(blockPos); //lightBlock = (byte) blockState.getLightBlock(chunk, blockPos); + //lightBlock = (byte) blockState.getLightBlock(chunk, blockPos); return light; } @@ -689,7 +703,7 @@ public class LodBuilder BlockState blockState = chunk.getBlockState(blockPos); if (blockState != null) { - if (!blockState.getFluidState().isEmpty()) + /*if (!blockState.getFluidState().isEmpty()) { return true; } @@ -707,7 +721,7 @@ public class LodBuilder } else { return false; - } + }*/ if (blockState.getBlock() != Blocks.AIR && blockState.getBlock() != Blocks.CAVE_AIR && blockState.getBlock() != Blocks.BARRIER) @@ -718,4 +732,26 @@ public class LodBuilder return false; } + + private boolean isLayerValidLodPoint(ChunkSection[] chunkSections, int sectionIndex, int y, int x, int z) + { + if (chunkSections[sectionIndex] == null) + { + // this section doesn't have any blocks, + // it is not a valid section + return false; + } else + { + if (chunkSections[sectionIndex].getBlockState(x, y, z) != null + && chunkSections[sectionIndex].getBlockState(x, y, z).getBlock() != Blocks.AIR + && chunkSections[sectionIndex].getBlockState(x, y, z).getBlock() != Blocks.CAVE_AIR + && chunkSections[sectionIndex].getBlockState(x, y, z).getBlock() != Blocks.BARRIER) + { + return true; + } + } + + return false; + } + } diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java index 441ddb1a6..424d788c8 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java @@ -61,13 +61,14 @@ public class CubicLodTemplate extends AbstractLodTemplate 0, posZ * width, bufferCenterBlockPos); - int color; + int color;/* boolean hasSkyLight = MinecraftWrapper.INSTANCE.getPlayer().level.dimensionType().hasSkyLight(); boolean hasRoof = MinecraftWrapper.INSTANCE.getPlayer().level.dimensionType().hasSkyLight(); int time = (int) (MinecraftWrapper.INSTANCE.getPlayer().level.getDayTime() - 13000); - boolean isDay = time < 0; + boolean isDay = time < 0;*/ //USE THIS IN THE boolean hasCeiling = MinecraftWrapper.INSTANCE.getPlayer().level.dimensionType().hasCeiling(); - color = DataPointUtil.getLightColor(data, (hasRoof & hasSkyLight), isDay); + //color = DataPointUtil.getLightColor(data, (hasRoof & hasSkyLight), isDay); + color = DataPointUtil.getColor(data); if (debugging != DebugMode.OFF) @@ -217,7 +218,7 @@ public class CubicLodTemplate extends AbstractLodTemplate addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha); addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha); addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha); - } else + }else { maxY = box.getMaxY(); tempMaxY = DataPointUtil.getHeight(data); @@ -262,7 +263,8 @@ public class CubicLodTemplate extends AbstractLodTemplate addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha); addPosAndColor(buffer, maxX, minY, maxZ, red, green, blue, alpha); addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha); - } else + } + else { maxY = box.getMaxY(); tempMaxY = DataPointUtil.getHeight(data); @@ -307,7 +309,8 @@ public class CubicLodTemplate extends AbstractLodTemplate addPosAndColor(buffer, maxX, maxY, maxZ, red, green, blue, alpha); addPosAndColor(buffer, minX, maxY, maxZ, red, green, blue, alpha); addPosAndColor(buffer, minX, minY, maxZ, red, green, blue, alpha); - } else + } + else { maxY = box.getMaxY(); tempMaxY = DataPointUtil.getHeight(data); @@ -352,7 +355,8 @@ public class CubicLodTemplate extends AbstractLodTemplate addPosAndColor(buffer, minX, maxY, minZ, red, green, blue, alpha); addPosAndColor(buffer, maxX, maxY, minZ, red, green, blue, alpha); addPosAndColor(buffer, maxX, minY, minZ, red, green, blue, alpha); - } else + } + else { maxY = box.getMaxY(); tempMaxY = DataPointUtil.getHeight(data); @@ -376,6 +380,7 @@ public class CubicLodTemplate extends AbstractLodTemplate } } } + } @Override diff --git a/src/main/java/com/seibel/lod/config/LodConfig.java b/src/main/java/com/seibel/lod/config/LodConfig.java index 76b1276a8..987a25bae 100644 --- a/src/main/java/com/seibel/lod/config/LodConfig.java +++ b/src/main/java/com/seibel/lod/config/LodConfig.java @@ -201,7 +201,7 @@ public class LodConfig + " Use 3d lods or 2d lods? \n" + " " + LodQualityMode.HEIGHTMAP.toString() + ": enable 2d lods with heightmap \n" + " " + LodQualityMode.MULTI_LOD.toString() + ": enable 3d lods with heightmap \n") - .defineEnum("lodGenerationQuality", LodQualityMode.HEIGHTMAP); + .defineEnum("lodQualityMode", LodQualityMode.HEIGHTMAP); maxGenerationDetail = builder .comment("\n\n" diff --git a/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java b/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java index 205ca5ef1..bab05d836 100644 --- a/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java +++ b/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java @@ -193,8 +193,16 @@ public class LodDimensionFileHandler data = bufferedReader.readLine(); bufferedReader.close(); + switch (region.getLodQualityMode()){ + default: + case HEIGHTMAP: + region.addLevel(new SingleLevelContainer(data)); + break; + case MULTI_LOD: + region.addLevel(new VerticalLevelContainer(data)); + break; + } //region.addLevel(new SingleLevelContainer(data)); - region.addLevel(new VerticalLevelContainer(data)); } catch (Exception e) { // the buffered reader encountered a diff --git a/src/main/java/com/seibel/lod/objects/LevelContainer.java b/src/main/java/com/seibel/lod/objects/LevelContainer.java index 94bcd2c36..75a1c28e9 100644 --- a/src/main/java/com/seibel/lod/objects/LevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/LevelContainer.java @@ -19,6 +19,15 @@ public interface LevelContainer */ public boolean addData(long[] data, int posX, int posZ); + /**With this you can add data to the level container + * + * @param data actual data to add in a array of long format. + * @param posX x position in the detail level + * @param posZ z position in the detail level + * @return true if correctly added, false otherwise + */ + public boolean addSingleData(long data, int posX, int posZ); + /**With this you can get data from the level container * * @param posX x position in the detail level @@ -27,6 +36,14 @@ public interface LevelContainer */ public long[] getData(int posX, int posZ); + /**With this you can get data from the level container + * + * @param posX x position in the detail level + * @param posZ z position in the detail level + * @return the data in long array format + */ + public long getSingleData(int posX, int posZ); + /** * @param posX x position in the detail level * @param posZ z position in the detail level diff --git a/src/main/java/com/seibel/lod/objects/LodDimension.java b/src/main/java/com/seibel/lod/objects/LodDimension.java index 6c2c3dd46..4229d16dd 100644 --- a/src/main/java/com/seibel/lod/objects/LodDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodDimension.java @@ -467,6 +467,44 @@ public class LodDimension return nodeAdded; } + + /** + * Add the given LOD to this dimension at the coordinate + * stored in the LOD. If an LOD already exists at the given + * coordinates it will be overwritten. + */ + public Boolean addSingleData(byte detailLevel, int posX, int posZ, long dataPoint, boolean dontSave, boolean serverQuality) + { + + // don't continue if the region can't be saved + int regionPosX = LevelPosUtil.getRegion(detailLevel, posX); + int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ); + + LodRegion region = getRegion(regionPosX, regionPosZ); + if (region == null) + return false; + boolean nodeAdded = region.addSingleData(detailLevel, posX, posZ, dataPoint, serverQuality); + // only save valid LODs to disk + if (!dontSave && fileHandler != null) + { + try + { + // mark the region as dirty so it will be saved to disk + int xIndex = (regionPosX - center.x) + halfWidth; + int zIndex = (regionPosZ - center.z) + halfWidth; + isRegionDirty[xIndex][zIndex] = true; + regen[xIndex][zIndex] = true; + regenDimension = true; + } catch (ArrayIndexOutOfBoundsException e) + { + e.printStackTrace(); + // This method was probably called when the dimension was changing size. + // Hopefully this shouldn't be an issue. + } + } + return nodeAdded; + } + public void setToRegen(int xRegion, int zRegion) { int xIndex = (xRegion - center.x) + halfWidth; @@ -535,6 +573,27 @@ public class LodDimension return region.getData(detailLevel, posX, posZ); } + /** + * Get the data point at the given X and Z coordinates + * in this dimension. + *
+ * Returns null if the LodChunk doesn't exist or + * is outside the loaded area. + */ + public long getSingleData(byte detailLevel, int posX, int posZ) + { + if (detailLevel > LodUtil.REGION_DETAIL_LEVEL) + throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max."); + + LodRegion region = getRegion(detailLevel, posX, posZ); + + if (region == null) + { + return DataPointUtil.EMPTY_DATA; + } + + return region.getSingleData(detailLevel, posX, posZ); + } /** * Get the data point at the given X and Z coordinates diff --git a/src/main/java/com/seibel/lod/objects/LodRegion.java b/src/main/java/com/seibel/lod/objects/LodRegion.java index b7ed4040d..2977bf5a4 100644 --- a/src/main/java/com/seibel/lod/objects/LodRegion.java +++ b/src/main/java/com/seibel/lod/objects/LodRegion.java @@ -59,6 +59,7 @@ public class LodRegion for (byte lod = minDetailLevel; lod <= LodUtil.REGION_DETAIL_LEVEL; lod++) { switch (lodQualityMode){ + default: case HEIGHTMAP: dataContainer[lod] = new SingleLevelContainer(lod); break; @@ -102,6 +103,31 @@ public class LodRegion } } + /** + * This method can be used to insert data into the LodRegion + * + * @param dataPoint + * @return + */ + public boolean addSingleData(byte detailLevel, int posX, int posZ, long dataPoint, boolean serverQuality) + { + posX = LevelPosUtil.getRegionModule(detailLevel, posX); + posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + if (!doesDataExist(detailLevel, posX, posZ) || serverQuality) + { + + //update the number of node present + //if (!doesDataExist(detailLevel, posX, posZ)) numberOfPoints++; + + //add the node data + this.dataContainer[detailLevel].addSingleData(dataPoint, posX, posZ); + return true; + } else + { + return false; + } + } + /** * This method will return the data in the position relative to the level of detail * @@ -114,6 +140,19 @@ public class LodRegion return dataContainer[detailLevel].getData(posX, posZ); } + /** + * This method will return the data in the position relative to the level of detail + * + * @return the data at the relative pos and level + */ + public long getSingleData(byte detailLevel, int posX, int posZ) + { + posX = LevelPosUtil.getRegionModule(detailLevel, posX); + posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + return dataContainer[detailLevel].getSingleData(posX, posZ); + } + + /** * This method will return all the levelPos that are renderable according to the requisite given in input * diff --git a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java index 88984802e..e85405f09 100644 --- a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java @@ -26,7 +26,7 @@ public class SingleLevelContainer implements LevelContainer return true; } - private boolean addSingleData(long newData, int posX, int posZ){ + public boolean addSingleData(long newData, int posX, int posZ){ posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); data[posX][posZ] = newData; @@ -42,7 +42,7 @@ public class SingleLevelContainer implements LevelContainer return dataArray; } - private long getSingleData(int posX, int posZ){ + public long getSingleData(int posX, int posZ){ posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); //Improve this using a thread map to long[] diff --git a/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java b/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java index 3de5e291b..9a845780d 100644 --- a/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java @@ -34,12 +34,26 @@ public class VerticalLevelContainer implements LevelContainer return true; } + public boolean addSingleData(long newData, int posX, int posZ){ + posX = LevelPosUtil.getRegionModule(detailLevel, posX); + posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + dataContainer[posX][posZ][0] = newData; + return true; + } + public long[] getData(int posX, int posZ){ posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); return dataContainer[posX][posZ]; } + public long getSingleData(int posX, int posZ){ + posX = LevelPosUtil.getRegionModule(detailLevel, posX); + posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + //Improve this using a thread map to long[] + return dataContainer[posX][posZ][0]; + } + public boolean doesItExist(int posX, int posZ){ long[] data = getData(posX,posZ); if(data == null) diff --git a/src/main/java/com/seibel/lod/util/LodUtil.java b/src/main/java/com/seibel/lod/util/LodUtil.java index 833579887..069c47fff 100644 --- a/src/main/java/com/seibel/lod/util/LodUtil.java +++ b/src/main/java/com/seibel/lod/util/LodUtil.java @@ -84,7 +84,7 @@ public class LodUtil public static final byte DETAIL_OPTIONS = 10; - public static final short MAX_VERTICAL_DATA = 256; + public static final short MAX_VERTICAL_DATA = 4; /** measured in Blocks
* detail level 9 */ @@ -326,41 +326,40 @@ public class LodUtil * Get a HashSet of all ChunkPos within the normal render distance * that should not be rendered. */ - public static HashSet getNearbyLodChunkPosToSkip(LodDimension lodDim, BlockPos playerPos) - { - int chunkRenderDist = mc.getRenderDistance(); - ChunkPos centerChunk = new ChunkPos(playerPos); - - // skip chunks that are already going to be rendered by Minecraft - HashSet posToSkip = getRenderedChunks(); - - // go through each chunk within the normal view distance - for (int x = centerChunk.x - chunkRenderDist; x < centerChunk.x + chunkRenderDist; x++) - { - for (int z = centerChunk.z - chunkRenderDist; z < centerChunk.z + chunkRenderDist; z++) - { - if (!lodDim.doesDataExist(LodUtil.CHUNK_DETAIL_LEVEL, x, z)) - continue; - /* - long[] dataVertical = lodDim.getData(LodUtil.CHUNK_DETAIL_LEVEL, x, z); - long data = dataVertical[dataVertical.length - 1]; + public static HashSet getNearbyLodChunkPosToSkip(LodDimension lodDim, BlockPos playerPos) + { + int chunkRenderDist = mc.getRenderDistance(); + ChunkPos centerChunk = new ChunkPos(playerPos); - short lodAverageHeight = DataPointUtil.getHeight(data); + // skip chunks that are already going to be rendered by Minecraft + HashSet posToSkip = getRenderedChunks(); - if (playerPos.getY() <= lodAverageHeight) - { - // don't draw Lod's that are taller than the player - // to prevent LODs being drawn on top of the player - posToSkip.add(new ChunkPos(x, z)); - }*/ - posToSkip.add(new ChunkPos(x, z)); - } - } - - return posToSkip; - } + // go through each chunk within the normal view distance + for (int x = centerChunk.x - chunkRenderDist; x < centerChunk.x + chunkRenderDist; x++) + { + for (int z = centerChunk.z - chunkRenderDist; z < centerChunk.z + chunkRenderDist; z++) + { + if (!lodDim.doesDataExist(LodUtil.CHUNK_DETAIL_LEVEL, x, z)) + continue; - /** + long data = lodDim.getSingleData(LodUtil.CHUNK_DETAIL_LEVEL, x, z); + + short lodAverageHeight = DataPointUtil.getHeight(data); + + if (playerPos.getY() <= lodAverageHeight) + { + // don't draw Lod's that are taller than the player + // to prevent LODs being drawn on top of the player + posToSkip.add(new ChunkPos(x, z)); + } + } + } + + return posToSkip; + } + + + /** * This method returns the ChunkPos of all chunks that Minecraft * is going to render this frame.

*

diff --git a/src/main/java/com/seibel/lod/util/ThreadMapUtil.java b/src/main/java/com/seibel/lod/util/ThreadMapUtil.java index 39ea8f798..dcdc333d2 100644 --- a/src/main/java/com/seibel/lod/util/ThreadMapUtil.java +++ b/src/main/java/com/seibel/lod/util/ThreadMapUtil.java @@ -5,48 +5,56 @@ import java.util.concurrent.ConcurrentMap; public class ThreadMapUtil { - public static final ConcurrentMap threadSingleAddDataMap = new ConcurrentHashMap(); - public static final ConcurrentMap threadSingleGetDataMap = new ConcurrentHashMap(); - public static final ConcurrentMap threadSingleUpdateMap = new ConcurrentHashMap(); - public static final ConcurrentMap threadBuilderArrayMap = new ConcurrentHashMap(); - public static final ConcurrentMap threadBuilderVerticalArrayMap = new ConcurrentHashMap(); - public static final ConcurrentMap threadVerticalAddDataMap = new ConcurrentHashMap(); - public static final ConcurrentMap threadVerticalGetDataMap = new ConcurrentHashMap(); - public static final ConcurrentMap threadVerticalUpdateMap = new ConcurrentHashMap(); - public static final ConcurrentMap threadVerticalIndexesMap = new ConcurrentHashMap(); + private static final int NUMBER_OF_DIRECTION = 4; + + public static final ConcurrentMap threadSingleAddDataMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadSingleGetDataMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadSingleUpdateMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadBuilderArrayMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadBuilderVerticalArrayMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadVerticalAddDataMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadVerticalGetDataMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadVerticalUpdateMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadVerticalIndexesMap = new ConcurrentHashMap(); - public static final ConcurrentMap projectionMap = new ConcurrentHashMap(); - public static final ConcurrentMap heightAndDepthMap = new ConcurrentHashMap(); - public static final ConcurrentMap singleDataToMergeMap = new ConcurrentHashMap(); + public static final ConcurrentMap threadAdjData = new ConcurrentHashMap(); + + public static final ConcurrentMap projectionMap = new ConcurrentHashMap(); + public static final ConcurrentMap heightAndDepthMap = new ConcurrentHashMap(); + public static final ConcurrentMap singleDataToMergeMap = new ConcurrentHashMap(); - public static long[] getSingleAddDataArray(){ - if(!threadSingleAddDataMap.containsKey(Thread.currentThread().getName()) || (threadSingleAddDataMap.get(Thread.currentThread().getName()) == null)) + public static long[] getSingleAddDataArray() + { + if (!threadSingleAddDataMap.containsKey(Thread.currentThread().getName()) || (threadSingleAddDataMap.get(Thread.currentThread().getName()) == null)) { threadSingleAddDataMap.put(Thread.currentThread().getName(), new long[1]); } return threadSingleAddDataMap.get(Thread.currentThread().getName()); } - public static long[] getSingleGetDataArray(){ - if(!threadSingleGetDataMap.containsKey(Thread.currentThread().getName()) || (threadSingleGetDataMap.get(Thread.currentThread().getName()) == null)) + public static long[] getSingleGetDataArray() + { + if (!threadSingleGetDataMap.containsKey(Thread.currentThread().getName()) || (threadSingleGetDataMap.get(Thread.currentThread().getName()) == null)) { threadSingleGetDataMap.put(Thread.currentThread().getName(), new long[1]); } return threadSingleGetDataMap.get(Thread.currentThread().getName()); } - public static long[] getSingleUpdateArray(){ - if(!threadSingleUpdateMap.containsKey(Thread.currentThread().getName()) || (threadSingleUpdateMap.get(Thread.currentThread().getName()) == null)) + public static long[] getSingleUpdateArray() + { + if (!threadSingleUpdateMap.containsKey(Thread.currentThread().getName()) || (threadSingleUpdateMap.get(Thread.currentThread().getName()) == null)) { threadSingleUpdateMap.put(Thread.currentThread().getName(), new long[4]); } return threadSingleUpdateMap.get(Thread.currentThread().getName()); } - public static long[][] getBuilderArray(){ - if(!threadBuilderArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderArrayMap.get(Thread.currentThread().getName()) == null)) + public static long[][] getBuilderArray() + { + if (!threadBuilderArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderArrayMap.get(Thread.currentThread().getName()) == null)) { long[][] array = new long[5][]; threadBuilderArrayMap.put(Thread.currentThread().getName(), array); @@ -54,8 +62,9 @@ public class ThreadMapUtil return threadBuilderArrayMap.get(Thread.currentThread().getName()); } - public static long[][][] getBuilderVerticalArray(){ - if(!threadBuilderVerticalArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()) == null)) + public static long[][][] getBuilderVerticalArray() + { + if (!threadBuilderVerticalArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()) == null)) { long[][][] array = new long[5][][]; threadBuilderVerticalArrayMap.put(Thread.currentThread().getName(), array); @@ -63,22 +72,33 @@ public class ThreadMapUtil return threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()); } - public static long[] addVerticalDataArray(){ - if(!threadVerticalAddDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMap.get(Thread.currentThread().getName()) == null)) + public static long[] addVerticalDataArray() + { + if (!threadVerticalAddDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMap.get(Thread.currentThread().getName()) == null)) { threadVerticalAddDataMap.put(Thread.currentThread().getName(), new long[16]); } return threadVerticalAddDataMap.get(Thread.currentThread().getName()); } - public static long[] getVerticalGetDataArray(){ - if(!threadVerticalGetDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalGetDataMap.get(Thread.currentThread().getName()) == null)) + public static long[] getVerticalGetDataArray() + { + if (!threadVerticalGetDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalGetDataMap.get(Thread.currentThread().getName()) == null)) { threadVerticalGetDataMap.put(Thread.currentThread().getName(), new long[16]); } return threadVerticalGetDataMap.get(Thread.currentThread().getName()); } + public static long[] getAdjDataArray() + { + if(!threadAdjData.containsKey(Thread.currentThread().getName()) || (threadAdjData.get(Thread.currentThread().getName()) == null)) + { + threadAdjData.put(Thread.currentThread().getName(), new long[NUMBER_OF_DIRECTION]); + } + return threadAdjData.get(Thread.currentThread().getName()); + } + public static long[][] getVerticalUpdateArray(){ if(!threadVerticalUpdateMap.containsKey(Thread.currentThread().getName()) || (threadVerticalUpdateMap.get(Thread.currentThread().getName()) == null)) {