Merge remote-tracking branch 'upstream-core/main'
# Conflicts: # core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiDebuggingConfig.java # core/src/main/java/com/seibel/distanthorizons/core/config/Config.java # core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java # core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java # core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataFileHandler.java # core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderDataMetaFile.java # core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java # core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java # core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java # core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java
This commit is contained in:
+1
-1
@@ -46,6 +46,6 @@ public class DhApiDebuggingConfig implements IDhApiDebuggingConfig
|
||||
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Debugging.lodOnlyMode); }
|
||||
|
||||
public IDhApiConfigValue<Boolean> debugWireframeRendering()
|
||||
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Debugging.DebugWireframeRendering.enableRendering); }
|
||||
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Debugging.DebugWireframe.enableRendering); }
|
||||
|
||||
}
|
||||
|
||||
@@ -1258,12 +1258,57 @@ public class Config
|
||||
|
||||
|
||||
|
||||
public static ConfigCategory debugWireframe = new ConfigCategory.Builder()
|
||||
.set(DebugWireframe.class)
|
||||
.build();
|
||||
|
||||
public static class DebugWireframe
|
||||
{
|
||||
public static ConfigEntry<Boolean> enableRendering = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment(""
|
||||
+ "If enabled, various wireframes for debugging internal functions will be drawn. \n"
|
||||
+ "\n"
|
||||
+ "NOTE: There WILL be performance hit! \n"
|
||||
+ " Additionally, only stuff that's loaded after you enable this \n"
|
||||
+ " will render their debug wireframes.")
|
||||
.build();
|
||||
|
||||
|
||||
public static ConfigEntry<Boolean> showWorldGenQueue = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment("Render queued world gen tasks?")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> showRenderSectionStatus = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment("Render LOD section status?")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> showFullDataFileStatus = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment("Render full data file status?")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> showFullDataFileSampling = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment("Render full data file sampling progress?")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> showRenderDataFileStatus = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.comment("Render render data file status?")
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// can be set to public inorder to show in the config file and UI
|
||||
public static ConfigCategory exampleConfigScreen = new ConfigCategory.Builder()
|
||||
.set(ExampleConfigScreen.class)
|
||||
.build();
|
||||
|
||||
|
||||
/** This class is used to debug the different features of the config GUI */
|
||||
// FIXME: WARNING: Some of the options in this class dont get show n in the default UI
|
||||
// This will throw a warning when opened in the default ui to tell you about it not showing
|
||||
|
||||
+28
-3
@@ -41,7 +41,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
* Used to map a numerical IDs to a Biome/BlockState pair.
|
||||
*
|
||||
* @author Leetom
|
||||
* @version 2022-10-2
|
||||
*/
|
||||
public class FullDataPointIdMap
|
||||
{
|
||||
@@ -61,7 +60,7 @@ public class FullDataPointIdMap
|
||||
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
|
||||
|
||||
/** should only be used for debugging */
|
||||
private final DhSectionPos pos;
|
||||
private DhSectionPos pos;
|
||||
|
||||
/** The index should be the same as the Entry's ID */
|
||||
private final ArrayList<Entry> entryList = new ArrayList<>();
|
||||
@@ -78,7 +77,7 @@ public class FullDataPointIdMap
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
// getters //
|
||||
//=========//
|
||||
|
||||
private Entry getEntry(int id)
|
||||
@@ -102,6 +101,12 @@ public class FullDataPointIdMap
|
||||
public IBiomeWrapper getBiomeWrapper(int id) { return this.getEntry(id).biome; }
|
||||
public IBlockStateWrapper getBlockStateWrapper(int id) { return this.getEntry(id).blockState; }
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// setters //
|
||||
//=========//
|
||||
|
||||
/**
|
||||
* If an entry with the given values already exists nothing will
|
||||
* be added but the existing item's ID will still be returned.
|
||||
@@ -169,6 +174,20 @@ public class FullDataPointIdMap
|
||||
return remappedEntryIds;
|
||||
}
|
||||
|
||||
/** Should only be used if this map is going to be reused, otherwise bad things will happen. */
|
||||
public void clear(DhSectionPos pos)
|
||||
{
|
||||
this.pos = pos;
|
||||
this.entryList.clear();
|
||||
this.idMap.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// serializing //
|
||||
//=============//
|
||||
|
||||
/** Serializes all contained entries into the given stream, formatted in UTF */
|
||||
public void serialize(DhDataOutputStream outputStream) throws IOException
|
||||
{
|
||||
@@ -235,6 +254,12 @@ public class FullDataPointIdMap
|
||||
return newMap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// overrides //
|
||||
//===========//
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other)
|
||||
{
|
||||
|
||||
+10
-9
@@ -36,10 +36,7 @@ public class FullDataArrayAccessor implements IFullDataAccessor
|
||||
{
|
||||
protected final FullDataPointIdMap mapping;
|
||||
|
||||
/**
|
||||
* A flattened 2D array (for the X and Z directions) containing an array for the Y direction.
|
||||
* TODO the flattened array is probably to reduce garbage collection overhead, but is doing it this way worth while? Having a 3D array would be much easier to understand
|
||||
*/
|
||||
/** A flattened 2D array (for the X and Z directions) containing an array for the Y direction. */
|
||||
protected final long[][] dataArrays;
|
||||
|
||||
/** measured in data points */
|
||||
@@ -133,20 +130,24 @@ public class FullDataArrayAccessor implements IFullDataAccessor
|
||||
/**
|
||||
* Takes a higher detail {@link FullDataArrayAccessor}'s and converts the data to a lower detail level.
|
||||
*
|
||||
* @param fullDataAccessor must be larger than this {@link FullDataArrayAccessor} and its width must a power of two larger (example: this.width = 4, other.width = 8)
|
||||
* @param incomingFullDataAccessor must be larger than this {@link FullDataArrayAccessor} and its width must a power of two larger (example: this.width = 4, other.width = 8)
|
||||
*/
|
||||
public void downsampleFrom(FullDataArrayAccessor fullDataAccessor)
|
||||
public void downsampleFrom(FullDataArrayAccessor incomingFullDataAccessor)
|
||||
{
|
||||
// validate that the incoming data isn't smaller than this accessor
|
||||
LodUtil.assertTrue(fullDataAccessor.width >= this.width && fullDataAccessor.width % this.width == 0);
|
||||
LodUtil.assertTrue(incomingFullDataAccessor.width >= this.width && incomingFullDataAccessor.width % this.width == 0);
|
||||
|
||||
int dataPointsPerWidthUnit = fullDataAccessor.width / this.width;
|
||||
int dataPointsPerWidthUnit = incomingFullDataAccessor.width / this.width;
|
||||
for (int xOffset = 0; xOffset < this.width; xOffset++)
|
||||
{
|
||||
for (int zOffset = 0; zOffset < this.width; zOffset++)
|
||||
{
|
||||
FullDataArrayAccessor subView = incomingFullDataAccessor.subView(dataPointsPerWidthUnit,
|
||||
xOffset * dataPointsPerWidthUnit,
|
||||
zOffset * dataPointsPerWidthUnit);
|
||||
|
||||
SingleColumnFullDataAccessor column = this.get(xOffset, zOffset);
|
||||
column.downsampleFrom(fullDataAccessor.subView(dataPointsPerWidthUnit, xOffset * dataPointsPerWidthUnit, zOffset * dataPointsPerWidthUnit));
|
||||
column.downsampleFrom(subView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -137,7 +137,7 @@ public class SingleColumnFullDataAccessor implements IFullDataAccessor
|
||||
{
|
||||
if (target.mapping.equals(this.mapping))
|
||||
{
|
||||
target.dataArrays[target.dataArrayIndex] = this.dataArrays[this.dataArrayIndex].clone();
|
||||
System.arraycopy(this.dataArrays[this.dataArrayIndex], 0, target.dataArrays[target.dataArrayIndex], 0, this.dataArrays[this.dataArrayIndex].length);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+131
-19
@@ -23,35 +23,49 @@ import com.google.common.collect.HashMultimap;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource;
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.FullDataMetaFile;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataInputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public abstract class AbstractFullDataSourceLoader
|
||||
{
|
||||
public static final HashMultimap<Class<? extends IFullDataSource>, AbstractFullDataSourceLoader> LOADER_REGISTRY = HashMultimap.create();
|
||||
public static final HashMap<Long, Class<? extends IFullDataSource>> DATATYPE_ID_REGISTRY = new HashMap<>();
|
||||
|
||||
private static final int AVAILABLE_PROCESSOR_COUNT = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
|
||||
public static final HashMultimap<Class<? extends IFullDataSource>, AbstractFullDataSourceLoader> loaderRegistry = HashMultimap.create();
|
||||
public final Class<? extends IFullDataSource> fullDataSourceClass;
|
||||
public static final HashMap<Long, Class<? extends IFullDataSource>> datatypeIdRegistry = new HashMap<>();
|
||||
|
||||
public final long datatypeId;
|
||||
public final byte[] loaderSupportedVersions;
|
||||
|
||||
/** used when pooling data sources */
|
||||
private final ArrayList<IFullDataSource> cachedSources = new ArrayList<>();
|
||||
private final ReadWriteLock cacheReadWriteLock = new ReentrantReadWriteLock();
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public AbstractFullDataSourceLoader(Class<? extends IFullDataSource> fullDataSourceClass, long datatypeId, byte[] loaderSupportedVersions)
|
||||
{
|
||||
this.datatypeId = datatypeId;
|
||||
this.loaderSupportedVersions = loaderSupportedVersions;
|
||||
Arrays.sort(loaderSupportedVersions); // sort to allow fast access
|
||||
this.fullDataSourceClass = fullDataSourceClass;
|
||||
if (datatypeIdRegistry.containsKey(datatypeId) && datatypeIdRegistry.get(datatypeId) != fullDataSourceClass)
|
||||
if (DATATYPE_ID_REGISTRY.containsKey(datatypeId) && DATATYPE_ID_REGISTRY.get(datatypeId) != fullDataSourceClass)
|
||||
{
|
||||
throw new IllegalArgumentException("Loader for datatypeId " + datatypeId + " already registered with different class: "
|
||||
+ datatypeIdRegistry.get(datatypeId) + " != " + fullDataSourceClass);
|
||||
+ DATATYPE_ID_REGISTRY.get(datatypeId) + " != " + fullDataSourceClass);
|
||||
}
|
||||
Set<AbstractFullDataSourceLoader> loaders = loaderRegistry.get(fullDataSourceClass);
|
||||
Set<AbstractFullDataSourceLoader> loaders = LOADER_REGISTRY.get(fullDataSourceClass);
|
||||
if (loaders.stream().anyMatch(other ->
|
||||
{
|
||||
// see if any loaderSupportsVersion conflicts with this one
|
||||
@@ -68,31 +82,129 @@ public abstract class AbstractFullDataSourceLoader
|
||||
throw new IllegalArgumentException("Loader for class " + fullDataSourceClass + " that supports one of the version in "
|
||||
+ Arrays.toString(loaderSupportedVersions) + " already registered!");
|
||||
}
|
||||
datatypeIdRegistry.put(datatypeId, fullDataSourceClass);
|
||||
loaderRegistry.put(fullDataSourceClass, this);
|
||||
DATATYPE_ID_REGISTRY.put(datatypeId, fullDataSourceClass);
|
||||
LOADER_REGISTRY.put(fullDataSourceClass, this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// loader getters //
|
||||
//================//
|
||||
|
||||
public static AbstractFullDataSourceLoader getLoader(long dataTypeId, byte dataVersion)
|
||||
{
|
||||
return LOADER_REGISTRY.get(DATATYPE_ID_REGISTRY.get(dataTypeId)).stream()
|
||||
.filter(loader -> Arrays.binarySearch(loader.loaderSupportedVersions, dataVersion) >= 0)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public static AbstractFullDataSourceLoader getLoader(Class<? extends IFullDataSource> clazz, byte dataVersion)
|
||||
{
|
||||
return LOADER_REGISTRY.get(clazz).stream()
|
||||
.filter(loader -> Arrays.binarySearch(loader.loaderSupportedVersions, dataVersion) >= 0)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// abstract methods //
|
||||
//==================//
|
||||
|
||||
protected abstract IFullDataSource createEmptyDataSource(DhSectionPos pos);
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// data loading //
|
||||
//==============//
|
||||
|
||||
/**
|
||||
* Can return null if any of the requirements aren't met.
|
||||
*
|
||||
* @throws InterruptedException if the loader thread is interrupted, generally happens when the level is shutting down
|
||||
*/
|
||||
public abstract IFullDataSource loadData(FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException, InterruptedException;
|
||||
|
||||
|
||||
|
||||
public static AbstractFullDataSourceLoader getLoader(long dataTypeId, byte dataVersion)
|
||||
public IFullDataSource loadDataSource(FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
return loaderRegistry.get(datatypeIdRegistry.get(dataTypeId)).stream()
|
||||
.filter(l -> Arrays.binarySearch(l.loaderSupportedVersions, dataVersion) >= 0)
|
||||
.findFirst().orElse(null);
|
||||
IFullDataSource dataSource = this.createEmptyDataSource(dataFile.pos);
|
||||
dataSource.populateFromStream(dataFile, inputStream, level);
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
public static AbstractFullDataSourceLoader getLoader(Class<? extends IFullDataSource> clazz, byte dataVersion)
|
||||
/** Should be used in conjunction with {@link AbstractFullDataSourceLoader#returnPooledDataSource} to return the pooled sources. */
|
||||
public IFullDataSource loadTemporaryDataSource(FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
return loaderRegistry.get(clazz).stream()
|
||||
.filter(loader -> Arrays.binarySearch(loader.loaderSupportedVersions, dataVersion) >= 0)
|
||||
.findFirst().orElse(null);
|
||||
IFullDataSource dataSource = this.tryGetPooledSource();
|
||||
if (dataSource != null)
|
||||
{
|
||||
dataSource.repopulateFromStream(dataFile, inputStream, level);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataSource = this.loadDataSource(dataFile, inputStream, level);
|
||||
}
|
||||
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=====================//
|
||||
// data source pooling //
|
||||
//=====================//
|
||||
|
||||
/** @return null if no pooled source exists */
|
||||
public IFullDataSource tryGetPooledSource()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.cacheReadWriteLock.readLock().lock();
|
||||
|
||||
int index = this.cachedSources.size() - 1;
|
||||
if (index == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.cachedSources.remove(index);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.cacheReadWriteLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Doesn't have to be called, if a data source isn't returned, nothing will be leaked.
|
||||
* It just means a new source must be constructed next time {@link AbstractFullDataSourceLoader#tryGetPooledSource} is called.
|
||||
*/
|
||||
public void returnPooledDataSource(IFullDataSource dataSource)
|
||||
{
|
||||
if (dataSource == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (dataSource.getClass() != this.fullDataSourceClass)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (this.cachedSources.size() > 25)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.cacheReadWriteLock.writeLock().lock();
|
||||
this.cachedSources.add(dataSource);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.cacheReadWriteLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-10
@@ -30,18 +30,10 @@ import java.io.IOException;
|
||||
|
||||
public class CompleteFullDataSourceLoader extends AbstractFullDataSourceLoader
|
||||
{
|
||||
public CompleteFullDataSourceLoader()
|
||||
{
|
||||
super(CompleteFullDataSource.class, CompleteFullDataSource.TYPE_ID, new byte[]{CompleteFullDataSource.DATA_FORMAT_VERSION});
|
||||
}
|
||||
public CompleteFullDataSourceLoader() { super(CompleteFullDataSource.class, CompleteFullDataSource.TYPE_ID, new byte[]{CompleteFullDataSource.DATA_FORMAT_VERSION}); }
|
||||
|
||||
@Override
|
||||
public IFullDataSource loadData(FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
CompleteFullDataSource dataSource = CompleteFullDataSource.createEmpty(dataFile.pos);
|
||||
dataSource.populateFromStream(dataFile, inputStream, level);
|
||||
return dataSource;
|
||||
}
|
||||
protected IFullDataSource createEmptyDataSource(DhSectionPos pos) { return CompleteFullDataSource.createEmpty(pos); }
|
||||
|
||||
/** Uses a given stream to create a temporary {@link CompleteFullDataSource}, which is not saved. */
|
||||
public CompleteFullDataSource loadData(DhSectionPos pos, DhDataInputStream inputStream, IDhLevel level) throws IOException, InterruptedException
|
||||
|
||||
+4
-10
@@ -19,9 +19,11 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.dataObjects.fullData.loader;
|
||||
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.CompleteFullDataSource;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource;
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.FullDataMetaFile;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataInputStream;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.HighDetailIncompleteFullDataSource;
|
||||
|
||||
@@ -29,17 +31,9 @@ import java.io.IOException;
|
||||
|
||||
public class HighDetailIncompleteFullDataSourceLoader extends AbstractFullDataSourceLoader
|
||||
{
|
||||
public HighDetailIncompleteFullDataSourceLoader()
|
||||
{
|
||||
super(HighDetailIncompleteFullDataSource.class, HighDetailIncompleteFullDataSource.TYPE_ID, new byte[]{HighDetailIncompleteFullDataSource.DATA_FORMAT_VERSION});
|
||||
}
|
||||
public HighDetailIncompleteFullDataSourceLoader() { super(HighDetailIncompleteFullDataSource.class, HighDetailIncompleteFullDataSource.TYPE_ID, new byte[]{HighDetailIncompleteFullDataSource.DATA_FORMAT_VERSION}); }
|
||||
|
||||
@Override
|
||||
public IFullDataSource loadData(FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
HighDetailIncompleteFullDataSource dataSource = HighDetailIncompleteFullDataSource.createEmpty(dataFile.pos);
|
||||
dataSource.populateFromStream(dataFile, inputStream, level);
|
||||
return dataSource;
|
||||
}
|
||||
protected IFullDataSource createEmptyDataSource(DhSectionPos pos) { return HighDetailIncompleteFullDataSource.createEmpty(pos); }
|
||||
|
||||
}
|
||||
|
||||
+4
-10
@@ -19,9 +19,11 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.dataObjects.fullData.loader;
|
||||
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.CompleteFullDataSource;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IFullDataSource;
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.FullDataMetaFile;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataInputStream;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.LowDetailIncompleteFullDataSource;
|
||||
|
||||
@@ -29,17 +31,9 @@ import java.io.IOException;
|
||||
|
||||
public class LowDetailIncompleteFullDataSourceLoader extends AbstractFullDataSourceLoader
|
||||
{
|
||||
public LowDetailIncompleteFullDataSourceLoader()
|
||||
{
|
||||
super(LowDetailIncompleteFullDataSource.class, LowDetailIncompleteFullDataSource.TYPE_ID, new byte[]{LowDetailIncompleteFullDataSource.DATA_FORMAT_VERSION});
|
||||
}
|
||||
public LowDetailIncompleteFullDataSourceLoader() { super(LowDetailIncompleteFullDataSource.class, LowDetailIncompleteFullDataSource.TYPE_ID, new byte[]{LowDetailIncompleteFullDataSource.DATA_FORMAT_VERSION}); }
|
||||
|
||||
@Override
|
||||
public IFullDataSource loadData(FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
LowDetailIncompleteFullDataSource dataSource = LowDetailIncompleteFullDataSource.createEmpty(dataFile.pos);
|
||||
dataSource.populateFromStream(dataFile, inputStream, level);
|
||||
return dataSource;
|
||||
}
|
||||
protected IFullDataSource createEmptyDataSource(DhSectionPos pos) { return LowDetailIncompleteFullDataSource.createEmpty(pos); }
|
||||
|
||||
}
|
||||
|
||||
+39
-10
@@ -43,6 +43,7 @@ import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.CheckForNull;
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -64,7 +65,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu
|
||||
/** written to the binary file to mark what {@link IFullDataSource} the binary file corresponds to */
|
||||
public static final long TYPE_ID = "CompleteFullDataSource".hashCode();
|
||||
|
||||
private final DhSectionPos sectionPos;
|
||||
private DhSectionPos sectionPos;
|
||||
private boolean isEmpty = true;
|
||||
public EDhApiWorldGenerationStep worldGenStep = EDhApiWorldGenerationStep.EMPTY;
|
||||
|
||||
@@ -96,7 +97,6 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu
|
||||
// stream handling //
|
||||
//=================//
|
||||
|
||||
|
||||
@Override
|
||||
public void writeSourceSummaryInfo(IDhLevel level, DhDataOutputStream outputStream) throws IOException
|
||||
{
|
||||
@@ -107,7 +107,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu
|
||||
|
||||
}
|
||||
@Override
|
||||
public FullDataSourceSummaryData readSourceSummaryInfo(@CheckForNull FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException
|
||||
public FullDataSourceSummaryData readSourceSummaryInfo(FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException
|
||||
{
|
||||
int dataDetail = inputStream.readInt();
|
||||
if (dataFile != null && dataFile.baseMetaData != null && dataDetail != dataFile.baseMetaData.dataLevel)
|
||||
@@ -205,12 +205,33 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu
|
||||
|
||||
|
||||
|
||||
long[][] dataPointArray = new long[width * width][];
|
||||
long[][] dataPointArrays;
|
||||
if (this.width == width) // attempt to use the existing dataArrays if possible
|
||||
{
|
||||
dataPointArrays = this.dataArrays;
|
||||
}
|
||||
else
|
||||
{
|
||||
dataPointArrays = new long[width * width][];
|
||||
}
|
||||
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
for (int z = 0; z < width; z++)
|
||||
{
|
||||
dataPointArray[x * width + z] = new long[dataInputStream.readInt()];
|
||||
int requestedArrayLength = dataInputStream.readInt();
|
||||
int arrayIndex = x * width + z;
|
||||
|
||||
// attempt to use the existing dataArrays if possible
|
||||
if (dataPointArrays[arrayIndex] == null || dataPointArrays[arrayIndex].length != requestedArrayLength)
|
||||
{
|
||||
dataPointArrays[arrayIndex] = new long[requestedArrayLength];
|
||||
}
|
||||
else
|
||||
{
|
||||
// clear the existing array to prevent any data leakage
|
||||
Arrays.fill(dataPointArrays[arrayIndex], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,20 +244,20 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu
|
||||
throw new IOException("invalid data length end guard");
|
||||
}
|
||||
|
||||
for (int xz = 0; xz < dataPointArray.length; xz++) // x and z are combined
|
||||
for (int xz = 0; xz < dataPointArrays.length; xz++) // x and z are combined
|
||||
{
|
||||
if (dataPointArray[xz].length != 0)
|
||||
if (dataPointArrays[xz].length != 0)
|
||||
{
|
||||
for (int y = 0; y < dataPointArray[xz].length; y++)
|
||||
for (int y = 0; y < dataPointArrays[xz].length; y++)
|
||||
{
|
||||
dataPointArray[xz][y] = dataInputStream.readLong();
|
||||
dataPointArrays[xz][y] = dataInputStream.readLong();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return dataPointArray;
|
||||
return dataPointArrays;
|
||||
}
|
||||
@Override
|
||||
public void setDataPoints(long[][] dataPoints)
|
||||
@@ -418,6 +439,14 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu
|
||||
|
||||
@Override
|
||||
public DhSectionPos getSectionPos() { return this.sectionPos; }
|
||||
|
||||
@Override
|
||||
public void resizeDataStructuresForRepopulation(DhSectionPos pos)
|
||||
{
|
||||
// no data structures need to be changed, only the source's position
|
||||
this.sectionPos = pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getDataDetailLevel() { return (byte) (this.sectionPos.getDetailLevel() - SECTION_SIZE_OFFSET); }
|
||||
|
||||
|
||||
+45
-13
@@ -77,12 +77,12 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
|
||||
|
||||
|
||||
protected final FullDataPointIdMap mapping;
|
||||
private final DhSectionPos sectionPos;
|
||||
private final FullDataArrayAccessor[] sparseData;
|
||||
private final DhLodPos chunkPos;
|
||||
private DhSectionPos sectionPos;
|
||||
private FullDataArrayAccessor[] sparseData;
|
||||
private DhLodPos chunkPos;
|
||||
|
||||
public final int sectionCount;
|
||||
public final int dataPointsPerSection;
|
||||
public int sectionCount;
|
||||
public int dataPointsPerSection;
|
||||
public boolean isEmpty = true;
|
||||
public EDhApiWorldGenerationStep worldGenStep = EDhApiWorldGenerationStep.EMPTY;
|
||||
private boolean isPromoted = false;
|
||||
@@ -362,7 +362,18 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
|
||||
{
|
||||
for (int dataPointColIndex = 0; dataPointColIndex < dataPoints[arrayAccessorIndex].length; dataPointColIndex++)
|
||||
{
|
||||
System.arraycopy(dataPoints[arrayAccessorIndex][dataPointColIndex], 0, this.sparseData[arrayAccessorIndex].get(dataPointColIndex).getRaw(), 0, dataPoints[dataPointColIndex].length);
|
||||
long[] incomingColumn = dataPoints[arrayAccessorIndex][dataPointColIndex];
|
||||
long[] destinationColumn = this.sparseData[arrayAccessorIndex].get(dataPointColIndex).getRaw();
|
||||
|
||||
// use the existing arrays if possible
|
||||
if (incomingColumn.length == destinationColumn.length)
|
||||
{
|
||||
System.arraycopy(incomingColumn, 0, destinationColumn, 0, incomingColumn.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.sparseData[arrayAccessorIndex].get(dataPointColIndex).setNew(incomingColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -384,10 +395,10 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeIdMappings(DhDataOutputStream outputStream) throws IOException
|
||||
public void writeIdMappings(DhDataOutputStream dataOutputStream) throws IOException
|
||||
{
|
||||
outputStream.writeInt(IFullDataSource.DATA_GUARD_BYTE);
|
||||
this.mapping.serialize(outputStream);
|
||||
dataOutputStream.writeInt(IFullDataSource.DATA_GUARD_BYTE);
|
||||
this.mapping.serialize(dataOutputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -419,16 +430,37 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
|
||||
// getters //
|
||||
//=========//
|
||||
|
||||
@Override
|
||||
public DhSectionPos getSectionPos() { return this.sectionPos; }
|
||||
@Override
|
||||
@Override
|
||||
public DhSectionPos getSectionPos() { return this.sectionPos; }
|
||||
|
||||
@Override
|
||||
public void resizeDataStructuresForRepopulation(DhSectionPos pos)
|
||||
{
|
||||
// update the position
|
||||
this.sectionPos = pos;
|
||||
this.sectionCount = BitShiftUtil.powerOfTwo(this.sectionPos.getDetailLevel() - SPARSE_UNIT_DETAIL);
|
||||
this.dataPointsPerSection = SECTION_SIZE / this.sectionCount;
|
||||
|
||||
this.chunkPos = this.sectionPos.getMinCornerLodPos(SPARSE_UNIT_DETAIL);
|
||||
|
||||
|
||||
// update the data container
|
||||
int dataPointCount = this.sectionCount * this.sectionCount;
|
||||
if (this.sparseData.length != dataPointCount)
|
||||
{
|
||||
this.sparseData = new FullDataArrayAccessor[this.sectionCount * this.sectionCount];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getDataDetailLevel() { return (byte) (this.sectionPos.getDetailLevel() - SECTION_SIZE_OFFSET); }
|
||||
|
||||
@Override
|
||||
public long getTypeId() { return TYPE_ID; }
|
||||
|
||||
@Override
|
||||
public byte getBinaryDataFormatVersion() { return DATA_FORMAT_VERSION; }
|
||||
public byte getBinaryDataFormatVersion() { return DATA_FORMAT_VERSION; }
|
||||
|
||||
@Override
|
||||
public EDhApiWorldGenerationStep getWorldGenStep() { return this.worldGenStep; }
|
||||
|
||||
+32
-34
@@ -67,7 +67,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp
|
||||
public static final long TYPE_ID = "LowDetailIncompleteFullDataSource".hashCode();
|
||||
|
||||
|
||||
private final DhSectionPos sectionPos;
|
||||
private DhSectionPos sectionPos;
|
||||
private final BitSet isColumnNotEmpty;
|
||||
|
||||
private boolean isEmpty = true;
|
||||
@@ -294,6 +294,14 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp
|
||||
|
||||
@Override
|
||||
public DhSectionPos getSectionPos() { return this.sectionPos; }
|
||||
|
||||
@Override
|
||||
public void resizeDataStructuresForRepopulation(DhSectionPos pos)
|
||||
{
|
||||
// no data structures need to be changed, only the source's position
|
||||
this.sectionPos = pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getDataDetailLevel() { return (byte) (this.sectionPos.getDetailLevel() - SECTION_SIZE_OFFSET); }
|
||||
@Override
|
||||
@@ -441,46 +449,36 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp
|
||||
}
|
||||
}
|
||||
|
||||
private void sampleFrom(CompleteFullDataSource completeSource)
|
||||
private void sampleFrom(CompleteFullDataSource inputSource)
|
||||
{
|
||||
DhSectionPos pos = completeSource.getSectionPos();
|
||||
DhSectionPos inputPos = inputSource.getSectionPos();
|
||||
this.isEmpty = false;
|
||||
this.downsampleFrom(completeSource);
|
||||
|
||||
if (this.getDataDetailLevel() > this.sectionPos.getDetailLevel()) // TODO what does this mean?
|
||||
|
||||
DhLodPos baseOffset = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel());
|
||||
DhSectionPos inputOffset = inputPos.convertNewToDetailLevel(this.getDataDetailLevel());
|
||||
int offsetX = inputOffset.getX() - baseOffset.x;
|
||||
int offsetZ = inputOffset.getZ() - baseOffset.z;
|
||||
|
||||
|
||||
int numberOfDataPointsToUpdate = WIDTH / this.sectionPos.getWidthCountForLowerDetailedSection(inputSource.getSectionPos().getDetailLevel()); // can be 0 if the input source is significantly smaller than this data source
|
||||
// should be 1 at minimum, to prevent divide by zero errors (and because trying to get 0 data points doesn't make any sense)
|
||||
numberOfDataPointsToUpdate = Math.max(1, numberOfDataPointsToUpdate);
|
||||
|
||||
|
||||
int inputFractionWidth = inputSource.width() / numberOfDataPointsToUpdate;
|
||||
for (int x = 0; x < numberOfDataPointsToUpdate; x++)
|
||||
{
|
||||
DhLodPos thisLodPos = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel());
|
||||
DhLodPos dataLodPos = pos.getMinCornerLodPos(this.getDataDetailLevel());
|
||||
|
||||
int offsetX = dataLodPos.x - thisLodPos.x;
|
||||
int offsetZ = dataLodPos.z - thisLodPos.z;
|
||||
int dataWidth = this.sectionPos.getWidthCountForLowerDetailedSection(this.getDataDetailLevel());
|
||||
|
||||
for (int xOffset = 0; xOffset < dataWidth; xOffset++)
|
||||
for (int z = 0; z < numberOfDataPointsToUpdate; z++)
|
||||
{
|
||||
for (int zOffset = 0; zOffset < dataWidth; zOffset++)
|
||||
{
|
||||
this.isColumnNotEmpty.set((offsetX + xOffset) * WIDTH + offsetZ + zOffset, true);
|
||||
}
|
||||
SingleColumnFullDataAccessor thisDataColumn = this.get(offsetX + x, offsetZ + z);
|
||||
SingleColumnFullDataAccessor inputDataColumn = inputSource.get(inputFractionWidth * x, inputFractionWidth * z);
|
||||
inputDataColumn.deepCopyTo(thisDataColumn);
|
||||
|
||||
int notEmptyIndex = (offsetX + x) * WIDTH + (offsetZ + z);
|
||||
this.isColumnNotEmpty.set(notEmptyIndex, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DhLodPos dataPos = pos.getSectionBBoxPos();
|
||||
int lowerSectionsPerData = this.sectionPos.getWidthCountForLowerDetailedSection(dataPos.detailLevel);
|
||||
if (dataPos.x % lowerSectionsPerData != 0 || dataPos.z % lowerSectionsPerData != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
DhLodPos basePos = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel());
|
||||
dataPos = dataPos.convertToDetailLevel(this.getDataDetailLevel());
|
||||
int offsetX = dataPos.x - basePos.x;
|
||||
int offsetZ = dataPos.z - basePos.z;
|
||||
this.isColumnNotEmpty.set(offsetX * WIDTH + offsetZ, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sampleFrom(LowDetailIncompleteFullDataSource spottySource)
|
||||
|
||||
+7
@@ -279,4 +279,11 @@ public interface IFullDataSource
|
||||
*/
|
||||
void populateFromStream(FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException, InterruptedException;
|
||||
|
||||
/**
|
||||
* Should only be implemented by {@link IStreamableFullDataSource} to prevent potential stream read/write inconsistencies.
|
||||
*
|
||||
* @see IStreamableFullDataSource#repopulateFromStream(FullDataMetaFile, DhDataInputStream, IDhLevel)
|
||||
*/
|
||||
void repopulateFromStream(FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException, InterruptedException;
|
||||
|
||||
}
|
||||
|
||||
+23
-8
@@ -22,11 +22,10 @@ package com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces;
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.FullDataPointIdMap;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.FullDataArrayAccessor;
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.FullDataMetaFile;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataInputStream;
|
||||
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataOutputStream;
|
||||
import com.seibel.distanthorizons.core.util.objects.dataStreams.*;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -40,8 +39,6 @@ import java.io.IOException;
|
||||
*
|
||||
* @param <SummaryDataType> defines the object holding this data source's summary data, extends {@link IStreamableFullDataSource.FullDataSourceSummaryData}.
|
||||
* @param <DataContainerType> defines the object holding the data points, probably long[][] or long[][][].
|
||||
* @apiNote James would've preferred to have this as an abstract class,
|
||||
* however that is impossible. See the apiNote in
|
||||
* {@link IStreamableFullDataSource#populateFromStream(FullDataMetaFile, DhDataInputStream, IDhLevel) populateFromStream}
|
||||
* for the full reasoning.
|
||||
*/
|
||||
@@ -52,14 +49,28 @@ public interface IStreamableFullDataSource<SummaryDataType extends IStreamableFu
|
||||
// stream handling //
|
||||
//=================//
|
||||
|
||||
/**
|
||||
* Clears and then overwrites any data in this object with the data from the given file and stream.
|
||||
* This is expected to be used with an existing {@link IStreamableFullDataSource} and can be used in place of a constructor to reuse an existing {@link IStreamableFullDataSource} object.
|
||||
*
|
||||
* @see IStreamableFullDataSource#populateFromStream
|
||||
*/
|
||||
@Override
|
||||
default void repopulateFromStream(FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
// clear/overwrite the old data
|
||||
this.resizeDataStructuresForRepopulation(dataFile.pos);
|
||||
this.getMapping().clear(dataFile.pos);
|
||||
|
||||
// set the new data
|
||||
this.populateFromStream(dataFile, inputStream, level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites any data in this object with the data from the given file and stream.
|
||||
* This is expected to be used with an empty {@link IStreamableFullDataSource} and functions similar to a constructor.
|
||||
*
|
||||
* @apiNote James would've preferred that {@link IStreamableFullDataSource} was an abstract class,
|
||||
* so this could've been a constructor.
|
||||
* However, several inheritors of this interface already extend {@link FullDataArrayAccessor}, making that impossible.
|
||||
*/
|
||||
@Override
|
||||
default void populateFromStream(FullDataMetaFile dataFile, DhDataInputStream inputStream, IDhLevel level) throws IOException, InterruptedException
|
||||
{
|
||||
SummaryDataType summaryData = this.readSourceSummaryInfo(dataFile, inputStream, level);
|
||||
@@ -79,6 +90,7 @@ public interface IStreamableFullDataSource<SummaryDataType extends IStreamableFu
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
default void writeToStream(DhDataOutputStream outputStream, IDhLevel level) throws IOException
|
||||
{
|
||||
this.writeSourceSummaryInfo(level, outputStream);
|
||||
@@ -94,6 +106,9 @@ public interface IStreamableFullDataSource<SummaryDataType extends IStreamableFu
|
||||
|
||||
|
||||
|
||||
/** Note: this should only be used if the data source is being reused. Normally data sources shouldn't change. */
|
||||
void resizeDataStructuresForRepopulation(DhSectionPos pos);
|
||||
|
||||
/**
|
||||
* Includes information about the source file that doesn't need to be saved in each data point. Like the source's size and y-level.
|
||||
*/
|
||||
|
||||
+3
-14
@@ -45,7 +45,7 @@ import java.util.concurrent.*;
|
||||
*
|
||||
* @see ColumnRenderBufferBuilder
|
||||
*/
|
||||
public class ColumnRenderBuffer extends AbstractRenderBuffer implements IDebugRenderable
|
||||
public class ColumnRenderBuffer extends AbstractRenderBuffer
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
@@ -71,19 +71,8 @@ public class ColumnRenderBuffer extends AbstractRenderBuffer implements IDebugRe
|
||||
{
|
||||
this.pos = pos;
|
||||
this.debugPos = debugPos;
|
||||
vbos = new GLVertexBuffer[0];
|
||||
vbosTransparent = new GLVertexBuffer[0];
|
||||
DebugRenderer.register(this);
|
||||
}
|
||||
|
||||
public void debugRender(DebugRenderer r)
|
||||
{
|
||||
if (closed || vbos == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Color c = Color.green;
|
||||
//r.renderBox(debugPos, 128, 128, 0.05f, c);
|
||||
this.vbos = new GLVertexBuffer[0];
|
||||
this.vbosTransparent = new GLVertexBuffer[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
+5
-4
@@ -69,8 +69,7 @@ public class FullDataToRenderDataTransformer
|
||||
// public transformer interface //
|
||||
//==============================//
|
||||
|
||||
public static CompletableFuture<ColumnRenderSource> transformFullDataToRenderSourceAsync(IFullDataSource fullDataSource, IDhClientLevel level) { return CompletableFuture.supplyAsync(() -> transformFullDataToRenderSource(fullDataSource, level), transformerThreadPool); }
|
||||
public static CompletableFuture<ColumnRenderSource> transformFullDataToRenderSourceAsync(CompletableFuture<IFullDataSource> fullDataSourceFuture, IDhClientLevel level) { return fullDataSourceFuture.thenApplyAsync((fullDataSource) -> transformFullDataToRenderSource(fullDataSource, level), transformerThreadPool); }
|
||||
public static CompletableFuture<ColumnRenderSource> transformFullDataToRenderSourceUsingExecutorAsync(IFullDataSource fullDataSource, IDhClientLevel level) { return CompletableFuture.supplyAsync(() -> transformFullDataToRenderSource(fullDataSource, level), transformerThreadPool); }
|
||||
private static ColumnRenderSource transformFullDataToRenderSource(IFullDataSource fullDataSource, IDhClientLevel level)
|
||||
{
|
||||
if (fullDataSource == null)
|
||||
@@ -184,9 +183,11 @@ public class FullDataToRenderDataTransformer
|
||||
{
|
||||
int baseX = pos.getMinCornerLodPos().getCornerBlockPos().x;
|
||||
int baseZ = pos.getMinCornerLodPos().getCornerBlockPos().z;
|
||||
for (int x = 0; x < pos.getWidthCountForLowerDetailedSection(dataDetail); x++)
|
||||
|
||||
int width = pos.getWidthCountForLowerDetailedSection(dataDetail);
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
for (int z = 0; z < pos.getWidthCountForLowerDetailedSection(dataDetail); z++)
|
||||
for (int z = 0; z < width; z++)
|
||||
{
|
||||
throwIfThreadInterrupted();
|
||||
|
||||
|
||||
+76
-21
@@ -32,12 +32,14 @@ import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhLodPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.render.renderer.DebugRenderer;
|
||||
import com.seibel.distanthorizons.core.util.MetaFileScanUtil;
|
||||
import com.seibel.distanthorizons.core.util.FileUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.MetaFileScanUtil;
|
||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@@ -394,28 +396,81 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
LowDetailIncompleteFullDataSource.createEmpty(pos);
|
||||
}
|
||||
|
||||
/** populates the given data source using the given array of files */
|
||||
protected CompletableFuture<IIncompleteFullDataSource> sampleFromFileArray(IIncompleteFullDataSource recipientFullDataSource, ArrayList<FullDataMetaFile> existingFiles)
|
||||
/**
|
||||
* Populates the given data source using the given array of files
|
||||
* @param usePooledDataSources if enabled the data sources necessary for this sampling will not be stored beyond what is necessary for the sampling.
|
||||
* This helps reduce garbage collector pressure if the data sources will never be used again.
|
||||
*/
|
||||
protected CompletableFuture<IIncompleteFullDataSource> sampleFromFileArray(IIncompleteFullDataSource recipientFullDataSource, ArrayList<FullDataMetaFile> existingFiles, boolean usePooledDataSources)
|
||||
{
|
||||
// read in the existing data
|
||||
final ArrayList<CompletableFuture<Void>> loadDataFutures = new ArrayList<>(existingFiles.size());
|
||||
for (FullDataMetaFile existingFile : existingFiles)
|
||||
boolean showFullDataFileSampling = Config.Client.Advanced.Debugging.DebugWireframe.showFullDataFileSampling.get();
|
||||
if (showFullDataFileSampling)
|
||||
{
|
||||
loadDataFutures.add(existingFile.getOrLoadCachedDataSourceAsync()
|
||||
.exceptionally((ex) -> /*Ignore file read errors*/null)
|
||||
.thenAccept((existingFullDataSource) ->
|
||||
{
|
||||
if (existingFullDataSource == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//LOGGER.info("Merging data from {} into {}", data.getSectionPos(), pos);
|
||||
recipientFullDataSource.sampleFrom(existingFullDataSource);
|
||||
})
|
||||
);
|
||||
DebugRenderer.makeParticle(new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(recipientFullDataSource.getSectionPos(), 64f, 72f, 0.03f, Color.MAGENTA),
|
||||
0.2, 32f));
|
||||
}
|
||||
return CompletableFuture.allOf(loadDataFutures.toArray(new CompletableFuture[0])).thenApply(voidObj -> recipientFullDataSource);
|
||||
|
||||
// read in the existing data
|
||||
final ArrayList<CompletableFuture<IFullDataSource>> sampleDataFutures = new ArrayList<>(existingFiles.size());
|
||||
for (int i = 0; i < existingFiles.size(); i++)
|
||||
{
|
||||
FullDataMetaFile existingFile = existingFiles.get(i);
|
||||
|
||||
|
||||
CompletableFuture<IFullDataSource> loadFileFuture = usePooledDataSources ? existingFile.getOrLoadCachedDataSourceAsync() : existingFile.getDataSourceWithoutCachingAsync();
|
||||
|
||||
CompletableFuture<IFullDataSource> sampleSourceFuture = loadFileFuture.whenComplete((existingFullDataSource, ex) ->
|
||||
{
|
||||
if (existingFullDataSource == null || ex != null)
|
||||
{
|
||||
// Ignore file read errors
|
||||
//LOGGER.warn(recipientFullDataSource.getSectionPos()+" sample from, file read error for file "+existingFile.pos+": "+ex.getMessage(), ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (showFullDataFileSampling)
|
||||
{
|
||||
DebugRenderer.makeParticle(new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(recipientFullDataSource.getSectionPos(), 64f, 72f, 0.03f, Color.MAGENTA.darker()),
|
||||
0.2, 32f));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
recipientFullDataSource.sampleFrom(existingFullDataSource);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warn("Unable to sample "+existingFullDataSource.getSectionPos()+" into "+recipientFullDataSource.getSectionPos(), e);
|
||||
//throw e;
|
||||
}
|
||||
|
||||
// pooling temporary data sources massively reduces garbage collector overhead when just sampling (going from ~8 GB/sec to ~90 MB/sec)
|
||||
if (!usePooledDataSources && !existingFile.cacheLoadingDataSource)
|
||||
{
|
||||
existingFile.clearCachedDataSource();
|
||||
|
||||
// get the data loader
|
||||
AbstractFullDataSourceLoader dataSourceLoader;
|
||||
if (existingFile.fullDataSourceLoader != null)
|
||||
{
|
||||
dataSourceLoader = existingFile.fullDataSourceLoader;
|
||||
}
|
||||
else
|
||||
{
|
||||
// shouldn't normally happen, but sometimes does
|
||||
dataSourceLoader = AbstractFullDataSourceLoader.getLoader(existingFile.baseMetaData.dataTypeId, existingFile.baseMetaData.binaryDataFormatVersion);
|
||||
}
|
||||
|
||||
dataSourceLoader.returnPooledDataSource(existingFullDataSource);
|
||||
}
|
||||
});
|
||||
|
||||
sampleDataFutures.add(sampleSourceFuture);
|
||||
}
|
||||
return CompletableFuture.allOf(sampleDataFutures.toArray(new CompletableFuture[0]))
|
||||
.thenApply(voidObj -> recipientFullDataSource);
|
||||
}
|
||||
|
||||
protected void makeFiles(ArrayList<DhSectionPos> posList, ArrayList<FullDataMetaFile> output)
|
||||
@@ -447,7 +502,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
else
|
||||
{
|
||||
this.makeFiles(missing, existFiles);
|
||||
return this.sampleFromFileArray(source, existFiles).thenApply(IIncompleteFullDataSource::tryPromotingToCompleteDataSource)
|
||||
return this.sampleFromFileArray(source, existFiles, true).thenApply(IIncompleteFullDataSource::tryPromotingToCompleteDataSource)
|
||||
.exceptionally((e) ->
|
||||
{
|
||||
FullDataMetaFile newMetaFile = this.removeCorruptedFile(pos, file, e);
|
||||
|
||||
+144
-20
@@ -87,6 +87,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
*/
|
||||
private DataSourceReferenceTracker.FullDataSourceSoftRef cachedFullDataSourceRef = new DataSourceReferenceTracker.FullDataSourceSoftRef(this,null);
|
||||
private final AtomicReference<CompletableFuture<IFullDataSource>> dataSourceLoadFutureRef = new AtomicReference<>(null);
|
||||
public volatile Boolean cacheLoadingDataSource = null;
|
||||
|
||||
// === Concurrent Write tracking ===
|
||||
private final AtomicReference<GuardedMultiAppendQueue> writeQueueRef = new AtomicReference<>(new GuardedMultiAppendQueue());
|
||||
@@ -113,7 +114,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
this.level = level;
|
||||
LodUtil.assertTrue(this.baseMetaData == null);
|
||||
this.doesFileExist = false;
|
||||
DebugRenderer.register(this);
|
||||
DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showFullDataFileStatus);
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +142,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
}
|
||||
|
||||
this.fullDataSourceClass = this.fullDataSourceLoader.fullDataSourceClass;
|
||||
DebugRenderer.register(this);
|
||||
DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showFullDataFileStatus);
|
||||
}
|
||||
|
||||
|
||||
@@ -160,14 +161,36 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
return this.cachedFullDataSourceRef.get();
|
||||
}
|
||||
|
||||
/** @return if any data was cleared */
|
||||
public boolean clearCachedDataSource()
|
||||
{
|
||||
boolean dataExists = this.cachedFullDataSourceRef.get() != null;
|
||||
if (dataExists)
|
||||
{
|
||||
this.cachedFullDataSourceRef.close();
|
||||
this.cachedFullDataSourceRef.clear();
|
||||
this.cacheLoadingDataSource = null;
|
||||
}
|
||||
|
||||
return dataExists;
|
||||
}
|
||||
|
||||
public CompletableFuture<IFullDataSource> getOrLoadCachedDataSourceAsync()
|
||||
|
||||
|
||||
public CompletableFuture<IFullDataSource> getDataSourceWithoutCachingAsync() { return this.getOrLoadCachedDataSourceAsync(false); }
|
||||
public CompletableFuture<IFullDataSource> getOrLoadCachedDataSourceAsync() { return this.getOrLoadCachedDataSourceAsync(true); }
|
||||
private CompletableFuture<IFullDataSource> getOrLoadCachedDataSourceAsync(boolean cacheLoadingSource)
|
||||
{
|
||||
checkAndLogPhantomDataSourceLifeCycles();
|
||||
|
||||
CompletableFuture<IFullDataSource> potentialLoadFuture = this.getCachedDataSourceAsync();
|
||||
if (potentialLoadFuture != null)
|
||||
{
|
||||
if (cacheLoadingSource)
|
||||
{
|
||||
this.cacheLoadingDataSource = true;
|
||||
}
|
||||
|
||||
// return the in-process future
|
||||
return potentialLoadFuture;
|
||||
}
|
||||
@@ -181,11 +204,13 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
// two threads attempted to start this job at the same time, only use the first future
|
||||
potentialLoadFuture = this.dataSourceLoadFutureRef.get();
|
||||
}
|
||||
|
||||
this.cacheLoadingDataSource = cacheLoadingSource;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CompletableFuture<IFullDataSource> dataSourceLoadFuture = potentialLoadFuture;
|
||||
final CompletableFuture<IFullDataSource> dataSourceLoadFuture = potentialLoadFuture;
|
||||
if (!this.doesFileExist)
|
||||
{
|
||||
// create a new Meta file and data source
|
||||
@@ -231,10 +256,21 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
try (FileInputStream fileInputStream = this.getFileInputStream();
|
||||
DhDataInputStream compressedStream = new DhDataInputStream(fileInputStream))
|
||||
{
|
||||
fullDataSource = this.fullDataSourceLoader.loadData(this, compressedStream, this.level);
|
||||
if (cacheLoadingSource)
|
||||
{
|
||||
fullDataSource = this.fullDataSourceLoader.loadDataSource(this, compressedStream, this.level);
|
||||
}
|
||||
else
|
||||
{
|
||||
fullDataSource = this.fullDataSourceLoader.loadTemporaryDataSource(this, compressedStream, this.level);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
/// TODO temporary fix
|
||||
dataSourceLoadFuture.completeExceptionally(ex);
|
||||
this.dataSourceLoadFutureRef.set(null);
|
||||
|
||||
// can happen if there is a missing file or the file was incorrectly formatted, or terminated early
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
@@ -373,11 +409,11 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
public CompletableFuture<Void> flushAndSaveAsync()
|
||||
{
|
||||
checkAndLogPhantomDataSourceLifeCycles();
|
||||
boolean isEmpty = this.writeQueueRef.get().queue.isEmpty() && !needsUpdate;
|
||||
boolean isEmpty = this.writeQueueRef.get().queue.isEmpty() && !this.needsUpdate;
|
||||
if (!isEmpty)
|
||||
{
|
||||
// This will flush the data to disk.
|
||||
return this.getOrLoadCachedDataSourceAsync().thenApply((fullDataSource) -> null /* ignore the result, just wait for the load to finish*/ );
|
||||
return this.getDataSourceWithoutCachingAsync().thenApply((fullDataSource) -> null /* ignore the result, just wait for the load to finish*/ );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -438,16 +474,22 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
return;
|
||||
}
|
||||
|
||||
IFullDataSource cached = this.cachedFullDataSourceRef.get();
|
||||
|
||||
|
||||
if (this.needsUpdate)
|
||||
{
|
||||
debugRenderer.renderBox(new DebugRenderer.Box(this.pos, 80f, 96f, 0.05f, Color.red));
|
||||
}
|
||||
|
||||
|
||||
IFullDataSource cachedDataSource = this.cachedFullDataSourceRef.get();
|
||||
boolean needsUpdate = !this.writeQueueRef.get().queue.isEmpty() || this.needsUpdate;
|
||||
|
||||
// determine the color
|
||||
Color color = Color.black;
|
||||
if (cached != null)
|
||||
if (cachedDataSource != null)
|
||||
{
|
||||
if (cached instanceof CompleteFullDataSource)
|
||||
if (cachedDataSource instanceof CompleteFullDataSource)
|
||||
{
|
||||
color = Color.GREEN;
|
||||
}
|
||||
@@ -455,7 +497,6 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
{
|
||||
color = Color.YELLOW;
|
||||
}
|
||||
|
||||
}
|
||||
else if (this.dataSourceLoadFutureRef.get() != null)
|
||||
{
|
||||
@@ -465,9 +506,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
{
|
||||
color = Color.RED;
|
||||
}
|
||||
|
||||
boolean needsUpdate = !this.writeQueueRef.get().queue.isEmpty() || this.needsUpdate;
|
||||
if (needsUpdate)
|
||||
else if (needsUpdate)
|
||||
{
|
||||
color = color.darker().darker();
|
||||
}
|
||||
@@ -557,16 +596,23 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
new DataObjSoftTracker(this, fullDataSource);
|
||||
}
|
||||
|
||||
if (this.pos.getDetailLevel() == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
|
||||
boolean showFullDataFileStatus = Config.Client.Advanced.Debugging.DebugWireframe.showFullDataFileStatus.get();
|
||||
boolean showFullDataFileSampling = Config.Client.Advanced.Debugging.DebugWireframe.showFullDataFileSampling.get();
|
||||
if (showFullDataFileStatus || showFullDataFileSampling)
|
||||
{
|
||||
Color color = dataSourceChanged ? Color.GREEN : Color.GREEN.darker().darker();
|
||||
DebugRenderer.makeParticle(new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(this.pos, 64f, 72f, 0.03f, Color.green.darker()),
|
||||
0.2, 32f));
|
||||
new DebugRenderer.Box(this.pos, 64f, 72f, 0.03f, color),
|
||||
0.2, 32f));
|
||||
}
|
||||
|
||||
|
||||
// save the updated data source
|
||||
this.cachedFullDataSourceRef = new DataSourceReferenceTracker.FullDataSourceSoftRef(this, fullDataSource);
|
||||
if (this.cacheLoadingDataSource)
|
||||
{
|
||||
// save the updated data source
|
||||
this.cachedFullDataSourceRef = new DataSourceReferenceTracker.FullDataSourceSoftRef(this, fullDataSource);
|
||||
}
|
||||
|
||||
// the task is complete
|
||||
completionFuture.complete(fullDataSource);
|
||||
@@ -575,13 +621,91 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
if (this.needsUpdate)
|
||||
{
|
||||
// another update was requested while this update was being processed
|
||||
this.getOrLoadCachedDataSourceAsync();
|
||||
if (this.cacheLoadingDataSource)
|
||||
{
|
||||
this.getOrLoadCachedDataSourceAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.getDataSourceWithoutCachingAsync();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return completionFuture;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
private void applyWriteQueueAndSave(IFullDataSource fullDataSourceToUpdate)
|
||||
{
|
||||
boolean dataChanged = this.applyWriteQueueToFullDataSource(fullDataSourceToUpdate);
|
||||
this.needsUpdate = false;
|
||||
|
||||
// attempt to promote the data source
|
||||
if (fullDataSourceToUpdate instanceof IIncompleteFullDataSource)
|
||||
{
|
||||
IFullDataSource newSource = ((IIncompleteFullDataSource) fullDataSourceToUpdate).tryPromotingToCompleteDataSource();
|
||||
dataChanged |= (newSource != fullDataSourceToUpdate);
|
||||
fullDataSourceToUpdate = newSource;
|
||||
}
|
||||
|
||||
|
||||
// the provider may need to modify other files based on this data source changing
|
||||
IFullDataSourceProvider.DataFileUpdateResult dataFileUpdateResult = this.fullDataSourceProvider.onDataFileUpdateAsync(fullDataSourceToUpdate, this, dataChanged);
|
||||
IFullDataSource fullDataSource = dataFileUpdateResult.fullDataSource;
|
||||
boolean dataSourceChanged = dataFileUpdateResult.dataSourceChanged;
|
||||
|
||||
|
||||
// only save to file if something was changed
|
||||
if (dataSourceChanged)
|
||||
{
|
||||
this.writeDataSource(fullDataSource);
|
||||
}
|
||||
|
||||
// keep track of non-null data sources
|
||||
if (fullDataSource != null)
|
||||
{
|
||||
new DataObjTracker(fullDataSource);
|
||||
new DataObjSoftTracker(this, fullDataSource);
|
||||
}
|
||||
|
||||
|
||||
boolean showFullDataFileStatus = Config.Client.Advanced.Debugging.DebugWireframe.showFullDataFileStatus.get();
|
||||
boolean showFullDataFileSampling = Config.Client.Advanced.Debugging.DebugWireframe.showFullDataFileSampling.get();
|
||||
if (showFullDataFileStatus || showFullDataFileSampling)
|
||||
{
|
||||
Color color;
|
||||
if (this.pos.getDetailLevel() == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
{
|
||||
color = Color.GREEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = Color.GREEN.darker().darker();
|
||||
}
|
||||
|
||||
DebugRenderer.makeParticle(new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(this.pos, 64f, 72f, 0.03f, color),
|
||||
0.2, 32f));
|
||||
}
|
||||
|
||||
|
||||
// save the updated data source
|
||||
this.cachedFullDataSourceRef = new DataSourceReferenceTracker.FullDataSourceSoftRef(this, fullDataSource);
|
||||
|
||||
|
||||
if (this.needsUpdate)
|
||||
{
|
||||
// another update was requested while this update was being processed
|
||||
this.getOrLoadCachedDataSourceAsync();
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/** @return true if the queue was not empty and chunk data was applied to this meta file's {@link IFullDataSource}. */
|
||||
private boolean applyWriteQueueToFullDataSource(IFullDataSource fullDataSource)
|
||||
{
|
||||
|
||||
+9
-8
@@ -139,11 +139,11 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
{
|
||||
ArrayList<FullDataMetaFile> existingFiles = new ArrayList<>();
|
||||
byte sectDetailLevel = (byte) (DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL + maxSectDataDetailLevel);
|
||||
pos.forEachChildAtLevel(sectDetailLevel, p -> existingFiles.add(getLoadOrMakeFile(p, true)));
|
||||
return sampleFromFileArray(dataSource, existingFiles).thenApply(this::tryPromoteDataSource)
|
||||
.exceptionally((e) ->
|
||||
pos.forEachChildAtLevel(sectDetailLevel, childPos -> existingFiles.add(this.getLoadOrMakeFile(childPos, true)));
|
||||
return this.sampleFromFileArray(dataSource, existingFiles, true).thenApply(this::tryPromoteDataSource)
|
||||
.exceptionally((ex) ->
|
||||
{
|
||||
FullDataMetaFile newMetaFile = removeCorruptedFile(pos, file, e);
|
||||
FullDataMetaFile newMetaFile = this.removeCorruptedFile(pos, file, ex);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
@@ -175,7 +175,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
|
||||
// Try update the gen queue on this data source. If null, then nothing was done.
|
||||
@Nullable
|
||||
private CompletableFuture<IFullDataSource> updateFromExistingDataSourcesAsync(FullDataMetaFile file, IIncompleteFullDataSource data)
|
||||
private CompletableFuture<IFullDataSource> updateFromExistingDataSourcesAsync(FullDataMetaFile file, IIncompleteFullDataSource data, boolean usePooledDataSources)
|
||||
{
|
||||
DhSectionPos pos = file.pos;
|
||||
ArrayList<FullDataMetaFile> existingFiles = new ArrayList<>();
|
||||
@@ -191,7 +191,8 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
{
|
||||
// There are other data source files to sample from.
|
||||
this.makeFiles(missingPositions, existingFiles);
|
||||
return this.sampleFromFileArray(data, existingFiles).thenApply(this::tryPromoteDataSource)
|
||||
return this.sampleFromFileArray(data, existingFiles, usePooledDataSources)
|
||||
.thenApply(this::tryPromoteDataSource)
|
||||
.exceptionally((e) ->
|
||||
{
|
||||
this.removeCorruptedFile(pos, file, e);
|
||||
@@ -205,7 +206,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
{
|
||||
DhSectionPos pos = file.pos;
|
||||
IIncompleteFullDataSource data = this.makeEmptyDataSource(pos);
|
||||
CompletableFuture<IFullDataSource> future = this.updateFromExistingDataSourcesAsync(file, data);
|
||||
CompletableFuture<IFullDataSource> future = this.updateFromExistingDataSourcesAsync(file, data, true);
|
||||
// Cant start gen task, so return the data
|
||||
return future == null ? CompletableFuture.completedFuture(data) : future;
|
||||
}
|
||||
@@ -228,7 +229,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
IWorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get();
|
||||
if (worldGenQueue != null)
|
||||
{
|
||||
CompletableFuture<IFullDataSource> future = this.updateFromExistingDataSourcesAsync(file, (IIncompleteFullDataSource) fullDataSource);
|
||||
CompletableFuture<IFullDataSource> future = this.updateFromExistingDataSourcesAsync(file, (IIncompleteFullDataSource) fullDataSource, false);
|
||||
if (future != null)
|
||||
{
|
||||
final boolean finalDataChanged = dataChanged;
|
||||
|
||||
+50
-36
@@ -66,7 +66,7 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements
|
||||
* When clearing, don't set to null, instead create a SoftReference containing null.
|
||||
* This makes null checks simpler.
|
||||
*/
|
||||
private DataSourceReferenceTracker.RenderDataSourceSoftRef cachedRenderDataSource = new DataSourceReferenceTracker.RenderDataSourceSoftRef(this, null);
|
||||
private DataSourceReferenceTracker.RenderDataSourceSoftRef cachedRenderDataSourceRef = new DataSourceReferenceTracker.RenderDataSourceSoftRef(this, null);
|
||||
private final AtomicReference<CompletableFuture<ColumnRenderSource>> renderSourceLoadFutureRef = new AtomicReference<>(null);
|
||||
|
||||
private final IDhClientLevel clientLevel;
|
||||
@@ -108,7 +108,7 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements
|
||||
this.clientLevel = clientLevel;
|
||||
LodUtil.assertTrue(this.baseMetaData == null);
|
||||
this.doesFileExist = this.file.exists();
|
||||
DebugRenderer.register(this);
|
||||
DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showRenderDataFileStatus);
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements
|
||||
this.clientLevel = clientLevel;
|
||||
LodUtil.assertTrue(this.baseMetaData != null);
|
||||
this.doesFileExist = this.file.exists();
|
||||
DebugRenderer.register(this);
|
||||
DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showRenderDataFileStatus);
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements
|
||||
LodUtil.assertTrue(this.pos.overlapsExactly(chunkSectionPos), "Chunk pos " + chunkSectionPos + " doesn't overlap with section " + this.pos);
|
||||
|
||||
// update the render source if one exists
|
||||
CompletableFuture<ColumnRenderSource> renderSourceLoadFuture = this.getCachedDataSourceAsync(false);
|
||||
CompletableFuture<ColumnRenderSource> renderSourceLoadFuture = this.getCachedDataSourceAsync(true);
|
||||
if (renderSourceLoadFuture == null)
|
||||
{
|
||||
return;
|
||||
@@ -148,17 +148,22 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements
|
||||
|
||||
renderSourceLoadFuture.thenAccept((renderSource) ->
|
||||
{
|
||||
boolean dataUpdated = renderSource.updateWithChunkData(chunkDataView, clientLevel);
|
||||
boolean dataUpdated = renderSource.updateWithChunkData(chunkDataView, this.clientLevel);
|
||||
|
||||
// add a debug renderer
|
||||
float offset = new Random(System.nanoTime() ^ Thread.currentThread().getId()).nextFloat() * 16f;
|
||||
Color debugColor = dataUpdated ? Color.blue : Color.red;
|
||||
DebugRenderer.makeParticle(
|
||||
new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(chunkDataView.getSectionPos(), 32f, 64f + offset, 0.07f, debugColor),
|
||||
2.0, 16f
|
||||
)
|
||||
);
|
||||
|
||||
// add a debug particle
|
||||
boolean showRenderDataFileStatus = Config.Client.Advanced.Debugging.DebugWireframe.showRenderDataFileStatus.get();
|
||||
if (showRenderDataFileStatus)
|
||||
{
|
||||
float offset = new Random(System.nanoTime() ^ Thread.currentThread().getId()).nextFloat() * 16f;
|
||||
Color debugColor = dataUpdated ? Color.blue : Color.red;
|
||||
DebugRenderer.makeParticle(
|
||||
new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(chunkDataView.getSectionPos(), 32f, 64f + offset, 0.07f, debugColor),
|
||||
2.0, 16f
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -208,7 +213,7 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements
|
||||
|
||||
this.updateRenderCacheAsync(newColumnRenderSource).whenComplete((voidObj, ex) ->
|
||||
{
|
||||
this.cachedRenderDataSource = new DataSourceReferenceTracker.RenderDataSourceSoftRef(this, newColumnRenderSource);
|
||||
this.cachedRenderDataSourceRef = new DataSourceReferenceTracker.RenderDataSourceSoftRef(this, newColumnRenderSource);
|
||||
|
||||
this.renderSourceLoadFutureRef.set(null);
|
||||
getSourceFuture.complete(newColumnRenderSource);
|
||||
@@ -256,7 +261,7 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements
|
||||
|
||||
this.renderSourceLoadFutureRef.set(null);
|
||||
|
||||
this.cachedRenderDataSource = new DataSourceReferenceTracker.RenderDataSourceSoftRef(this, renderSource);
|
||||
this.cachedRenderDataSourceRef = new DataSourceReferenceTracker.RenderDataSourceSoftRef(this, renderSource);
|
||||
getSourceFuture.complete(renderSource);
|
||||
});
|
||||
}
|
||||
@@ -336,26 +341,36 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements
|
||||
|
||||
|
||||
// convert the full data source into a render source
|
||||
CompletableFuture<ColumnRenderSource> transformFuture = FullDataToRenderDataTransformer.transformFullDataToRenderSourceAsync(fullDataSourceFuture, this.clientLevel)
|
||||
.handle((newRenderSource, ex) ->
|
||||
CompletableFuture<ColumnRenderSource> transformFuture = fullDataSourceFuture
|
||||
.handle((fullDataSource, ex) ->
|
||||
{
|
||||
if (ex == null)
|
||||
{
|
||||
ColumnRenderSource newRenderSource = null;
|
||||
try
|
||||
{
|
||||
newRenderSource = FullDataToRenderDataTransformer.transformFullDataToRenderSourceUsingExecutorAsync(fullDataSource, this.clientLevel).join();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Unable to transform full data to render data for file: "+this.file, e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (newRenderSource != null)
|
||||
{
|
||||
renderSource.updateFromRenderSource(newRenderSource);
|
||||
|
||||
// update the meta data
|
||||
this.baseMetaData.dataVersion.set(renderDataVersionRef.value);
|
||||
this.baseMetaData.dataLevel = renderSource.getDataDetail();
|
||||
this.baseMetaData.dataTypeId = RENDER_SOURCE_TYPE_ID;
|
||||
this.baseMetaData.binaryDataFormatVersion = renderSource.getRenderDataFormatVersion();
|
||||
|
||||
// save to file
|
||||
this.save(renderSource);
|
||||
}
|
||||
|
||||
// update the meta data
|
||||
this.baseMetaData.dataVersion.set(renderDataVersionRef.value);
|
||||
this.baseMetaData.dataLevel = renderSource.getDataDetail();
|
||||
this.baseMetaData.dataTypeId = RENDER_SOURCE_TYPE_ID;
|
||||
this.baseMetaData.binaryDataFormatVersion = renderSource.getRenderDataFormatVersion();
|
||||
|
||||
// save to file
|
||||
this.save(renderSource);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
@@ -438,16 +453,15 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements
|
||||
@Override
|
||||
public void debugRender(DebugRenderer debugRenderer)
|
||||
{
|
||||
if (!Config.Client.Advanced.Debugging.DebugWireframeRendering.renderDataMetaFile.get()) return;
|
||||
|
||||
Color color = Color.black;
|
||||
|
||||
ColumnRenderSource cached = this.cachedRenderDataSource.get();
|
||||
if (cached != null)
|
||||
if (this.cachedRenderDataSourceRef.get() != null)
|
||||
{
|
||||
color = Color.GREEN;
|
||||
return;
|
||||
//color = Color.GREEN;
|
||||
}
|
||||
else if (this.renderSourceLoadFutureRef.get() != null)
|
||||
|
||||
// determine the color
|
||||
Color color = Color.black;
|
||||
if (this.renderSourceLoadFutureRef.get() != null)
|
||||
{
|
||||
color = Color.BLUE;
|
||||
}
|
||||
@@ -478,7 +492,7 @@ public class RenderDataMetaFile extends AbstractMetaDataContainerFile implements
|
||||
|
||||
|
||||
// attempt to get the cached render source
|
||||
ColumnRenderSource cachedRenderDataSource = this.cachedRenderDataSource.get();
|
||||
ColumnRenderSource cachedRenderDataSource = this.cachedRenderDataSourceRef.get();
|
||||
if (cachedRenderDataSource == null)
|
||||
{
|
||||
// no cached data exists and no one is trying to load it
|
||||
|
||||
+5
-13
@@ -125,7 +125,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
{
|
||||
throw new IllegalArgumentException(IDhApiWorldGenerator.class.getSimpleName() + ": max granularity smaller than min granularity!");
|
||||
}
|
||||
DebugRenderer.register(this);
|
||||
DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showWorldGenQueue);
|
||||
LOGGER.info("Created world gen queue");
|
||||
}
|
||||
|
||||
@@ -673,7 +673,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
LOGGER.warn("Failed to close generation queue: ", e);
|
||||
}
|
||||
LOGGER.info("Finished closing " + WorldGenerationQueue.class.getSimpleName());
|
||||
DebugRenderer.unregister(this);
|
||||
DebugRenderer.unregister(this, Config.Client.Advanced.Debugging.DebugWireframe.showWorldGenQueue);
|
||||
}
|
||||
|
||||
|
||||
@@ -720,18 +720,10 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
|
||||
//=======//
|
||||
|
||||
@Override
|
||||
public void debugRender(DebugRenderer r)
|
||||
public void debugRender(DebugRenderer renderer)
|
||||
{
|
||||
if (!Config.Client.Advanced.Debugging.DebugWireframeRendering.worldGenerationQueue.get()) return;
|
||||
|
||||
//if (true) return;
|
||||
waitingTasks.keySet().forEach((pos) -> {
|
||||
//DhLodPos pos = t.pos;
|
||||
r.renderBox(new DebugRenderer.Box(pos, -32f, 64f, 0.05f, Color.blue));
|
||||
});
|
||||
this.inProgressGenTasksByLodPos.forEach((pos, t) -> {
|
||||
r.renderBox(new DebugRenderer.Box(pos, -32f, 64f, 0.05f, Color.red));
|
||||
});
|
||||
this.waitingTasks.keySet().forEach((pos) -> { renderer.renderBox(new DebugRenderer.Box(pos, -32f, 64f, 0.05f, Color.blue)); });
|
||||
this.inProgressGenTasksByLodPos.forEach((pos, t) -> { renderer.renderBox(new DebugRenderer.Box(pos, -32f, 64f, 0.05f, Color.red)); });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -204,14 +204,14 @@ public class DhClientServerLevel extends DhLevel implements IDhClientLevel, IDhS
|
||||
@Override
|
||||
public void onWorldGenTaskComplete(DhSectionPos pos)
|
||||
{
|
||||
//if (pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
DebugRenderer.makeParticle(
|
||||
new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(pos, 128f, 156f, 0.09f, Color.red.darker()),
|
||||
0.2, 32f
|
||||
)
|
||||
);
|
||||
clientside.reloadPos(pos);
|
||||
|
||||
this.clientside.reloadPos(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -95,28 +95,7 @@ public class LodRenderSection implements IDebugRenderable
|
||||
this.pos = pos;
|
||||
this.parentQuadTree = parentQuadTree;
|
||||
|
||||
DebugRenderer.register(this);
|
||||
}
|
||||
|
||||
public void debugRender(DebugRenderer debugRenderer)
|
||||
{
|
||||
if (!Config.Client.Advanced.Debugging.DebugWireframeRendering.lodRenderSection.get()) return;
|
||||
|
||||
Color color = Color.red;
|
||||
|
||||
if (this.renderSourceProvider == null) color = Color.black;
|
||||
|
||||
if (this.renderSourceLoadFuture != null) color = Color.yellow;
|
||||
|
||||
if (renderSource != null)
|
||||
{
|
||||
color = Color.blue;
|
||||
if (buildRenderBufferFuture != null) color = Color.magenta;
|
||||
if (canRenderNow()) color = Color.cyan;
|
||||
if (canRenderNow() && isRenderingEnabled) color = Color.green;
|
||||
}
|
||||
|
||||
debugRenderer.renderBox(new DebugRenderer.Box(this.pos, 400, 8f, Objects.hashCode(this), 0.1f, color));
|
||||
DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showRenderSectionStatus);
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +142,8 @@ public class LodRenderSection implements IDebugRenderable
|
||||
public void reload(ILodRenderSourceProvider renderDataProvider)
|
||||
{
|
||||
// debug rendering
|
||||
if (this.pos.getDetailLevel() == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
boolean showRenderSectionStatus = Config.Client.Advanced.Debugging.DebugWireframe.showRenderSectionStatus.get();
|
||||
if (showRenderSectionStatus && this.pos.getDetailLevel() == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
{
|
||||
DebugRenderer.makeParticle(
|
||||
new DebugRenderer.BoxParticle(
|
||||
@@ -250,18 +230,13 @@ public class LodRenderSection implements IDebugRenderable
|
||||
);
|
||||
}
|
||||
|
||||
//================//
|
||||
// Render Methods //
|
||||
//================//
|
||||
private void cancelBuildBuffer()
|
||||
{
|
||||
if (this.buildRenderBufferFuture != null)
|
||||
{
|
||||
//LOGGER.info("Cancelling build of render buffer for {}", sectionPos);
|
||||
this.buildRenderBufferFuture.cancel(true);
|
||||
this.buildRenderBufferFuture = null;
|
||||
}
|
||||
}
|
||||
public void markBufferDirty() { this.lastSwapLocalVersion = -1; }
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// buffer building //
|
||||
//=================//
|
||||
|
||||
private LodRenderSection[] getNeighbors()
|
||||
{
|
||||
@@ -304,6 +279,34 @@ public class LodRenderSection implements IDebugRenderable
|
||||
public boolean canSwapBuffer() { return this.buildRenderBufferFuture != null && this.buildRenderBufferFuture.isDone(); }
|
||||
|
||||
|
||||
private void cancelBuildBuffer()
|
||||
{
|
||||
if (this.buildRenderBufferFuture != null)
|
||||
{
|
||||
//LOGGER.info("Cancelling build of render buffer for {}", sectionPos);
|
||||
this.buildRenderBufferFuture.cancel(true);
|
||||
this.buildRenderBufferFuture = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public synchronized void disposeRenderData() // synchronized is a band-aid solution to prevent a rare bug where the future isn't canceled in the right order
|
||||
{
|
||||
this.disposeRenderBuffer();
|
||||
this.renderSource = null;
|
||||
if (this.renderSourceLoadFuture != null)
|
||||
{
|
||||
this.renderSourceLoadFuture.cancel(true);
|
||||
this.renderSourceLoadFuture = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void disposeRenderBuffer()
|
||||
{
|
||||
this.cancelBuildBuffer();
|
||||
this.disposeActiveBuffer = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try and swap in new render buffer for this section. Note that before this call, there should be no other
|
||||
@@ -327,7 +330,8 @@ public class LodRenderSection implements IDebugRenderable
|
||||
if (this.canBuildBuffer())
|
||||
{
|
||||
// debug
|
||||
if (this.pos.getDetailLevel() == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
boolean showRenderSectionStatus = Config.Client.Advanced.Debugging.DebugWireframe.showRenderSectionStatus.get();
|
||||
if (showRenderSectionStatus && this.pos.getDetailLevel() == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
{
|
||||
DebugRenderer.makeParticle(
|
||||
new DebugRenderer.BoxParticle(
|
||||
@@ -426,30 +430,43 @@ public class LodRenderSection implements IDebugRenderable
|
||||
public void dispose()
|
||||
{
|
||||
this.disposeRenderData();
|
||||
DebugRenderer.unregister(this);
|
||||
DebugRenderer.unregister(this, Config.Client.Advanced.Debugging.DebugWireframe.showRenderSectionStatus);
|
||||
if (this.disposeActiveBuffer && this.activeRenderBufferRef.get() != null)
|
||||
{
|
||||
this.activeRenderBufferRef.get().close();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void disposeRenderData() // synchronized is a band-aid solution to prevent a rare bug where the future isn't canceled in the right order
|
||||
@Override
|
||||
public void debugRender(DebugRenderer debugRenderer)
|
||||
{
|
||||
this.disposeRenderBuffer();
|
||||
this.renderSource = null;
|
||||
if (this.renderSourceLoadFuture != null)
|
||||
Color color = Color.red;
|
||||
if (this.renderSourceProvider == null)
|
||||
{
|
||||
this.renderSourceLoadFuture.cancel(true);
|
||||
this.renderSourceLoadFuture = null;
|
||||
color = Color.black;
|
||||
}
|
||||
else if (this.renderSourceLoadFuture != null)
|
||||
{
|
||||
color = Color.yellow;
|
||||
}
|
||||
else if (this.renderSource != null)
|
||||
{
|
||||
color = Color.blue;
|
||||
if (this.buildRenderBufferFuture != null)
|
||||
{
|
||||
color = Color.magenta;
|
||||
}
|
||||
else if (this.canRenderNow())
|
||||
{
|
||||
color = Color.cyan;
|
||||
}
|
||||
else if (this.canRenderNow() && this.isRenderingEnabled)
|
||||
{
|
||||
color = Color.green;
|
||||
}
|
||||
}
|
||||
|
||||
debugRenderer.renderBox(new DebugRenderer.Box(this.pos, 400, 8f, Objects.hashCode(this), 0.1f, color));
|
||||
}
|
||||
|
||||
public void disposeRenderBuffer()
|
||||
{
|
||||
this.cancelBuildBuffer();
|
||||
this.disposeActiveBuffer = true;
|
||||
}
|
||||
|
||||
public void markBufferDirty() { this.lastSwapLocalVersion = -1; }
|
||||
|
||||
}
|
||||
|
||||
+269
-168
@@ -22,6 +22,7 @@ package com.seibel.distanthorizons.core.render.renderer;
|
||||
import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod;
|
||||
import com.seibel.distanthorizons.api.enums.config.ELoggerMode;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedSpamLogger;
|
||||
@@ -39,6 +40,7 @@ import com.seibel.distanthorizons.coreapi.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import java.awt.*;
|
||||
@@ -52,7 +54,6 @@ import java.util.concurrent.PriorityBlockingQueue;
|
||||
public class DebugRenderer
|
||||
{
|
||||
public static DebugRenderer INSTANCE = new DebugRenderer();
|
||||
public DebugRenderer() { }
|
||||
|
||||
public static final ConfigBasedLogger logger = new ConfigBasedLogger(
|
||||
LogManager.getLogger(TestRenderer.class), () -> ELoggerMode.LOG_ALL_TO_CHAT);
|
||||
@@ -60,6 +61,24 @@ public class DebugRenderer
|
||||
LogManager.getLogger(TestRenderer.class), () -> ELoggerMode.LOG_ALL_TO_CHAT, 1);
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
|
||||
// rendering setup
|
||||
private ShaderProgram basicShader;
|
||||
private GLVertexBuffer boxBuffer;
|
||||
private GLElementBuffer boxOutlineBuffer;
|
||||
private VertexAttribute va;
|
||||
private boolean init = false;
|
||||
|
||||
// used when rendering
|
||||
private Mat4f transformThiFrame;
|
||||
private Vec3f camPosFloatThisFrame;
|
||||
|
||||
|
||||
private final RendererLists rendererLists = new RendererLists();
|
||||
private final PriorityBlockingQueue<BoxParticle> particles = new PriorityBlockingQueue<>();
|
||||
|
||||
|
||||
|
||||
// A box from 0,0,0 to 1,1,1
|
||||
private static final float[] box_vertices = {
|
||||
// Pos x y z
|
||||
@@ -90,6 +109,145 @@ public class DebugRenderer
|
||||
3, 7,
|
||||
};
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public DebugRenderer() { }
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// registration //
|
||||
//==============//
|
||||
|
||||
public static void makeParticle(BoxParticle particle)
|
||||
{
|
||||
if (INSTANCE != null && Config.Client.Advanced.Debugging.DebugWireframe.enableRendering.get())
|
||||
{
|
||||
INSTANCE.particles.add(particle);
|
||||
}
|
||||
}
|
||||
|
||||
public static void register(IDebugRenderable renderable, ConfigEntry<Boolean> config) { if (INSTANCE != null) { INSTANCE.addRenderer(renderable, config); } }
|
||||
public void addRenderer(IDebugRenderable renderable, ConfigEntry<Boolean> config) { this.rendererLists.addRenderable(renderable, config); }
|
||||
|
||||
public static void unregister(IDebugRenderable renderable, ConfigEntry<Boolean> config) { if (INSTANCE != null) { INSTANCE.removeRenderer(renderable, config); } }
|
||||
private void removeRenderer(IDebugRenderable renderable, ConfigEntry<Boolean> config) { this.rendererLists.removeRenderable(renderable, config); }
|
||||
|
||||
public static void clearRenderables() { INSTANCE.rendererLists.clearRenderables(); }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// rendering //
|
||||
//===========//
|
||||
|
||||
public void init()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.init = true;
|
||||
this.va = VertexAttribute.create();
|
||||
this.va.bind();
|
||||
// Pos
|
||||
this.va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec3Pointer(false));
|
||||
this.va.completeAndCheck(Float.BYTES * 3);
|
||||
this.basicShader = new ShaderProgram("shaders/debug/vert.vert", "shaders/debug/frag.frag",
|
||||
"fragColor", new String[]{"vPosition"});
|
||||
this.createBuffer();
|
||||
}
|
||||
|
||||
private void createBuffer()
|
||||
{
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect(box_vertices.length * Float.BYTES);
|
||||
buffer.order(ByteOrder.nativeOrder());
|
||||
buffer.asFloatBuffer().put(box_vertices);
|
||||
buffer.rewind();
|
||||
|
||||
this.boxBuffer = new GLVertexBuffer(false);
|
||||
this.boxBuffer.bind();
|
||||
this.boxBuffer.uploadBuffer(buffer, 8, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES);
|
||||
|
||||
buffer = ByteBuffer.allocateDirect(box_outline_indices.length * Integer.BYTES);
|
||||
buffer.order(ByteOrder.nativeOrder());
|
||||
buffer.asIntBuffer().put(box_outline_indices);
|
||||
buffer.rewind();
|
||||
|
||||
this.boxOutlineBuffer = new GLElementBuffer(false);
|
||||
this.boxOutlineBuffer.bind();
|
||||
this.boxOutlineBuffer.uploadBuffer(buffer, EGpuUploadMethod.DATA, box_outline_indices.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
public void render(Mat4f transform)
|
||||
{
|
||||
this.transformThiFrame = transform;
|
||||
Vec3d camPos = MC_RENDER.getCameraExactPosition();
|
||||
camPosFloatThisFrame = new Vec3f((float) camPos.x, (float) camPos.y, (float) camPos.z);
|
||||
|
||||
GLState glState = new GLState();
|
||||
this.init();
|
||||
|
||||
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer());
|
||||
GL32.glViewport(0, 0, MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight());
|
||||
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
|
||||
//GL32.glLineWidth(2);
|
||||
GL32.glEnable(GL32.GL_DEPTH_TEST);
|
||||
GL32.glDisable(GL32.GL_STENCIL_TEST);
|
||||
GL32.glDisable(GL32.GL_BLEND);
|
||||
GL32.glDisable(GL32.GL_SCISSOR_TEST);
|
||||
|
||||
this.basicShader.bind();
|
||||
this.va.bind();
|
||||
this.va.bindBufferToAllBindingPoint(this.boxBuffer.getId());
|
||||
|
||||
this.boxOutlineBuffer.bind();
|
||||
|
||||
this.rendererLists.render(this);
|
||||
|
||||
|
||||
BoxParticle head = null;
|
||||
while ((head = this.particles.poll()) != null && head.isDead(System.nanoTime()))
|
||||
{
|
||||
}
|
||||
if (head != null)
|
||||
{
|
||||
this.particles.add(head);
|
||||
}
|
||||
|
||||
for (BoxParticle particle : this.particles)
|
||||
{
|
||||
this.renderBox(particle.getBox());
|
||||
}
|
||||
|
||||
|
||||
glState.restore();
|
||||
}
|
||||
|
||||
public void renderBox(Box box)
|
||||
{
|
||||
Mat4f boxTransform = Mat4f.createTranslateMatrix(box.a.x - this.camPosFloatThisFrame.x, box.a.y - this.camPosFloatThisFrame.y, box.a.z - this.camPosFloatThisFrame.z);
|
||||
boxTransform.multiply(Mat4f.createScaleMatrix(box.b.x - box.a.x, box.b.y - box.a.y, box.b.z - box.a.z));
|
||||
Mat4f t = this.transformThiFrame.copy();
|
||||
t.multiply(boxTransform);
|
||||
this.basicShader.setUniform(this.basicShader.getUniformLocation("transform"), t);
|
||||
this.basicShader.setUniform(this.basicShader.getUniformLocation("uColor"), box.color);
|
||||
GL32.glDrawElements(GL32.GL_LINES, box_outline_indices.length, GL32.GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
public static final class Box
|
||||
{
|
||||
public Vec3f a;
|
||||
@@ -149,14 +307,6 @@ public class DebugRenderer
|
||||
|
||||
}
|
||||
|
||||
ShaderProgram basicShader;
|
||||
GLVertexBuffer boxBuffer;
|
||||
GLElementBuffer boxOutlineBuffer;
|
||||
VertexAttribute va;
|
||||
boolean init = false;
|
||||
|
||||
private final LinkedList<WeakReference<IDebugRenderable>> renderers = new LinkedList<>();
|
||||
|
||||
public static final class BoxParticle implements Comparable<BoxParticle>
|
||||
{
|
||||
public Box box;
|
||||
@@ -172,35 +322,27 @@ public class DebugRenderer
|
||||
this.yChange = yChange;
|
||||
}
|
||||
|
||||
public BoxParticle(Box box, long ns, float yChange)
|
||||
{
|
||||
this(box, System.nanoTime(), ns, yChange);
|
||||
}
|
||||
public BoxParticle(Box box, long nanoSecondDuratoin, float yChange) { this(box, System.nanoTime(), nanoSecondDuratoin, yChange); }
|
||||
|
||||
public BoxParticle(Box box, double secondDuration, float yChange) { this(box, System.nanoTime(), (long) (secondDuration * 1000000000), yChange); }
|
||||
|
||||
public BoxParticle(Box box, double s, float yChange)
|
||||
{
|
||||
this(box, System.nanoTime(), (long) (s * 1000000000), yChange);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull DebugRenderer.BoxParticle o)
|
||||
public int compareTo(@NotNull BoxParticle particle)
|
||||
{
|
||||
return Long.compare(startTime + duration, o.startTime + o.duration);
|
||||
return Long.compare(this.startTime + this.duration, particle.startTime + particle.duration);
|
||||
}
|
||||
|
||||
Box getBox()
|
||||
public Box getBox()
|
||||
{
|
||||
long now = System.nanoTime();
|
||||
float percent = (now - startTime) / (float) duration;
|
||||
float percent = (now - this.startTime) / (float) this.duration;
|
||||
percent = (float) Math.pow(percent, 4);
|
||||
float yDiff = yChange * percent;
|
||||
return new Box(new Vec3f(box.a.x, box.a.y + yDiff, box.a.z), new Vec3f(box.b.x, box.b.y + yDiff, box.b.z), box.color);
|
||||
float yDiff = this.yChange * percent;
|
||||
return new Box(new Vec3f(this.box.a.x, this.box.a.y + yDiff, this.box.a.z), new Vec3f(this.box.b.x, this.box.b.y + yDiff, this.box.b.z), this.box.color);
|
||||
}
|
||||
|
||||
boolean isDead(long time)
|
||||
{
|
||||
return time - startTime > duration;
|
||||
}
|
||||
public boolean isDead(long time) { return (time - this.startTime) > this.duration; }
|
||||
|
||||
}
|
||||
|
||||
@@ -209,17 +351,16 @@ public class DebugRenderer
|
||||
public Box box;
|
||||
public BoxParticle particaleOnClose;
|
||||
|
||||
|
||||
public BoxWithLife(Box box, long ns, float yChange, Color deathColor)
|
||||
{
|
||||
this.box = box;
|
||||
this.particaleOnClose = new BoxParticle(new Box(box.a, box.b, deathColor), -1, ns, yChange);
|
||||
DebugRenderer.register(this);
|
||||
register(this, null);
|
||||
}
|
||||
|
||||
public BoxWithLife(Box box, long ns, float yChange)
|
||||
{
|
||||
this(box, ns, yChange, box.color);
|
||||
}
|
||||
|
||||
public BoxWithLife(Box box, long ns, float yChange) { this(box, ns, yChange, box.color); }
|
||||
|
||||
public BoxWithLife(Box box, double s, float yChange, Color deathColor)
|
||||
{
|
||||
@@ -227,46 +368,74 @@ public class DebugRenderer
|
||||
this.particaleOnClose = new BoxParticle(new Box(box.a, box.b, deathColor), s, yChange);
|
||||
}
|
||||
|
||||
public BoxWithLife(Box box, double s, float yChange)
|
||||
{
|
||||
this(box, s, yChange, box.color);
|
||||
}
|
||||
public BoxWithLife(Box box, double s, float yChange) { this(box, s, yChange, box.color); }
|
||||
|
||||
@Override
|
||||
public void debugRender(DebugRenderer r)
|
||||
{
|
||||
r.renderBox(box);
|
||||
}
|
||||
public void debugRender(DebugRenderer renderer) { renderer.renderBox(this.box); }
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
makeParticle(new BoxParticle(particaleOnClose.getBox(), System.nanoTime(), particaleOnClose.duration, particaleOnClose.yChange));
|
||||
DebugRenderer.unregister(this);
|
||||
makeParticle(new BoxParticle(this.particaleOnClose.getBox(), System.nanoTime(), this.particaleOnClose.duration, this.particaleOnClose.yChange));
|
||||
unregister(this, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final PriorityBlockingQueue<BoxParticle> particles = new PriorityBlockingQueue<>();
|
||||
|
||||
public static void unregister(IDebugRenderable r)
|
||||
{
|
||||
if (INSTANCE == null) return;
|
||||
INSTANCE.removeRenderer(r);
|
||||
}
|
||||
|
||||
public static void makeParticle(BoxParticle particle)
|
||||
private static class RendererLists
|
||||
{
|
||||
if (INSTANCE == null) return;
|
||||
if (!Config.Client.Advanced.Debugging.DebugWireframeRendering.enableRendering.get()) return;
|
||||
INSTANCE.particles.add(particle);
|
||||
}
|
||||
|
||||
private void removeRenderer(IDebugRenderable r)
|
||||
{
|
||||
synchronized (this.renderers)
|
||||
public final LinkedList<WeakReference<IDebugRenderable>> generalRenderableList = new LinkedList<>();
|
||||
|
||||
private final HashMap<ConfigEntry<Boolean>, LinkedList<WeakReference<IDebugRenderable>>> renderableListByConfig = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
// registration //
|
||||
|
||||
public void addRenderable(IDebugRenderable renderable, @Nullable ConfigEntry<Boolean> config)
|
||||
{
|
||||
Iterator<WeakReference<IDebugRenderable>> iterator = this.renderers.iterator();
|
||||
synchronized (this)
|
||||
{
|
||||
if (config != null)
|
||||
{
|
||||
if (!this.renderableListByConfig.containsKey(config))
|
||||
{
|
||||
this.renderableListByConfig.put(config, new LinkedList<>());
|
||||
}
|
||||
|
||||
LinkedList<WeakReference<IDebugRenderable>> renderableList = this.renderableListByConfig.get(config);
|
||||
renderableList.add(new WeakReference<>(renderable));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.generalRenderableList.add(new WeakReference<>(renderable));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeRenderable(IDebugRenderable renderable, @Nullable ConfigEntry<Boolean> config)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (config != null)
|
||||
{
|
||||
if (this.renderableListByConfig.containsKey(config))
|
||||
{
|
||||
LinkedList<WeakReference<IDebugRenderable>> renderableList = this.renderableListByConfig.get(config);
|
||||
this.removeRenderableFromInternalList(renderableList, renderable);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.removeRenderableFromInternalList(this.generalRenderableList, renderable);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void removeRenderableFromInternalList(LinkedList<WeakReference<IDebugRenderable>> rendererList, IDebugRenderable renderable)
|
||||
{
|
||||
Iterator<WeakReference<IDebugRenderable>> iterator = rendererList.iterator();
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
WeakReference<IDebugRenderable> renderableRef = iterator.next();
|
||||
@@ -275,131 +444,63 @@ public class DebugRenderer
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
if (renderableRef.get() == r)
|
||||
|
||||
if (renderableRef.get() == renderable)
|
||||
{
|
||||
iterator.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearRenderables() { INSTANCE.renderers.clear(); }
|
||||
|
||||
public void init()
|
||||
{
|
||||
if (init) return;
|
||||
init = true;
|
||||
va = VertexAttribute.create();
|
||||
va.bind();
|
||||
// Pos\
|
||||
va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec3Pointer(false));
|
||||
va.completeAndCheck(Float.BYTES * 3);
|
||||
basicShader = new ShaderProgram("shaders/debug/vert.vert", "shaders/debug/frag.frag",
|
||||
"fragColor", new String[]{"vPosition"});
|
||||
createBuffer();
|
||||
}
|
||||
|
||||
private void createBuffer()
|
||||
{
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect(box_vertices.length * Float.BYTES);
|
||||
buffer.order(ByteOrder.nativeOrder());
|
||||
buffer.asFloatBuffer().put(box_vertices);
|
||||
buffer.rewind();
|
||||
boxBuffer = new GLVertexBuffer(false);
|
||||
boxBuffer.bind();
|
||||
boxBuffer.uploadBuffer(buffer, 8, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES);
|
||||
|
||||
buffer = ByteBuffer.allocateDirect(box_outline_indices.length * Integer.BYTES);
|
||||
buffer.order(ByteOrder.nativeOrder());
|
||||
buffer.asIntBuffer().put(box_outline_indices);
|
||||
buffer.rewind();
|
||||
boxOutlineBuffer = new GLElementBuffer(false);
|
||||
boxOutlineBuffer.bind();
|
||||
boxOutlineBuffer.uploadBuffer(buffer, EGpuUploadMethod.DATA, box_outline_indices.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
public void addRenderer(IDebugRenderable r)
|
||||
{
|
||||
if (!Config.Client.Advanced.Debugging.DebugWireframeRendering.enableRendering.get()) return;
|
||||
synchronized (renderers)
|
||||
public void clearRenderables()
|
||||
{
|
||||
renderers.add(new WeakReference<>(r));
|
||||
}
|
||||
}
|
||||
|
||||
public static void register(IDebugRenderable r)
|
||||
{
|
||||
if (INSTANCE == null) return;
|
||||
INSTANCE.addRenderer(r);
|
||||
}
|
||||
|
||||
private Mat4f transform_this_frame;
|
||||
private Vec3f camf;
|
||||
|
||||
public void renderBox(Box box)
|
||||
{
|
||||
Mat4f boxTransform = Mat4f.createTranslateMatrix(box.a.x - camf.x, box.a.y - camf.y, box.a.z - camf.z);
|
||||
boxTransform.multiply(Mat4f.createScaleMatrix(box.b.x - box.a.x, box.b.y - box.a.y, box.b.z - box.a.z));
|
||||
Mat4f t = transform_this_frame.copy();
|
||||
t.multiply(boxTransform);
|
||||
basicShader.setUniform(basicShader.getUniformLocation("transform"), t);
|
||||
basicShader.setUniform(basicShader.getUniformLocation("uColor"), box.color);
|
||||
GL32.glDrawElements(GL32.GL_LINES, box_outline_indices.length, GL32.GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
|
||||
public void render(Mat4f transform)
|
||||
{
|
||||
transform_this_frame = transform;
|
||||
Vec3d cam = MC_RENDER.getCameraExactPosition();
|
||||
camf = new Vec3f((float) cam.x, (float) cam.y, (float) cam.z);
|
||||
|
||||
GLState state = new GLState();
|
||||
init();
|
||||
|
||||
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer());
|
||||
GL32.glViewport(0, 0, MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight());
|
||||
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
|
||||
//GL32.glLineWidth(2);
|
||||
GL32.glEnable(GL32.GL_DEPTH_TEST);
|
||||
GL32.glDisable(GL32.GL_STENCIL_TEST);
|
||||
GL32.glDisable(GL32.GL_BLEND);
|
||||
GL32.glDisable(GL32.GL_SCISSOR_TEST);
|
||||
|
||||
basicShader.bind();
|
||||
va.bind();
|
||||
va.bindBufferToAllBindingPoint(boxBuffer.getId());
|
||||
|
||||
boxOutlineBuffer.bind();
|
||||
|
||||
synchronized (renderers)
|
||||
{
|
||||
Iterator<WeakReference<IDebugRenderable>> it = renderers.iterator();
|
||||
while (it.hasNext())
|
||||
for (ConfigEntry<Boolean> config : this.renderableListByConfig.keySet())
|
||||
{
|
||||
WeakReference<IDebugRenderable> ref = it.next();
|
||||
IDebugRenderable r = ref.get();
|
||||
if (r == null)
|
||||
LinkedList<WeakReference<IDebugRenderable>> renderableList = this.renderableListByConfig.get(config);
|
||||
if (config.get() && renderableList != null)
|
||||
{
|
||||
it.remove();
|
||||
continue;
|
||||
renderableList.clear();
|
||||
}
|
||||
r.debugRender(this);
|
||||
}
|
||||
}
|
||||
|
||||
BoxParticle head = null;
|
||||
while ((head = particles.poll()) != null && head.isDead(System.nanoTime()))
|
||||
{
|
||||
}
|
||||
if (head != null)
|
||||
{
|
||||
particles.add(head);
|
||||
}
|
||||
particles.forEach(b -> renderBox(b.getBox()));
|
||||
|
||||
state.restore();
|
||||
|
||||
// rendering //
|
||||
|
||||
public void render(DebugRenderer debugRenderer)
|
||||
{
|
||||
this.renderList(debugRenderer, this.generalRenderableList);
|
||||
|
||||
for (ConfigEntry<Boolean> config : this.renderableListByConfig.keySet())
|
||||
{
|
||||
LinkedList<WeakReference<IDebugRenderable>> renderableList = this.renderableListByConfig.get(config);
|
||||
if (config.get() && renderableList != null && renderableList.size() != 0)
|
||||
{
|
||||
this.renderList(debugRenderer, renderableList);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void renderList(DebugRenderer debugRenderer, LinkedList<WeakReference<IDebugRenderable>> rendererList)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
Iterator<WeakReference<IDebugRenderable>> iterator = rendererList.iterator();
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
WeakReference<IDebugRenderable> ref = iterator.next();
|
||||
IDebugRenderable renderable = ref.get();
|
||||
if (renderable == null)
|
||||
{
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
renderable.debugRender(debugRenderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -198,6 +198,8 @@ public class LodRenderer
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// get MC's shader program and save MC's render state so we can restore it later
|
||||
LagSpikeCatcher drawSaveGLState = new LagSpikeCatcher();
|
||||
GLState minecraftGlState = new GLState();
|
||||
@@ -348,7 +350,7 @@ public class LodRenderer
|
||||
|
||||
this.shaderProgram.unbind();
|
||||
|
||||
if (Config.Client.Advanced.Debugging.DebugWireframeRendering.enableRendering.get())
|
||||
if (Config.Client.Advanced.Debugging.DebugWireframe.enableRendering.get())
|
||||
{
|
||||
profiler.popPush("Debug wireframes");
|
||||
// Note: this can be very slow if a lot of boxes are being rendered
|
||||
@@ -460,4 +462,4 @@ public class LodRenderer
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,17 +49,24 @@ public class FileUtil
|
||||
}
|
||||
|
||||
|
||||
if (file.renameTo(corruptedFile))
|
||||
if (file.exists())
|
||||
{
|
||||
LOGGER.error("Renamed corrupted file to [" + corruptedFileName + "].");
|
||||
if (file.renameTo(corruptedFile))
|
||||
{
|
||||
LOGGER.error("Renamed corrupted file to [" + corruptedFileName + "].");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.error("Failed to rename corrupted file to [" + corruptedFileName + "]. Attempting to delete file...");
|
||||
if (!file.delete())
|
||||
{
|
||||
LOGGER.error("Unable to delete corrupted file [" + corruptedFileName + "].");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.error("Failed to rename corrupted file to [" + corruptedFileName + "]. Attempting to delete file...");
|
||||
if (!file.delete())
|
||||
{
|
||||
LOGGER.error("Unable to delete corrupted file [" + corruptedFileName + "].");
|
||||
}
|
||||
LOGGER.error("Corrupted file [" + file + "] doesn't exist.");
|
||||
}
|
||||
|
||||
return corruptedFile;
|
||||
|
||||
@@ -409,10 +409,6 @@
|
||||
"Only Render LODs",
|
||||
"distanthorizons.config.client.advanced.debugging.lodOnlyMode.@tooltip":
|
||||
"If enabled this will disable (most) vanilla Minecraft rendering. \n\nNOTE: Do not report any issues when this mode is on! \nThis setting is only for fun and debugging. \nMod compatibility is not guaranteed.",
|
||||
"distanthorizons.config.client.advanced.debugging.debugWireframeRendering":
|
||||
"Enable Debug Wireframe Rendering",
|
||||
"distanthorizons.config.client.advanced.debugging.debugWireframeRendering.@tooltip":
|
||||
"If enabled, various wireframes for debugging internal functions will be drawn.",
|
||||
"distanthorizons.config.client.advanced.debugging.enableWhiteWorld":
|
||||
"Enable white world",
|
||||
"distanthorizons.config.client.advanced.debugging.enableWhiteWorld.@tooltip":
|
||||
@@ -522,7 +518,26 @@
|
||||
"Linkable test",
|
||||
"distanthorizons.config.client.advanced.debugging.exampleConfigScreen.linkableTest.@tooltip":
|
||||
"The value of this should be the same as in Category Test",
|
||||
|
||||
|
||||
|
||||
"distanthorizons.config.client.advanced.debugging.debugWireframe":
|
||||
"Debug Wireframe",
|
||||
|
||||
"distanthorizons.config.client.advanced.debugging.debugWireframe.enableRendering":
|
||||
"Enable Debug Wireframe Rendering",
|
||||
"distanthorizons.config.client.advanced.debugging.debugWireframe.enableRendering.@tooltip":
|
||||
"If enabled, various wireframes for debugging internal functions will be drawn.",
|
||||
"distanthorizons.config.client.advanced.debugging.debugWireframe.showWorldGenQueue":
|
||||
"Show World Gen Queue",
|
||||
"distanthorizons.config.client.advanced.debugging.debugWireframe.showRenderSectionStatus":
|
||||
"Show Render Section Status",
|
||||
"distanthorizons.config.client.advanced.debugging.debugWireframe.showFullDataFileStatus":
|
||||
"Show Full Data file Status",
|
||||
"distanthorizons.config.client.advanced.debugging.debugWireframe.showFullDataFileSampling":
|
||||
"Show Full Data file Sampling",
|
||||
"distanthorizons.config.client.advanced.debugging.debugWireframe.showRenderDataFileStatus":
|
||||
"Show Render Data file Status",
|
||||
|
||||
|
||||
"distanthorizons.config.client.resetSettingsConfirmation":
|
||||
"Reset All Settings?",
|
||||
|
||||
Reference in New Issue
Block a user