From 85a0110af60fa4ee9a171f3a26aa23c0e69f834a Mon Sep 17 00:00:00 2001 From: James Seibel Date: Mon, 27 Sep 2021 07:59:55 -0500 Subject: [PATCH] comments and regactor LodDimension --- .../seibel/lod/builders/LodBufferBuilder.java | 14 +- .../lod/handlers/LodDimensionFileHandler.java | 4 +- .../com/seibel/lod/objects/LodDimension.java | 664 +++++++++--------- .../com/seibel/lod/objects/LodRegion.java | 1 + .../com/seibel/lod/proxy/ClientProxy.java | 6 +- .../com/seibel/lod/render/LodRenderer.java | 8 +- 6 files changed, 355 insertions(+), 342 deletions(-) diff --git a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java index 26c0d8304..f895b247d 100644 --- a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java @@ -199,11 +199,11 @@ public class LodBufferBuilder { for (int zRegion = 0; zRegion < lodDim.getWidth(); zRegion++) { - if (lodDim.isRegionToRegen(xRegion, zRegion) || fullRegen) + if (lodDim.doesRegionNeedBufferRegen(xRegion, zRegion) || fullRegen) { RegionPos regionPos = new RegionPos( - xRegion + lodDim.getCenterX() - Math.floorDiv(lodDim.getWidth(), 2), - zRegion + lodDim.getCenterZ() - Math.floorDiv(lodDim.getWidth(), 2)); + xRegion + lodDim.getCenterRegionPosX() - Math.floorDiv(lodDim.getWidth(), 2), + zRegion + lodDim.getCenterRegionPosZ() - Math.floorDiv(lodDim.getWidth(), 2)); // local position in the vbo and bufferBuilder arrays BufferBuilder currentBuffer = buildableBuffers[xRegion][zRegion]; @@ -449,7 +449,7 @@ public class LodBufferBuilder { for (int z = 0; z < buildableBuffers.length; z++) { - if (fullRegen || lodDim.isRegionToRegen(x, z)) + if (fullRegen || lodDim.doesRegionNeedBufferRegen(x, z)) { // for some reason BufferBuilder.vertexCounts // isn't reset unless this is called, which can cause @@ -469,7 +469,7 @@ 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.isRegionToRegen(x, z))) + if (buildableBuffers[x][z] != null && buildableBuffers[x][z].building() && (fullRegen || lodDim.doesRegionNeedBufferRegen(x, z))) buildableBuffers[x][z].end(); } @@ -490,11 +490,11 @@ public class LodBufferBuilder { for (int z = 0; z < buildableVbos.length; z++) { - if (fullRegen || lodDim.isRegionToRegen(x, z)) + if (fullRegen || lodDim.doesRegionNeedBufferRegen(x, z)) { ByteBuffer builderBuffer = buildableBuffers[x][z].popNextBuffer().getSecond(); vboUpload(buildableVbos[x][z], builderBuffer); - lodDim.setRegenByArrayIndex(x, z, false); + lodDim.setRegenRegionBufferByArrayIndex(x, z, false); } } } diff --git a/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java b/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java index 83863ea11..7fc9b0e8e 100644 --- a/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java +++ b/src/main/java/com/seibel/lod/handlers/LodDimensionFileHandler.java @@ -238,10 +238,10 @@ public class LodDimensionFileHandler { for (int j = 0; j < lodDimension.getWidth(); j++) { - if (lodDimension.isRegionToRegen(i,j) && lodDimension.getRegionByArrayIndex(i,j) != null) + if (lodDimension.doesRegionNeedBufferRegen(i,j) && lodDimension.getRegionByArrayIndex(i,j) != null) { saveRegionToFile(lodDimension.getRegionByArrayIndex(i,j)); - lodDimension.setRegenByArrayIndex(i, j,false); + lodDimension.setRegenRegionBufferByArrayIndex(i, j,false); } } } diff --git a/src/main/java/com/seibel/lod/objects/LodDimension.java b/src/main/java/com/seibel/lod/objects/LodDimension.java index 0159c5010..fb8984d46 100644 --- a/src/main/java/com/seibel/lod/objects/LodDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodDimension.java @@ -28,7 +28,11 @@ import com.seibel.lod.enums.GenerationPriority; import com.seibel.lod.enums.LodTemplate; import com.seibel.lod.enums.VerticalQuality; import com.seibel.lod.handlers.LodDimensionFileHandler; -import com.seibel.lod.util.*; +import com.seibel.lod.util.DataPointUtil; +import com.seibel.lod.util.DetailDistanceUtil; +import com.seibel.lod.util.LevelPosUtil; +import com.seibel.lod.util.LodThreadFactory; +import com.seibel.lod.util.LodUtil; import com.seibel.lod.wrappers.MinecraftWrapper; import net.minecraft.util.math.ChunkPos; @@ -43,54 +47,45 @@ import net.minecraft.world.server.ServerWorld; * * @author Leonardo Amato * @author James Seibel - * @version 9-18-2021 + * @version 9-26-2021 */ public class LodDimension { - public final DimensionType dimension; - - /** - * measured in regions - */ + + /** measured in regions */ private volatile int width; - /** - * measured in regions - */ + /** measured in regions */ private volatile int halfWidth; - + // these three variables are private to force use of the getWidth() method // which is a safer way to get the width then directly asking the arrays - /** - * stores all the regions in this dimension - */ + /** stores all the regions in this dimension */ public volatile LodRegion[][] regions; - - /** - * stores if the region at the given x and z index needs to be saved to disk - */ + + /** stores if the region at the given x and z index needs to be saved to disk */ private volatile boolean[][] isRegionDirty; - /** - * stores if the region at the given x and z index needs to be regenerated - */ - private volatile boolean[][] regionNeedsRegen; - /** - * stores if the buffer size at the given x and z index needs to be changed - */ - private volatile boolean[][] setupBuffer; - + /** stores if the region at the given x and z index needs to be regenerated */ + private volatile boolean[][] regenRegionBuffer; + /** stores if the buffer size at the given x and z index needs to be changed */ + private volatile boolean[][] recreateRegionBuffer; + /** * if true that means there are regions in this dimension * that need to have their buffers rebuilt. */ - public volatile boolean regenDimension = false; - - private volatile RegionPos center; - private volatile ChunkPos lastGenChunk; - private volatile ChunkPos lastCutChunk; + public volatile boolean regenDimensionBuffers = false; + private LodDimensionFileHandler fileHandler; - private ExecutorService cutAndGenThreads = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName() + " - cutAndGen")); - + + private volatile RegionPos center; + + /** prevents the cutAndExpandThread from expanding at the same location multiple times */ + private volatile ChunkPos lastExpandedChunk; + /** prevents the cutAndExpandThread from cutting at the same location multiple times */ + private volatile ChunkPos lastCutChunk; + private ExecutorService cutAndExpandThread = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName() + " - Cut and Expand")); + /** * Creates the dimension centered at (0,0) * @@ -99,60 +94,55 @@ public class LodDimension public LodDimension(DimensionType newDimension, LodWorld lodWorld, int newWidth) { lastCutChunk = null; - lastGenChunk = null; + lastExpandedChunk = null; dimension = newDimension; width = newWidth; halfWidth = width / 2; MinecraftWrapper mc = MinecraftWrapper.INSTANCE; + if (newDimension != null && lodWorld != null) { try { - File saveDir; if (mc.hasSingleplayerServer()) { // local world - + ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(newDimension); - + // provider needs a separate variable to prevent // the compiler from complaining ServerChunkProvider provider = serverWorld.getChunkSource(); saveDir = new File(provider.dataStorage.dataFolder.getCanonicalFile().getPath() + File.separatorChar + "lod"); - } else + } + else { // connected to server - + saveDir = new File(mc.getGameDirectory().getCanonicalFile().getPath() + - File.separatorChar + "lod server data" + File.separatorChar + mc.getCurrentDimensionId()); + File.separatorChar + "lod server data" + File.separatorChar + mc.getCurrentDimensionId()); } - + fileHandler = new LodDimensionFileHandler(saveDir, this); - } catch (IOException e) + } + catch (IOException e) { // the file handler wasn't able to be created // we won't be able to read or write any files } } - - + + regions = new LodRegion[width][width]; isRegionDirty = new boolean[width][width]; - regionNeedsRegen = new boolean[width][width]; - setupBuffer = new boolean[width][width]; - - //treeGenerator((int) mc.player.getX(),(int) mc.player.getZ()); - - // populate isRegionDirty - for (int i = 0; i < width; i++) - for (int j = 0; j < width; j++) - isRegionDirty[i][j] = false; - + regenRegionBuffer = new boolean[width][width]; + recreateRegionBuffer = new boolean[width][width]; + center = new RegionPos(0, 0); } - - + + /** * Move the center of this LodDimension and move all owned * regions over by the given x and z offset.

@@ -163,28 +153,24 @@ public class LodDimension { int xOffset = regionOffset.x; int zOffset = regionOffset.z; - + // if the x or z offset is equal to or greater than - // the total size, just delete the current data + // the total width, just delete the current data // and update the centerX and/or centerZ if (Math.abs(xOffset) >= width || Math.abs(zOffset) >= width) { for (int x = 0; x < width; x++) - { for (int z = 0; z < width; z++) - { regions[x][z] = null; - } - } - + // update the new center center.x += xOffset; center.z += zOffset; - + return; } - - + + // X if (xOffset > 0) { @@ -199,7 +185,8 @@ public class LodDimension regions[x][z] = null; } } - } else + } + else { // move everything over to the right (as the center moves to the left) for (int x = width - 1; x >= 0; x--) @@ -209,14 +196,12 @@ public class LodDimension if (x + xOffset >= 0) regions[x][z] = regions[x + xOffset][z]; else - { regions[x][z] = null; - } } } } - - + + // Z if (zOffset > 0) { @@ -231,7 +216,8 @@ public class LodDimension regions[x][z] = null; } } - } else + } + else { // move everything down (as the center moves up) for (int x = 0; x < width; x++) @@ -245,62 +231,58 @@ public class LodDimension } } } - - + + // update the new center center.x += xOffset; center.z += zOffset; } - - + + /** - * return needed memory in bytes + * return the minimum needed memory in bytes */ public int getMinMemoryNeeded() { int count = 0; LodRegion region; - + for (int x = 0; x < regions.length; x++) { for (int z = 0; z < regions.length; z++) { region = regions[x][z]; if (region != null) - { count += region.getMinMemoryNeeded(LodConfig.CLIENT.graphics.lodTemplate.get()); - } } } return count; } - - + + /** - * Gets the region at the given X and Z + * Gets the region at the given LevelPos *
* Returns null if the region doesn't exist * or is outside the loaded area. */ - public LodRegion getRegion(byte detailLevel, int posX, int posZ) + public LodRegion getRegion(byte detailLevel, int levelPosX, int levelPosZ) { - int xRegion = LevelPosUtil.getRegion(detailLevel, posX); - int zRegion = LevelPosUtil.getRegion(detailLevel, posZ); + int xRegion = LevelPosUtil.getRegion(detailLevel, levelPosX); + int zRegion = LevelPosUtil.getRegion(detailLevel, levelPosZ); int xIndex = (xRegion - center.x) + halfWidth; int zIndex = (zRegion - center.z) + halfWidth; - + if (!regionIsInRange(xRegion, zRegion)) return null; - //throw new ArrayIndexOutOfBoundsException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " out of range"); - else if (regions[xIndex][zIndex] == null) - return null; - //throw new InvalidParameterException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " not currently initialized"); + //throw new ArrayIndexOutOfBoundsException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " out of range"); else if (regions[xIndex][zIndex].getMinDetailLevel() > detailLevel) return null; //throw new InvalidParameterException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " currently only reach level " + regions[xIndex][zIndex].getMinDetailLevel()); + return regions[xIndex][zIndex]; } - + /** * Gets the region at the given X and Z *
@@ -311,24 +293,20 @@ public class LodDimension { int xIndex = (regionPosX - center.x) + halfWidth; int zIndex = (regionPosZ - center.z) + halfWidth; - + if (!regionIsInRange(regionPosX, regionPosZ)) return null; - //throw new ArrayIndexOutOfBoundsException("Region " + regionPosX + " " + regionPosZ + " out of range"); - else if (regions[xIndex][zIndex] == null) - return null; - //throw new InvalidParameterException("Region " + regionPosX + " " + regionPosZ + " not currently initialized"); + //throw new ArrayIndexOutOfBoundsException("Region " + regionPosX + " " + regionPosZ + " out of range"); + return regions[xIndex][zIndex]; } - - /** - * Useful when needing to iterate over every region. - */ + + /** Useful when iterating over every region. */ public LodRegion getRegionByArrayIndex(int xIndex, int zIndex) { return regions[xIndex][zIndex]; } - + /** * Overwrite the LodRegion at the location of newRegion with newRegion. * @@ -338,77 +316,87 @@ public class LodDimension { int xIndex = (newRegion.regionPosX - center.x) + halfWidth; int zIndex = (newRegion.regionPosZ - center.z) + halfWidth; - + if (!regionIsInRange(newRegion.regionPosX, newRegion.regionPosZ)) // out of range throw new ArrayIndexOutOfBoundsException("Region " + newRegion.regionPosX + ", " + newRegion.regionPosZ + " out of range"); - + regions[xIndex][zIndex] = newRegion; } - - + + /** - * + * Deletes nodes that are a higher detail then necessary, freeing + * up memory. */ - public void treeCutter(int playerPosX, int playerPosZ) + public void cutRegionNodesAsync(int playerPosX, int playerPosZ) { ChunkPos newPlayerChunk = new ChunkPos(LevelPosUtil.getChunkPos((byte) 0, playerPosX), LevelPosUtil.getChunkPos((byte) 0, playerPosZ)); + if (lastCutChunk == null) lastCutChunk = new ChunkPos(newPlayerChunk.x + 1, newPlayerChunk.z - 1); + + // don't run the tree cutter multiple times + // for the same location if (newPlayerChunk.x != lastCutChunk.x || newPlayerChunk.z != lastCutChunk.z) { lastCutChunk = newPlayerChunk; + Thread thread = new Thread(() -> { int regionX; int regionZ; int minDistance; byte detail; - byte levelToCut; - + byte minAllowedDetailLevel; + + // go over every region in the dimension for (int x = 0; x < regions.length; x++) { for (int z = 0; z < regions.length; z++) { regionX = (x + center.x) - halfWidth; regionZ = (z + center.z) - halfWidth; - //we start checking from the first circle. If the whole region is in the circle - //we proceed to cut all the level lower than the level of circle 1 and we break - //if this is not the case w + if (regions[x][z] != null) { + // check what detail level this region should be + // and cut it if it is higher then that minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ, playerPosX, playerPosZ); detail = DetailDistanceUtil.getTreeCutDetailFromDistance(minDistance); - levelToCut = DetailDistanceUtil.getCutLodDetail(detail); - if (regions[x][z].getMinDetailLevel() > levelToCut) + minAllowedDetailLevel = DetailDistanceUtil.getCutLodDetail(detail); + + if (regions[x][z].getMinDetailLevel() > minAllowedDetailLevel) { - regions[x][z].cutTree(levelToCut); - setupBuffer[x][z] = true; + regions[x][z].cutTree(minAllowedDetailLevel); + recreateRegionBuffer[x][z] = true; } } - }// region z }// region z - }); - cutAndGenThreads.execute(thread); + + cutAndExpandThread.execute(thread); } } - - /** - * - */ - public void treeGenerator(int playerPosX, int playerPosZ) + + /** Either expands or loads all regions in the rendered LOD area */ + public void expandOrLoadRegionsAsync(int playerPosX, int playerPosZ) { DistanceGenerationMode generationMode = LodConfig.CLIENT.worldGenerator.distanceGenerationMode.get(); ChunkPos newPlayerChunk = new ChunkPos(LevelPosUtil.getChunkPos((byte) 0, playerPosX), LevelPosUtil.getChunkPos((byte) 0, playerPosZ)); VerticalQuality verticalQuality = LodConfig.CLIENT.worldGenerator.lodQualityMode.get(); - - if (lastGenChunk == null) - lastGenChunk = new ChunkPos(newPlayerChunk.x + 1, newPlayerChunk.z - 1); - if (newPlayerChunk.x != lastGenChunk.x || newPlayerChunk.z != lastGenChunk.z) + + + if (lastExpandedChunk == null) + lastExpandedChunk = new ChunkPos(newPlayerChunk.x + 1, newPlayerChunk.z - 1); + + // don't run the expander multiple times + // for the same location + if (newPlayerChunk.x != lastExpandedChunk.x || newPlayerChunk.z != lastExpandedChunk.z) { - lastGenChunk = newPlayerChunk; + lastExpandedChunk = newPlayerChunk; + Thread thread = new Thread(() -> { int regionX; @@ -417,6 +405,7 @@ public class LodDimension int minDistance; byte detail; byte levelToGen; + for (int x = 0; x < regions.length; x++) { for (int z = 0; z < regions.length; z++) @@ -425,57 +414,60 @@ public class LodDimension regionZ = (z + center.z) - halfWidth; final RegionPos regionPos = new RegionPos(regionX, regionZ); region = regions[x][z]; - //We require that the region we are checking is loaded with at least this level - + minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ, playerPosX, playerPosZ); detail = DetailDistanceUtil.getTreeGenDetailFromDistance(minDistance); levelToGen = DetailDistanceUtil.getLodGenDetail(detail).detailLevel; + + // check that the region isn't null and at least this detail level if (region == null || region.getGenerationMode() != generationMode) { - //First case, region has to be initialized - - //We check if there is a file at the target level + // First case, region has to be created + + // try to get the region from file regions[x][z] = getRegionFromFile(regionPos, levelToGen, generationMode, verticalQuality); - - //if there is no file we initialize the region + + // if there is no region file create a empty region if (regions[x][z] == null) - { regions[x][z] = new LodRegion(levelToGen, regionPos, generationMode, verticalQuality); - } - regionNeedsRegen[x][z] = true; - regenDimension = true; - setupBuffer[x][z] = true; - - } else if (region.getMinDetailLevel() > levelToGen) + + regenRegionBuffer[x][z] = true; + regenDimensionBuffers = true; + recreateRegionBuffer[x][z] = true; + } + else if (region.getMinDetailLevel() > levelToGen) { - //Second case, region has been initialized but at a higher level - //We expand the region by introducing the missing layer + // Second case, the region exists at a higher detail level. + + // Expand the region by introducing the missing layer region.expand(levelToGen); - setupBuffer[x][z] = true; + recreateRegionBuffer[x][z] = true; } } } }); - cutAndGenThreads.execute(thread); + + cutAndExpandThread.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. + * coordinate it will be overwritten. */ public Boolean addData(byte detailLevel, int posX, int posZ, int verticalIndex, long data, boolean dontSave) { - - // don't continue if the region can't be saved int regionPosX = LevelPosUtil.getRegion(detailLevel, posX); int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ); - + + // don't continue if the region can't be saved LodRegion region = getRegion(regionPosX, regionPosZ); if (region == null) return false; + boolean nodeAdded = region.addData(detailLevel, posX, posZ, verticalIndex, data); + // only save valid LODs to disk if (!dontSave && fileHandler != null) { @@ -484,152 +476,169 @@ public class LodDimension // 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; - regionNeedsRegen[xIndex][zIndex] = true; - regenDimension = true; - } catch (ArrayIndexOutOfBoundsException e) + regenRegionBuffer[xIndex][zIndex] = true; + regenDimensionBuffers = true; + } + catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); - // This method was probably called when the dimension was changing size. + // If this happens, the 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) + + /** marks the region at the given region position to have its buffer rebuilt */ + public void markRegionBufferToRegen(int xRegion, int zRegion) { int xIndex = (xRegion - center.x) + halfWidth; int zIndex = (zRegion - center.z) + halfWidth; - regionNeedsRegen[xIndex][zIndex] = true; + regenRegionBuffer[xIndex][zIndex] = true; } - + /** - * method to get all the quadtree level that have to be generated based on the position of the player - * - * @return list of quadTrees + * Returns every position that need to be generated based on the position of the player */ public PosToGenerateContainer getDataToGenerate(int maxDataToGenerate, int playerPosX, int playerPosZ) { PosToGenerateContainer posToGenerate; LodRegion region; + // TODO what are dx, dz, and t? int x, z, dx, dz, t; x = 0; z = 0; dx = 0; dz = -1; + + // TODO please comment what this code is doing switch (LodConfig.CLIENT.worldGenerator.generationPriority.get()) { - default: - case NEAR_FIRST: - posToGenerate = new PosToGenerateContainer((byte) 10, maxDataToGenerate, 0, playerPosX, playerPosZ); - int playerChunkX = LevelPosUtil.getChunkPos(LodUtil.BLOCK_DETAIL_LEVEL, playerPosX); - int playerChunkZ = LevelPosUtil.getChunkPos(LodUtil.BLOCK_DETAIL_LEVEL, playerPosZ); - int xChunkToCheck; - int zChunkToCheck; - byte detailLevel; - int posX; - int posZ; - long data; - int numbChunksWide = (width) * 32; - int circleLimit = Integer.MAX_VALUE; - for (int i = 0; i < numbChunksWide * numbChunksWide; i++) + default: + case NEAR_FIRST: + posToGenerate = new PosToGenerateContainer((byte) 10, maxDataToGenerate, 0, playerPosX, playerPosZ); + + int playerChunkX = LevelPosUtil.getChunkPos(LodUtil.BLOCK_DETAIL_LEVEL, playerPosX); + int playerChunkZ = LevelPosUtil.getChunkPos(LodUtil.BLOCK_DETAIL_LEVEL, playerPosZ); + + int xChunkToCheck; + int zChunkToCheck; + byte detailLevel; + int posX; + int posZ; + long data; + int numbChunksWide = (width) * 32; + int circleLimit = Integer.MAX_VALUE; + + for (int i = 0; i < numbChunksWide * numbChunksWide; i++) + { + // use this for circular generation + if (maxDataToGenerate < 0) { - // use this for square generation - - // use this for circular generation - if (maxDataToGenerate < 0) - { - if (circleLimit < Math.abs(x) && circleLimit < Math.abs(z)) - break; - } else if (maxDataToGenerate == 0) - { + if (circleLimit < Math.abs(x) && circleLimit < Math.abs(z)) + break; + } + else if (maxDataToGenerate == 0) + { + maxDataToGenerate--; + circleLimit = (int) (Math.abs(x) * 1.41f); + } + + xChunkToCheck = x + playerChunkX; + zChunkToCheck = z + playerChunkZ; + + region = getRegion(LodUtil.CHUNK_DETAIL_LEVEL, xChunkToCheck, zChunkToCheck); + if (region == null) + continue; + + detailLevel = region.getMinDetailLevel(); + + posX = LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, xChunkToCheck, detailLevel); + posZ = LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, zChunkToCheck, detailLevel); + data = getSingleData(detailLevel, posX, posZ); + + if (DataPointUtil.getGenerationMode(data) < LodConfig.CLIENT.worldGenerator.distanceGenerationMode.get().complexity) + { + posToGenerate.addPosToGenerate(detailLevel, posX, posZ); + if (maxDataToGenerate >= 0) maxDataToGenerate--; - circleLimit = (int) (Math.abs(x) * 1.41f); - } - - xChunkToCheck = x + playerChunkX; - zChunkToCheck = z + playerChunkZ; - //distance = LevelPosUtil.maxDistance(LodUtil.CHUNK_DETAIL_LEVEL, xChunkToCheck, zChunkToCheck, playerChunkX, playerChunkZ); - region = getRegion(LodUtil.CHUNK_DETAIL_LEVEL, xChunkToCheck, zChunkToCheck); - if (region == null) - continue; - detailLevel = region.getMinDetailLevel(); - - posX = LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, xChunkToCheck, detailLevel); - posZ = LevelPosUtil.convert(LodUtil.CHUNK_DETAIL_LEVEL, zChunkToCheck, detailLevel); - data = getSingleData(detailLevel, posX, posZ); - if (DataPointUtil.getGenerationMode(data) < LodConfig.CLIENT.worldGenerator.distanceGenerationMode.get().complexity) - { - posToGenerate.addPosToGenerate(detailLevel, posX, posZ); - if (maxDataToGenerate >= 0) - maxDataToGenerate--; - } - if ((x == z) || ((x < 0) && (x == -z)) || ((x > 0) && (x == 1 - z))) - { - t = dx; - dx = -dz; - dz = t; - } - x += dx; - z += dz; } - break; - case FAR_FIRST: - posToGenerate = new PosToGenerateContainer((byte) 8, maxDataToGenerate, (int) (maxDataToGenerate * 0.25), playerPosX, playerPosZ); - int n = regions.length; - int xRegion; - int zRegion; - - for (int i = 0; i < width * width; i++) + + if ((x == z) || ((x < 0) && (x == -z)) || ((x > 0) && (x == 1 - z))) { - xRegion = x + center.x; - zRegion = z + center.z; - region = getRegion(xRegion, zRegion); - if (region != null) - region.getDataToGenerate(posToGenerate, playerPosX, playerPosZ); - if ((x == z) || ((x < 0) && (x == -z)) || ((x > 0) && (x == 1 - z))) - { - t = dx; - dx = -dz; - dz = t; - } - x += dx; - z += dz; + t = dx; + dx = -dz; + dz = t; } - break; + x += dx; + z += dz; + } + break; + + + case FAR_FIRST: + posToGenerate = new PosToGenerateContainer((byte) 8, maxDataToGenerate, (int) (maxDataToGenerate * 0.25), playerPosX, playerPosZ); + + int xRegion; + int zRegion; + + for (int i = 0; i < width * width; i++) + { + xRegion = x + center.x; + zRegion = z + center.z; + + region = getRegion(xRegion, zRegion); + if (region != null) + region.getDataToGenerate(posToGenerate, playerPosX, playerPosZ); + + + if ((x == z) || ((x < 0) && (x == -z)) || ((x > 0) && (x == 1 - z))) + { + t = dx; + dx = -dz; + dz = t; + } + x += dx; + z += dz; + } + break; } return posToGenerate; } - + /** - * method to get all the nodes that have to be rendered based on the position of the player - * - * @return list of nodes + * Returns every node that should be rendered based on the position of the player. + * + * TODO why isn't posToRender returned? it would make it a bit more clear what is happening */ public void getDataToRender(PosToRenderContainer posToRender, RegionPos regionPos, int playerPosX, - int playerPosZ) + int playerPosZ) { LodRegion region = getRegion(regionPos.x, regionPos.z); if (region != null) region.getDataToRender(posToRender, playerPosX, playerPosZ, LodConfig.CLIENT.worldGenerator.generationPriority.get() == GenerationPriority.NEAR_FIRST); } - + + /** + * Determines how many vertical LODs could be used + * for the given region at the given detail level + */ 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."); - + throw new IllegalArgumentException("getMaxVerticalData 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. @@ -641,18 +650,15 @@ public class LodDimension { 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.getData(detailLevel, posX, posZ, verticalIndex); } - - + + /** * Get the data point at the given X and Z coordinates * in this dimension. @@ -664,49 +670,59 @@ public class LodDimension { 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); } - + + /** Clears the given region */ 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 isRegionToRegen(int xIndex, int zIndex) - { - return regionNeedsRegen[xIndex][zIndex]; - } - - public boolean isBufferToSetup(int xIndex, int zIndex) - { - return setupBuffer[xIndex][zIndex]; - } - - public void setRegenByArrayIndex(int xIndex, int zIndex, boolean newRegen) - { - regionNeedsRegen[xIndex][zIndex] = newRegen; - } - + /** - * Get the data point at the given X and Z coordinates + * Returns if the buffer at the given array index needs + * to have its buffer regenerated. + */ + public boolean doesRegionNeedBufferRegen(int xIndex, int zIndex) + { + return regenRegionBuffer[xIndex][zIndex]; + } + + /** + * TODO we aren't currently using this, is there a reason for that? + * is this significantly different than regenRegionBuffer? + * + * Returns if the buffer at the given array index needs + * to have its buffer resized. + */ + public boolean doesRegionNeedBufferResized(int xIndex, int zIndex) + { + return recreateRegionBuffer[xIndex][zIndex]; + } + + /** + * Sets if the buffer at the given array index needs + * to have its buffer regenerated. + */ + public void setRegenRegionBufferByArrayIndex(int xIndex, int zIndex, boolean newRegen) + { + regenRegionBuffer[xIndex][zIndex] = newRegen; + } + + /** + * Get the data point at the given LevelPos * in this dimension. *
* Returns null if the LodChunk doesn't exist or @@ -716,45 +732,39 @@ public class LodDimension { 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.updateArea(detailLevel, posX, posZ); } - + /** - * return true if and only if the node at that position exist + * Returns true if a region exists at the given LevelPos */ public boolean doesDataExist(byte detailLevel, int posX, int posZ) { LodRegion region = getRegion(detailLevel, posX, posZ); - if (region == null) - { return false; - } - + return region.doesDataExist(detailLevel, posX, posZ); } - + /** - * Get the region at the given X and Z coordinates from the - * RegionFileHandler. + * Loads the region at the given RegionPos from file, + * if a file exists for that region. */ - public LodRegion getRegionFromFile(RegionPos regionPos, byte detailLevel, DistanceGenerationMode - generationMode, VerticalQuality verticalQuality) + public LodRegion getRegionFromFile(RegionPos regionPos, byte detailLevel, + DistanceGenerationMode generationMode, VerticalQuality verticalQuality) { if (fileHandler != null) return fileHandler.loadRegionFromFile(detailLevel, regionPos, generationMode, verticalQuality); else return null; } - + /** * Save all dirty regions in this LodDimension to file. */ @@ -762,31 +772,32 @@ public class LodDimension { fileHandler.saveDirtyRegionsToFileAsync(); } - - + + /** - * Returns whether the region at the given X and Z coordinates + * Returns whether the region at the given RegionPos * is within the loaded range. */ public boolean regionIsInRange(int regionX, int regionZ) { int xIndex = (regionX - center.x) + halfWidth; int zIndex = (regionZ - center.z) + halfWidth; - + return xIndex >= 0 && xIndex < width && zIndex >= 0 && zIndex < width; } - - - public int getCenterX() + + /** Returns the dimension's center region position X value */ + public int getCenterRegionPosX() { return center.x; } - - public int getCenterZ() + + /** Returns the dimension's center region position Z value */ + public int getCenterRegionPosZ() { return center.z; } - + /** * returns the width of the dimension in regions */ @@ -798,35 +809,36 @@ public class LodDimension // source to make sure it is in sync with region // and isRegionDirty return regions.length; - } else + } + else { return width; } } - - + + /** Update the width of this dimension, in regions */ public void setRegionWidth(int newWidth) { width = newWidth; halfWidth = Math.floorDiv(width, 2); - + regions = new LodRegion[width][width]; isRegionDirty = new boolean[width][width]; - regionNeedsRegen = new boolean[width][width]; - setupBuffer = new boolean[width][width]; - + regenRegionBuffer = new boolean[width][width]; + recreateRegionBuffer = new boolean[width][width]; + // populate isRegionDirty for (int i = 0; i < width; i++) for (int j = 0; j < width; j++) isRegionDirty[i][j] = false; } - - + + @Override public String toString() { LodRegion region; - + StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("Dimension : \n"); for (int x = 0; x < regions.length; x++) @@ -838,7 +850,7 @@ public class LodDimension { stringBuilder.append("n"); stringBuilder.append("\t"); - + } else { stringBuilder.append(region.getMinDetailLevel()); @@ -849,11 +861,11 @@ public class LodDimension } return stringBuilder.toString(); } - + public int getMemoryRequired(int x, int z, LodTemplate template) { /*return regions[x][z].getMinMemoryNeeded(template);*/ - + /*TODO add memory use calculated with the following cases switch (LodConfig.CLIENT.graphics.detailDropOff.get()) { diff --git a/src/main/java/com/seibel/lod/objects/LodRegion.java b/src/main/java/com/seibel/lod/objects/LodRegion.java index 8b763f51c..b6015883f 100644 --- a/src/main/java/com/seibel/lod/objects/LodRegion.java +++ b/src/main/java/com/seibel/lod/objects/LodRegion.java @@ -449,6 +449,7 @@ public class LodRegion } /** + * TODO what does this do? * @param detailLevel */ public void expand(byte detailLevel) diff --git a/src/main/java/com/seibel/lod/proxy/ClientProxy.java b/src/main/java/com/seibel/lod/proxy/ClientProxy.java index 652f70c22..4922d4c36 100644 --- a/src/main/java/com/seibel/lod/proxy/ClientProxy.java +++ b/src/main/java/com/seibel/lod/proxy/ClientProxy.java @@ -128,8 +128,8 @@ public class ClientProxy viewDistanceChangedEvent(); playerMoveEvent(lodDim); - lodDim.treeCutter((int) mc.getPlayer().getX(), (int) mc.getPlayer().getZ()); - lodDim.treeGenerator((int) mc.getPlayer().getX(), (int) mc.getPlayer().getZ()); + lodDim.cutRegionNodesAsync((int) mc.getPlayer().getX(), (int) mc.getPlayer().getZ()); + lodDim.expandOrLoadRegionsAsync((int) mc.getPlayer().getX(), (int) mc.getPlayer().getZ()); // Note to self: @@ -313,7 +313,7 @@ public class ClientProxy { // make sure the dimension is centered RegionPos playerRegionPos = new RegionPos(mc.getPlayer().blockPosition()); - RegionPos worldRegionOffset = new RegionPos(playerRegionPos.x - lodDim.getCenterX(), playerRegionPos.z - lodDim.getCenterZ()); + RegionPos worldRegionOffset = new RegionPos(playerRegionPos.x - lodDim.getCenterRegionPosX(), playerRegionPos.z - lodDim.getCenterRegionPosZ()); if (worldRegionOffset.x != 0 || worldRegionOffset.z != 0) { lodWorld.saveAllDimensions(); diff --git a/src/main/java/com/seibel/lod/render/LodRenderer.java b/src/main/java/com/seibel/lod/render/LodRenderer.java index f71f4110a..46e761278 100644 --- a/src/main/java/com/seibel/lod/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/render/LodRenderer.java @@ -287,7 +287,7 @@ public class LodRenderer { for (int j = 0; j < vbos.length; j++) { - RegionPos vboPos = new RegionPos(i + lodDim.getCenterX() - lodDim.getWidth() / 2, j + lodDim.getCenterZ() - lodDim.getWidth() / 2); + RegionPos vboPos = new RegionPos(i + lodDim.getCenterRegionPosX() - lodDim.getWidth() / 2, j + lodDim.getCenterRegionPosZ() - lodDim.getWidth() / 2); if (cullingDisabled || RenderUtil.isRegionInViewFrustum(renderInfo.getBlockPosition(), cameraDir, vboPos.blockPos())) { if ((i > halfWidth - quarterWidth && i < halfWidth + quarterWidth) && (j > halfWidth - quarterWidth && j < halfWidth + quarterWidth)) @@ -821,10 +821,10 @@ public class LodRenderer // check if there is any newly generated terrain to show if (newTime - prevChunkTime > LodConfig.CLIENT.buffers.bufferRebuildLodChangeTimeout.get()) { - if (lodDim.regenDimension) + if (lodDim.regenDimensionBuffers) { partialRegen = true; - lodDim.regenDimension = false; + lodDim.regenDimensionBuffers = false; } prevChunkTime = newTime; } @@ -864,7 +864,7 @@ public class LodRenderer { vanillaRenderedChunks[xIndex][zIndex] = true; vanillaRenderedChunksChanged = true; - lodDim.setToRegen(pos.getRegionX(), pos.getRegionZ()); + lodDim.markRegionBufferToRegen(pos.getRegionX(), pos.getRegionZ()); } } }