From 29b3e9fadc4827787c4f6b0dd1468bb7c5162190 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Tue, 13 Jul 2021 20:40:55 +0200 Subject: [PATCH] The lodQuadTree is now correctly converted to use LodDataPoint and DistanceGenerationMode --- src/main/java/com/seibel/lod/LodMain.java | 6 +- ...LodBufferBuilder.java => LodBufferBuilder} | 3 + .../lod/builders/LodNodeBufferBuilder.java | 141 ++++- .../seibel/lod/builders/LodNodeBuilder.java | 12 +- .../lodTemplates/AbstractLodTemplate.java | 10 +- .../lodTemplates/CubicLodTemplate.java | 27 +- .../lodTemplates/DynamicLodTemplate.java | 8 +- .../lodTemplates/TriangularLodTemplate.java | 8 +- .../worldGeneration/LodChunkGenWorker.java | 581 ------------------ .../java/com/seibel/lod/objects/HOWTOUSE.txt | 29 + .../com/seibel/lod/proxy/ClientProxy.java | 128 ++-- .../render/{LodRenderer.java => LodRenderer} | 0 .../com/seibel/lod/render/RenderUtil.java | 2 +- 13 files changed, 249 insertions(+), 706 deletions(-) rename src/main/java/com/seibel/lod/builders/{LodBufferBuilder.java => LodBufferBuilder} (99%) delete mode 100644 src/main/java/com/seibel/lod/builders/worldGeneration/LodChunkGenWorker.java create mode 100644 src/main/java/com/seibel/lod/objects/HOWTOUSE.txt rename src/main/java/com/seibel/lod/render/{LodRenderer.java => LodRenderer} (100%) diff --git a/src/main/java/com/seibel/lod/LodMain.java b/src/main/java/com/seibel/lod/LodMain.java index cd54212a9..0d896cbc9 100644 --- a/src/main/java/com/seibel/lod/LodMain.java +++ b/src/main/java/com/seibel/lod/LodMain.java @@ -1,10 +1,10 @@ package com.seibel.lod; +import com.seibel.lod.render.LodNodeRenderer; import org.lwjgl.opengl.GL; import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.proxy.ClientProxy; -import com.seibel.lod.render.LodRenderer; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -42,9 +42,9 @@ public class LodMain Thread setFancyFog = new Thread(() -> { - LodRenderer.fancyFogAvailable = GL.getCapabilities().GL_NV_fog_distance; + LodNodeRenderer.fancyFogAvailable = GL.getCapabilities().GL_NV_fog_distance; - if (!LodRenderer.fancyFogAvailable) + if (!LodNodeRenderer.fancyFogAvailable) { ClientProxy.LOGGER.info("This GPU does not support GL_NV_fog_distance. This means that fancy fog options will not be available."); } diff --git a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodBufferBuilder similarity index 99% rename from src/main/java/com/seibel/lod/builders/LodBufferBuilder.java rename to src/main/java/com/seibel/lod/builders/LodBufferBuilder index d97a505d3..fedeb3216 100644 --- a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBufferBuilder @@ -205,9 +205,12 @@ public class LodBufferBuilder // get the desired LodTemplate and // add this LOD to the buffer + /* LodConfig.CLIENT.lodTemplate.get(). template.addLodToBuffer(currentBuffer, lodDim, lod, xOffset, yOffset, zOffset, renderer.debugging); + + */ } } diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java index 54c29988e..84ec8df98 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java @@ -1,17 +1,18 @@ package com.seibel.lod.builders; -import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.NearFarBuffer; -import com.seibel.lod.objects.LodQuadTreeNode; -import com.seibel.lod.objects.LodQuadTreeDimension; +import com.seibel.lod.builders.worldGeneration.LodNodeGenWorker; +import com.seibel.lod.enums.DistanceGenerationMode; +import com.seibel.lod.handlers.LodConfig; +import com.seibel.lod.objects.*; import com.seibel.lod.render.LodNodeRenderer; -import com.seibel.lod.render.LodRenderer; import com.seibel.lod.util.LodUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.biome.BiomeContainer; import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.WorldWorkerManager; import org.lwjgl.opengl.GL11; import java.util.ArrayList; @@ -125,35 +126,117 @@ public class LodNodeBufferBuilder // generate our new buildable buffers - buildableNearBuffer.begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); - buildableFarBuffer.begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); + buildableNearBuffer.begin(GL11.GL_QUADS, LodNodeRenderer.LOD_VERTEX_FORMAT); + buildableFarBuffer.begin(GL11.GL_QUADS, LodNodeRenderer.LOD_VERTEX_FORMAT); + + // x axis + for (int i = 0; i < numbChunksWide; i++) + { + // z axis + for (int j = 0; j < numbChunksWide; j++) + { + int chunkX = i + (startX / LodChunk.WIDTH); + int chunkZ = j + (startZ / LodChunk.WIDTH); + + // skip any chunks that Minecraft is going to render + if(isCoordInCenterArea(i, j, (numbChunksWide / 2)) + && renderer.vanillaRenderedChunks.contains(new ChunkPos(chunkX, chunkZ))) + { + continue; + } - List lodToRender = new ArrayList<>(); - lodToRender.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 0, LodQuadTreeDimension.FULL_COMPLEXITY_MASK, 100000,0)); - /* - lodToRender.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 9, 100000,8000)); - lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 8, 8000,4000)); - lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 7, 4000,2000)); - lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 6, 2000,1000)); - lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 5, 1000,500)); - lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 4, 500,250)); - lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 3, 250,0)); -*/ - for(LodQuadTreeNode data : lodToRender){ - BufferBuilder currentBuffer = null; -/* - if (isCoordinateInNearFogArea(i, j, numbChunksWide / 2)) - currentBuffer = buildableNearBuffer; - else - currentBuffer = buildableFarBuffer; - */ - currentBuffer = buildableFarBuffer; + // set where this square will be drawn in the world + double xOffset = (LodChunk.WIDTH * i) + // offset by the number of LOD blocks + startX; // offset so the center LOD block is centered underneath the player + double yOffset = 0; + double zOffset = (LodChunk.WIDTH * j) + startZ; - // get the desired LodTemplate and - // add this LOD to the buffer + LodQuadTreeNode lod = lodDim.getLodFromCoordinates(chunkX, chunkZ, (byte) 4); + + if (lod == null || lod.getComplexity() == DistanceGenerationMode.NONE) + { + // generate a new chunk if no chunk currently exists + // and we aren't waiting on any other chunks to generate + if (lod == null && numberOfChunksWaitingToGenerate < maxChunkGenRequests) + { + ChunkPos pos = new ChunkPos(chunkX, chunkZ); + + // determine if this position is closer to the player + // than the previous + int newDistance = playerChunkPos.getChessboardDistance(pos); + + if (newDistance < minChunkDist) + { + // this chunk is closer, clear any previous + // positions and update the new minimum distance + minChunkDist = newDistance; + chunksToGenReserve = chunksToGen; + + chunkGenIndex = 0; + chunksToGen = new ChunkPos[maxChunkGenRequests]; + chunksToGen[chunkGenIndex] = pos; + chunkGenIndex++; + } + else if (newDistance <= minChunkDist) + { + // this chunk position is as close or closers than the + // minimum distance + if(chunkGenIndex < maxChunkGenRequests) + { + // we are still under the number of chunks to generate + // add this position to the list + chunksToGen[chunkGenIndex] = pos; + chunkGenIndex++; + } + } + + } + // don't render this null chunk + continue; + } + + + BufferBuilder currentBuffer = null; + if (isCoordinateInNearFogArea(i, j, numbChunksWide / 2)) + currentBuffer = buildableNearBuffer; + else + currentBuffer = buildableFarBuffer; + + // get the desired LodTemplate and + // add this LOD to the buffer + LodConfig.CLIENT.lodTemplate.get(). + template.addLodToBuffer(currentBuffer, lodDim, lod, + xOffset, yOffset, zOffset, renderer.debugging); + } } + // TODO add a way for a server side mod to generate chunks requested here + if(mc.hasSingleplayerServer()) + { + ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension); + + // make sure we have as many chunks to generate as we are allowed + if (chunkGenIndex < maxChunkGenRequests) + { + for(int i = chunkGenIndex, j = 0; i < maxChunkGenRequests; i++, j++) + { + chunksToGen[i] = chunksToGenReserve[j]; + } + } + + // start chunk generation + for(ChunkPos chunkPos : chunksToGen) + { + if(chunkPos == null) + break; + + numberOfChunksWaitingToGenerate++; + + LodNodeGenWorker genWorker = new LodNodeGenWorker(chunkPos, renderer, lodChunkBuilder, this, lodDim, serverWorld, biomeContainer); + WorldWorkerManager.addWorker(genWorker); + } + } // x axis // finish the buffer building diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java index fbc1b3314..4ede0f9f7 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java @@ -63,8 +63,10 @@ public class LodNodeBuilder { */ public void generateLodNodeAsync(IChunk chunk, LodQuadTreeWorld lodWorld, IWorld world) { - if (lodWorld == null || !lodWorld.getIsWorldLoaded()) + if (lodWorld == null || !lodWorld.getIsWorldLoaded()) { + System.out.println("This case?"); return; + } // don't try to create an LOD object // if for some reason we aren't @@ -82,20 +84,24 @@ public class LodNodeBuilder { LodQuadTreeDimension lodDim; if (lodWorld.getLodDimension(dim) == null) { + System.out.println("Adding"); lodDim = new LodQuadTreeDimension(dim, lodWorld, regionWidth); lodWorld.addLodDimension(lodDim); } else { + System.out.println("Not adding"); lodDim = lodWorld.getLodDimension(dim); } lodDim.addNode(node); } catch (IllegalArgumentException | NullPointerException e) { + e.printStackTrace(); // if the world changes while LODs are being generated // they will throw errors as they try to access things that no longer // exist. } }); lodGenThreadPool.execute(thread); + System.out.println("Is this ENDING?"); return; } @@ -266,6 +272,8 @@ public class LodNodeBuilder { * otherwise use the */ private Color generateLodColorForArea(IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ) { + return Color.BLUE; + /* ChunkSection[] chunkSections = chunk.getSections(); int numbOfBlocks = 0; @@ -345,6 +353,8 @@ public class LodNodeBuilder { blue /= numbOfBlocks; return new Color(red, green, blue); + + */ } diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java index 0c3b79600..56902cfe0 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java @@ -4,6 +4,8 @@ import com.seibel.lod.enums.LodDetail; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; import net.minecraft.client.renderer.BufferBuilder; /** @@ -15,10 +17,10 @@ import net.minecraft.client.renderer.BufferBuilder; */ public abstract class AbstractLodTemplate { - public abstract void addLodToBuffer(BufferBuilder buffer, - LodDimension lodDim, LodChunk lod, - double xOffset, double yOffset, double zOffset, - boolean debugging); + public abstract void addLodToBuffer(BufferBuilder buffer, + LodQuadTreeDimension lodDim, LodQuadTreeNode centerLod, + double xOffset, double yOffset, double zOffset, + boolean debugging); /** add the given position and color to the buffer */ protected void addPosAndColor(BufferBuilder buffer, 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 c5200df5d..d446a7747 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java @@ -8,6 +8,8 @@ import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.util.math.AxisAlignedBB; @@ -28,9 +30,9 @@ public class CubicLodTemplate extends AbstractLodTemplate @Override public void addLodToBuffer(BufferBuilder buffer, - LodDimension lodDim, LodChunk centerLod, - double xOffset, double yOffset, double zOffset, - boolean debugging) + LodQuadTreeDimension lodDim, LodQuadTreeNode centerLod, + double xOffset, double yOffset, double zOffset, + boolean debugging) { AxisAlignedBB bbox; @@ -39,28 +41,19 @@ public class CubicLodTemplate extends AbstractLodTemplate LodDetail detail = LodConfig.CLIENT.lodDetail.get(); int halfWidth = detail.dataPointWidth / 2; - - for(int i = 0; i < detail.dataPointLengthCount * detail.dataPointLengthCount; i++) - { - int startX = detail.startX[i]; - int startZ = detail.startZ[i]; - int endX = detail.endX[i]; - int endZ = detail.endZ[i]; - // returns null if the lod is empty at the given location bbox = generateBoundingBox( - centerLod.getAverageHeightOverArea(startX, startZ, endX, endZ), - centerLod.getAverageDepthOverArea(startX, startZ, endX, endZ), + centerLod.lodDataPoint.height, + centerLod.lodDataPoint.depth, detail.dataPointWidth, - xOffset - (halfWidth / 2) + detail.startX[i], + xOffset - (centerLod.width / 2), yOffset, - zOffset - (halfWidth / 2) + detail.startZ[i]); + zOffset - (centerLod.width / 2)); if (bbox != null) { - addBoundingBoxToBuffer(buffer, bbox, centerLod.getAverageColorOverArea(startX, startZ, endX, endZ, debugging)); + addBoundingBoxToBuffer(buffer, bbox, centerLod.lodDataPoint.color); } - } } diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/DynamicLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/DynamicLodTemplate.java index 7203aa273..c50f726ec 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/DynamicLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/DynamicLodTemplate.java @@ -4,6 +4,8 @@ import com.seibel.lod.enums.LodDetail; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; import net.minecraft.client.renderer.BufferBuilder; /** @@ -19,9 +21,9 @@ public class DynamicLodTemplate extends AbstractLodTemplate { @Override public void addLodToBuffer(BufferBuilder buffer, - LodDimension lodDim, LodChunk lod, - double xOffset, double yOffset, double zOffset, - boolean debugging) + LodQuadTreeDimension lodDim, LodQuadTreeNode centerLod, + double xOffset, double yOffset, double zOffset, + boolean debugging) { System.err.println("DynamicLodTemplate not implemented!"); } diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/TriangularLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/TriangularLodTemplate.java index d1188f6ba..9215ada38 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/TriangularLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/TriangularLodTemplate.java @@ -4,6 +4,8 @@ import com.seibel.lod.enums.LodDetail; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; import net.minecraft.client.renderer.BufferBuilder; /** @@ -17,9 +19,9 @@ public class TriangularLodTemplate extends AbstractLodTemplate { @Override public void addLodToBuffer(BufferBuilder buffer, - LodDimension lodDim, LodChunk lod, - double xOffset, double yOffset, double zOffset, - boolean debugging) + LodQuadTreeDimension lodDim, LodQuadTreeNode centerLod, + double xOffset, double yOffset, double zOffset, + boolean debugging) { System.err.println("DynamicLodTemplate not implemented!"); } diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodChunkGenWorker.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodChunkGenWorker.java deleted file mode 100644 index 17a769e4e..000000000 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodChunkGenWorker.java +++ /dev/null @@ -1,581 +0,0 @@ -package com.seibel.lod.builders.worldGeneration; - -import java.util.ConcurrentModificationException; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.function.Supplier; - -import com.seibel.lod.builders.LodBufferBuilder; -import com.seibel.lod.builders.LodBuilderConfig; -import com.seibel.lod.builders.LodChunkBuilder; -import com.seibel.lod.enums.DistanceGenerationMode; -import com.seibel.lod.handlers.LodConfig; -import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDimension; -import com.seibel.lod.objects.LodRegion; -import com.seibel.lod.proxy.ClientProxy; -import com.seibel.lod.render.LodRenderer; - -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.util.WeightedList.Entry; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.util.palette.UpgradeData; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.BiomeContainer; -import net.minecraft.world.chunk.ChunkPrimer; -import net.minecraft.world.chunk.ChunkStatus; -import net.minecraft.world.chunk.IChunk; -import net.minecraft.world.gen.ChunkGenerator; -import net.minecraft.world.gen.Heightmap; -import net.minecraft.world.gen.blockstateprovider.WeightedBlockStateProvider; -import net.minecraft.world.gen.feature.BlockClusterFeatureConfig; -import net.minecraft.world.gen.feature.ConfiguredFeature; -import net.minecraft.world.gen.feature.DecoratedFeatureConfig; -import net.minecraft.world.gen.feature.FeatureSpread; -import net.minecraft.world.gen.feature.FeatureSpreadConfig; -import net.minecraft.world.gen.feature.IceAndSnowFeature; -import net.minecraft.world.gen.feature.NoFeatureConfig; -import net.minecraft.world.gen.placement.ConfiguredPlacement; -import net.minecraft.world.gen.placement.DecoratedPlacementConfig; -import net.minecraft.world.gen.placement.IPlacementConfig; -import net.minecraft.world.gen.placement.NoiseDependant; -import net.minecraft.world.server.ServerChunkProvider; -import net.minecraft.world.server.ServerWorld; -import net.minecraft.world.server.ServerWorldLightManager; -import net.minecraftforge.common.WorldWorkerManager.IWorker; - -/** - * This is used to generate a LodChunk at a given ChunkPos. - * - * @author James Seibel - * @version 7-4-2021 - */ -public class LodChunkGenWorker implements IWorker -{ - public static final ExecutorService genThreads = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); - - private boolean threadStarted = false; - private LodChunkGenThread thread; - - /** If a configured feature fails for whatever reason, - * add it to this list, this is to hopefully remove any - * features that could cause issues down the line. */ - private static ConcurrentHashMap> configuredFeaturesToAvoid = new ConcurrentHashMap<>(); - - - - public LodChunkGenWorker(ChunkPos newPos, LodRenderer newLodRenderer, - LodChunkBuilder newLodBuilder, LodBufferBuilder newLodBufferBuilder, - LodDimension newLodDimension, ServerWorld newServerWorld, - BiomeContainer newBiomeContainer) - { - if (newServerWorld == null) - throw new IllegalArgumentException("LodChunkGenWorker must have a non-null ServerWorld"); - - thread = new LodChunkGenThread(newPos, newLodRenderer, - newLodBuilder, newLodBufferBuilder, - newLodDimension, newServerWorld); - } - - @Override - public boolean doWork() - { - if (!threadStarted) - { - // make sure we don't generate this chunk again - thread.lodDim.addLod(new LodChunk(thread.pos)); - - thread.lodBufferBuilder.numberOfChunksWaitingToGenerate--; - - if (LodConfig.CLIENT.distanceGenerationMode.get() == DistanceGenerationMode.SERVER) - { - // if we are using SERVER generation that has to be done - // synchronously to prevent crashing and harmful - // interactions with the normal world generator - thread.run(); - } - else - { - // Every other method can - // be done asynchronously - genThreads.execute(thread); - } - - threadStarted = true; - - // useful for debugging -// ClientProxy.LOGGER.info(thread.lodDim.getNumberOfLods()); - } - - return false; - } - - @Override - public boolean hasWork() - { - return !threadStarted; - } - - - - - private class LodChunkGenThread implements Runnable - { - public final ServerWorld serverWorld; - public final LodDimension lodDim; - public final LodChunkBuilder lodChunkBuilder; - public final LodRenderer lodRenderer; - private LodBufferBuilder lodBufferBuilder; - - private ChunkPos pos; - - public LodChunkGenThread(ChunkPos newPos, LodRenderer newLodRenderer, - LodChunkBuilder newLodBuilder, LodBufferBuilder newLodBufferBuilder, - LodDimension newLodDimension, ServerWorld newServerWorld) - { - pos = newPos; - lodRenderer = newLodRenderer; - lodChunkBuilder = newLodBuilder; - lodBufferBuilder = newLodBufferBuilder; - lodDim = newLodDimension; - serverWorld = newServerWorld; - } - - @Override - public void run() - { - // only generate LodChunks if they can - // be added to the current LodDimension - if (lodDim.regionIsInRange(pos.x / LodRegion.SIZE, pos.z / LodRegion.SIZE)) - { -// long startTime = System.currentTimeMillis(); - - switch(LodConfig.CLIENT.distanceGenerationMode.get()) - { - case BIOME_ONLY: - case BIOME_ONLY_SIMULATE_HEIGHT: - // fastest - generateUsingBiomesOnly(); - break; - case SURFACE: - // faster - generateUsingSurface(); - break; - case FEATURES: - // fast - generateUsingFeatures(); - break; - case SERVER: - // very slow - generateWithServer(); - break; - } - - lodRenderer.regenerateLODsNextFrame(); - - -// if (lodDim.getLodFromCoordinates(pos.x, pos.z) != null) -// ClientProxy.LOGGER.info(pos.x + " " + pos.z + " Success!"); -// else -// ClientProxy.LOGGER.info(pos.x + " " + pos.z); - -// long endTime = System.currentTimeMillis(); -// System.out.println(endTime - startTime); - - }// if in range - - }// run - - - - /** - * takes about 2-5 ms - */ - private void generateUsingBiomesOnly() - { - List chunkList = new LinkedList<>(); - ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY); - chunkList.add(chunk); - - ServerChunkProvider chunkSource = serverWorld.getChunkSource(); - ChunkGenerator chunkGen = chunkSource.generator; - - - // generate the terrain (this is thread safe) - ChunkStatus.EMPTY.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - // override the chunk status so we can run the next generator stage - chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); - ChunkStatus.BIOMES.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); - - - // generate fake height data for this LOD - int seaLevel = serverWorld.getSeaLevel(); - - boolean simulateHeight = LodConfig.CLIENT.distanceGenerationMode.get() == DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT; - boolean inTheEnd = false; - - // add fake heightmap data so our LODs aren't at height 0 - Heightmap heightmap = new Heightmap(chunk, LodChunk.DEFAULT_HEIGHTMAP); - for(int x = 0; x < LodChunk.WIDTH && !inTheEnd; x++) - { - for(int z = 0; z < LodChunk.WIDTH && !inTheEnd; z++) - { - if (simulateHeight) - { - // TODO use the biomes around each block to smooth out the transition - - // these heights are of course aren't super accurate, - // they are just to simulate height data where there isn't any - switch(chunk.getBiomes().getNoiseBiome(x, seaLevel, z).getBiomeCategory()) - { - case NETHER: - heightmap.setHeight(x, z, serverWorld.getHeight() / 2); - break; - - case EXTREME_HILLS: - heightmap.setHeight(x, z, seaLevel + 30); - break; - case MESA: - heightmap.setHeight(x, z, seaLevel + 20); - break; - case JUNGLE: - heightmap.setHeight(x, z, seaLevel + 20); - break; - case BEACH: - heightmap.setHeight(x, z, seaLevel + 5); - break; - case NONE: - heightmap.setHeight(x, z, 0); - break; - - case OCEAN: - case RIVER: - heightmap.setHeight(x, z, seaLevel); - break; - - case THEEND: - inTheEnd = true; - break; - - // DESERT - // FOREST - // ICY - // MUSHROOM - // SAVANNA - // SWAMP - // TAIGA - // PLAINS - default: - heightmap.setHeight(x, z, seaLevel + 10); - break; - }// heightmap switch - } - else - { - // we aren't simulating height - // always use sea level - heightmap.setHeight(x, z, seaLevel); - } - }// z - }// x - - chunk.setHeightmap(LodChunk.DEFAULT_HEIGHTMAP, heightmap.getRawData()); - - - LodChunk lod; - if (!inTheEnd) - { - lod = lodChunkBuilder.generateLodFromChunk(chunk, new LodBuilderConfig(true, true, false)); - } - else - { - // if we are in the end, don't generate any chunks. - // Since we don't know where the islands are, everything - // generates the same and it looks really bad. - lod = new LodChunk(chunk.getPos().x, chunk.getPos().z); - } - lodDim.addLod(lod); - } - - - /** - * takes about 10 - 20 ms - */ - private void generateUsingSurface() - { - List chunkList = new LinkedList<>(); - ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY); - chunkList.add(chunk); - LodServerWorld lodServerWorld = new LodServerWorld(serverWorld, chunk); - - ServerChunkProvider chunkSource = serverWorld.getChunkSource(); - ChunkGenerator chunkGen = chunkSource.generator; - - - // generate the terrain (this is thread safe) - ChunkStatus.EMPTY.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - // override the chunk status so we can run the next generator stage - chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); - ChunkStatus.BIOMES.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - ChunkStatus.NOISE.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - ChunkStatus.SURFACE.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - - // this feature has proved to be thread safe - // so we will add it - IceAndSnowFeature snowFeature = new IceAndSnowFeature(NoFeatureConfig.CODEC); - snowFeature.place(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition(), null); - - - LodChunk lod = lodChunkBuilder.generateLodFromChunk(chunk, new LodBuilderConfig(false, true, true)); - lodDim.addLod(lod); - } - - - /** - * takes about 15 - 20 ms - * - * Causes concurrentModification Exceptions, - * which could cause instability or world generation bugs - */ - private void generateUsingFeatures() - { - List chunkList = new LinkedList<>(); - ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY); - chunkList.add(chunk); - LodServerWorld lodServerWorld = new LodServerWorld(serverWorld, chunk); - - ServerChunkProvider chunkSource = serverWorld.getChunkSource(); - ChunkGenerator chunkGen = chunkSource.generator; - - - // generate the terrain (this is thread safe) - ChunkStatus.EMPTY.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - // override the chunk status so we can run the next generator stage - chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); - ChunkStatus.BIOMES.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - ChunkStatus.NOISE.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - ChunkStatus.SURFACE.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - - - // get all the biomes in the chunk - HashSet biomes = new HashSet<>(); - for (int x = 0; x < LodChunk.WIDTH; x++) - { - for (int z = 0; z < LodChunk.WIDTH; z++) - { - Biome biome = chunk.getBiomes().getNoiseBiome(x, serverWorld.getSeaLevel(), z); - - // Issue #35 - // For some reason Jungle biomes cause incredible lag - // the features here must be interacting with each other - // in unpredictable ways (specifically tree feature generation). - // When generating Features my CPU usage generally hovers around 30 - 40% - // when generating Jungles it spikes to 100%. - if (biome.getBiomeCategory() != Biome.Category.JUNGLE) - { - // should probably use the heightmap here instead of seaLevel, - // but this seems to get the job done well enough - biomes.add(biome); - } - } - } - - - // generate all the features related to this chunk. - // this may or may not be thread safe - for (Biome biome : biomes) - { - List>>> featuresForState = biome.generationSettings.features(); - - for(int featureStateToGenerate = 0; featureStateToGenerate < featuresForState.size(); featureStateToGenerate++) - { - for(Supplier> featureSupplier : featuresForState.get(featureStateToGenerate)) - { - ConfiguredFeature configuredFeature = featureSupplier.get(); - - if (configuredFeaturesToAvoid.containsKey(configuredFeature.hashCode())) - continue; - - - try - { - configuredFeature.place(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition()); - } - catch(ConcurrentModificationException e) - { - // This will happen. I'm not sure what to do about it - // except pray that it doesn't effect the normal world generation - // in any harmful way - - // Issue #35 - // I tried cloning the config for each feature, but that - // path was blocked since I can't clone lambda methods. - // I tried using a deep cloning library and discovered - // the problem there. - // ( https://github.com/kostaskougios/cloning ) - - configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); -// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); - } - catch(UnsupportedOperationException e) - { - // This will happen when the LodServerWorld - // isn't able to return something that a feature - // generator needs - - configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); -// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); - } - catch(Exception e) - { - // I'm not sure what happened, print to the log - - System.out.println(); - System.out.println(); - e.printStackTrace(); - System.out.println(); - //ClientProxy.LOGGER.error("error class: \"" + configuredfeature.config.getClass() + "\""); - System.out.println(); - - configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); -// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); - } - } - } - } - - // generate a Lod like normal - LodChunk lod = lodChunkBuilder.generateLodFromChunk(chunk); - lodDim.addLod(lod); - } - - - /** - * on pre generated chunks 0 - 1 ms - * on un generated chunks 0 - 50 ms - * with the median seeming to hover around 15 - 30 ms - * and outliers in the 100 - 200 ms range - * - * Note this should not be multithreaded and does cause server/simulation lag - * (Higher lag for generating than loading) - */ - private void generateWithServer() - { - lodChunkBuilder.generateLodChunkAsync(serverWorld.getChunk(pos.x, pos.z, ChunkStatus.FEATURES), ClientProxy.getLodWorld(), serverWorld); - } - - - - - - - //================// - // Unused methods // - //================// - - // Sadly I wasn't able to get these to work, - // they are here for documentation purposes - - @SuppressWarnings({ "rawtypes", "unchecked", "unused" }) - private DecoratedFeatureConfig cloneDecoratedFeatureConfig(DecoratedFeatureConfig config) - { - IPlacementConfig placementConfig = null; - - Class oldConfigClass = config.decorator.config().getClass(); - - if (oldConfigClass == FeatureSpreadConfig.class) - { - FeatureSpreadConfig oldPlacementConfig = (FeatureSpreadConfig) config.decorator.config(); - FeatureSpread oldSpread = oldPlacementConfig.count(); - - placementConfig = new FeatureSpreadConfig(oldSpread); - } - else if(oldConfigClass == DecoratedPlacementConfig.class) - { - DecoratedPlacementConfig oldPlacementConfig = (DecoratedPlacementConfig) config.decorator.config(); - placementConfig = new DecoratedPlacementConfig(oldPlacementConfig.inner(), oldPlacementConfig.outer()); - } - else if(oldConfigClass == NoiseDependant.class) - { - NoiseDependant oldPlacementConfig = (NoiseDependant) config.decorator.config(); - placementConfig = new NoiseDependant(oldPlacementConfig.noiseLevel, oldPlacementConfig.belowNoise, oldPlacementConfig.aboveNoise); - } - else - { -// ClientProxy.LOGGER.debug("unkown decorated placement config: \"" + config.decorator.config().getClass() + "\""); - return config; - } - - - ConfiguredPlacement newPlacement = new ConfiguredPlacement(config.decorator.decorator, placementConfig); - return new DecoratedFeatureConfig(config.feature, newPlacement); - } - - - @SuppressWarnings("unused") - private BlockClusterFeatureConfig cloneBlockClusterFeatureConfig(BlockClusterFeatureConfig config) - { - WeightedBlockStateProvider provider = new WeightedBlockStateProvider(); - for(Entry state : ((WeightedBlockStateProvider) config.stateProvider).weightedList.entries) - provider.weightedList.entries.add(state); - - HashSet whitelist = new HashSet<>(); - for(Block block : config.whitelist) - whitelist.add(block); - - HashSet blacklist = new HashSet<>(); - for(BlockState state : config.blacklist) - blacklist.add(state); - - - BlockClusterFeatureConfig.Builder builder = new BlockClusterFeatureConfig.Builder(provider, config.blockPlacer); - builder.whitelist(whitelist); - builder.blacklist(blacklist); - builder.xspread(config.xspread); - builder.yspread(config.yspread); - builder.zspread(config.zspread); - if(config.canReplace) { builder.canReplace(); } - if(config.needWater) { builder.needWater(); } - if(config.project) { builder.noProjection(); } - builder.tries(config.tries); - - - return builder.build(); - } - - } - - - /* - * performance/generation tests related to - * serverWorld.getChunk(x, z, ChunkStatus. *** ) - - true/false is whether they generated blocks or not - the time is how long it took to generate - - ChunkStatus.EMPTY 0 - 1 ms false (empty, what did you expect? :P) - ChunkStatus.STRUCTURE_REFERENCES 1 - 2 ms false (no height, only generates some chunks) - ChunkStatus.BIOMES 1 - 10 ms false (no height) - ChunkStatus.NOISE 4 - 15 ms true (all blocks are stone) - ChunkStatus.LIQUID_CARVERS 6 - 12 ms true (no snow/trees, just grass) - ChunkStatus.SURFACE 5 - 15 ms true (no snow/trees, just grass) - ChunkStatus.CARVERS 5 - 30 ms true (no snow/trees, just grass) - ChunkStatus.FEATURES 7 - 25 ms true - ChunkStatus.HEIGHTMAPS 20 - 40 ms true - ChunkStatus.LIGHT 20 - 40 ms true - ChunkStatus.FULL 30 - 50 ms true - ChunkStatus.SPAWN 50 - 80 ms true - - - At this point I would suggest using FEATURES, as it generates snow and trees - (and any other object that is needed to make biomes distinct) - - Otherwise if snow/trees aren't necessary SURFACE is the next fastest (although not by much) - */ -} diff --git a/src/main/java/com/seibel/lod/objects/HOWTOUSE.txt b/src/main/java/com/seibel/lod/objects/HOWTOUSE.txt new file mode 100644 index 000000000..c9051e34d --- /dev/null +++ b/src/main/java/com/seibel/lod/objects/HOWTOUSE.txt @@ -0,0 +1,29 @@ +This are the file that you should use + +DistanceGenerationMode (added NONE) +LodQuadTreeDimensionFileHandler +LodDataPoint (added hash and equal function) +LodQuadTreeNode +LodQuadTree +LodQuadTreeDimension +LodQuadTreeWorld (this is identical to LodWorld but uses LodQuadTreeDimension) + +HOW IT WORK +I've tried to make this classes as similar at yours. This way you could even do the same stuff that you are doing now +like using all the Lod with the same quality. LodDetail is not used anywhere and is replaced by a level value in +LodQuadTreeNode. + +A LodQuadTree has a quad tree structure. So it has 4 children of the same type and a LodQuadTreeNode that contain all +the information of the node such as position, level (the level is the depth of the quad tree) and the LodDataPoint. +If in the future you want to add multiple LodDataPoint per position (maybe you want to show floating island) you could still +do it by transforming the lodDataPoint variable in a LodDataPoint array. + +The two most important factor of a Node is the level and the level position. At level 9 you find the region (of width 2^9=512) +at level 4 you find the chunk (of width 2^4=16) and at level 0 you find the blocks (of width 2^0=1). The pos is like the +region pos and the chunk pos but for every level. +The complexity of a node indicate how the node was built, so i've used the DistanceGenerationMode enum. The complexity is +ordered by the order in the enum (NONE -> BIOME_ONLY -> BIOME_ONLY_SIMULATE_HEIGHT -> SURFACE -> FEATURES -> SERVER). The idea +is that you cannot override a node with a node that is less complex. This way you could use different type of generation based +on the distance. + +HOW TO USE diff --git a/src/main/java/com/seibel/lod/proxy/ClientProxy.java b/src/main/java/com/seibel/lod/proxy/ClientProxy.java index 02a450897..1f6f2aaf5 100644 --- a/src/main/java/com/seibel/lod/proxy/ClientProxy.java +++ b/src/main/java/com/seibel/lod/proxy/ClientProxy.java @@ -1,16 +1,13 @@ package com.seibel.lod.proxy; +import com.seibel.lod.builders.LodNodeBufferBuilder; +import com.seibel.lod.builders.LodNodeBuilder; +import com.seibel.lod.objects.*; +import com.seibel.lod.render.LodNodeRenderer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import com.seibel.lod.builders.LodBufferBuilder; -import com.seibel.lod.builders.LodChunkBuilder; import com.seibel.lod.handlers.LodConfig; -import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDimension; -import com.seibel.lod.objects.LodRegion; -import com.seibel.lod.objects.LodWorld; -import com.seibel.lod.render.LodRenderer; import com.seibel.lod.util.LodUtil; import net.minecraft.client.Minecraft; @@ -31,10 +28,10 @@ public class ClientProxy { public static final Logger LOGGER = LogManager.getLogger("LOD"); - private static LodWorld lodWorld = new LodWorld(); - private static LodChunkBuilder lodChunkBuilder = new LodChunkBuilder(); - private static LodBufferBuilder lodBufferBuilder = new LodBufferBuilder(lodChunkBuilder); - private static LodRenderer renderer = new LodRenderer(lodBufferBuilder); + private static LodQuadTreeWorld lodWorld = new LodQuadTreeWorld(); + private static LodNodeBuilder lodChunkBuilder = new LodNodeBuilder(); + private static LodNodeBufferBuilder lodBufferBuilder = new LodNodeBufferBuilder(lodChunkBuilder); + private static LodNodeRenderer renderer = new LodNodeRenderer(lodBufferBuilder); Minecraft mc = Minecraft.getInstance(); @@ -59,41 +56,39 @@ public class ClientProxy { if (mc == null || mc.player == null || !lodWorld.getIsWorldLoaded()) return; - - // update each regions' width to match the new render distance - int newWidth = Math.max(4, - // TODO is this logic good? - (mc.options.renderDistance * LodChunk.WIDTH * 2 * LodConfig.CLIENT.lodChunkRadiusMultiplier.get()) / LodRegion.SIZE - ); - if (lodChunkBuilder.regionWidth != newWidth) - { - lodWorld.resizeDimensionRegionWidth(newWidth); - lodChunkBuilder.regionWidth = newWidth; - - // skip this frame, hopefully the lodWorld - // should have everything set up by then - return; - } - - LodDimension lodDim = lodWorld.getLodDimension(mc.player.level.dimensionType()); - if (lodDim == null) - return; - - - // offset the regions - double playerX = mc.player.getX(); - double playerZ = mc.player.getZ(); - - int xOffset = ((int)playerX / (LodChunk.WIDTH * LodRegion.SIZE)) - lodDim.getCenterX(); - int zOffset = ((int)playerZ / (LodChunk.WIDTH * LodRegion.SIZE)) - lodDim.getCenterZ(); - - if (xOffset != 0 || zOffset != 0) - { - lodDim.move(xOffset, zOffset); - } - - - // TODO for testing + try { + // update each regions' width to match the new render distance + int newWidth = Math.max(4, + // TODO is this logic good? + (mc.options.renderDistance * LodChunk.WIDTH * 2 * LodConfig.CLIENT.lodChunkRadiusMultiplier.get()) / LodRegion.SIZE + ); + if (lodChunkBuilder.regionWidth != newWidth) { + lodWorld.resizeDimensionRegionWidth(newWidth); + lodChunkBuilder.regionWidth = newWidth; + + // skip this frame, hopefully the lodWorld + // should have everything set up by then + return; + } + + LodQuadTreeDimension lodDim = lodWorld.getLodDimension(mc.player.level.dimensionType()); + if (lodDim == null) + return; + + + // offset the regions + double playerX = mc.player.getX(); + double playerZ = mc.player.getZ(); + + int xOffset = ((int) playerX / (LodChunk.WIDTH * LodRegion.SIZE)) - lodDim.getCenterX(); + int zOffset = ((int) playerZ / (LodChunk.WIDTH * LodRegion.SIZE)) - lodDim.getCenterZ(); + + if (xOffset != 0 || zOffset != 0) { + lodDim.move(xOffset, zOffset); + } + + + // TODO for testing // LodConfig.CLIENT.debugMode.set(false); // LodConfig.CLIENT.lodDetail.set(LodDetail.DOUBLE); // LodConfig.CLIENT.lodColorStyle.set(LodColorStyle.INDIVIDUAL_SIDES); @@ -101,19 +96,22 @@ public class ClientProxy // LodConfig.CLIENT.distanceGenerationMode.set(DistanceGenerationMode.FEATURES); // LodConfig.CLIENT.fogDistance.set(FogDistance.FAR); // LodConfig.CLIENT.fogDrawOverride.set(FogDrawOverride.ALWAYS_DRAW_FOG_FANCY); - - // Note to self: - // if "unspecified" shows up in the pie chart, it is - // possibly because the amount of time between sections - // is too small for the profile to measure - IProfiler profiler = mc.getProfiler(); - profiler.pop(); // get out of "terrain" - profiler.push("LOD"); - - renderer.drawLODs(lodDim, partialTicks, mc.getProfiler()); - - profiler.pop(); // end LOD - profiler.push("terrain"); // restart terrain + + // Note to self: + // if "unspecified" shows up in the pie chart, it is + // possibly because the amount of time between sections + // is too small for the profile to measure + IProfiler profiler = mc.getProfiler(); + profiler.pop(); // get out of "terrain" + profiler.push("LOD"); + + renderer.drawLODs(lodDim, partialTicks, mc.getProfiler()); + + profiler.pop(); // end LOD + profiler.push("terrain"); // restart terrain + }catch (Exception e){ + return; + } } @@ -126,13 +124,15 @@ public class ClientProxy @SubscribeEvent public void chunkLoadEvent(ChunkEvent.Load event) { - lodChunkBuilder.generateLodChunkAsync(event.getChunk(), lodWorld, event.getWorld()); + lodChunkBuilder.generateLodNodeAsync(event.getChunk(), lodWorld, event.getWorld()); } @SubscribeEvent public void worldLoadEvent(WorldEvent.Load event) { + + System.out.println("Loading world"); // the player just loaded a new world/dimension lodWorld.selectWorld(LodUtil.getWorldID(event.getWorld())); // make sure the correct LODs are being rendered @@ -164,7 +164,7 @@ public class ClientProxy event.getClass() == BlockEvent.PortalSpawnEvent.class) { // recreate the LOD where the blocks were changed - lodChunkBuilder.generateLodChunkAsync(event.getWorld().getChunk(event.getPos()), lodWorld, event.getWorld()); + lodChunkBuilder.generateLodNodeAsync(event.getWorld().getChunk(event.getPos()), lodWorld, event.getWorld()); } } @@ -175,17 +175,17 @@ public class ClientProxy // public getters // //================// - public static LodWorld getLodWorld() + public static LodQuadTreeWorld getLodWorld() { return lodWorld; } - public static LodChunkBuilder getLodBuilder() + public static LodNodeBuilder getLodBuilder() { return lodChunkBuilder; } - public static LodRenderer getRenderer() + public static LodNodeRenderer getRenderer() { return renderer; } diff --git a/src/main/java/com/seibel/lod/render/LodRenderer.java b/src/main/java/com/seibel/lod/render/LodRenderer similarity index 100% rename from src/main/java/com/seibel/lod/render/LodRenderer.java rename to src/main/java/com/seibel/lod/render/LodRenderer diff --git a/src/main/java/com/seibel/lod/render/RenderUtil.java b/src/main/java/com/seibel/lod/render/RenderUtil.java index d575d7eda..03210c5db 100644 --- a/src/main/java/com/seibel/lod/render/RenderUtil.java +++ b/src/main/java/com/seibel/lod/render/RenderUtil.java @@ -86,7 +86,7 @@ public class RenderUtil */ public static int getMaxRadiusMultiplierWithAvaliableMemory(LodTemplate lodTemplate, LodDetail lodDetail) { - int maxNumberOfLods = LodRenderer.MAX_ALOCATEABLE_DIRECT_MEMORY / lodTemplate.getBufferMemoryForSingleLod(lodDetail); + int maxNumberOfLods = LodNodeRenderer.MAX_ALOCATEABLE_DIRECT_MEMORY / lodTemplate.getBufferMemoryForSingleLod(lodDetail); int numbLodsWide = (int) Math.sqrt(maxNumberOfLods); return numbLodsWide / (2 * mc.options.renderDistance);