diff --git a/src/main/java/com/seibel/lod/core/api/EventApi.java b/src/main/java/com/seibel/lod/core/api/EventApi.java index ca4f48623..57e831a2e 100644 --- a/src/main/java/com/seibel/lod/core/api/EventApi.java +++ b/src/main/java/com/seibel/lod/core/api/EventApi.java @@ -96,7 +96,7 @@ public class EventApi public void chunkLoadEvent(IChunkWrapper chunk, IDimensionTypeWrapper dimType) { - ApiShared.lodBuilder.generateLodNodeAsync(chunk, ApiShared.lodWorld, dimType, DistanceGenerationMode.FULL); + ApiShared.lodBuilder.generateLodNodeAsync(chunk, ApiShared.lodWorld, dimType, DistanceGenerationMode.FULL, true); } public void worldSaveEvent() diff --git a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java index bca3a0bbe..646672558 100644 --- a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java +++ b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java @@ -461,21 +461,22 @@ public class LodBufferBuilderFactory int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - playerChunkX; int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - playerChunkZ; - // Currently fixing below - // FIXME: We don't need to ignore rendered chunks! Just build it and leave it for the renderer to decide! - //We don't want to render this fake block if - //The block is inside the render distance with, is not bigger than a chunk and is positioned in a chunk set as vanilla rendered - // - //The block is in the player chunk or in a chunk adjacent to the player - //if(isThisPositionGoingToBeRendered(detailLevel, posX, posZ, playerChunkX, playerChunkZ, vanillaRenderedChunks, gameChunkRenderDistance)) - //{ - // continue; - //} + // TODO: In the future, We don't need to ignore rendered chunks! Just build it and leave it for the renderer to decide! + // We don't want to render this fake block if + // The block is inside the render distance with, is not bigger than a chunk and is positioned in a chunk set as vanilla rendered + + // The block is in the player chunk or in a chunk adjacent to the player + if(detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL && + isThisPositionGoingToBeRendered(LevelPosUtil.getChunkPos(detailLevel, posX), + LevelPosUtil.getChunkPos(detailLevel, posZ))) + { + continue; + } //we check if the block to render is not in player chunk boolean posNotInPlayerChunk = !(chunkXdist == 0 && chunkZdist == 0); - - // We extract the adj data in the four cardinal direction + + // We extract the adj data in the four cardinal direction // we first reset the adjShadeDisabled. This is used to disable the shade on the border when we have transparent block like water or glass // to avoid having a "darker border" underground @@ -558,31 +559,20 @@ public class LodBufferBuilderFactory return true; } - - + // Will be removed in a1.7 @Deprecated - private boolean isThisPositionGoingToBeRendered(byte detailLevel, int posX, int posZ, int chunkPosX, int chunkPosZ, boolean[][] vanillaRenderedChunks, int gameChunkRenderDistance){ + private boolean isThisPositionGoingToBeRendered(int chunkX, int chunkZ){ + MovableGridList chunkGrid = ClientApi.renderer.vanillaRenderedChunks; + Boolean isRendered = chunkGrid.get(chunkX, chunkZ); + // skip any chunks that Minecraft is going to render - int chunkXdist = LevelPosUtil.getChunkPos(detailLevel, posX) - chunkPosX; - int chunkZdist = LevelPosUtil.getChunkPos(detailLevel, posZ) - chunkPosZ; - + if (isRendered == null || !isRendered) return false; + // check if the chunk is on the border - boolean isItBorderPos; if (CONFIG.client().graphics().advancedGraphics().getVanillaOverdraw() == VanillaOverdraw.BORDER) - isItBorderPos = LodUtil.isBorderChunk(vanillaRenderedChunks, chunkXdist + gameChunkRenderDistance + 1, chunkZdist + gameChunkRenderDistance + 1); + return !LodUtil.isBorderChunk(ClientApi.renderer.vanillaRenderedChunks, chunkX, chunkZ); else - isItBorderPos = false; - - - //boolean smallRenderDistance = gameChunkRenderDistance <= LodUtil.MINIMUM_RENDER_DISTANCE_FOR_PARTIAL_OVERDRAW; - - // get the positions that will be rendered - - return (gameChunkRenderDistance >= Math.abs(chunkXdist) - && gameChunkRenderDistance >= Math.abs(chunkZdist) - && detailLevel <= LodUtil.CHUNK_DETAIL_LEVEL - && vanillaRenderedChunks[chunkXdist + gameChunkRenderDistance + 1][chunkZdist + gameChunkRenderDistance + 1]) - && (!isItBorderPos); + return true; } diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java index d26c86ad0..8af36d0d7 100644 --- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java +++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java @@ -90,10 +90,10 @@ public class LodBuilder public void generateLodNodeAsync(IChunkWrapper chunk, LodWorld lodWorld, IDimensionTypeWrapper dim) { - generateLodNodeAsync(chunk, lodWorld, dim, DistanceGenerationMode.FULL); + generateLodNodeAsync(chunk, lodWorld, dim, DistanceGenerationMode.FULL, false); } - public void generateLodNodeAsync(IChunkWrapper chunk, LodWorld lodWorld, IDimensionTypeWrapper dim, DistanceGenerationMode generationMode) + public void generateLodNodeAsync(IChunkWrapper chunk, LodWorld lodWorld, IDimensionTypeWrapper dim, DistanceGenerationMode generationMode, boolean override) { if (lodWorld == null || lodWorld.getIsWorldNotLoaded()) return; @@ -130,7 +130,7 @@ public class LodBuilder { lodDim = lodWorld.getLodDimension(dim); } - generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(generationMode)); + generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(generationMode), override); //} //catch (IllegalArgumentException | NullPointerException e) //{ @@ -149,14 +149,14 @@ public class LodBuilder */ public void generateLodNodeFromChunk(LodDimension lodDim, IChunkWrapper chunk) throws IllegalArgumentException { - generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig()); + generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(), false); } /** * Creates a LodNode for a chunk in the given world. * @throws IllegalArgumentException thrown if either the chunk or world is null. */ - public void generateLodNodeFromChunk(LodDimension lodDim, IChunkWrapper chunk, LodBuilderConfig config) + public void generateLodNodeFromChunk(LodDimension lodDim, IChunkWrapper chunk, LodBuilderConfig config, boolean override) throws IllegalArgumentException { //long executeTime = System.currentTimeMillis(); @@ -204,7 +204,9 @@ public class LodBuilder { posX = LevelPosUtil.convert((byte) 0, chunk.getChunkPosX() * 16 + startX, minDetailLevel); posZ = LevelPosUtil.convert((byte) 0, chunk.getChunkPosZ() * 16 + startZ, minDetailLevel); - if (!lodDim.doesDataExist(minDetailLevel, posX, posZ)) { + long oldData = lodDim.getSingleData(minDetailLevel, posX, posZ); + if (override || !DataPointUtil.doesItExist(oldData) || + DataPointUtil.getGenerationMode(oldData) DIRECTION_NORMAL_MAP = new HashMap() {{ diff --git a/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java b/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java index d0a280a49..1e580769b 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java @@ -210,14 +210,14 @@ public class VerticalLevelContainer implements LevelContainer } private static long[] downgradeVerticalSize(int oldVertSize, int newVertSize, long[] data) { - long[] dataToMerge = new long[oldVertSize]; int size = data.length/oldVertSize; + long[] dataToMerge = new long[oldVertSize]; long[] newData = new long[size * newVertSize]; for (int i = 0; i < size; i++) { - System.arraycopy(oldVertSize, i * oldVertSize, dataToMerge, 0, oldVertSize); - dataToMerge = DataPointUtil.mergeMultiData(dataToMerge, oldVertSize, newVertSize); - System.arraycopy(dataToMerge, 0, newData, i * newVertSize, newVertSize); + System.arraycopy(data, i * oldVertSize, dataToMerge, 0, oldVertSize); + long[] tempBuffer = DataPointUtil.mergeMultiData(dataToMerge, oldVertSize, newVertSize); + System.arraycopy(tempBuffer, 0, newData, i * newVertSize, newVertSize); } return newData; } diff --git a/src/main/java/com/seibel/lod/core/render/LodRenderer.java b/src/main/java/com/seibel/lod/core/render/LodRenderer.java index c78d41c06..b80ed2bac 100644 --- a/src/main/java/com/seibel/lod/core/render/LodRenderer.java +++ b/src/main/java/com/seibel/lod/core/render/LodRenderer.java @@ -59,21 +59,6 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper; */ public class LodRenderer { - public static class VanillaRenderedChunksList extends GridList { - private static final long serialVersionUID = -5448501880911391315L; - - public final int centerX; - public final int centerZ; - - public VanillaRenderedChunksList(int range, int centerX, int centerZ) { - super(range); - this.centerX = centerX; - this.centerZ = centerZ; - for (int i=0; i vanillaRenderedChunks; public int vanillaRenderedChunksCenterX; public int vanillaRenderedChunksCenterZ; public int vanillaRenderedChunksRefreshTimer; @@ -504,50 +489,43 @@ public class LodRenderer // returns whether anything changed private boolean updateVanillaRenderedChunks(LodDimension lodDim, boolean recreateChunks) { short chunkRenderDistance = (short) MC_RENDER.getRenderDistance(); - int chunkX = Math.floorDiv(previousPos.getX(), 16); - int chunkZ = Math.floorDiv(previousPos.getZ(), 16); + int chunkX = Math.floorDiv(lastUpdatedPos.getX(), 16); + int chunkZ = Math.floorDiv(lastUpdatedPos.getZ(), 16); // if the player is high enough, draw all LODs - if (previousPos.getY() > 256) { - vanillaRenderedChunks = new VanillaRenderedChunksList( + if (lastUpdatedPos.getY() > 256) { + vanillaRenderedChunks = new MovableGridList( chunkRenderDistance, chunkX, chunkZ); return true; } - VanillaRenderedChunksList chunkList; - - if (recreateChunks) { - vanillaRenderedChunks = new VanillaRenderedChunksList(chunkRenderDistance, chunkX, chunkZ); - return true; - } else { - chunkList = vanillaRenderedChunks; - chunkX = chunkList.centerX; - chunkZ = chunkList.centerZ; - chunkRenderDistance = (short) vanillaRenderedChunks.gridCentreToEdge; - } + MovableGridList chunkList; boolean anyChanged = false; + if (recreateChunks || vanillaRenderedChunks.gridCentreToEdge != chunkRenderDistance) { + chunkList = new MovableGridList(chunkRenderDistance, chunkX, chunkZ); + anyChanged = true; + } else { + // anyChanged = vanillaRenderedChunks.move(chunkX, chunkZ); + // chunkList = vanillaRenderedChunks; + chunkList = new MovableGridList(chunkRenderDistance, chunkX, chunkZ); + anyChanged = true; + } + LagSpikeCatcher getChunks = new LagSpikeCatcher(); - Set chunkPosToSkip = LodUtil.getNearbyLodChunkPosToSkip(lodDim, previousPos); + Set chunkPosToSkip = LodUtil.getNearbyLodChunkPosToSkip(lodDim, lastUpdatedPos); getChunks.end("LodDrawSetup:UpdateStatus:UpdateVanillaChunks:getChunks"); for (AbstractChunkPosWrapper pos : chunkPosToSkip) { - int xIndex = (pos.getX() - chunkX) + (chunkRenderDistance + 1); - int zIndex = (pos.getZ() - chunkZ) + (chunkRenderDistance + 1); - // sometimes we are given chunks that are outside the render distance, // This prevents index out of bounds exceptions - if (xIndex >= 0 && zIndex >= 0 - && xIndex < vanillaRenderedChunks.gridSize - && zIndex < vanillaRenderedChunks.gridSize) + if (!chunkList.inRange(pos.getX(), pos.getZ())) continue; + Boolean oldBool = chunkList.swap(pos.getX(), pos.getZ(), true); + if (oldBool == null || !oldBool) { - if (!chunkList.get(chunkList.calculateOffset(xIndex, zIndex))) - { - chunkList.set(chunkList.calculateOffset(xIndex, zIndex), true); - anyChanged = true; - lodDim.markRegionBufferToRegen(pos.getRegionX(), pos.getRegionZ()); - } + anyChanged = true; + lodDim.markRegionBufferToRegen(pos.getRegionX(), pos.getRegionZ()); } } - vanillaRenderedChunks = chunkList; + if (anyChanged) vanillaRenderedChunks = chunkList; return anyChanged; } @@ -577,12 +555,12 @@ public class LodRenderer // check if the player has moved if (newTime - prevPlayerPosTime > CONFIG.client().advanced().buffers().getRebuildTimes().playerMoveTimeout) { - if (previousPos == null - || Math.abs(newPos.getX() - previousPos.getX()) > CONFIG.client().advanced().buffers().getRebuildTimes().playerMoveDistance*16 - || Math.abs(newPos.getZ() - previousPos.getZ()) > CONFIG.client().advanced().buffers().getRebuildTimes().playerMoveDistance*16) + if (lastUpdatedPos == null + || Math.abs(newPos.getX() - lastUpdatedPos.getX()) > CONFIG.client().advanced().buffers().getRebuildTimes().playerMoveDistance*16 + || Math.abs(newPos.getZ() - lastUpdatedPos.getZ()) > CONFIG.client().advanced().buffers().getRebuildTimes().playerMoveDistance*16) { tryPartialGen = true; - previousPos = newPos; + lastUpdatedPos = newPos; posUpdated = true; } prevPlayerPosTime = newTime; @@ -604,7 +582,7 @@ public class LodRenderer if (tryFullGen && !posUpdated) { - previousPos = newPos; + lastUpdatedPos = newPos; posUpdated = true; } shouldUpdateChunks |= posUpdated; diff --git a/src/main/java/com/seibel/lod/core/util/LodUtil.java b/src/main/java/com/seibel/lod/core/util/LodUtil.java index d14b41932..f301aa520 100644 --- a/src/main/java/com/seibel/lod/core/util/LodUtil.java +++ b/src/main/java/com/seibel/lod/core/util/LodUtil.java @@ -394,6 +394,7 @@ public class LodUtil * @param z relative (to the matrix) z chunk to check * @return true if and only if the chunk is a border of the renderable chunks */ + @Deprecated public static boolean isBorderChunk(boolean[][] vanillaRenderedChunks, int x, int z) { if (x < 0 || z < 0 || x >= vanillaRenderedChunks.length || z >= vanillaRenderedChunks[0].length) @@ -410,6 +411,17 @@ public class LodUtil } return false; } + public static boolean isBorderChunk(MovableGridList vanillaRenderedChunks, int chunkX, int chunkZ) + { + for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS) + { + int tempX = chunkX + lodDirection.getNormal().x; + int tempZ = chunkZ + lodDirection.getNormal().z; + Boolean b = vanillaRenderedChunks.get(tempX, tempZ); + if (b == null || !b) return true; + } + return false; + } /** This is copied from Minecraft's MathHelper class */ diff --git a/src/main/java/com/seibel/lod/core/util/MovableGridList.java b/src/main/java/com/seibel/lod/core/util/MovableGridList.java index acdb4c67d..d620321da 100644 --- a/src/main/java/com/seibel/lod/core/util/MovableGridList.java +++ b/src/main/java/com/seibel/lod/core/util/MovableGridList.java @@ -67,11 +67,25 @@ public class MovableGridList extends ArrayList implements List { } // return null if x,y is outside of the grid + // Otherwise, return the new value (for chaining) public T setAndGet(int x, int y, T t) { x = x-centerX+gridCentreToEdge; y = y-centerY+gridCentreToEdge; return _setDirect(x,y, t) ? t : null; } + // return null if x,y is outside of the grid + // Otherwise, return the old value + public T swap(int x, int y, T t) { + x = x-centerX+gridCentreToEdge; + y = y-centerY+gridCentreToEdge; + return _swapDirect(x,y, t); + } + + public boolean inRange(int x, int y) { + x = x-centerX+gridCentreToEdge; + y = y-centerY+gridCentreToEdge; + return (x>=0 && x=0 && y=gridSize || y<0 || y>=gridSize) return null; @@ -82,9 +96,14 @@ public class MovableGridList extends ArrayList implements List { super.set(x + y * gridSize, t); return true; } + private final T _swapDirect(int x, int y, T t) { + if (x<0 || x>=gridSize || y<0 || y>=gridSize) return null; + return super.set(x + y * gridSize, t); + } - public void move(int newCenterX, int newCenterY) { - if (centerX == newCenterX && centerY == newCenterY) return; + // Return false if haven't changed. Return true if it did + public boolean move(int newCenterX, int newCenterY) { + if (centerX == newCenterX && centerY == newCenterY) return false; int deltaX = newCenterX - centerX; int deltaY = newCenterY - centerY; @@ -97,7 +116,7 @@ public class MovableGridList extends ArrayList implements List { // update the new center centerX = newCenterX; centerY = newCenterY; - return; + return true; } centerX = newCenterX; centerY = newCenterY; @@ -147,6 +166,7 @@ public class MovableGridList extends ArrayList implements List { } } } + return true; } public void move(int newCenterX, int newCenterY, Consumer d) { diff --git a/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java b/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java index 886e9603a..03722b04b 100644 --- a/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java +++ b/src/main/java/com/seibel/lod/core/wrapperInterfaces/minecraft/IMinecraftRenderWrapper.java @@ -101,9 +101,6 @@ public interface IMinecraftRenderWrapper IWrapperFactory factory = SingletonHandler.get(IWrapperFactory.class); int chunkRenderDist = this.getRenderDistance(); - // if we have a odd render distance, we'll have a empty gap. This way we'll overlap by 1 instead, - // which is preferable to having a hole in the world - chunkRenderDist = chunkRenderDist % 2 == 0 ? chunkRenderDist : chunkRenderDist - 1; AbstractChunkPosWrapper centerChunkPos = mcWrapper.getPlayerChunkPos(); int startChunkX = centerChunkPos.getX() - chunkRenderDist; @@ -111,9 +108,9 @@ public interface IMinecraftRenderWrapper // add every position within render distance HashSet renderedPos = new HashSet(); - for (int chunkX = 0; chunkX < (chunkRenderDist * 2); chunkX++) + for (int chunkX = 0; chunkX < (chunkRenderDist * 2+1); chunkX++) { - for(int chunkZ = 0; chunkZ < (chunkRenderDist * 2); chunkZ++) + for(int chunkZ = 0; chunkZ < (chunkRenderDist * 2+1); chunkZ++) { renderedPos.add(factory.createChunkPos(startChunkX + chunkX, startChunkZ + chunkZ)); }