small changes
This commit is contained in:
@@ -60,7 +60,7 @@ public class LodBufferBuilder
|
||||
/**
|
||||
* 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(LodConfig.CLIENT.numberOfWorldGenerationThreads.get(), new LodThreadFactory(this.getClass().getSimpleName() + " - builder"));
|
||||
|
||||
/**
|
||||
* The buffers that are used to create LODs using far fog
|
||||
|
||||
@@ -21,13 +21,13 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentNavigableMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import com.seibel.lod.enums.DistanceGenerationMode;
|
||||
import com.seibel.lod.handlers.LodDimensionFileHandler;
|
||||
import com.seibel.lod.objects.LevelPos.LevelPos;
|
||||
import com.seibel.lod.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.util.LodThreadFactory;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -36,6 +36,7 @@ import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.server.ServerChunkProvider;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
|
||||
/**
|
||||
* This object holds all loaded LOD regions
|
||||
* for a given dimension.
|
||||
@@ -63,8 +64,10 @@ public class LodDimension
|
||||
public volatile boolean isRegionDirty[][];
|
||||
|
||||
private volatile RegionPos center;
|
||||
|
||||
private volatile ChunkPos lastGenChunk;
|
||||
private volatile ChunkPos lastCutChunk;
|
||||
private LodDimensionFileHandler fileHandler;
|
||||
private ExecutorService cutAndGenThreads = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName() + " - cutAndGen"));
|
||||
|
||||
/**
|
||||
* Creates the dimension centered at (0,0)
|
||||
@@ -73,6 +76,8 @@ public class LodDimension
|
||||
*/
|
||||
public LodDimension(DimensionType newDimension, LodWorld lodWorld, int newWidth)
|
||||
{
|
||||
lastCutChunk = null;
|
||||
lastGenChunk = null;
|
||||
dimension = newDimension;
|
||||
width = newWidth;
|
||||
halfWidth = (int) Math.floor(width / 2);
|
||||
@@ -237,7 +242,8 @@ public class LodDimension
|
||||
for (int z = 0; z < regions.length; z++)
|
||||
{
|
||||
region = regions[x][z];
|
||||
if(region != null){
|
||||
if (region != null)
|
||||
{
|
||||
count += region.getMinMemoryNeeded();
|
||||
}
|
||||
}
|
||||
@@ -304,92 +310,124 @@ public class LodDimension
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void treeCutter(int playerPosX, int playerPosZ)
|
||||
{
|
||||
int regionX;
|
||||
int regionZ;
|
||||
LevelPos levelPos = new LevelPos();
|
||||
|
||||
for (int x = 0; x < regions.length; x++)
|
||||
ChunkPos newPlayerChunk = (new LevelPos((byte) 0, playerPosX, playerPosZ)).getChunkPos();
|
||||
if (lastCutChunk == null)
|
||||
lastCutChunk = new ChunkPos(newPlayerChunk.x + 1, newPlayerChunk.z - 1);
|
||||
if (newPlayerChunk.x != lastCutChunk.x || newPlayerChunk.z != lastCutChunk.z)
|
||||
{
|
||||
for (int z = 0; z < regions.length; z++)
|
||||
lastCutChunk = newPlayerChunk;
|
||||
Thread thread = new Thread(() ->
|
||||
{
|
||||
regionX = (x + center.x) - halfWidth;
|
||||
regionZ = (z + center.z) - halfWidth;
|
||||
levelPos.changeParameters(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ);
|
||||
//we start checking from the first circle. If the whole region is in the circle
|
||||
//we proceed to cut all the level lower than the level of circle 1 and we break
|
||||
//if this is not the case w
|
||||
for(byte index = LodUtil.BLOCK_DETAIL_LEVEL; index <= LodUtil.DETAIL_OPTIONS; index++){
|
||||
if(DetailDistanceUtil.getDistanceTreeCut(index + 1) > levelPos.minDistance(playerPosX, playerPosZ)){
|
||||
int regionX;
|
||||
int regionZ;
|
||||
LevelPos levelPos = new LevelPos();
|
||||
|
||||
byte cutDetailLevel = DetailDistanceUtil.getCutLodDetail(index);
|
||||
|
||||
if(regions[x][z] != null)
|
||||
for (int x = 0; x < regions.length; x++)
|
||||
{
|
||||
for (int z = 0; z < regions.length; z++)
|
||||
{
|
||||
regionX = (x + center.x) - halfWidth;
|
||||
regionZ = (z + center.z) - halfWidth;
|
||||
levelPos.changeParameters(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ);
|
||||
//we start checking from the first circle. If the whole region is in the circle
|
||||
//we proceed to cut all the level lower than the level of circle 1 and we break
|
||||
//if this is not the case w
|
||||
for (byte index = LodUtil.BLOCK_DETAIL_LEVEL; index <= LodUtil.DETAIL_OPTIONS; index++)
|
||||
{
|
||||
if(regions[x][z].getMinDetailLevel() > cutDetailLevel){
|
||||
regions[x][z].cutTree(cutDetailLevel);
|
||||
if (DetailDistanceUtil.getDistanceTreeCut(index + 1) > levelPos.minDistance(playerPosX, playerPosZ))
|
||||
{
|
||||
|
||||
byte cutDetailLevel = DetailDistanceUtil.getCutLodDetail(index);
|
||||
|
||||
if (regions[x][z] != null)
|
||||
{
|
||||
if (regions[x][z].getMinDetailLevel() > cutDetailLevel)
|
||||
{
|
||||
regions[x][z].cutTree(cutDetailLevel);
|
||||
}
|
||||
}
|
||||
//once we
|
||||
break;
|
||||
}
|
||||
}
|
||||
//once we
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}// region z
|
||||
}// region z
|
||||
|
||||
});
|
||||
cutAndGenThreads.execute(thread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void treeGenerator(int playerPosX, int playerPosZ)
|
||||
{
|
||||
int regionX;
|
||||
int regionZ;
|
||||
LevelPos levelPos = new LevelPos();
|
||||
RegionPos regionPos;
|
||||
LodRegion region;
|
||||
byte targetDetailLevel;
|
||||
for (int x = 0; x < regions.length; x++)
|
||||
|
||||
ChunkPos newPlayerChunk = (new LevelPos((byte) 0, playerPosX, playerPosZ)).getChunkPos();
|
||||
|
||||
if (lastGenChunk == null)
|
||||
lastGenChunk = new ChunkPos(newPlayerChunk.x + 1, newPlayerChunk.z - 1);
|
||||
if (newPlayerChunk.x != lastGenChunk.x || newPlayerChunk.z != lastGenChunk.z)
|
||||
{
|
||||
for (int z = 0; z < regions.length; z++)
|
||||
lastGenChunk = newPlayerChunk;
|
||||
Thread thread = new Thread(() ->
|
||||
{
|
||||
regionX = (x + center.x) - halfWidth;
|
||||
regionZ = (z + center.z) - halfWidth;
|
||||
levelPos.changeParameters(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ);
|
||||
regionPos = new RegionPos(regionX, regionZ);
|
||||
|
||||
for(byte index = LodUtil.BLOCK_DETAIL_LEVEL; index <= LodUtil.REGION_DETAIL_LEVEL; index++){
|
||||
|
||||
//As soon as we find in which circle the region should be we analyze it
|
||||
if(DetailDistanceUtil.getDistanceTreeGen(index + 1) > levelPos.minDistance(playerPosX, playerPosZ)){
|
||||
|
||||
region = regions[x][z];
|
||||
//We require that the region we are checking is loaded with at least this level
|
||||
targetDetailLevel = DetailDistanceUtil.getLodDetail(index).detailLevel;
|
||||
|
||||
if (region == null)
|
||||
int regionX;
|
||||
int regionZ;
|
||||
LodRegion region;
|
||||
LevelPos levelPos = new LevelPos();
|
||||
List<Callable<Boolean>> genThreads = new ArrayList<>();
|
||||
for (int x = 0; x < regions.length; x++)
|
||||
{
|
||||
for (int z = 0; z < regions.length; z++)
|
||||
{
|
||||
regionX = (x + center.x) - halfWidth;
|
||||
regionZ = (z + center.z) - halfWidth;
|
||||
levelPos.changeParameters(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ);
|
||||
final RegionPos regionPos = new RegionPos(regionX, regionZ);
|
||||
for (byte index = LodUtil.BLOCK_DETAIL_LEVEL; index <= LodUtil.REGION_DETAIL_LEVEL; index++)
|
||||
{
|
||||
//First case, region has to be initialized
|
||||
|
||||
//We check if there is a file at the target level
|
||||
regions[x][z] = getRegionFromFile(regionPos, targetDetailLevel);
|
||||
|
||||
//if there is no file we initialize the region
|
||||
if (regions[x][z] == null)
|
||||
//As soon as we find in which circle the region should be we analyze it
|
||||
if (DetailDistanceUtil.getDistanceTreeGen(index + 1) > levelPos.minDistance(playerPosX, playerPosZ))
|
||||
{
|
||||
regions[x][z] = new LodRegion(targetDetailLevel, regionPos);
|
||||
}
|
||||
|
||||
}else if(region.getMinDetailLevel() > targetDetailLevel){
|
||||
//Second case, region has been initialized but at a higher level
|
||||
//We expand the region by introducing the missing layer
|
||||
region.expand(targetDetailLevel);
|
||||
region = regions[x][z];
|
||||
//We require that the region we are checking is loaded with at least this level
|
||||
byte targetDetailLevel = DetailDistanceUtil.getLodDetail(index).detailLevel;
|
||||
|
||||
if (region == null)
|
||||
{
|
||||
//First case, region has to be initialized
|
||||
|
||||
//We check if there is a file at the target level
|
||||
regions[x][z] = getRegionFromFile(regionPos, targetDetailLevel);
|
||||
|
||||
//if there is no file we initialize the region
|
||||
if (regions[x][z] == null)
|
||||
{
|
||||
regions[x][z] = new LodRegion(targetDetailLevel, regionPos);
|
||||
}
|
||||
|
||||
} else if (region.getMinDetailLevel() > targetDetailLevel)
|
||||
{
|
||||
//Second case, region has been initialized but at a higher level
|
||||
//We expand the region by introducing the missing layer
|
||||
region.expand(targetDetailLevel);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
;
|
||||
});
|
||||
cutAndGenThreads.execute(thread);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,7 +499,8 @@ public class LodDimension
|
||||
region = getRegion(new LevelPos(LodUtil.REGION_DETAIL_LEVEL, regionPos.x, regionPos.z).getConvertedLevelPos(detailLevel));
|
||||
listOfData.addAll(region.getDataToGenerate(playerPosX, playerPosZ, start, end, generation, detailLevel, dataNumber));
|
||||
}
|
||||
}catch (Exception e){
|
||||
} catch (Exception e)
|
||||
{
|
||||
//e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@@ -470,9 +509,9 @@ public class LodDimension
|
||||
List<LevelPos> levelMinPosList = new ArrayList<>();
|
||||
dataNumber = Math.min(dataNumber, listOfData.size());
|
||||
|
||||
for(int i=0; i<dataNumber; i++)
|
||||
for (int i = 0; i < dataNumber; i++)
|
||||
{
|
||||
LevelPos min = Collections.min(listOfData, LevelPos.getPosComparator(playerPosX,playerPosZ));
|
||||
LevelPos min = Collections.min(listOfData, LevelPos.getPosComparator(playerPosX, playerPosZ));
|
||||
listOfData.remove(min);
|
||||
levelMinPosList.add(min);
|
||||
}
|
||||
@@ -484,7 +523,7 @@ public class LodDimension
|
||||
*
|
||||
* @return list of nodes
|
||||
*/
|
||||
public void getDataToRender(ConcurrentNavigableMap<LevelPos,List<Integer>> dataToRender, RegionPos regionPos, int playerPosX, int playerPosZ, int start, int end, byte detailLevel, boolean zFix)
|
||||
public void getDataToRender(ConcurrentNavigableMap<LevelPos, List<Integer>> dataToRender, RegionPos regionPos, int playerPosX, int playerPosZ, int start, int end, byte detailLevel, boolean zFix)
|
||||
{
|
||||
LevelPos regionLevelPos = new LevelPos(LodUtil.REGION_DETAIL_LEVEL, regionPos.x, regionPos.z);
|
||||
try
|
||||
@@ -493,9 +532,10 @@ public class LodDimension
|
||||
start <= regionLevelPos.maxDistance(playerPosX, playerPosZ))
|
||||
{
|
||||
LodRegion region = getRegion(new LevelPos(LodUtil.REGION_DETAIL_LEVEL, regionPos.x, regionPos.z).getConvertedLevelPos(detailLevel));
|
||||
region.getDataToRender(dataToRender,playerPosX, playerPosZ, start, end, detailLevel,zFix);
|
||||
region.getDataToRender(dataToRender, playerPosX, playerPosZ, start, end, detailLevel, zFix);
|
||||
}
|
||||
}catch (Exception e){
|
||||
} catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@@ -536,7 +576,8 @@ public class LodDimension
|
||||
|
||||
return region.getData(levelPos);
|
||||
|
||||
}catch (Exception e){
|
||||
} catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -595,7 +636,8 @@ public class LodDimension
|
||||
}
|
||||
|
||||
return region.doesDataExist(levelPos.clone());
|
||||
}catch (Exception e){
|
||||
} catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -704,12 +746,12 @@ public class LodDimension
|
||||
for (int z = 0; z < regions.length; z++)
|
||||
{
|
||||
region = regions[x][z];
|
||||
if(region == null)
|
||||
if (region == null)
|
||||
{
|
||||
stringBuilder.append("n");
|
||||
stringBuilder.append("\t");
|
||||
|
||||
}else
|
||||
} else
|
||||
{
|
||||
stringBuilder.append(region.getMinDetailLevel());
|
||||
stringBuilder.append("\t");
|
||||
|
||||
@@ -57,258 +57,266 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
*/
|
||||
public class ClientProxy
|
||||
{
|
||||
public static final Logger LOGGER = LogManager.getLogger("LOD");
|
||||
|
||||
private static LodWorld lodWorld = new LodWorld();
|
||||
private static LodBuilder lodBuilder = new LodBuilder();
|
||||
private static LodBufferBuilder lodBufferBuilder = new LodBufferBuilder();
|
||||
private static LodRenderer renderer = new LodRenderer(lodBufferBuilder);
|
||||
private static LodWorldGenerator lodWorldGenerator = LodWorldGenerator.INSTANCE;
|
||||
public static final Logger LOGGER = LogManager.getLogger("LOD");
|
||||
|
||||
private boolean configOverrideReminderPrinted = false;
|
||||
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
private static LodWorld lodWorld = new LodWorld();
|
||||
private static LodBuilder lodBuilder = new LodBuilder();
|
||||
private static LodBufferBuilder lodBufferBuilder = new LodBufferBuilder();
|
||||
private static LodRenderer renderer = new LodRenderer(lodBufferBuilder);
|
||||
private static LodWorldGenerator lodWorldGenerator = LodWorldGenerator.INSTANCE;
|
||||
|
||||
private boolean configOverrideReminderPrinted = false;
|
||||
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
|
||||
|
||||
/** This is used to determine if the LODs should be regenerated */
|
||||
public static int previousChunkRenderDistance = 0;
|
||||
/** This is used to determine if the LODs should be regenerated */
|
||||
public static int previousLodRenderDistance = 0;
|
||||
|
||||
/** can be set if we want to recalculate variables related
|
||||
* to the LOD view distance */
|
||||
private boolean recalculateWidths = false;
|
||||
/**
|
||||
* This is used to determine if the LODs should be regenerated
|
||||
*/
|
||||
public static int previousChunkRenderDistance = 0;
|
||||
/**
|
||||
* This is used to determine if the LODs should be regenerated
|
||||
*/
|
||||
public static int previousLodRenderDistance = 0;
|
||||
|
||||
|
||||
public ClientProxy()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//==============//
|
||||
// render event //
|
||||
//==============//
|
||||
|
||||
/**
|
||||
* Do any setup that is required to draw LODs
|
||||
* and then tell the LodRenderer to draw.
|
||||
*/
|
||||
public void renderLods(float partialTicks)
|
||||
{
|
||||
if (mc == null || mc.player == null || !lodWorld.getIsWorldLoaded())
|
||||
return;
|
||||
applyConfigOverrides();
|
||||
|
||||
viewDistanceChangedEvent();
|
||||
|
||||
LodDimension lodDim = lodWorld.getLodDimension(mc.player.level.dimensionType());
|
||||
if (lodDim == null)
|
||||
return;
|
||||
/**
|
||||
* can be set if we want to recalculate variables related
|
||||
* to the LOD view distance
|
||||
*/
|
||||
private boolean recalculateWidths = false;
|
||||
|
||||
|
||||
playerMoveEvent(lodDim);
|
||||
//System.out.println("memory needed " + lodDim.getMinMemoryNeeded() + " byte");
|
||||
//System.out.println(lodDim);
|
||||
public ClientProxy()
|
||||
{
|
||||
|
||||
lodDim.treeCutter((int) mc.player.getX(),(int) mc.player.getZ());
|
||||
lodDim.treeGenerator((int) mc.player.getX(),(int) mc.player.getZ());
|
||||
// comment out when creating a release
|
||||
|
||||
|
||||
// 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 profiler 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"
|
||||
|
||||
|
||||
// these can't be set until after the buffers are built (in renderer.drawLODs)
|
||||
// otherwise the buffers may be set to the wrong size, or not changed at all
|
||||
previousChunkRenderDistance = mc.options.renderDistance;
|
||||
previousLodRenderDistance = LodConfig.CLIENT.lodChunkRenderDistance.get();
|
||||
}
|
||||
|
||||
|
||||
private void applyConfigOverrides()
|
||||
{
|
||||
// remind the developer(s). that config override is active
|
||||
if (!configOverrideReminderPrinted)
|
||||
{
|
||||
mc.player.sendMessage(new StringTextComponent("Debug settings enabled!"), mc.player.getUUID());
|
||||
configOverrideReminderPrinted = true;
|
||||
}
|
||||
|
||||
// LodConfig.CLIENT.drawLODs.set(true);
|
||||
LodConfig.CLIENT.debugMode.set(false);
|
||||
|
||||
LodConfig.CLIENT.maxDrawDetail.set(LodDetail.FULL);
|
||||
LodConfig.CLIENT.maxGenerationDetail.set(LodDetail.FULL);
|
||||
//==============//
|
||||
// render event //
|
||||
//==============//
|
||||
|
||||
LodConfig.CLIENT.fogDistance.set(FogDistance.FAR);
|
||||
LodConfig.CLIENT.fogDrawOverride.set(FogDrawOverride.ALWAYS_DRAW_FOG_FANCY);
|
||||
LodConfig.CLIENT.shadingMode.set(ShadingMode.DARKEN_SIDES);
|
||||
LodConfig.CLIENT.brightnessMultiplier.set(1.0);
|
||||
LodConfig.CLIENT.saturationMultiplier.set(1.0);
|
||||
|
||||
LodConfig.CLIENT.distanceGenerationMode.set(DistanceGenerationMode.SURFACE);
|
||||
LodConfig.CLIENT.lodChunkRenderDistance.set(128);
|
||||
LodConfig.CLIENT.lodDistanceCalculatorType.set(DistanceCalculatorType.LINEAR);
|
||||
LodConfig.CLIENT.lodQuality.set(2);
|
||||
LodConfig.CLIENT.allowUnstableFeatureGeneration.set(false);
|
||||
LodConfig.CLIENT.numberOfWorldGenerationThreads.set(Runtime.getRuntime().availableProcessors());
|
||||
|
||||
// has to be set in the config file
|
||||
// LodConfig.CLIENT.numberOfWorldGenerationThreads.set(16);
|
||||
}
|
||||
|
||||
|
||||
//==============//
|
||||
// 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)
|
||||
{
|
||||
lodBuilder.generateLodNodeAsync(event.getChunk(), lodWorld, event.getWorld(), DistanceGenerationMode.SERVER);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void worldSaveEvent(WorldEvent.Save event)
|
||||
{
|
||||
if (lodWorld != null)
|
||||
lodWorld.saveAllDimensions();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void worldLoadEvent(WorldEvent.Load event)
|
||||
{
|
||||
// the player just loaded a new world/dimension
|
||||
lodWorld.selectWorld(LodUtil.getWorldID(event.getWorld()));
|
||||
// make sure the correct LODs are being rendered
|
||||
// (if this isn't done the previous world's LODs may be drawn)
|
||||
renderer.regenerateLODsNextFrame();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void worldUnloadEvent(WorldEvent.Unload event)
|
||||
{
|
||||
// the player just unloaded a world/dimension
|
||||
|
||||
if (mc.getConnection().getLevel() == null)
|
||||
{
|
||||
// if this isn't done unfinished tasks may be left in the queue
|
||||
// preventing new LodChunks form being generated
|
||||
LodNodeGenWorker.restartExecuterService();
|
||||
|
||||
LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.set(0);
|
||||
// the player has disconnected from a server
|
||||
lodWorld.deselectWorld();
|
||||
|
||||
|
||||
// hopefully this should reduce issues related to the buffer builder
|
||||
// breaking when changing worlds.
|
||||
renderer.destroyBuffers();
|
||||
recalculateWidths = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SubscribeEvent
|
||||
public void blockChangeEvent(BlockEvent event)
|
||||
{
|
||||
if (event.getClass() == BlockEvent.BreakEvent.class ||
|
||||
event.getClass() == BlockEvent.EntityPlaceEvent.class ||
|
||||
event.getClass() == BlockEvent.EntityMultiPlaceEvent.class ||
|
||||
event.getClass() == BlockEvent.FluidPlaceBlockEvent.class ||
|
||||
event.getClass() == BlockEvent.PortalSpawnEvent.class)
|
||||
{
|
||||
// recreate the LOD where the blocks were changed
|
||||
lodBuilder.generateLodNodeAsync(event.getWorld().getChunk(event.getPos()), lodWorld, event.getWorld());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==================//
|
||||
// frame LOD events //
|
||||
//==================//
|
||||
|
||||
/**
|
||||
* Re-centers the given LodDimension if it needs to be.
|
||||
*/
|
||||
private void playerMoveEvent(LodDimension lodDim)
|
||||
{
|
||||
// make sure the dimension is centered
|
||||
RegionPos playerRegionPos = new RegionPos(mc.player.blockPosition());
|
||||
RegionPos worldRegionOffset = new RegionPos(playerRegionPos.x - lodDim.getCenterX(), playerRegionPos.z - lodDim.getCenterZ());
|
||||
if (worldRegionOffset.x != 0 || worldRegionOffset.z != 0)
|
||||
{
|
||||
lodWorld.saveAllDimensions();
|
||||
lodDim.move(worldRegionOffset);
|
||||
LOGGER.info("offset: " + worldRegionOffset.x + "," + worldRegionOffset.z + "\t center: " + lodDim.getCenterX() + "," + lodDim.getCenterZ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Re-sizes all LodDimensions if they needs to be.
|
||||
*/
|
||||
private void viewDistanceChangedEvent()
|
||||
{
|
||||
// calculate how wide the dimension(s) should be in regions
|
||||
int chunksWide = LodConfig.CLIENT.lodChunkRenderDistance.get() * 2 + 1;
|
||||
int newWidth = (int) Math.ceil(chunksWide / (float) LodUtil.REGION_WIDTH_IN_CHUNKS);
|
||||
newWidth = (newWidth % 2 == 0) ? (newWidth += 1) : (newWidth += 2); // make sure we have a odd number of regions
|
||||
|
||||
// do the dimensions need to change in size?
|
||||
if (lodBuilder.defaultDimensionWidthInRegions != newWidth || recalculateWidths)
|
||||
{
|
||||
// update the dimensions to fit the new width
|
||||
lodWorld.resizeDimensionRegionWidth(newWidth);
|
||||
lodBuilder.defaultDimensionWidthInRegions = newWidth;
|
||||
renderer.setupBuffers(newWidth);
|
||||
|
||||
recalculateWidths = false;
|
||||
//LOGGER.info("new dimension width in regions: " + newWidth + "\t potential: " + newWidth );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//================//
|
||||
// public getters //
|
||||
//================//
|
||||
|
||||
public static LodWorld getLodWorld()
|
||||
{
|
||||
return lodWorld;
|
||||
}
|
||||
|
||||
public static LodBuilder getLodBuilder()
|
||||
{
|
||||
return lodBuilder;
|
||||
}
|
||||
|
||||
public static LodRenderer getRenderer()
|
||||
{
|
||||
return renderer;
|
||||
}
|
||||
/**
|
||||
* Do any setup that is required to draw LODs
|
||||
* and then tell the LodRenderer to draw.
|
||||
*/
|
||||
public void renderLods(float partialTicks)
|
||||
{
|
||||
if (mc == null || mc.player == null || !lodWorld.getIsWorldLoaded())
|
||||
return;
|
||||
|
||||
viewDistanceChangedEvent();
|
||||
|
||||
LodDimension lodDim = lodWorld.getLodDimension(mc.player.level.dimensionType());
|
||||
if (lodDim == null)
|
||||
return;
|
||||
|
||||
|
||||
playerMoveEvent(lodDim);
|
||||
//System.out.println("memory needed " + lodDim.getMinMemoryNeeded() + " byte");
|
||||
//System.out.println(lodDim);
|
||||
|
||||
lodDim.treeCutter((int) mc.player.getX(), (int) mc.player.getZ());
|
||||
lodDim.treeGenerator((int) mc.player.getX(), (int) mc.player.getZ());
|
||||
|
||||
|
||||
// comment out when creating a release
|
||||
applyConfigOverrides();
|
||||
|
||||
|
||||
// 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 profiler 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"
|
||||
|
||||
|
||||
// these can't be set until after the buffers are built (in renderer.drawLODs)
|
||||
// otherwise the buffers may be set to the wrong size, or not changed at all
|
||||
previousChunkRenderDistance = mc.options.renderDistance;
|
||||
previousLodRenderDistance = LodConfig.CLIENT.lodChunkRenderDistance.get();
|
||||
}
|
||||
|
||||
|
||||
private void applyConfigOverrides()
|
||||
{
|
||||
// remind the developer(s). that config override is active
|
||||
if (!configOverrideReminderPrinted)
|
||||
{
|
||||
mc.player.sendMessage(new StringTextComponent("Debug settings enabled!"), mc.player.getUUID());
|
||||
configOverrideReminderPrinted = true;
|
||||
}
|
||||
|
||||
// LodConfig.CLIENT.drawLODs.set(true);
|
||||
LodConfig.CLIENT.debugMode.set(false);
|
||||
|
||||
LodConfig.CLIENT.maxDrawDetail.set(LodDetail.FULL);
|
||||
LodConfig.CLIENT.maxGenerationDetail.set(LodDetail.FULL);
|
||||
|
||||
LodConfig.CLIENT.fogDistance.set(FogDistance.FAR);
|
||||
LodConfig.CLIENT.fogDrawOverride.set(FogDrawOverride.ALWAYS_DRAW_FOG_FANCY);
|
||||
LodConfig.CLIENT.shadingMode.set(ShadingMode.DARKEN_SIDES);
|
||||
LodConfig.CLIENT.brightnessMultiplier.set(1.0);
|
||||
LodConfig.CLIENT.saturationMultiplier.set(1.0);
|
||||
|
||||
LodConfig.CLIENT.distanceGenerationMode.set(DistanceGenerationMode.SURFACE);
|
||||
LodConfig.CLIENT.lodChunkRenderDistance.set(128);
|
||||
LodConfig.CLIENT.lodDistanceCalculatorType.set(DistanceCalculatorType.LINEAR);
|
||||
LodConfig.CLIENT.lodQuality.set(2);
|
||||
LodConfig.CLIENT.allowUnstableFeatureGeneration.set(false);
|
||||
LodConfig.CLIENT.numberOfWorldGenerationThreads.set(Runtime.getRuntime().availableProcessors());
|
||||
|
||||
// has to be set in the config file
|
||||
// LodConfig.CLIENT.numberOfWorldGenerationThreads.set(16);
|
||||
}
|
||||
|
||||
|
||||
//==============//
|
||||
// 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)
|
||||
{
|
||||
lodBuilder.generateLodNodeAsync(event.getChunk(), lodWorld, event.getWorld(), DistanceGenerationMode.SERVER);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void worldSaveEvent(WorldEvent.Save event)
|
||||
{
|
||||
if (lodWorld != null)
|
||||
lodWorld.saveAllDimensions();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void worldLoadEvent(WorldEvent.Load event)
|
||||
{
|
||||
// the player just loaded a new world/dimension
|
||||
lodWorld.selectWorld(LodUtil.getWorldID(event.getWorld()));
|
||||
// make sure the correct LODs are being rendered
|
||||
// (if this isn't done the previous world's LODs may be drawn)
|
||||
renderer.regenerateLODsNextFrame();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void worldUnloadEvent(WorldEvent.Unload event)
|
||||
{
|
||||
// the player just unloaded a world/dimension
|
||||
|
||||
if (mc.getConnection().getLevel() == null)
|
||||
{
|
||||
// if this isn't done unfinished tasks may be left in the queue
|
||||
// preventing new LodChunks form being generated
|
||||
LodNodeGenWorker.restartExecuterService();
|
||||
|
||||
LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.set(0);
|
||||
// the player has disconnected from a server
|
||||
lodWorld.deselectWorld();
|
||||
|
||||
|
||||
// hopefully this should reduce issues related to the buffer builder
|
||||
// breaking when changing worlds.
|
||||
renderer.destroyBuffers();
|
||||
recalculateWidths = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SubscribeEvent
|
||||
public void blockChangeEvent(BlockEvent event)
|
||||
{
|
||||
if (event.getClass() == BlockEvent.BreakEvent.class ||
|
||||
event.getClass() == BlockEvent.EntityPlaceEvent.class ||
|
||||
event.getClass() == BlockEvent.EntityMultiPlaceEvent.class ||
|
||||
event.getClass() == BlockEvent.FluidPlaceBlockEvent.class ||
|
||||
event.getClass() == BlockEvent.PortalSpawnEvent.class)
|
||||
{
|
||||
// recreate the LOD where the blocks were changed
|
||||
lodBuilder.generateLodNodeAsync(event.getWorld().getChunk(event.getPos()), lodWorld, event.getWorld());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==================//
|
||||
// frame LOD events //
|
||||
//==================//
|
||||
|
||||
/**
|
||||
* Re-centers the given LodDimension if it needs to be.
|
||||
*/
|
||||
private void playerMoveEvent(LodDimension lodDim)
|
||||
{
|
||||
// make sure the dimension is centered
|
||||
RegionPos playerRegionPos = new RegionPos(mc.player.blockPosition());
|
||||
RegionPos worldRegionOffset = new RegionPos(playerRegionPos.x - lodDim.getCenterX(), playerRegionPos.z - lodDim.getCenterZ());
|
||||
if (worldRegionOffset.x != 0 || worldRegionOffset.z != 0)
|
||||
{
|
||||
lodWorld.saveAllDimensions();
|
||||
lodDim.move(worldRegionOffset);
|
||||
LOGGER.info("offset: " + worldRegionOffset.x + "," + worldRegionOffset.z + "\t center: " + lodDim.getCenterX() + "," + lodDim.getCenterZ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Re-sizes all LodDimensions if they needs to be.
|
||||
*/
|
||||
private void viewDistanceChangedEvent()
|
||||
{
|
||||
// calculate how wide the dimension(s) should be in regions
|
||||
int chunksWide = LodConfig.CLIENT.lodChunkRenderDistance.get() * 2 + 1;
|
||||
int newWidth = (int) Math.ceil(chunksWide / (float) LodUtil.REGION_WIDTH_IN_CHUNKS);
|
||||
newWidth = (newWidth % 2 == 0) ? (newWidth += 1) : (newWidth += 2); // make sure we have a odd number of regions
|
||||
|
||||
// do the dimensions need to change in size?
|
||||
if (lodBuilder.defaultDimensionWidthInRegions != newWidth || recalculateWidths)
|
||||
{
|
||||
// update the dimensions to fit the new width
|
||||
lodWorld.resizeDimensionRegionWidth(newWidth);
|
||||
lodBuilder.defaultDimensionWidthInRegions = newWidth;
|
||||
renderer.setupBuffers(newWidth);
|
||||
|
||||
recalculateWidths = false;
|
||||
//LOGGER.info("new dimension width in regions: " + newWidth + "\t potential: " + newWidth );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//================//
|
||||
// public getters //
|
||||
//================//
|
||||
|
||||
public static LodWorld getLodWorld()
|
||||
{
|
||||
return lodWorld;
|
||||
}
|
||||
|
||||
public static LodBuilder getLodBuilder()
|
||||
{
|
||||
return lodBuilder;
|
||||
}
|
||||
|
||||
public static LodRenderer getRenderer()
|
||||
{
|
||||
return renderer;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user