diff --git a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java index 6f595a3f1..da1564904 100644 --- a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java @@ -28,6 +28,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.locks.ReentrantLock; +import com.seibel.lod.util.*; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL15C; @@ -43,10 +44,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.vertex.VertexBuffer; @@ -224,12 +221,21 @@ public class LodBufferBuilder Callable dataToRenderThread = () -> { Map adjData = new HashMap<>(); + int maxVerticalData; if (LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == LodQualityMode.HEIGHTMAP) { - adjData.put(Direction.WEST, new long[1]); - adjData.put(Direction.EAST, new long[1]); - adjData.put(Direction.SOUTH, new long[1]); - adjData.put(Direction.NORTH, new long[1]); + maxVerticalData = 1; + } else + { + maxVerticalData = DetailDistanceUtil.getMaxVerticalData(0); + } + + for (Direction direction : Box.ADJ_DIRECTIONS) + { + if (adjData.containsKey(direction) && LodConfig.CLIENT.worldGenerator.lodQualityMode.get() == LodQualityMode.MULTI_LOD) + { + adjData.put(direction, new long[DetailDistanceUtil.getMaxVerticalData(0)]); + } } //previous setToRender chache if (setsToRender[xR][zR] == null) @@ -257,12 +263,12 @@ public class LodBufferBuilder int zAdj; int chunkXdist; int chunkZdist; - + // keep a local version so we don't have to worry about indexOutOfBounds Exceptions // if it changes in the LodRenderer while we are working here - boolean[][] vanillaRenderedChunks = renderer.vanillaRenderedChunks; + boolean[][] vanillaRenderedChunks = renderer.vanillaRenderedChunks; short gameChunkRenderDistance = (short) (vanillaRenderedChunks.length / 2 - 1); - + for (int index = 0; index < posToRender.getNumberOfPos(); index++) { detailLevel = posToRender.getNthDetailLevel(index); @@ -297,7 +303,9 @@ public class LodBufferBuilder adjData.get(direction)[0] = lodDim.getSingleData(detailLevel, xAdj, zAdj); } else { - adjData.put(direction, lodDim.getData(detailLevel, xAdj, zAdj)); + adjData.put(direction, new long[DetailDistanceUtil.getMaxVerticalData(lodDim.getMaxVerticalData(detailLevel,posX,posZ))]); + for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, xAdj, zAdj); verticalIndex++) + adjData.get(direction)[verticalIndex] = lodDim.getData(detailLevel, xAdj, zAdj, verticalIndex); } } else @@ -319,7 +327,9 @@ public class LodBufferBuilder adjData.get(direction)[0] = lodDim.getSingleData(detailLevel, xAdj, zAdj); } else { - adjData.put(direction, lodDim.getData(detailLevel, xAdj, zAdj)); + adjData.put(direction, new long[DetailDistanceUtil.getMaxVerticalData(lodDim.getMaxVerticalData(detailLevel,posX,posZ))]); + for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, xAdj, zAdj); verticalIndex++) + adjData.get(direction)[verticalIndex] = lodDim.getData(detailLevel, xAdj, zAdj, verticalIndex); } } else { @@ -346,13 +356,14 @@ public class LodBufferBuilder } else if (region.getLodQualityMode() == LodQualityMode.MULTI_LOD) { - for (long dataPoint : lodDim.getData(detailLevel, posX, posZ)) + long data; + for (int verticalIndex = 0; verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ); verticalIndex++) { - 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, renderer.lightMap); - } + data = lodDim.getData(detailLevel, posX, posZ, verticalIndex); + if (DataPointUtil.isItVoid(data) || DataPointUtil.doesItExist(data)) + break; + LodConfig.CLIENT.graphics.lodTemplate.get().template.addLodToBuffer(currentBuffer, playerBlockPosRounded, data, adjData, + detailLevel, posX, posZ, boxCache[xR][zR], renderer.previousDebugMode, renderer.lightMap); } } @@ -512,14 +523,14 @@ public class LodBufferBuilder private void uploadBuffers(boolean fullRegen, LodDimension lodDim) { GlProxy glProxy = GlProxy.getInstance(); - + try { // make sure we are uploading to a different OpenGL context, // to prevent interference (IE stuttering) with the Minecraft context. glProxy.setGlContext(GlProxyContext.LOD_BUILDER); - - + + for (int x = 0; x < buildableVbos.length; x++) { for (int z = 0; z < buildableVbos.length; z++) @@ -532,25 +543,23 @@ public class LodBufferBuilder } } } - - + + // make sure all the buffers have been uploaded. // this probably is necessary, but it makes me feel good :) GL11.glFlush(); - } - catch (IllegalStateException e) + } catch (IllegalStateException e) { ClientProxy.LOGGER.error(LodBufferBuilder.class.getSimpleName() + " - UploadBuffers failed: " + e.getMessage()); e.printStackTrace(); - } - finally + } finally { // make sure no buffer is bound if (glProxy.getGlContext() == GlProxyContext.LOD_BUILDER) { GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); } - + // make sure the context is disabled glProxy.setGlContext(GlProxyContext.NONE); } @@ -579,8 +588,8 @@ public class LodBufferBuilder // is faster for transferring data. They must put the data in different memory // or something. GL15C.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, uploadBuffer); - - + + GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); } } diff --git a/src/main/java/com/seibel/lod/builders/LodBuilder.java b/src/main/java/com/seibel/lod/builders/LodBuilder.java index 26f97eddd..112d0dc25 100644 --- a/src/main/java/com/seibel/lod/builders/LodBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBuilder.java @@ -88,7 +88,7 @@ public class LodBuilder public static final ConcurrentMap colorMap = new ConcurrentHashMap<>(); public static final ConcurrentMap shapeMap = new ConcurrentHashMap<>(); - public static final ModelDataMap dataMap = new ModelDataMap.Builder().build() ; + public static final ModelDataMap dataMap = new ModelDataMap.Builder().build(); /** * If no blocks are found in the area in determineBottomPointForArea return this @@ -134,7 +134,7 @@ public class LodBuilder // get the textures for blocks if (mc.getClientWorld() == null) return; - + DimensionType dim = world.dimensionType(); LodDimension lodDim; @@ -239,17 +239,28 @@ public class LodBuilder isServer); break; case MULTI_LOD: - long[][] dataToMergeVertical; + long[] dataToMergeVertical; dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ, endX, endZ); - data = DataPointUtil.mergeMultiData(dataToMergeVertical); + data = DataPointUtil.mergeMultiData(dataToMergeVertical, detailLevel); if (data.length == 0 || data == null) data = new long[]{DataPointUtil.EMPTY_DATA}; - lodDim.addData(detailLevel, - posX, - posZ, - data, - false, - isServer); + //lodDim.clear(detailLevel, posX, posZ); + for (int verticalIndex = 0; (verticalIndex < data.length) && (verticalIndex < lodDim.getMaxVerticalData(detailLevel, posX, posZ)); verticalIndex++) + { + lodDim.addData(detailLevel, + posX, + posZ, + verticalIndex, + data[verticalIndex], + false, + isServer); + long dataTest = lodDim.getData(detailLevel, + posX, + posZ, + verticalIndex); + System.out.println(DataPointUtil.toString(dataTest)); + } + break; } @@ -263,11 +274,12 @@ public class LodBuilder } - private long[][] createVerticalDataToMerge(LodDetail detail, IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ) + private long[] createVerticalDataToMerge(LodDetail detail, IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ) { - long[][] dataToMerge = ThreadMapUtil.getBuilderVerticalArray()[detail.detailLevel]; - ChunkPos chunkPos = chunk.getPos(); + long[] dataToMerge = ThreadMapUtil.getBuilderVerticalArray()[detail.detailLevel]; + int verticalData = DataPointUtil.WORLD_HEIGHT; + ChunkPos chunkPos = chunk.getPos(); int size = 1 << detail.detailLevel; int height = 0; int depth = 0; @@ -286,17 +298,18 @@ public class LodBuilder BlockPos.Mutable blockPos = new BlockPos.Mutable(0, 0, 0); int index = 0; + if (dataToMerge == null) { - dataToMerge = new long[size * size][DataPointUtil.WORLD_HEIGHT]; + dataToMerge = new long[size * size * DataPointUtil.WORLD_HEIGHT]; } //dataToMerge = new long[size * size][1024]; for (index = 0; index < size * size; index++) { - for (int i = 0; i < dataToMerge[index].length; i++) + for (int verticalIndex = 0; verticalIndex < verticalData; verticalIndex++) { - dataToMerge[index][i] = 0; + dataToMerge[index * verticalData + verticalIndex] = DataPointUtil.EMPTY_DATA; } xRel = Math.floorMod(index, size) + startX; zRel = Math.floorDiv(index, size) + startZ; @@ -314,21 +327,20 @@ public class LodBuilder //If the lod is at default, then we set this as void data if (height == DEFAULT_HEIGHT) { - dataToMerge[index][0] = DataPointUtil.createVoidDataPoint(generation); + dataToMerge[index * verticalData + 0] = DataPointUtil.createVoidDataPoint(generation); break; } yAbs = height - 1; // We search light on above air block depth = determineBottomPointFrom(chunk, config, xRel, zRel, yAbs, blockPos); - if(hasCeiling && topBlock) + if (hasCeiling && topBlock) { yAbs = depth; color = generateLodColor(chunk, config, xRel, yAbs, zRel, blockPos); blockPos.set(xAbs, yAbs - 1, zAbs); light = getLightValue(chunk, blockPos, true); - } - else + } else { color = generateLodColor(chunk, config, xRel, yAbs, zRel, blockPos); blockPos.set(xAbs, yAbs + 1, zAbs); @@ -337,14 +349,14 @@ public class LodBuilder blockPos.set(xAbs, yAbs + 1, zAbs); light = getLightValue(chunk, blockPos, hasCeiling && topBlock); lightBlock = light & 0b1111; - if(!hasCeiling && topBlock) + if (!hasCeiling && topBlock) lightSky = 15; //default max light else lightSky = (light >> 4) & 0b1111; topBlock = false; - dataToMerge[index][count] = DataPointUtil.createDataPoint(height, depth, color, lightSky, lightBlock, generation); + dataToMerge[index * verticalData + count] = DataPointUtil.createDataPoint(height, depth, color, lightSky, lightBlock, generation); yAbs = depth - 1; count++; } @@ -605,7 +617,7 @@ public class LodBuilder blockLight = world.getBrightness(LightType.BLOCK, blockPos); skyLight = world.getBrightness(LightType.SKY, blockPos); - if(ceilingTopBlock) + if (ceilingTopBlock) blockPos.set(blockPos.getX(), blockPos.getY() + 1, blockPos.getZ()); else blockPos.set(blockPos.getX(), blockPos.getY() - 1, blockPos.getZ()); @@ -625,19 +637,17 @@ public class LodBuilder World world = mc.getClientWorld(); TextureAtlasSprite texture; - if(topTextureRequired) + if (topTextureRequired) { List quad = ((IForgeBakedModel) mc.getModelManager().getBlockModelShaper().getBlockModel(blockState)).getQuads(blockState, Direction.UP, new Random(0), dataMap); if (!quad.isEmpty()) { texture = quad.get(0).getSprite(); - } - else + } else { texture = mc.getModelManager().getBlockModelShaper().getTexture(blockState, world, blockPos); } - } - else + } else { texture = mc.getModelManager().getBlockModelShaper().getTexture(blockState, world, blockPos); } @@ -660,7 +670,7 @@ public class LodBuilder /*if (blockState.getBlock() instanceof LeavesBlock) color = 0; else*/ - continue; + continue; } else { color = texture.getPixelRGBA(k, i, j); diff --git a/src/main/java/com/seibel/lod/objects/LevelContainer.java b/src/main/java/com/seibel/lod/objects/LevelContainer.java index b03a293e7..a60bef3d2 100644 --- a/src/main/java/com/seibel/lod/objects/LevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/LevelContainer.java @@ -4,14 +4,16 @@ public interface LevelContainer { public static final char VERTICAL_DATA_DELIMITER = '\t'; public static final char DATA_DELIMITER = ' '; + /**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 + * @param index z position in the detail level * @return true if correctly added, false otherwise */ - public boolean addData(long[] data, int posX, int posZ); + public boolean addData(long data, int posX, int posZ, int index); /**With this you can add data to the level container * @@ -28,7 +30,7 @@ public interface LevelContainer * @param posZ z position in the detail level * @return the data in long array format */ - public long[] getData(int posX, int posZ); + public long getData(int posX, int posZ, int index); /**With this you can get data from the level container * @@ -50,6 +52,11 @@ public interface LevelContainer */ public byte getDetailLevel(); + + public int getMaxVerticalData(); + + public void clear(int posX, int posZ); + /**This return a level container with detail level lower than the current level. * The new level container may use information of this level. * @return the new level container diff --git a/src/main/java/com/seibel/lod/objects/LodDimension.java b/src/main/java/com/seibel/lod/objects/LodDimension.java index c8d4353dc..da96d4f95 100644 --- a/src/main/java/com/seibel/lod/objects/LodDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodDimension.java @@ -444,23 +444,23 @@ public class LodDimension cutAndGenThreads.execute(thread); } } - + /** * 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 addData(byte detailLevel, int posX, int posZ, long[] dataPoint, boolean dontSave, boolean serverQuality) + public Boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, long data, 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.addData(detailLevel, posX, posZ, dataPoint, serverQuality); + boolean nodeAdded = region.addData(detailLevel, posX, posZ, verticalIndex, data, serverQuality); // only save valid LODs to disk if (!dontSave && fileHandler != null) { @@ -565,7 +565,22 @@ public class LodDimension if (region != null) region.getDataToRender(posToRender, playerPosX, playerPosZ); } - + + public int getMaxVerticalData(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 0; + } + + return region.getMaxVerticalData(detailLevel); + } + /** * Get the data point at the given X and Z coordinates * in this dimension. @@ -573,7 +588,7 @@ public class LodDimension * Returns null if the LodChunk doesn't exist or * is outside the loaded area. */ - public long[] getData(byte detailLevel, int posX, int posZ) + public long getData(byte detailLevel, int posX, int posZ, int verticalIndex) { if (detailLevel > LodUtil.REGION_DETAIL_LEVEL) throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max."); @@ -582,12 +597,13 @@ public class LodDimension if (region == null) { - return new long[]{DataPointUtil.EMPTY_DATA}; + return DataPointUtil.EMPTY_DATA; } - return region.getData(detailLevel, posX, posZ); + return region.getData(detailLevel, posX, posZ, verticalIndex); } - + + /** * Get the data point at the given X and Z coordinates * in this dimension. @@ -609,7 +625,21 @@ public class LodDimension return region.getSingleData(detailLevel, posX, posZ); } - + + public void clear(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; + } + + region.clear(detailLevel, posX, posZ); + } public boolean getRegenByArrayIndex(int xIndex, int zIndex) { @@ -761,4 +791,5 @@ public class LodDimension } return stringBuilder.toString(); } + } diff --git a/src/main/java/com/seibel/lod/objects/LodRegion.java b/src/main/java/com/seibel/lod/objects/LodRegion.java index ddadfb905..08dde130b 100644 --- a/src/main/java/com/seibel/lod/objects/LodRegion.java +++ b/src/main/java/com/seibel/lod/objects/LodRegion.java @@ -79,13 +79,17 @@ public class LodRegion return generationMode; } + public int getMaxVerticalData(byte detailLevel) + { + return dataContainer[detailLevel].getMaxVerticalData(); + } + /** * This method can be used to insert data into the LodRegion * - * @param dataPoint * @return if the data was added successfully */ - public boolean addData(byte detailLevel, int posX, int posZ, long[] dataPoint, boolean serverQuality) + public boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, long data, boolean serverQuality) { posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); @@ -97,12 +101,12 @@ public class LodRegion try { //add the node data - this.dataContainer[detailLevel].addData(dataPoint, posX, posZ); + this.dataContainer[detailLevel].addData(data, posX, posZ, verticalIndex); return true; } catch (NullPointerException e) { - String detailMessage = "pos: [" + posX + "," + posZ + "] dataPoint: [" + dataPoint + "] serverQuality: [" + serverQuality + "] dataContainer"; + String detailMessage = "pos: [" + posX + "," + posZ + "] dataPoint: [" + data + "] serverQuality: [" + serverQuality + "] dataContainer"; detailMessage += this.dataContainer != null ? ": [NULL]" : " at detailLevel: [" + dataContainer[detailLevel] + "]"; ClientProxy.LOGGER.error("addSingleData: " + e.getMessage() + "\t" + detailMessage); @@ -156,11 +160,9 @@ public class LodRegion * * @return the data at the relative pos and level */ - public long[] getData(byte detailLevel, int posX, int posZ) + public long getData(byte detailLevel, int posX, int posZ, int verticalIndex) { - posX = LevelPosUtil.getRegionModule(detailLevel, posX); - posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); - return dataContainer[detailLevel].getData(posX, posZ); + return dataContainer[detailLevel].getData(posX, posZ,verticalIndex); } /** @@ -170,12 +172,13 @@ public class LodRegion */ 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); } - + public void clear(byte detailLevel, int posX, int posZ) + { + dataContainer[detailLevel].clear(posX, posZ); + } /** * This method will return all the levelPos that are renderable according to the requisite given in input * @@ -378,7 +381,7 @@ public class LodRegion if(dataContainer[detailLevel].doesItExist(posX,posZ)) { //We take the bottom information always - return DataPointUtil.getGenerationMode(dataContainer[detailLevel].getData(posX,posZ)[0]); + return DataPointUtil.getGenerationMode(dataContainer[detailLevel].getSingleData(posX,posZ)); }else { return DistanceGenerationMode.NONE.complexity; diff --git a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java index 9fc1a2390..b76ac228d 100644 --- a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java @@ -1,6 +1,8 @@ package com.seibel.lod.objects; import com.seibel.lod.util.*; + +import javax.xml.crypto.Data; import java.util.Arrays; public class SingleLevelContainer implements LevelContainer @@ -8,51 +10,61 @@ public class SingleLevelContainer implements LevelContainer public final byte detailLevel; public final int size; - public final long[][] data; + public final long[][] dataContainer; public SingleLevelContainer(byte detailLevel) { this.detailLevel = detailLevel; size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); - data = new long[size][size]; + dataContainer = new long[size][size]; } - public boolean addData(long[] newData, int posX, int posZ){ - + public void clear(int posX, int posZ) + { posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); - data[posX][posZ] = newData[0]; + dataContainer[posX][posZ] = DataPointUtil.EMPTY_DATA; + } + + public boolean addData(long data, int posX, int posZ, int index) + { + posX = LevelPosUtil.getRegionModule(detailLevel, posX); + posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + dataContainer[posX][posZ] = data; return true; } - public 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; + dataContainer[posX][posZ] = newData; return true; } - public long[] getData(int posX, int posZ){ - long[] dataArray = ThreadMapUtil.getSingleGetDataArray(); + public long getData(int posX, int posZ, int index) + { posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); //Improve this using a thread map to long[] - dataArray[0] = data[posX][posZ]; - return dataArray; + return dataContainer[posX][posZ]; } - public 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[] - return data[posX][posZ]; + return dataContainer[posX][posZ]; } - public byte getDetailLevel(){ + public byte getDetailLevel() + { return detailLevel; } - public LevelContainer expand(){ + public LevelContainer expand() + { return new SingleLevelContainer((byte) (getDetailLevel() - 1)); } @@ -64,22 +76,23 @@ public class SingleLevelContainer implements LevelContainer detailLevel = inputData[index]; index++; size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - detailLevel); - this.data = new long[size][size]; + this.dataContainer = new long[size][size]; for (int x = 0; x < size; x++) { for (int z = 0; z < size; z++) { newData = 0; - if(inputData[index] == 0) + if (inputData[index] == 0) index++; - else if(index + 7 >= inputData.length) - break; - else { - for (tempIndex = 0; tempIndex < 8; tempIndex++) - newData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex); - index = index + 8; - } - data[x][z] = newData; + else if (index + 7 >= inputData.length) + break; + else + { + for (tempIndex = 0; tempIndex < 8; tempIndex++) + newData += (((long) inputData[index + tempIndex]) & 0xff) << (8 * tempIndex); + index = index + 8; + } + dataContainer[x][z] = newData; } } @@ -101,15 +114,19 @@ public class SingleLevelContainer implements LevelContainer { childPosX = 2 * posX + x; childPosZ = 2 * posZ + z; - dataToMerge[2*x + z] = ((SingleLevelContainer) lowerLevelContainer).getSingleData(childPosX, childPosZ); + dataToMerge[2 * x + z] = ((SingleLevelContainer) lowerLevelContainer).getSingleData(childPosX, childPosZ); } } data = DataPointUtil.mergeSingleData(dataToMerge); - addSingleData(data,posX,posZ); + addSingleData(data, posX, posZ); } + public int getMaxVerticalData(){ + return 1; + } - public boolean doesItExist(int posX, int posZ){ + public boolean doesItExist(int posX, int posZ) + { posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); //Improve this using a thread map to long[] @@ -127,14 +144,16 @@ public class SingleLevelContainer implements LevelContainer { for (int z = 0; z < size; z++) { - if(data[x][z] == 0){ + if (dataContainer[x][z] == 0) + { tempData[index] = 0; index++; - } else { - for (tempIndex = 0; tempIndex < 8; tempIndex++) - tempData[index + tempIndex] = (byte) (data[x][z] >>> (8 * tempIndex)); - index += 8; - } + } else + { + for (tempIndex = 0; tempIndex < 8; tempIndex++) + tempData[index + tempIndex] = (byte) (dataContainer[x][z] >>> (8 * tempIndex)); + index += 8; + } } } return Arrays.copyOfRange(tempData, 0, index); diff --git a/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java b/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java index f4be55b6b..d958289c8 100644 --- a/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java @@ -1,9 +1,6 @@ package com.seibel.lod.objects; -import com.seibel.lod.util.DataPointUtil; -import com.seibel.lod.util.LevelPosUtil; -import com.seibel.lod.util.LodUtil; -import com.seibel.lod.util.ThreadMapUtil; +import com.seibel.lod.util.*; import java.security.InvalidParameterException; import java.util.Arrays; @@ -15,13 +12,14 @@ public class VerticalLevelContainer implements LevelContainer public final int size; public final int maxVerticalData; - public final long[][][] dataContainer; + public final long[] dataContainer; public VerticalLevelContainer(byte detailLevel) { this.detailLevel = detailLevel; size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); - dataContainer = new long[size][size][1]; + maxVerticalData = DetailDistanceUtil.getMaxVerticalData(detailLevel); + dataContainer = new long[size * size * DetailDistanceUtil.getMaxVerticalData(detailLevel)]; } @Override @@ -30,38 +28,51 @@ public class VerticalLevelContainer implements LevelContainer return detailLevel; } - public boolean addData(long[] newData, int posX, int posZ){ + public void clear(int posX, int posZ){ + posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); - dataContainer[posX][posZ] = newData; + int index = 0; + for(int i = 0; i < maxVerticalData; i++){ + index = posX*size*maxVerticalData + posZ*maxVerticalData + i; + dataContainer[index] = DataPointUtil.EMPTY_DATA; + } + } + + public boolean addData(long data, int posX, int posZ, int verticalIndex){ + + posX = LevelPosUtil.getRegionModule(detailLevel, posX); + posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + dataContainer[posX*size*maxVerticalData + posZ*maxVerticalData + verticalIndex] = data; 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 boolean addSingleData(long data, int posX, int posZ){ + return addData(data, posX, posZ, 0); } - public long[] getData(int posX, int posZ){ + public long getData(int posX, int posZ, int verticalIndex){ posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); - return dataContainer[posX][posZ]; + return dataContainer[posX*size*maxVerticalData + posZ*maxVerticalData + verticalIndex]; } 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]; + return getData(posX,posZ,0); + } + + public int getMaxVerticalData(){ + return maxVerticalData; + } + + public int getSize(){ + return size; } public boolean doesItExist(int posX, int posZ){ - long[] data = getData(posX,posZ); - if(data == null) - return false; - return DataPointUtil.doesItExist(data[0]); + posX = LevelPosUtil.getRegionModule(detailLevel, posX); + posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + return DataPointUtil.doesItExist(getSingleData(posX,posZ)); } public VerticalLevelContainer(byte inputData[]) @@ -104,7 +115,8 @@ public class VerticalLevelContainer implements LevelContainer public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ) { //We reset the array - long[][] dataToMerge = ThreadMapUtil.getVerticalUpdateArray(); + //long[] dataToMerge = ThreadMapUtil.getVerticalUpdateArray(maxVerticalData); + long[] dataToMerge = new long[4*lowerLevelContainer.getMaxVerticalData()]; int childPosX; int childPosZ; @@ -117,11 +129,19 @@ public class VerticalLevelContainer implements LevelContainer { childPosX = 2 * posX + x; childPosZ = 2 * posZ + z; - dataToMerge[2*z + x] = lowerLevelContainer.getData(childPosX, childPosZ); + for(int verticalIndex = 0; verticalIndex < maxVerticalData; verticalIndex++) + dataToMerge[(z*2+x)*maxVerticalData + verticalIndex] = lowerLevelContainer.getData(childPosX, childPosZ, verticalIndex); } } - data = DataPointUtil.mergeMultiData(dataToMerge); - addData(data,posX,posZ); + data = DataPointUtil.mergeMultiData(dataToMerge, lowerLevelContainer.getDetailLevel()); + + for(int verticalIndex = 0; (verticalIndex < data.length) && (verticalIndex < maxVerticalData); verticalIndex++) + { + addData(data[verticalIndex], + posX, + posZ, + verticalIndex); + } } public byte[] toDataString() diff --git a/src/main/java/com/seibel/lod/util/DataPointUtil.java b/src/main/java/com/seibel/lod/util/DataPointUtil.java index c7ccc5c7c..f5fbf7842 100644 --- a/src/main/java/com/seibel/lod/util/DataPointUtil.java +++ b/src/main/java/com/seibel/lod/util/DataPointUtil.java @@ -4,6 +4,9 @@ import com.seibel.lod.enums.DistanceGenerationMode; import net.minecraft.client.renderer.texture.NativeImage; +import java.lang.reflect.Array; +import java.util.Arrays; + public class DataPointUtil { /* @@ -281,7 +284,7 @@ public class DataPointUtil int size = dataToMerge.length / inputVerticalData; short[] projection = ThreadMapUtil.getProjectionShort((WORLD_HEIGHT + 1) / 16); short[][] heightAndDepth = ThreadMapUtil.getHeightAndDepth(inputVerticalData); - long[] singleDataToMerge = ThreadMapUtil.getSingleAddDataToMerge(dataToMerge.length); + long[] singleDataToMerge = ThreadMapUtil.getSingleAddDataToMerge(size); int genMode = DistanceGenerationMode.SERVER.complexity; boolean allEmpty = true; boolean allVoid = true; @@ -383,7 +386,7 @@ public class DataPointUtil { depth = heightAndDepth[j][0]; height = heightAndDepth[j][1]; - for(int k = 0; k < dataToMerge.length; k++){ + for(int k = 0; k < size; k++){ singleDataToMerge[k] = 0; } for (int index = 0; index < size; index++) diff --git a/src/main/java/com/seibel/lod/util/ThreadMapUtil.java b/src/main/java/com/seibel/lod/util/ThreadMapUtil.java index d5219b749..d94c5527e 100644 --- a/src/main/java/com/seibel/lod/util/ThreadMapUtil.java +++ b/src/main/java/com/seibel/lod/util/ThreadMapUtil.java @@ -11,7 +11,7 @@ public class ThreadMapUtil 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 threadBuilderVerticalArrayMap = new ConcurrentHashMap<>(); public static final ConcurrentMap threadVerticalAddDataMap = new ConcurrentHashMap<>(); public static final ConcurrentMap threadVerticalGetDataMap = new ConcurrentHashMap<>(); public static final ConcurrentMap threadVerticalUpdateMap = new ConcurrentHashMap<>(); @@ -62,11 +62,11 @@ public class ThreadMapUtil return threadBuilderArrayMap.get(Thread.currentThread().getName()); } - public static long[][][] getBuilderVerticalArray() + public static long[][] getBuilderVerticalArray() { if (!threadBuilderVerticalArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()) == null)) { - long[][][] array = new long[5][][]; + long[][] array = new long[5][]; threadBuilderVerticalArrayMap.put(Thread.currentThread().getName(), array); } return threadBuilderVerticalArrayMap.get(Thread.currentThread().getName());