Close #32 (make distance generation independent of the buffer builder)
This commit is contained in:
@@ -18,21 +18,15 @@
|
||||
package com.seibel.lod.builders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import com.seibel.lod.builders.worldGeneration.LodNodeGenWorker;
|
||||
import com.seibel.lod.enums.DistanceGenerationMode;
|
||||
import com.seibel.lod.handlers.LodConfig;
|
||||
import com.seibel.lod.objects.LevelPos;
|
||||
import com.seibel.lod.objects.LodDataPoint;
|
||||
@@ -44,32 +38,25 @@ import com.seibel.lod.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.util.LodThreadFactory;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.vertex.VertexBuffer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.common.WorldWorkerManager;
|
||||
|
||||
/**
|
||||
* This object is used to create NearFarBuffer objects.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 8-22-2021
|
||||
* @version 8-24-2021
|
||||
*/
|
||||
public class LodBufferBuilder
|
||||
{
|
||||
private Minecraft mc;
|
||||
|
||||
/** This holds the thread used to generate new LODs off the main thread. */
|
||||
private ExecutorService mainGenThread = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName() + " - main"));
|
||||
/** This holds the threads used to generate buffers. */
|
||||
private ExecutorService bufferBuilderThreads = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new LodThreadFactory(this.getClass().getSimpleName() + " - builder"));
|
||||
//private ExecutorService bufferBuilderThreads = Executors.newFixedThreadPool(2, new LodThreadFactory(this.getClass().getSimpleName() + " - builder"));
|
||||
|
||||
private LodBuilder LodQuadTreeNodeBuilder;
|
||||
|
||||
/** The buffers that are used to create LODs using far fog */
|
||||
public volatile BufferBuilder[][] buildableBuffers;
|
||||
|
||||
@@ -85,35 +72,12 @@ public class LodBufferBuilder
|
||||
*/
|
||||
public boolean generatingBuffers = false;
|
||||
|
||||
/**
|
||||
* if this is true the LOD buffers are currently being
|
||||
* regenerated.
|
||||
*/
|
||||
public Set<ChunkPos> positionWaitingToBeGenerated = new HashSet<>();
|
||||
|
||||
/**
|
||||
* if this is true new LOD buffers have been generated
|
||||
* and are waiting to be swapped with the drawable buffers
|
||||
*/
|
||||
private boolean switchVbos = false;
|
||||
|
||||
/**
|
||||
* This keeps track of how many chunk generation requests are on going.
|
||||
* This is to prevent chunks from being generated for a long time in an area
|
||||
* the player is no longer in.
|
||||
*/
|
||||
public AtomicInteger numberOfChunksWaitingToGenerate = new AtomicInteger(0);
|
||||
|
||||
|
||||
/**
|
||||
* how many chunks to generate outside of the player's
|
||||
* view distance at one time. (or more specifically how
|
||||
* many requests to make at one time).
|
||||
* I multiply by 8 to make sure there is always a buffer of chunk requests,
|
||||
* to make sure the CPU is always busy and we can generate LODs as quickly as
|
||||
* possible.
|
||||
*/
|
||||
public int maxChunkGenRequests = LodConfig.CLIENT.numberOfWorldGenerationThreads.get() * 8;
|
||||
|
||||
/** Size of the buffer builders in bytes last time we created them */
|
||||
public int previousBufferSize = 0;
|
||||
@@ -127,14 +91,12 @@ public class LodBufferBuilder
|
||||
|
||||
|
||||
|
||||
public LodBufferBuilder(LodBuilder newLodBuilder)
|
||||
public LodBufferBuilder()
|
||||
{
|
||||
mc = Minecraft.getInstance();
|
||||
LodQuadTreeNodeBuilder = newLodBuilder;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private LodDimension previousDimension = null;
|
||||
|
||||
|
||||
/**
|
||||
@@ -156,11 +118,6 @@ public class LodBufferBuilder
|
||||
if (buildableBuffers == null)
|
||||
throw new IllegalStateException("\"generateLodBuffersAsync\" was called before the \"setupBuffers\" method was called.");
|
||||
|
||||
if (previousDimension != lodDim)
|
||||
{
|
||||
previousDimension = lodDim;
|
||||
}
|
||||
|
||||
|
||||
generatingBuffers = true;
|
||||
|
||||
@@ -181,19 +138,12 @@ public class LodBufferBuilder
|
||||
long treeEnd = System.currentTimeMillis();
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
ArrayList<GenerationRequest> chunksToGen = new ArrayList<>(maxChunkGenRequests);
|
||||
// if we don't have a full number of chunks to generate in chunksToGen
|
||||
// we can top it off from the reserve
|
||||
ArrayList<GenerationRequest> chunksToGenReserve = new ArrayList<>(maxChunkGenRequests);
|
||||
|
||||
|
||||
ArrayList<Callable<Boolean>> builderThreads = new ArrayList<>(lodDim.regions.length * lodDim.regions.length);
|
||||
|
||||
|
||||
startBuffers();
|
||||
|
||||
// used when determining which chunks are closer when queuing distance
|
||||
// generation
|
||||
int minChunkDist = Integer.MAX_VALUE;
|
||||
|
||||
// =====================//
|
||||
// RENDERING PART //
|
||||
// =====================//
|
||||
@@ -286,182 +236,6 @@ public class LodBufferBuilder
|
||||
}
|
||||
}
|
||||
long renderEnd = System.currentTimeMillis();
|
||||
|
||||
|
||||
// =====================//
|
||||
// GENERATION PART //
|
||||
// =====================//
|
||||
|
||||
|
||||
List<LevelPos> posListToGenerate;
|
||||
List<GenerationRequest> generationRequestList = new ArrayList<>();
|
||||
|
||||
/**TODO can give a totally different generation*/
|
||||
/*
|
||||
for (byte detail = LodUtil.BLOCK_DETAIL_LEVEL; detail <= LodUtil.REGION_DETAIL_LEVEL; detail++)
|
||||
{
|
||||
if (!posListToGenerate.isEmpty()) break;
|
||||
for (byte detailGen = LodUtil.BLOCK_DETAIL_LEVEL; detailGen <= LodUtil.REGION_DETAIL_LEVEL; detailGen++)
|
||||
{
|
||||
if (!posListToGenerate.isEmpty()) break;
|
||||
posListToGenerate.addAll(lodDim.getDataToGenerate(
|
||||
playerBlockPosRounded.getX(),
|
||||
playerBlockPosRounded.getZ(),
|
||||
(int) (distancesLinear[detailGen]*1.5),
|
||||
(int) (distancesLinear[detailGen+1]*1.5),
|
||||
(byte) distancesGenerators[detailGen].complexity,
|
||||
detail,
|
||||
16));
|
||||
System.out.println("HERE");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
long genReqStart = 0;
|
||||
long genReqEnd = 0;
|
||||
long genStart = 0;
|
||||
long genEnd = 0;
|
||||
|
||||
if (LodConfig.CLIENT.distanceGenerationMode.get() != DistanceGenerationMode.NONE)
|
||||
{
|
||||
int requesting = maxChunkGenRequests;
|
||||
|
||||
genReqStart = System.currentTimeMillis();
|
||||
//we firstly make sure that the world is filled with half region wide block
|
||||
for (byte detailGen = LodConfig.CLIENT.maxGenerationDetail.get().detailLevel; detailGen <= LodUtil.REGION_DETAIL_LEVEL; detailGen++)
|
||||
{
|
||||
if (requesting == 0) break;
|
||||
posListToGenerate = lodDim.getDataToGenerate(
|
||||
playerBlockPosRounded.getX(),
|
||||
playerBlockPosRounded.getZ(),
|
||||
DetailDistanceUtil.getDistanceGeneration(detailGen),
|
||||
DetailDistanceUtil.getDistanceGeneration(detailGen + 1),
|
||||
LodConfig.CLIENT.distanceGenerationMode.get().complexity,
|
||||
(byte) 9,
|
||||
requesting/2);
|
||||
for(LevelPos levelPos : posListToGenerate){
|
||||
generationRequestList.add(new GenerationRequest(levelPos,LodConfig.CLIENT.distanceGenerationMode.get(), DetailDistanceUtil.getLodDetail(detailGen)));
|
||||
}
|
||||
requesting = maxChunkGenRequests - generationRequestList.size();
|
||||
|
||||
}
|
||||
|
||||
//we then fill the world with the rest of the block
|
||||
for (byte detailGen = LodConfig.CLIENT.maxGenerationDetail.get().detailLevel; detailGen <= LodUtil.REGION_DETAIL_LEVEL; detailGen++)
|
||||
{
|
||||
if (requesting == 0) break;
|
||||
posListToGenerate = lodDim.getDataToGenerate(
|
||||
playerBlockPosRounded.getX(),
|
||||
playerBlockPosRounded.getZ(),
|
||||
DetailDistanceUtil.getDistanceGeneration(detailGen),
|
||||
DetailDistanceUtil.getDistanceGeneration(detailGen + 1),
|
||||
LodConfig.CLIENT.distanceGenerationMode.get().complexity,
|
||||
DetailDistanceUtil.getLodDetail(detailGen).detailLevel,
|
||||
maxChunkGenRequests);
|
||||
for(LevelPos levelPos : posListToGenerate){
|
||||
generationRequestList.add(new GenerationRequest(levelPos,LodConfig.CLIENT.distanceGenerationMode.get(), DetailDistanceUtil.getLodDetail(detailGen)));
|
||||
}
|
||||
requesting = maxChunkGenRequests - generationRequestList.size();
|
||||
}
|
||||
|
||||
// determine which points in the posListToGenerate
|
||||
// should actually be queued up
|
||||
for (GenerationRequest generationRequest : generationRequestList)
|
||||
{
|
||||
ChunkPos chunkPos = generationRequest.getChunkPos();
|
||||
|
||||
if (numberOfChunksWaitingToGenerate.get() < maxChunkGenRequests)
|
||||
{
|
||||
|
||||
if (positionWaitingToBeGenerated.contains(chunkPos))
|
||||
{
|
||||
//ClientProxy.LOGGER.debug(pos + " asked to be generated again.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// determine if this position is closer to the player
|
||||
// than the previous
|
||||
int newDistance = playerChunkPos.getChessboardDistance(chunkPos);
|
||||
|
||||
if (newDistance < minChunkDist)
|
||||
{
|
||||
// this chunk is closer, clear any previous
|
||||
// positions and update the new minimum distance
|
||||
minChunkDist = newDistance;
|
||||
|
||||
// move all the old chunks into the reserve
|
||||
ArrayList<GenerationRequest> oldReserve = new ArrayList<>(chunksToGenReserve);
|
||||
chunksToGenReserve.clear();
|
||||
chunksToGenReserve.addAll(chunksToGen);
|
||||
// top off reserve with whatever was in oldReerve
|
||||
for (int i = 0; i < oldReserve.size(); i++)
|
||||
{
|
||||
if (chunksToGenReserve.size() < maxChunkGenRequests)
|
||||
chunksToGenReserve.add(oldReserve.get(i));
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
chunksToGen.clear();
|
||||
chunksToGen.add(generationRequest);
|
||||
}
|
||||
else if (newDistance == minChunkDist)
|
||||
{
|
||||
// this chunk position as close as the minimum distance
|
||||
if (chunksToGen.size() < maxChunkGenRequests)
|
||||
{
|
||||
// we are still under the number of chunks to generate
|
||||
// add this position to the list
|
||||
chunksToGen.add(generationRequest);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this chunk is farther away than the minimum distance,
|
||||
// add it to the reserve to make sure we always have a full reserve
|
||||
chunksToGenReserve.add(generationRequest);
|
||||
}
|
||||
|
||||
} // lod null and can generate more chunks
|
||||
} // positions to generate
|
||||
|
||||
genReqEnd = System.currentTimeMillis();
|
||||
|
||||
genStart = System.currentTimeMillis();
|
||||
// queue up chunks to be generated
|
||||
if (mc.hasSingleplayerServer())
|
||||
{
|
||||
// issue #19
|
||||
// TODO add a way for a server side mod to generate chunks requested here
|
||||
ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension);
|
||||
|
||||
// make sure we have as many chunks to generate as we are allowed
|
||||
if (chunksToGen.size() < maxChunkGenRequests)
|
||||
{
|
||||
Iterator<GenerationRequest> reserveIterator = chunksToGenReserve.iterator();
|
||||
while (chunksToGen.size() < maxChunkGenRequests && reserveIterator.hasNext())
|
||||
{
|
||||
chunksToGen.add(reserveIterator.next());
|
||||
}
|
||||
}
|
||||
|
||||
// start chunk generation
|
||||
for (GenerationRequest generationRequest : generationRequestList)
|
||||
{
|
||||
// don't add null chunkPos (which shouldn't happen anyway)
|
||||
// or add more to the generation queue
|
||||
ChunkPos chunkPos = generationRequest.getChunkPos();
|
||||
if (chunkPos == null || numberOfChunksWaitingToGenerate.get() >= maxChunkGenRequests)
|
||||
continue;
|
||||
|
||||
positionWaitingToBeGenerated.add(chunkPos);
|
||||
numberOfChunksWaitingToGenerate.addAndGet(1);
|
||||
LodNodeGenWorker genWorker = new LodNodeGenWorker(chunkPos,generationRequest.generationMode, generationRequest.detail, renderer, LodQuadTreeNodeBuilder, this, lodDim, serverWorld);
|
||||
WorldWorkerManager.addWorker(genWorker);
|
||||
}
|
||||
}
|
||||
genEnd = System.currentTimeMillis();
|
||||
} // if distanceGenerationMode != DistanceGenerationMode.NONE
|
||||
|
||||
|
||||
// finish the buffer building
|
||||
@@ -476,18 +250,11 @@ public class LodBufferBuilder
|
||||
|
||||
long treeTime = treeEnd - treeStart;
|
||||
|
||||
|
||||
long renderingTime = renderEnd - renderStart;
|
||||
|
||||
long genReqTime = genReqEnd - genReqStart;
|
||||
|
||||
long genTime = genEnd - genStart;
|
||||
|
||||
ClientProxy.LOGGER.info("Buffer Build time: " + buildTime + " ms" + '\n' +
|
||||
"Tree cutting time: " + treeTime + " ms" + '\n' +
|
||||
"Rendering time: " + renderingTime + " ms" + '\n' +
|
||||
"Generation request time: " + genReqTime + " ms" + '\n' +
|
||||
"Generation time: " + genTime + " ms");
|
||||
"Rendering time: " + renderingTime + " ms");
|
||||
|
||||
// mark that the buildable buffers as ready to swap
|
||||
switchVbos = true;
|
||||
|
||||
Reference in New Issue
Block a user