fixed and optimize a lot of stuff.
This commit is contained in:
+27
-29
@@ -118,38 +118,36 @@ public class ApiEventInjector extends DependencyInjector<IDhApiEvent> implements
|
||||
@Override
|
||||
public <T, U extends IDhApiEvent<T>> boolean fireAllEvents(Class<U> abstractEvent, T eventParameterObject)
|
||||
{
|
||||
boolean cancelEvent = false;
|
||||
|
||||
// if this is a one time event, record that it was called
|
||||
if (ApiEventDefinitionHandler.INSTANCE.getEventDefinition(abstractEvent).isOneTimeEvent &&
|
||||
!this.firedOneTimeEventParamsByEventInterface.containsKey(abstractEvent))
|
||||
{
|
||||
this.firedOneTimeEventParamsByEventInterface.put(abstractEvent, eventParameterObject);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// fire each bound event
|
||||
ArrayList<U> eventList = this.getAll(abstractEvent);
|
||||
for (IDhApiEvent<T> event : eventList)
|
||||
{
|
||||
if (event != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// fire each event and record if any of them
|
||||
// request to cancel the event.
|
||||
cancelEvent |= event.fireEvent(eventParameterObject);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Exception thrown by event handler [" + event.getClass().getSimpleName() + "] for event type [" + abstractEvent.getSimpleName() + "], error:" + e.getMessage(), e);
|
||||
try {
|
||||
boolean cancelEvent = false;
|
||||
|
||||
// if this is a one time event, record that it was called
|
||||
if (ApiEventDefinitionHandler.INSTANCE.getEventDefinition(abstractEvent).isOneTimeEvent &&
|
||||
!this.firedOneTimeEventParamsByEventInterface.containsKey(abstractEvent)) {
|
||||
this.firedOneTimeEventParamsByEventInterface.put(abstractEvent, eventParameterObject);
|
||||
}
|
||||
|
||||
|
||||
// fire each bound event
|
||||
ArrayList<U> eventList = this.getAll(abstractEvent);
|
||||
for (IDhApiEvent<T> event : eventList) {
|
||||
if (event != null) {
|
||||
try {
|
||||
// fire each event and record if any of them
|
||||
// request to cancel the event.
|
||||
cancelEvent |= event.fireEvent(eventParameterObject);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Exception thrown by event handler [" + event.getClass().getSimpleName() + "] for event type [" + abstractEvent.getSimpleName() + "], error:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cancelEvent;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
//LOGGER.error("Exception thrown while firing events for event type [" + abstractEvent.getSimpleName() + "], error:" + e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return cancelEvent;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+18
-8
@@ -1,11 +1,13 @@
|
||||
package com.seibel.distanthorizons.core.dataObjects.render;
|
||||
|
||||
import com.kitfox.svg.A;
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.dataObjects.transformers.FullDataToRenderDataTransformer;
|
||||
import com.seibel.distanthorizons.core.render.renderer.DebugRenderer;
|
||||
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataOutputStream;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.columnViews.ColumnArrayView;
|
||||
@@ -18,7 +20,10 @@ import com.seibel.distanthorizons.core.util.RenderDataPointUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Stores the render data used to generate OpenGL buffers.
|
||||
@@ -56,6 +61,8 @@ public class ColumnRenderSource
|
||||
|
||||
private boolean isEmpty = true;
|
||||
public EDhApiWorldGenerationStep worldGenStep;
|
||||
|
||||
public AtomicLong localVersion = new AtomicLong(0); // used to track changes to the data source, so that buffers can be updated when necessary
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
@@ -222,7 +229,6 @@ public class ColumnRenderSource
|
||||
/** Overrides any data that has not been written directly using write(). Skips empty source dataPoints. */
|
||||
public void updateFromRenderSource(ColumnRenderSource renderSource)
|
||||
{
|
||||
|
||||
// validate we are writing for the same location
|
||||
LodUtil.assertTrue(renderSource.sectionPos.equals(this.sectionPos));
|
||||
|
||||
@@ -239,8 +245,7 @@ public class ColumnRenderSource
|
||||
}
|
||||
// the source isn't empty, this object won't be empty after the method finishes
|
||||
this.isEmpty = false;
|
||||
|
||||
|
||||
|
||||
for (int i = 0; i < this.renderDataContainer.length; i += this.verticalDataCount)
|
||||
{
|
||||
int thisGenMode = RenderDataPointUtil.getGenerationMode(this.renderDataContainer[i]);
|
||||
@@ -277,11 +282,17 @@ public class ColumnRenderSource
|
||||
}
|
||||
}
|
||||
|
||||
public void fastWrite(ChunkSizedFullDataAccessor chunkData, IDhClientLevel level)
|
||||
public boolean fastWrite(ChunkSizedFullDataAccessor chunkData, IDhClientLevel level)
|
||||
{
|
||||
try
|
||||
{
|
||||
FullDataToRenderDataTransformer.writeFullDataChunkToColumnData(this, level, chunkData);
|
||||
if (FullDataToRenderDataTransformer.writeFullDataChunkToColumnData(this, level, chunkData)) {
|
||||
localVersion.incrementAndGet();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
@@ -293,6 +304,7 @@ public class ColumnRenderSource
|
||||
// expected if the transformer is shut down, the exception can be ignored
|
||||
// LOGGER.warn(ColumnRenderSource.class.getSimpleName()+" fast write interrupted.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -321,10 +333,7 @@ public class ColumnRenderSource
|
||||
/** @return how many data points wide this {@link ColumnRenderSource} is. */
|
||||
public int getWidthInDataPoints() { return BitShiftUtil.powerOfTwo(this.getDetailOffset()); }
|
||||
public byte getDetailOffset() { return SECTION_SIZE_OFFSET; }
|
||||
|
||||
|
||||
|
||||
|
||||
public byte getRenderDataFormatVersion() { return DATA_FORMAT_VERSION; }
|
||||
|
||||
/**
|
||||
@@ -352,6 +361,7 @@ public class ColumnRenderSource
|
||||
this.debugSourceFlags[x * SECTION_SIZE + z] = flag;
|
||||
}
|
||||
}
|
||||
localVersion.incrementAndGet();
|
||||
}
|
||||
|
||||
public DebugSourceFlag debugGetFlag(int ox, int oz) { return this.debugSourceFlags[ox * SECTION_SIZE + oz]; }
|
||||
|
||||
+3
-5
@@ -52,15 +52,13 @@ public class ColumnRenderBufferBuilder
|
||||
//==============//
|
||||
// vbo building //
|
||||
//==============//
|
||||
|
||||
/** @return null if busy */
|
||||
|
||||
public static CompletableFuture<ColumnRenderBuffer> buildBuffers(IDhClientLevel clientLevel, Reference<ColumnRenderBuffer> renderBufferRef, ColumnRenderSource renderSource, ColumnRenderSource[] adjData)
|
||||
{
|
||||
if (isBusy())
|
||||
/* if (isBusy())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}*/
|
||||
//LOGGER.info("RenderRegion startBuild @ {}", renderSource.sectionPos);
|
||||
return CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
|
||||
+17
@@ -159,5 +159,22 @@ public final class ColumnArrayView implements IColumnDataView
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public int getDataHash() {
|
||||
return arrayHash(data, offset, size);
|
||||
}
|
||||
|
||||
private static int arrayHash(long[] a, int offset, int length) {
|
||||
if (a == null)
|
||||
return 0;
|
||||
int result = 1;
|
||||
int end = offset + length;
|
||||
for (int i = offset; i < end; i++) {
|
||||
long element = a[i];
|
||||
int elementHash = (int)(element ^ (element >>> 32));
|
||||
result = 31 * result + elementHash;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+13
-7
@@ -22,6 +22,8 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.distanthorizons.coreapi.util.BitShiftUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Handles converting {@link ChunkSizedFullDataAccessor}, {@link IIncompleteFullDataSource},
|
||||
* and {@link IFullDataSource}'s to {@link ColumnRenderSource}.
|
||||
@@ -156,7 +158,7 @@ public class FullDataToRenderDataTransformer
|
||||
* @throws InterruptedException Can be caused by interrupting the thread upstream.
|
||||
* Generally thrown if the method is running after the client leaves the current world.
|
||||
*/
|
||||
public static void writeFullDataChunkToColumnData(ColumnRenderSource renderSource, IDhClientLevel level, ChunkSizedFullDataAccessor chunkDataView) throws InterruptedException, IllegalArgumentException
|
||||
public static boolean writeFullDataChunkToColumnData(ColumnRenderSource renderSource, IDhClientLevel level, ChunkSizedFullDataAccessor chunkDataView) throws InterruptedException, IllegalArgumentException
|
||||
{
|
||||
final DhSectionPos renderSourcePos = renderSource.getSectionPos();
|
||||
|
||||
@@ -169,8 +171,8 @@ public class FullDataToRenderDataTransformer
|
||||
|
||||
final int sourceDataPointBlockWidth = BitShiftUtil.powerOfTwo(renderSource.getDataDetail());
|
||||
|
||||
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
if (chunkDataView.detailLevel == renderSource.getDataDetail())
|
||||
{
|
||||
// confirm the render source contains this chunk
|
||||
@@ -181,15 +183,16 @@ public class FullDataToRenderDataTransformer
|
||||
{
|
||||
throw new IllegalArgumentException("Data offset is out of bounds");
|
||||
}
|
||||
|
||||
|
||||
throwIfThreadInterrupted();
|
||||
|
||||
for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++)
|
||||
{
|
||||
for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++)
|
||||
{
|
||||
throwIfThreadInterrupted();
|
||||
|
||||
ColumnArrayView columnArrayView = renderSource.getVerticalDataPointView(blockOffsetX + x, blockOffsetZ + z);
|
||||
int hash = columnArrayView.getDataHash();
|
||||
|
||||
SingleColumnFullDataAccessor fullArrayView = chunkDataView.get(x, z);
|
||||
|
||||
convertColumnData(level,
|
||||
@@ -201,12 +204,15 @@ public class FullDataToRenderDataTransformer
|
||||
{
|
||||
LodUtil.assertTrue(renderSource.doesDataPointExist(blockOffsetX + x, blockOffsetZ + z));
|
||||
}
|
||||
|
||||
changed |= hash != columnArrayView.getDataHash();
|
||||
}
|
||||
}
|
||||
renderSource.fillDebugFlag(blockOffsetX, blockOffsetZ, LodUtil.CHUNK_WIDTH, LodUtil.CHUNK_WIDTH, ColumnRenderSource.DebugSourceFlag.DIRECT);
|
||||
|
||||
|
||||
renderSource.markNotEmpty();
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static void convertColumnData(IDhClientLevel level, int blockX, int blockZ, ColumnArrayView columnArrayView, SingleColumnFullDataAccessor fullArrayView, int genMode)
|
||||
|
||||
+10
-12
@@ -54,6 +54,15 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
private SoftReference<IFullDataSource> cachedFullDataSource = new SoftReference<>(null);
|
||||
private final AtomicReference<CompletableFuture<IFullDataSource>> dataSourceLoadFutureRef = new AtomicReference<>(null);
|
||||
|
||||
private static final class CacheQueryResult {
|
||||
public final CompletableFuture<IFullDataSource> future;
|
||||
public final boolean needsLoad;
|
||||
public CacheQueryResult(CompletableFuture<IFullDataSource> future, boolean needsLoad) {
|
||||
this.future = future;
|
||||
this.needsLoad = needsLoad;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugRender(DebugRenderer r) {
|
||||
IFullDataSource cached = cachedFullDataSource.get();
|
||||
@@ -309,15 +318,6 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
data.getDataDetailLevel(), data.getWorldGenStep(), (loader == null ? 0 : loader.datatypeId), data.getBinaryDataFormatVersion());
|
||||
}
|
||||
|
||||
private static final class CacheQueryResult {
|
||||
public final CompletableFuture<IFullDataSource> future;
|
||||
public final boolean needsLoad;
|
||||
public CacheQueryResult(CompletableFuture<IFullDataSource> future, boolean needsLoad) {
|
||||
this.future = future;
|
||||
this.needsLoad = needsLoad;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return one of the following:
|
||||
* the cached {@link IFullDataSource},
|
||||
@@ -328,11 +328,9 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I
|
||||
{
|
||||
// this data source is being written to, use the existing future
|
||||
CompletableFuture<IFullDataSource> dataSourceLoadFuture = this.dataSourceLoadFutureRef.get();
|
||||
if (dataSourceLoadFuture != null)
|
||||
{
|
||||
if (dataSourceLoadFuture != null) {
|
||||
return new CacheQueryResult(dataSourceLoadFuture, false);
|
||||
}
|
||||
|
||||
// attempt to get the cached data source
|
||||
IFullDataSource cachedFullDataSource = this.cachedFullDataSource.get();
|
||||
if (cachedFullDataSource == null) {
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ public interface ILodRenderSourceProvider extends AutoCloseable
|
||||
CompletableFuture<Void> flushAndSaveAsync();
|
||||
|
||||
/** Returns true if the data was refreshed, false otherwise */
|
||||
boolean refreshRenderSource(ColumnRenderSource source);
|
||||
//boolean refreshRenderSource(ColumnRenderSource source);
|
||||
|
||||
/** Deletes any data stored in the render cache so it can be re-created */
|
||||
void deleteRenderCache();
|
||||
|
||||
+119
-56
@@ -1,6 +1,8 @@
|
||||
package com.seibel.distanthorizons.core.file.renderfile;
|
||||
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor;
|
||||
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.metaData.AbstractMetaDataContainerFile;
|
||||
import com.seibel.distanthorizons.core.file.metaData.BaseMetaData;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
@@ -11,18 +13,23 @@ import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderLoader;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource;
|
||||
import com.seibel.distanthorizons.core.level.IDhClientLevel;
|
||||
import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable;
|
||||
import com.seibel.distanthorizons.core.util.AtomicsUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataInputStream;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
public class RenderMetaDataFile extends AbstractMetaDataContainerFile implements IDebugRenderable
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
@@ -32,13 +39,35 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
* When clearing, don't set to null, instead create a SoftReference containing null.
|
||||
* This will make null checks simpler.
|
||||
*/
|
||||
private SoftReference<ColumnRenderSource> cachedRenderDataSourceRef = new SoftReference<>(null);
|
||||
private SoftReference<ColumnRenderSource> cachedRenderDataSource = new SoftReference<>(null);
|
||||
private final AtomicReference<CompletableFuture<ColumnRenderSource>> renderSourceLoadFutureRef = new AtomicReference<>(null);
|
||||
|
||||
private final RenderSourceFileHandler fileHandler;
|
||||
private boolean doesFileExist;
|
||||
|
||||
|
||||
|
||||
|
||||
private static final class CacheQueryResult {
|
||||
public final CompletableFuture<ColumnRenderSource> future;
|
||||
public final boolean needsLoad;
|
||||
public CacheQueryResult(CompletableFuture<ColumnRenderSource> future, boolean needsLoad) {
|
||||
this.future = future;
|
||||
this.needsLoad = needsLoad;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugRender(DebugRenderer r) {
|
||||
ColumnRenderSource cached = cachedRenderDataSource.get();
|
||||
Color c = Color.black;
|
||||
if (cached != null) {
|
||||
c = Color.GREEN;
|
||||
} else if (renderSourceLoadFutureRef.get() != null) {
|
||||
c = Color.BLUE;
|
||||
} else if (doesFileExist) {
|
||||
c = Color.RED;
|
||||
}
|
||||
r.renderBox(new DebugRenderer.Box(pos, 0, 256, 0.05f, c));
|
||||
}
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
@@ -57,6 +86,7 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
this.fileHandler = fileHandler;
|
||||
LodUtil.assertTrue(this.baseMetaData == null);
|
||||
this.doesFileExist = this.file.exists();
|
||||
DebugRenderer.register(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,6 +97,7 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
{
|
||||
return new RenderMetaDataFile(fileHandler, path);
|
||||
}
|
||||
|
||||
private RenderMetaDataFile(RenderSourceFileHandler fileHandler, File path) throws IOException
|
||||
{
|
||||
super(path);
|
||||
@@ -74,10 +105,10 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
LodUtil.assertTrue(this.baseMetaData != null);
|
||||
|
||||
this.doesFileExist = this.file.exists();
|
||||
|
||||
DebugRenderer.register(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// FIXME: This can cause concurrent modification of LodRenderSource.
|
||||
// Not sure if it will cause issues or not.
|
||||
public void updateChunkIfSourceExists(ChunkSizedFullDataAccessor chunkDataView, IDhClientLevel level)
|
||||
@@ -86,19 +117,23 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
LodUtil.assertTrue(this.pos.getSectionBBoxPos().overlapsExactly(chunkPos), "Chunk pos "+chunkPos+" doesn't overlap with section "+this.pos);
|
||||
|
||||
// update the render source if one exists
|
||||
CompletableFuture<ColumnRenderSource> readSourceFuture = this.getCachedDataSourceAsync();
|
||||
if (readSourceFuture != null)
|
||||
{
|
||||
if (chunkDataView.getLodPos().detailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
CompletableFuture<ColumnRenderSource> renderSourceLoadFuture = getCachedDataSourceAsync();
|
||||
if (renderSourceLoadFuture == null) return;
|
||||
|
||||
/* renderSourceLoadFuture.thenAccept((renderSource) -> {
|
||||
boolean worked = renderSource.fastWrite(chunkDataView, level);
|
||||
|
||||
if (pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) {
|
||||
float offset = new Random(System.nanoTime() ^ Thread.currentThread().getId()).nextFloat() * 16f;
|
||||
Color c = worked ? Color.blue : Color.red;
|
||||
DebugRenderer.makeParticle(
|
||||
new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(chunkDataView.getLodPos(), 0, 256f, 0.05f, Color.blue),
|
||||
0.5, 512f
|
||||
new DebugRenderer.Box(chunkDataView.getLodPos(), 0, 64f + offset, 0.07f, c),
|
||||
2.0, 16f
|
||||
)
|
||||
);
|
||||
readSourceFuture.thenAccept((renderSource) -> renderSource.fastWrite(chunkDataView, level));
|
||||
}
|
||||
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> flushAndSave(ExecutorService renderCacheThread)
|
||||
@@ -107,51 +142,78 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
{
|
||||
return CompletableFuture.completedFuture(null); // No need to save if the file doesn't exist.
|
||||
}
|
||||
|
||||
CompletableFuture<ColumnRenderSource> source = this.getCachedDataSourceAsync();
|
||||
CompletableFuture<ColumnRenderSource> source = getCachedDataSourceAsync();
|
||||
if (source == null)
|
||||
{
|
||||
return CompletableFuture.completedFuture(null); // If there is no cached data, there is no need to save.
|
||||
}
|
||||
|
||||
return source.thenAccept((columnRenderSource) -> { }); // Otherwise, wait for the data to be read (which also flushes changes to the file).
|
||||
}
|
||||
private CacheQueryResult getOrStartCachedDataSourceAsync()
|
||||
{
|
||||
// use the existing future
|
||||
CompletableFuture<ColumnRenderSource> renderSourceLoadFuture = getCachedDataSourceAsync();
|
||||
if (renderSourceLoadFuture == null) {
|
||||
// Make a new future, and CAS it, or return the existing future
|
||||
CompletableFuture<ColumnRenderSource> newFuture = new CompletableFuture<>();
|
||||
CompletableFuture<ColumnRenderSource> cas = AtomicsUtil.compareAndExchange(renderSourceLoadFutureRef, null, newFuture);
|
||||
if (cas == null) {
|
||||
return new CacheQueryResult(newFuture, true);
|
||||
} else {
|
||||
return new CacheQueryResult(cas, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return new CacheQueryResult(renderSourceLoadFuture, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private CompletableFuture<ColumnRenderSource> getCachedDataSourceAsync()
|
||||
{
|
||||
// attempt to get the cached data source
|
||||
ColumnRenderSource cachedRenderDataSource = this.cachedRenderDataSourceRef.get();
|
||||
if (cachedRenderDataSource != null)
|
||||
{
|
||||
return this.fileHandler.onReadRenderSourceLoadedFromCacheAsync(this, cachedRenderDataSource)
|
||||
// wait for the handler to finish before returning the renderSource
|
||||
.handle((voidObj, ex) -> cachedRenderDataSource);
|
||||
// use the existing future
|
||||
CompletableFuture<ColumnRenderSource> renderSourceLoadFuture = renderSourceLoadFutureRef.get();
|
||||
if (renderSourceLoadFuture != null) {
|
||||
return renderSourceLoadFuture;
|
||||
}
|
||||
// attempt to get the cached render source
|
||||
ColumnRenderSource cachedRenderDataSource = this.cachedRenderDataSource.get();
|
||||
if (cachedRenderDataSource == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
// Make a new future, and CAS it, or return the existing future
|
||||
CompletableFuture<ColumnRenderSource> newFuture = new CompletableFuture<>();
|
||||
CompletableFuture<ColumnRenderSource> cas = AtomicsUtil.compareAndExchange(renderSourceLoadFutureRef, null, newFuture);
|
||||
if (cas == null) {
|
||||
this.fileHandler.onReadRenderSourceLoadedFromCacheAsync(this, cachedRenderDataSource)
|
||||
// wait for the handler to finish before returning the renderSource
|
||||
.handle((voidObj, ex) -> {
|
||||
newFuture.complete(cachedRenderDataSource);
|
||||
renderSourceLoadFutureRef.set(null);
|
||||
return null;
|
||||
});
|
||||
return newFuture;
|
||||
}
|
||||
else {
|
||||
return cas;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// the data source hasn't been loaded
|
||||
// and isn't in the process of being loaded
|
||||
return null;
|
||||
}
|
||||
|
||||
public CompletableFuture<ColumnRenderSource> loadOrGetCachedDataSourceAsync(Executor fileReaderThreads, IDhLevel level)
|
||||
{
|
||||
CompletableFuture<ColumnRenderSource> getCachedFuture = this.getCachedDataSourceAsync();
|
||||
if (getCachedFuture != null)
|
||||
CacheQueryResult getCachedFuture = this.getOrStartCachedDataSourceAsync();
|
||||
if (!getCachedFuture.needsLoad)
|
||||
{
|
||||
return getCachedFuture;
|
||||
return getCachedFuture.future;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Create an empty and non-completed future.
|
||||
// Note: I do this before actually filling in the future so that I can ensure only
|
||||
// one task is submitted to the thread pool.
|
||||
CompletableFuture<ColumnRenderSource> loadRenderSourceFuture = new CompletableFuture<>();
|
||||
|
||||
CompletableFuture<ColumnRenderSource> future = getCachedFuture.future;
|
||||
// load or create the render source
|
||||
if (!this.doesFileExist)
|
||||
{
|
||||
// create a new Meta file
|
||||
|
||||
this.fileHandler.onCreateRenderFileAsync(this)
|
||||
.thenApply((renderSource) ->
|
||||
{
|
||||
@@ -164,13 +226,15 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
if (ex != null)
|
||||
{
|
||||
LOGGER.error("Uncaught error on creation {}: ", this.file, ex);
|
||||
loadRenderSourceFuture.complete(null);
|
||||
this.cachedRenderDataSourceRef = new SoftReference<>(null);
|
||||
cachedRenderDataSource = new SoftReference<>(null);
|
||||
renderSourceLoadFutureRef.set(null);
|
||||
future.complete(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
loadRenderSourceFuture.complete(renderSource);
|
||||
this.cachedRenderDataSourceRef = new SoftReference<>(renderSource);
|
||||
cachedRenderDataSource = new SoftReference<>(renderSource);
|
||||
renderSourceLoadFutureRef.set(null);
|
||||
future.complete(renderSource);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -198,25 +262,24 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile
|
||||
renderSource = this.fileHandler.onRenderFileLoaded(renderSource, this);
|
||||
return renderSource;
|
||||
}, fileReaderThreads)
|
||||
.whenComplete((renderSource, ex) ->
|
||||
.whenComplete((renderSource, ex) ->
|
||||
{
|
||||
if (ex != null)
|
||||
{
|
||||
LOGGER.error("Error loading file {}: ", this.file, ex);
|
||||
loadRenderSourceFuture.complete(null);
|
||||
this.cachedRenderDataSourceRef = new SoftReference<>(null);
|
||||
cachedRenderDataSource = new SoftReference<>(null);
|
||||
renderSourceLoadFutureRef.set(null);
|
||||
future.complete(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
loadRenderSourceFuture.complete(renderSource);
|
||||
this.cachedRenderDataSourceRef = new SoftReference<>(renderSource);
|
||||
cachedRenderDataSource = new SoftReference<>(renderSource);
|
||||
renderSourceLoadFutureRef.set(null);
|
||||
future.complete(renderSource);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
return loadRenderSourceFuture;
|
||||
return future;
|
||||
}
|
||||
|
||||
private BaseMetaData makeMetaData(ColumnRenderSource renderSource)
|
||||
|
||||
+8
-15
@@ -311,11 +311,6 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
|
||||
|
||||
private CompletableFuture<Void> updateCacheAsync(ColumnRenderSource renderSource, RenderMetaDataFile file)
|
||||
{
|
||||
if (this.cacheUpdateLockBySectionPos.putIfAbsent(file.pos, new Object()) != null)
|
||||
{
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
// get the full data source loading future
|
||||
CompletableFuture<IFullDataSource> fullDataSourceFuture = this.fullDataSourceProvider.read(renderSource.getSectionPos());
|
||||
fullDataSourceFuture = fullDataSourceFuture.thenApply((fullDataSource) ->
|
||||
@@ -327,8 +322,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
|
||||
LOGGER.error("Exception when getting data for updateCache()", ex);
|
||||
return null;
|
||||
});
|
||||
|
||||
|
||||
|
||||
// future returned
|
||||
CompletableFuture<Void> transformationCompleteFuture = new CompletableFuture<>();
|
||||
|
||||
@@ -362,12 +356,8 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
|
||||
LOGGER.error("Exception when updating render file using data source: ", ex);
|
||||
}
|
||||
}
|
||||
|
||||
transformationCompleteFuture.complete(null);
|
||||
})
|
||||
.thenRun(() -> this.cacheUpdateLockBySectionPos.remove(file.pos));
|
||||
|
||||
|
||||
});
|
||||
return transformationCompleteFuture;
|
||||
}
|
||||
|
||||
@@ -378,7 +368,9 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
|
||||
return renderSource;
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> onReadRenderSourceLoadedFromCacheAsync(RenderMetaDataFile file, ColumnRenderSource data) { return this.updateCacheAsync(data, file); }
|
||||
public CompletableFuture<Void> onReadRenderSourceLoadedFromCacheAsync(RenderMetaDataFile file, ColumnRenderSource data) {
|
||||
return this.updateCacheAsync(data, file);
|
||||
}
|
||||
|
||||
private void writeRenderSourceToFile(ColumnRenderSource currentRenderSource, RenderMetaDataFile file, ColumnRenderSource newRenderSource)
|
||||
{
|
||||
@@ -388,6 +380,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
|
||||
}
|
||||
|
||||
currentRenderSource.updateFromRenderSource(newRenderSource);
|
||||
currentRenderSource.localVersion.incrementAndGet();
|
||||
|
||||
//file.metaData.dataVersion.set(newDataVersion);
|
||||
file.baseMetaData.dataLevel = currentRenderSource.getDataDetail();
|
||||
@@ -395,7 +388,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
|
||||
file.baseMetaData.binaryDataFormatVersion = currentRenderSource.getRenderDataFormatVersion();
|
||||
file.save(currentRenderSource);
|
||||
}
|
||||
|
||||
/*
|
||||
public boolean refreshRenderSource(ColumnRenderSource renderSource)
|
||||
{
|
||||
RenderMetaDataFile file = this.filesBySectionPos.get(renderSource.getSectionPos());
|
||||
@@ -418,7 +411,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
|
||||
// return false;
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
//=====================//
|
||||
// clearing / shutdown //
|
||||
|
||||
+3
-2
@@ -621,12 +621,13 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable
|
||||
|
||||
@Override
|
||||
public void debugRender(DebugRenderer r) {
|
||||
if (true) return;
|
||||
CheckingTasks.forEach((t) -> {
|
||||
DhLodPos pos = t.pos;
|
||||
r.renderBox(new DebugRenderer.Box(pos, -32f, 128f, 0.05f, Color.blue));
|
||||
r.renderBox(new DebugRenderer.Box(pos, -32f, 64f, 0.05f, Color.blue));
|
||||
});
|
||||
this.inProgressGenTasksByLodPos.forEach((pos, t) -> {
|
||||
r.renderBox(new DebugRenderer.Box(pos, -32f, 128f, 0.05f, Color.red));
|
||||
r.renderBox(new DebugRenderer.Box(pos, -32f, 64f, 0.05f, Color.red));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.seibel.distanthorizons.core.level;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDebugRendering;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.ERendererMode;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
@@ -42,6 +44,8 @@ public class ClientLevelModule {
|
||||
// tick methods //
|
||||
//==============//
|
||||
|
||||
private EDebugRendering lastDebugRendering = EDebugRendering.OFF;
|
||||
|
||||
public void clientTick()
|
||||
{
|
||||
ClientRenderState clientRenderState = this.ClientRenderStateRef.get();
|
||||
@@ -69,6 +73,18 @@ public class ClientLevelModule {
|
||||
}
|
||||
}
|
||||
clientRenderState.quadtree.tick(new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos()));
|
||||
|
||||
boolean isBuffersDirty = false;
|
||||
EDebugRendering newDebugRendering = Config.Client.Advanced.Debugging.debugRendering.get();
|
||||
if (newDebugRendering != lastDebugRendering)
|
||||
{
|
||||
lastDebugRendering = newDebugRendering;
|
||||
isBuffersDirty = true;
|
||||
}
|
||||
if (isBuffersDirty) {
|
||||
clientRenderState.renderer.bufferHandler.MarkAllBuffersDirty();
|
||||
}
|
||||
|
||||
clientRenderState.renderer.bufferHandler.updateQuadTreeRenderSources();
|
||||
}
|
||||
|
||||
@@ -236,8 +252,6 @@ public class ClientLevelModule {
|
||||
public final RenderSourceFileHandler renderSourceFileHandler;
|
||||
public final LodRenderer renderer;
|
||||
|
||||
|
||||
|
||||
public ClientRenderState(IDhClientLevel dhClientLevel, IFullDataSourceProvider fullDataSourceProvider,
|
||||
AbstractSaveStructure saveStructure)
|
||||
{
|
||||
|
||||
@@ -176,7 +176,7 @@ public class DhClientServerLevel extends DhLevel implements IDhClientLevel, IDhS
|
||||
if (pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
DebugRenderer.makeParticle(
|
||||
new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(pos, 0, 256f, 0.05f, Color.red),
|
||||
new DebugRenderer.Box(pos, 0, 256f, 0.09f, Color.red),
|
||||
0.5, 512f
|
||||
)
|
||||
);
|
||||
|
||||
@@ -145,7 +145,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
DhSectionPos rootPos = rootPosIterator.next();
|
||||
if (this.getNode(rootPos) == null)
|
||||
{
|
||||
this.setValue(rootPos, new LodRenderSection(rootPos));
|
||||
this.setValue(rootPos, new LodRenderSection(this, rootPos));
|
||||
}
|
||||
|
||||
QuadNode<LodRenderSection> rootNode = this.getNode(rootPos);
|
||||
@@ -162,7 +162,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
// make sure the node is created
|
||||
if (quadNode == null && this.isSectionPosInBounds(sectionPos)) // the position bounds should only fail when at the edge of the user's render distance
|
||||
{
|
||||
rootNode.setValue(sectionPos, new LodRenderSection(sectionPos));
|
||||
rootNode.setValue(sectionPos, new LodRenderSection(this, sectionPos));
|
||||
quadNode = rootNode.getNode(sectionPos);
|
||||
}
|
||||
if (quadNode == null)
|
||||
@@ -176,7 +176,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
// create a new render section if missing
|
||||
if (renderSection == null)
|
||||
{
|
||||
LodRenderSection newRenderSection = new LodRenderSection(sectionPos);
|
||||
LodRenderSection newRenderSection = new LodRenderSection(this, sectionPos);
|
||||
rootNode.setValue(sectionPos, newRenderSection);
|
||||
|
||||
renderSection = newRenderSection;
|
||||
|
||||
@@ -48,6 +48,8 @@ public class LodRenderSection implements IDebugRenderable
|
||||
|
||||
//FIXME: Temp Hack to prevent swapping buffers too quickly
|
||||
private long lastNs = -1;
|
||||
private long lastSwapLocalVersion = -1;
|
||||
private boolean neighborUpdated = false;
|
||||
/** 2 sec */
|
||||
private static final long SWAP_TIMEOUT_IN_NS = 2_000000000L;
|
||||
/** 1 sec */
|
||||
@@ -58,10 +60,12 @@ public class LodRenderSection implements IDebugRenderable
|
||||
|
||||
/** a reference is used so the render buffer can be swapped to and from the buffer builder */
|
||||
public final AtomicReference<ColumnRenderBuffer> activeRenderBufferRef = new AtomicReference<>();
|
||||
|
||||
private final QuadTree<LodRenderSection> parentQuadTree;
|
||||
|
||||
|
||||
public LodRenderSection(DhSectionPos pos) {
|
||||
public LodRenderSection(QuadTree<LodRenderSection> parentQuadTree, DhSectionPos pos) {
|
||||
this.pos = pos;
|
||||
this.parentQuadTree = parentQuadTree;
|
||||
|
||||
DebugRenderer.register(this);
|
||||
}
|
||||
@@ -108,6 +112,7 @@ public class LodRenderSection implements IDebugRenderable
|
||||
this.renderSourceLoadFuture = null;
|
||||
this.renderSource = renderSource;
|
||||
this.lastNs = -1;
|
||||
markBufferDirty();
|
||||
if (this.reloadRenderSourceOnceLoaded)
|
||||
{
|
||||
this.reloadRenderSourceOnceLoaded = false;
|
||||
@@ -138,7 +143,7 @@ public class LodRenderSection implements IDebugRenderable
|
||||
if (pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
DebugRenderer.makeParticle(
|
||||
new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(pos, 0, 256f, 0.05f, Color.cyan),
|
||||
new DebugRenderer.Box(pos, 0, 256f, 0.03f, Color.cyan),
|
||||
0.5, 512f
|
||||
)
|
||||
);
|
||||
@@ -205,20 +210,44 @@ public class LodRenderSection implements IDebugRenderable
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInBuildBufferTimeout() {
|
||||
if (this.lastNs == -1) return false;
|
||||
//return true;
|
||||
|
||||
boolean inTimeout = System.nanoTime() - this.lastNs < SWAP_TIMEOUT_IN_NS;
|
||||
private boolean isBufferOutdated() {
|
||||
//if (this.lastNs == -1) return false;
|
||||
/* boolean inTimeout = System.nanoTime() - this.lastNs < SWAP_TIMEOUT_IN_NS;
|
||||
if (!inTimeout && ColumnRenderBufferBuilder.isBusy()) {
|
||||
this.lastNs += (long) (SWAP_BUSY_COLLISION_TIMEOUT_IN_NS * Math.random());
|
||||
inTimeout = true;
|
||||
return true;
|
||||
}*/
|
||||
return neighborUpdated || renderSource.localVersion.get() - lastSwapLocalVersion > 0;
|
||||
}
|
||||
|
||||
private LodRenderSection[] getNeighbors()
|
||||
{
|
||||
LodRenderSection[] adjacents = new LodRenderSection[ELodDirection.ADJ_DIRECTIONS.length];
|
||||
for (ELodDirection direction : ELodDirection.ADJ_DIRECTIONS) {
|
||||
try {
|
||||
DhSectionPos adjPos = pos.getAdjacentPos(direction);
|
||||
LodRenderSection adjRenderSection = parentQuadTree.getValue(adjPos);
|
||||
// adjacent render sources might be null
|
||||
adjacents[direction.ordinal() - 2] = adjRenderSection;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
// adjacent positions can be out of bounds, in that case a null render source will be used
|
||||
}
|
||||
}
|
||||
return adjacents;
|
||||
}
|
||||
|
||||
private void tellNeighborsUpdated()
|
||||
{
|
||||
LodRenderSection[] adjacents = getNeighbors();
|
||||
for (LodRenderSection adj : adjacents) {
|
||||
if (adj != null) {
|
||||
adj.neighborUpdated = true;
|
||||
}
|
||||
}
|
||||
return inTimeout;
|
||||
}
|
||||
|
||||
/** @return true if this section is loaded and set to render */
|
||||
public boolean canBuildBuffer() { return this.renderSource != null && this.buildRenderBufferFuture == null && !isInBuildBufferTimeout() && !this.renderSource.isEmpty(); }
|
||||
public boolean canBuildBuffer() { return this.renderSource != null && this.buildRenderBufferFuture == null && !this.renderSource.isEmpty() && isBufferOutdated(); }
|
||||
|
||||
/** @return true if this section is loaded and set to render */
|
||||
public boolean canSwapBuffer() { return this.buildRenderBufferFuture != null && this.buildRenderBufferFuture.isDone(); }
|
||||
@@ -230,40 +259,46 @@ public class LodRenderSection implements IDebugRenderable
|
||||
* places storing or referencing the render buffer.
|
||||
* @return True if the swap was successful. False if swap is not needed or if it is in progress.
|
||||
*/
|
||||
public boolean tryBuildAndSwapBuffer(QuadTree<LodRenderSection> tree)
|
||||
public boolean tryBuildAndSwapBuffer()
|
||||
{
|
||||
boolean didSwapped = false;
|
||||
if (canBuildBuffer()) {
|
||||
//if (false)
|
||||
if (pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
|
||||
DebugRenderer.makeParticle(
|
||||
new DebugRenderer.BoxParticle(
|
||||
new DebugRenderer.Box(pos, 0, 256f, 0.1f, Color.yellow),
|
||||
0.8, 512f
|
||||
new DebugRenderer.Box(pos, 0, 256f, -0.1f, Color.yellow),
|
||||
1.0, 512f
|
||||
)
|
||||
);
|
||||
ColumnRenderSource[] adjacentSources = new ColumnRenderSource[ELodDirection.ADJ_DIRECTIONS.length];
|
||||
for (ELodDirection direction : ELodDirection.ADJ_DIRECTIONS) {
|
||||
try {
|
||||
DhSectionPos adjPos = pos.getAdjacentPos(direction);
|
||||
LodRenderSection adjRenderSection = tree.getValue(adjPos);
|
||||
// adjacent render sources can be null
|
||||
if (adjRenderSection != null) {
|
||||
adjacentSources[direction.ordinal() - 2] = adjRenderSection.renderSource; // can be null
|
||||
}
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
// adjacent positions can be out of bounds, in that case a null render source will be used
|
||||
neighborUpdated = false;
|
||||
long newVs = renderSource.localVersion.get();
|
||||
if (lastSwapLocalVersion != newVs) {
|
||||
lastSwapLocalVersion = newVs;
|
||||
tellNeighborsUpdated();
|
||||
}
|
||||
LodRenderSection[] adjacents = getNeighbors();
|
||||
ColumnRenderSource[] adjacentSources = new ColumnRenderSource[ELodDirection.ADJ_DIRECTIONS.length];
|
||||
for (int i = 0; i < ELodDirection.ADJ_DIRECTIONS.length; i++) {
|
||||
LodRenderSection adj = adjacents[i];
|
||||
if (adj != null) {
|
||||
adjacentSources[i] = adj.getRenderSource();
|
||||
}
|
||||
}
|
||||
this.buildRenderBufferFuture =
|
||||
ColumnRenderBufferBuilder.buildBuffers(level, this.inactiveRenderBufferRef, renderSource, adjacentSources);
|
||||
this.buildRenderBufferFuture = ColumnRenderBufferBuilder.buildBuffers(level, this.inactiveRenderBufferRef, renderSource, adjacentSources);
|
||||
}
|
||||
if (canSwapBuffer()) {
|
||||
this.lastNs = System.nanoTime();
|
||||
ColumnRenderBuffer newBuffer;
|
||||
try {
|
||||
newBuffer = this.buildRenderBufferFuture.getNow(null);
|
||||
LodUtil.assertTrue(newBuffer != null && newBuffer.buffersUploaded, "The buffer future for "+pos+" returned an un-built buffer.");
|
||||
this.buildRenderBufferFuture = null;
|
||||
if (newBuffer == null) {
|
||||
// failed.
|
||||
markBufferDirty();
|
||||
return false;
|
||||
}
|
||||
LodUtil.assertTrue(newBuffer.buffersUploaded, "The buffer future for "+pos+" returned an un-built buffer.");
|
||||
ColumnRenderBuffer oldBuffer = this.activeRenderBufferRef.getAndSet(newBuffer);
|
||||
if (oldBuffer != null)
|
||||
{
|
||||
@@ -324,4 +359,9 @@ public class LodRenderSection implements IDebugRenderable
|
||||
buffer.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void markBufferDirty() {
|
||||
tellNeighborsUpdated();
|
||||
lastSwapLocalVersion = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,9 +165,19 @@ public class RenderBufferHandler
|
||||
//TODO: Directional culling
|
||||
this.loadedNearToFarBuffers.forEach(loadedBuffer -> loadedBuffer.buffer.renderTransparent(renderContext));
|
||||
}
|
||||
|
||||
|
||||
private boolean rebuildAllBuffers = false;
|
||||
|
||||
public void MarkAllBuffersDirty()
|
||||
{
|
||||
this.rebuildAllBuffers = true;
|
||||
}
|
||||
|
||||
public void updateQuadTreeRenderSources()
|
||||
{
|
||||
boolean rebuildAllBuffers = this.rebuildAllBuffers;
|
||||
this.rebuildAllBuffers = false;
|
||||
|
||||
Iterator<QuadNode<LodRenderSection>> nodeIterator = this.lodQuadTree.nodeIterator();
|
||||
while (nodeIterator.hasNext())
|
||||
{
|
||||
@@ -175,7 +185,11 @@ public class RenderBufferHandler
|
||||
try {
|
||||
if (renderSection != null)
|
||||
{
|
||||
renderSection.tryBuildAndSwapBuffer(lodQuadTree);
|
||||
if (rebuildAllBuffers)
|
||||
{
|
||||
renderSection.markBufferDirty();
|
||||
}
|
||||
renderSection.tryBuildAndSwapBuffer();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
Reference in New Issue
Block a user