Close #32 (make distance generation independent of the buffer builder)

This commit is contained in:
James Seibel
2021-08-24 21:47:51 -05:00
parent a0dcde48ae
commit a464176a25
4 changed files with 332 additions and 257 deletions
@@ -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;
@@ -26,7 +26,6 @@ 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.LodBuilder;
import com.seibel.lod.builders.LodBuilderConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
@@ -71,7 +70,7 @@ import net.minecraftforge.common.WorldWorkerManager.IWorker;
* This is used to generate a LodChunk at a given ChunkPos.
*
* @author James Seibel
* @version 8-21-2021
* @version 8-24-2021
*/
public class LodNodeGenWorker implements IWorker
{
@@ -88,7 +87,7 @@ public class LodNodeGenWorker implements IWorker
public LodNodeGenWorker(ChunkPos newPos, DistanceGenerationMode newGenerationMode, LodDetail newDetaillevel, LodRenderer newLodRenderer,
LodBuilder newLodBuilder, LodBufferBuilder newLodBufferBuilder,
LodBuilder newLodBuilder,
LodDimension newLodDimension, ServerWorld newServerWorld)
{
// just a few sanity checks
@@ -101,9 +100,6 @@ public class LodNodeGenWorker implements IWorker
if (newLodBuilder == null)
throw new IllegalArgumentException("LodChunkGenThread requires a non-null LodChunkBuilder");
if (newLodBufferBuilder == null)
throw new IllegalArgumentException("LodChunkGenThread requires a non-null LodBufferBuilder");
if (newLodDimension == null)
throw new IllegalArgumentException("LodChunkGenThread requires a non-null LodDimension");
@@ -113,7 +109,7 @@ public class LodNodeGenWorker implements IWorker
thread = new LodChunkGenThread(newPos, newGenerationMode, newDetaillevel, newLodRenderer,
newLodBuilder, newLodBufferBuilder,
newLodBuilder,
newLodDimension, newServerWorld);
}
@@ -165,12 +161,11 @@ public class LodNodeGenWorker implements IWorker
public final LodDetail detailLevel;
public final LodBuilder lodBuilder;
public final LodRenderer lodRenderer;
private LodBufferBuilder lodBufferBuilder;
private ChunkPos pos;
public LodChunkGenThread(ChunkPos newPos, DistanceGenerationMode newGenerationMode, LodDetail newDetailLevel, LodRenderer newLodRenderer,
LodBuilder newLodBuilder, LodBufferBuilder newLodBufferBuilder,
LodBuilder newLodBuilder,
LodDimension newLodDimension, ServerWorld newServerWorld)
{
pos = newPos;
@@ -178,7 +173,6 @@ public class LodNodeGenWorker implements IWorker
detailLevel = newDetailLevel;
lodRenderer = newLodRenderer;
lodBuilder = newLodBuilder;
lodBufferBuilder = newLodBufferBuilder;
lodDim = newLodDimension;
serverWorld = newServerWorld;
}
@@ -247,10 +241,10 @@ public class LodNodeGenWorker implements IWorker
finally
{
// decrement how many threads are running
thread.lodBufferBuilder.numberOfChunksWaitingToGenerate.addAndGet(-1);
LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.addAndGet(-1);
// this position is no longer being generated
lodBufferBuilder.positionWaitingToBeGenerated.remove(pos);
LodWorldGenerator.INSTANCE.positionWaitingToBeGenerated.remove(pos);
}
}// run
@@ -0,0 +1,298 @@
package com.seibel.lod.builders.worldGeneration;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import com.seibel.lod.builders.GenerationRequest;
import com.seibel.lod.builders.LodBuilder;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.handlers.LodConfig;
import com.seibel.lod.objects.LevelPos;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.render.LodRenderer;
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.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.WorldWorkerManager;
/**
* A singleton that handles all long distance LOD world generation.
*
* @author James Seibel
* @version 8-24-2021
*/
public class LodWorldGenerator
{
public Minecraft mc = Minecraft.getInstance();
/** This holds the thread used to generate new LODs off the main thread. */
private ExecutorService mainGenThread = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName() + " world generator"));
/** we only want to queue up one generator thread at a time */
private boolean generatorThreadRunning = false;
/**
* 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;
/**
* This keeps track of how many chunk generation requests are on going. This is
* to limit how many chunks are queued at once. 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);
public Set<ChunkPos> positionWaitingToBeGenerated = new HashSet<>();
/** Singleton copy of this object */
public static final LodWorldGenerator INSTANCE = new LodWorldGenerator();
private LodWorldGenerator()
{
}
/**
* Queues up LodNodeGenWorkers for the given lodDimension.
*
* @param renderer needed so the LodNodeGenWorkers can flag that the
* buffers need to be rebuilt.
*/
public void queueGenerationRequests(LodDimension lodDim, LodRenderer renderer, LodBuilder lodBuilder)
{
if (LodConfig.CLIENT.distanceGenerationMode.get() != DistanceGenerationMode.NONE
&& !generatorThreadRunning
&& mc.hasSingleplayerServer())
{
// the thread is now running, don't queue up another thread
generatorThreadRunning = true;
// just in case the config is changed
maxChunkGenRequests = LodConfig.CLIENT.numberOfWorldGenerationThreads.get() * 16;
Thread generatorThread = new Thread(() ->
{
try
{
// round the player's block position down to the nearest chunk BlockPos
ChunkPos playerChunkPos = new ChunkPos(mc.player.blockPosition());
BlockPos playerBlockPosRounded = playerChunkPos.getWorldPosition();
// used when determining which chunks are closer when queuing distance
// generation
int minChunkDist = Integer.MAX_VALUE;
List<LevelPos> levelPosListToGen;
List<GenerationRequest> generationRequestList = new ArrayList<>();
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 this reserve
ArrayList<GenerationRequest> chunksToGenReserve = new ArrayList<>(maxChunkGenRequests);
// how many level positions to
int requesting = maxChunkGenRequests;
/** 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"); } }
*/
//=======================================//
// create the generation Request objects //
//=======================================//
// start by generating half-region sized blocks...
for (byte detailGen = LodConfig.CLIENT.maxGenerationDetail.get().detailLevel; detailGen <= LodUtil.REGION_DETAIL_LEVEL; detailGen++)
{
if (requesting == 0)
break;
levelPosListToGen = 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 : levelPosListToGen)
{
generationRequestList.add(new GenerationRequest(levelPos, LodConfig.CLIENT.distanceGenerationMode.get(), DetailDistanceUtil.getLodDetail(detailGen)));
}
requesting = maxChunkGenRequests - generationRequestList.size();
}
// ...then once the world is filled with half-region sized blocks
// fill in the rest
for (byte detailGen = LodConfig.CLIENT.maxGenerationDetail.get().detailLevel; detailGen <= LodUtil.REGION_DETAIL_LEVEL; detailGen++)
{
if (requesting == 0)
break;
levelPosListToGen = 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 : levelPosListToGen)
{
generationRequestList.add(new GenerationRequest(levelPos, LodConfig.CLIENT.distanceGenerationMode.get(), DetailDistanceUtil.getLodDetail(detailGen)));
}
requesting = maxChunkGenRequests - generationRequestList.size();
}
//====================================//
// get the closet generation requests //
//====================================//
// determine which points in the posListToGenerate
// should actually be queued to generate
for (GenerationRequest generationRequest : generationRequestList)
{
ChunkPos chunkPos = generationRequest.getChunkPos();
if (numberOfChunksWaitingToGenerate.get() < maxChunkGenRequests)
{
// prevent generating the same chunk multiple times
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
// fill up chunksToGen from the reserve if it isn't full
// already
if (chunksToGen.size() < maxChunkGenRequests)
{
Iterator<GenerationRequest> reserveIterator = chunksToGenReserve.iterator();
while (chunksToGen.size() < maxChunkGenRequests && reserveIterator.hasNext())
{
chunksToGen.add(reserveIterator.next());
}
}
//=============================//
// start the LodNodeGenWorkers //
//=============================//
// issue #19
// TODO add a way for a server side mod to generate chunks requested here
ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension);
// 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, lodBuilder, lodDim, serverWorld);
WorldWorkerManager.addWorker(genWorker);
}
}
catch (Exception e)
{
// this shouldn't ever happen, but just in case
e.printStackTrace();
}
finally
{
generatorThreadRunning = false;
}
});
mainGenThread.execute(generatorThread);
} // if distanceGenerationMode != DistanceGenerationMode.NONE && !generatorThreadRunning
}
}
@@ -23,6 +23,7 @@ import org.apache.logging.log4j.Logger;
import com.seibel.lod.builders.LodBufferBuilder;
import com.seibel.lod.builders.LodBuilder;
import com.seibel.lod.builders.worldGeneration.LodNodeGenWorker;
import com.seibel.lod.builders.worldGeneration.LodWorldGenerator;
import com.seibel.lod.enums.DistanceCalculatorType;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.FogDistance;
@@ -39,6 +40,7 @@ import com.seibel.lod.util.LodUtil;
import net.minecraft.client.Minecraft;
import net.minecraft.profiler.IProfiler;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.ChunkEvent;
import net.minecraftforge.event.world.WorldEvent;
@@ -49,7 +51,7 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
* and is the starting point for most of this program.
*
* @author James_Seibel
* @version 8-17-2021
* @version 8-24-2021
*/
public class ClientProxy
{
@@ -57,8 +59,9 @@ public class ClientProxy
private static LodWorld lodWorld = new LodWorld();
private static LodBuilder lodBuilder = new LodBuilder();
private static LodBufferBuilder lodBufferBuilder = new LodBufferBuilder(lodBuilder);
private static LodBufferBuilder lodBufferBuilder = new LodBufferBuilder();
private static LodRenderer renderer = new LodRenderer(lodBufferBuilder);
private static LodWorldGenerator lodWorldGenerator = LodWorldGenerator.INSTANCE;
private boolean configOverrideReminderPrinted = false;
@@ -141,7 +144,7 @@ public class ClientProxy
}
// LodConfig.CLIENT.drawLODs.set(true);
LodConfig.CLIENT.debugMode.set(false);
LodConfig.CLIENT.debugMode.set(true);
LodConfig.CLIENT.maxDrawDetail.set(LodDetail.FULL);
LodConfig.CLIENT.maxGenerationDetail.set(LodDetail.FULL);
@@ -158,7 +161,7 @@ public class ClientProxy
LodConfig.CLIENT.lodDistanceCalculatorType.set(DistanceCalculatorType.LINEAR);
LodConfig.CLIENT.lodQuality.set(2);
LodConfig.CLIENT.allowUnstableFeatureGeneration.set(false);
LodConfig.CLIENT.numberOfWorldGenerationThreads.set(8);
LodConfig.CLIENT.numberOfWorldGenerationThreads.set(16);
// has to be set in the config file
// LodConfig.CLIENT.numberOfWorldGenerationThreads.set(16);
@@ -169,6 +172,19 @@ public class ClientProxy
// forge events //
//==============//
@SubscribeEvent
public void serverTickEvent(TickEvent.ServerTickEvent event)
{
if (mc == null || mc.player == null || !lodWorld.getIsWorldLoaded())
return;
LodDimension lodDim = lodWorld.getLodDimension(mc.player.level.dimensionType());
if (lodDim == null)
return;
lodWorldGenerator.queueGenerationRequests(lodDim, renderer, lodBuilder);
}
@SubscribeEvent
public void chunkLoadEvent(ChunkEvent.Load event)
{
@@ -203,7 +219,7 @@ public class ClientProxy
// preventing new LodChunks form being generated
LodNodeGenWorker.restartExecuterService();
lodBufferBuilder.numberOfChunksWaitingToGenerate.set(0);
LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.set(0);
// the player has disconnected from a server
lodWorld.deselectWorld();