diff --git a/core/src/main/java/com/seibel/lod/core/datatype/AbstractDataSourceLoader.java b/core/src/main/java/com/seibel/lod/core/datatype/AbstractDataSourceLoader.java index 81da97a38..7ef4b2498 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/AbstractDataSourceLoader.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/AbstractDataSourceLoader.java @@ -61,7 +61,7 @@ public abstract class AbstractDataSourceLoader loaderRegistry.put(clazz, this); } - // Can return null as meaning the requirement is not met + /** Can return null as meaning the requirement is not met */ public abstract ILodDataSource loadData(DataMetaFile dataFile, InputStream data, IDhLevel level) throws IOException; diff --git a/core/src/main/java/com/seibel/lod/core/datatype/AbstractRenderSourceLoader.java b/core/src/main/java/com/seibel/lod/core/datatype/AbstractRenderSourceLoader.java index 372ac53e5..fa0e8a6ef 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/AbstractRenderSourceLoader.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/AbstractRenderSourceLoader.java @@ -63,7 +63,7 @@ public abstract class AbstractRenderSourceLoader this.detailOffset = detailOffset; } - // Can return null as meaning the file is out of date or something + /** Can return null if the file is out of date or something */ public abstract ILodRenderSource loadRender(RenderMetaFile renderFile, InputStream data, IDhLevel level) throws IOException; public abstract ILodRenderSource createRender(ILodDataSource dataSource, IDhClientLevel level); diff --git a/core/src/main/java/com/seibel/lod/core/datatype/IIncompleteDataSource.java b/core/src/main/java/com/seibel/lod/core/datatype/IIncompleteDataSource.java index 9e4e9158a..a55a5d9ce 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/IIncompleteDataSource.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/IIncompleteDataSource.java @@ -5,7 +5,10 @@ import com.seibel.lod.core.datatype.full.accessor.SingleFullArrayView; public interface IIncompleteDataSource extends ILodDataSource { void sampleFrom(ILodDataSource source); + ILodDataSource trySelfPromote(); - // Return null if doesn't exist + + /** @return null if the data doesn't exist */ SingleFullArrayView tryGet(int x, int z); + } diff --git a/core/src/main/java/com/seibel/lod/core/datatype/ILodRenderSource.java b/core/src/main/java/com/seibel/lod/core/datatype/ILodRenderSource.java index 5310b64db..dcb6affa3 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/ILodRenderSource.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/ILodRenderSource.java @@ -45,4 +45,5 @@ public interface ILodRenderSource /** Overrides any data that has not been written directly using write(). Skips empty source dataPoints. */ void updateFromRenderSource(ILodRenderSource source); + } diff --git a/core/src/main/java/com/seibel/lod/core/datatype/PlaceHolderRenderSource.java b/core/src/main/java/com/seibel/lod/core/datatype/PlaceHolderRenderSource.java index e0fff4c5f..88896c2a5 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/PlaceHolderRenderSource.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/PlaceHolderRenderSource.java @@ -25,13 +25,13 @@ public class PlaceHolderRenderSource implements ILodRenderSource public byte getDataDetail() { return 0; } @Override - public void enableRender(IDhClientLevel level, LodQuadTree quadTree){ /* TODO */ } + public void enableRender(IDhClientLevel level, LodQuadTree quadTree) { /* TODO */ } @Override - public void disableRender(){ /* TODO */ } + public void disableRender() { /* TODO */ } @Override - public void dispose(){ /* TODO */ } + public void dispose() { /* TODO */ } @Override public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference referenceSlots) { return false; } @@ -59,5 +59,4 @@ public class PlaceHolderRenderSource implements ILodRenderSource @Override public void updateFromRenderSource(ILodRenderSource source) { /* TODO */ } - } diff --git a/core/src/main/java/com/seibel/lod/core/datatype/transform/ChunkToLodBuilder.java b/core/src/main/java/com/seibel/lod/core/datatype/transform/ChunkToLodBuilder.java index 0b0987fc0..408956da2 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/transform/ChunkToLodBuilder.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/transform/ChunkToLodBuilder.java @@ -13,16 +13,19 @@ import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; import org.apache.logging.log4j.LogManager; //FIXME: To-Be-Used class -public class ChunkToLodBuilder { - public static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(), - () -> Config.Client.Advanced.Debugging.DebugSwitch.logLodBuilderEvent.get()); +public class ChunkToLodBuilder +{ + public static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(), () -> Config.Client.Advanced.Debugging.DebugSwitch.logLodBuilderEvent.get()); public static final long MAX_TICK_TIME_NS = 1000000000L / 20L; public static final int THREAD_COUNT = 1; - - static class Task { + + private static class Task + { final DhChunkPos chunkPos; final CompletableFuture future; - Task(DhChunkPos chunkPos, CompletableFuture future) { + + Task(DhChunkPos chunkPos, CompletableFuture future) + { this.chunkPos = chunkPos; this.future = future; } @@ -31,65 +34,91 @@ public class ChunkToLodBuilder { private final ConcurrentLinkedDeque taskToBuild = new ConcurrentLinkedDeque<>(); private final ExecutorService executor = LodUtil.makeThreadPool(THREAD_COUNT, ChunkToLodBuilder.class); private final AtomicInteger runningCount = new AtomicInteger(0); - - public CompletableFuture tryGenerateData(IChunkWrapper chunk) { - if (chunk == null) throw new NullPointerException("ChunkWrapper cannot be null!"); + + + + public CompletableFuture tryGenerateData(IChunkWrapper chunk) + { + if (chunk == null) + throw new NullPointerException("ChunkWrapper cannot be null!"); + IChunkWrapper oldChunk = latestChunkToBuild.put(chunk.getChunkPos(), chunk); // an Exchange operation // If there's old chunk, that means we just replaced an unprocessed old request on generating data on this pos. // if so, we can just return null to signal this, as the old request's future will instead be the proper one // that will return the latest generated data. - if (oldChunk != null) return null; + if (oldChunk != null) + return null; + // Otherwise, it means we're the first to do so. Lets submit our task to this entry. CompletableFuture future = new CompletableFuture<>(); taskToBuild.addLast(new Task(chunk.getChunkPos(), future)); return future; } - - public void tick() { + + public void tick() + { if (runningCount.get() >= THREAD_COUNT) return; if (taskToBuild.isEmpty()) return; - for (int i = 0; i { - try { + CompletableFuture.runAsync(() -> + { + try + { _tick(); - } finally { + } + finally + { runningCount.decrementAndGet(); } }, executor); } } - - private void _tick() { + + private void _tick() + { long time = System.nanoTime(); int count = 0; boolean allDone = false; - while (true) { - if (System.nanoTime() - time > MAX_TICK_TIME_NS && !taskToBuild.isEmpty()) break; + while (true) + { + if (System.nanoTime() - time > MAX_TICK_TIME_NS && !taskToBuild.isEmpty()) + break; + Task task = taskToBuild.pollFirst(); - if (task == null) { + if (task == null) + { allDone = true; break; } + count++; IChunkWrapper latestChunk = latestChunkToBuild.remove(task.chunkPos); // Basically an Exchange operation - if (latestChunk == null) { + if (latestChunk == null) + { LOGGER.error("Somehow Task at {} has latestChunk as null! Skipping task!", task.chunkPos); task.future.complete(null); continue; } - - try { - if (LodDataBuilder.canGenerateLodFromChunk(latestChunk)) { + + try + { + if (LodDataBuilder.canGenerateLodFromChunk(latestChunk)) + { ChunkSizedData data = LodDataBuilder.createChunkData(latestChunk); - if (data != null) { + if (data != null) + { task.future.complete(data); continue; } } - } catch (Exception ex) { + } + catch (Exception ex) + { LOGGER.error("Error while processing Task at {}!", task.chunkPos, ex); } + // Failed to build due to chunk not meeting requirement. IChunkWrapper casChunk = latestChunkToBuild.putIfAbsent(task.chunkPos, latestChunk); // CAS operation with expected=null if (casChunk == null || latestChunk.isStillValid()) // That means CAS have been successful @@ -98,11 +127,16 @@ public class ChunkToLodBuilder { task.future.complete(null); count--; } + long time2 = System.nanoTime(); - if (!allDone) { + if (!allDone) + { //LOGGER.info("Completed {} tasks in {} in this tick", count, Duration.ofNanos(time2 - time)); - } else if (count > 0) { + } + else if (count > 0) + { //LOGGER.info("Completed all {} tasks in {}", count, Duration.ofNanos(time2 - time)); } } + } diff --git a/core/src/main/java/com/seibel/lod/core/datatype/transform/DataRenderTransformer.java b/core/src/main/java/com/seibel/lod/core/datatype/transform/DataRenderTransformer.java index 770fd38ea..bfac956f4 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/transform/DataRenderTransformer.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/transform/DataRenderTransformer.java @@ -11,21 +11,26 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; //TODO: Merge this with FullToColumnTransformer -public class DataRenderTransformer { +public class DataRenderTransformer +{ public static final ExecutorService TRANSFORMER_THREADS = LodUtil.makeThreadPool(4, "Data/Render Transformer"); - - public static CompletableFuture transformDataSource(ILodDataSource data, IDhClientLevel level) { + + public static CompletableFuture transformDataSource(ILodDataSource data, IDhClientLevel level) + { return CompletableFuture.supplyAsync(() -> transform(data, level), TRANSFORMER_THREADS); } - - public static CompletableFuture asyncTransformDataSource(CompletableFuture data, IDhClientLevel level) { + + public static CompletableFuture asyncTransformDataSource(CompletableFuture data, IDhClientLevel level) + { return data.thenApplyAsync((d) -> transform(d, level), TRANSFORMER_THREADS); } - - private static ILodRenderSource transform(ILodDataSource dataSource, IDhClientLevel level) { + + private static ILodRenderSource transform(ILodDataSource dataSource, IDhClientLevel level) + { if (dataSource == null) return null; return ColumnRenderLoader.loaderRegistry.get(ColumnRenderSource.class) .stream().findFirst().get().createRender(dataSource, level); } + } diff --git a/core/src/main/java/com/seibel/lod/core/datatype/transform/FullToColumnTransformer.java b/core/src/main/java/com/seibel/lod/core/datatype/transform/FullToColumnTransformer.java index e5014ff1c..82f2390a4 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/transform/FullToColumnTransformer.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/transform/FullToColumnTransformer.java @@ -26,7 +26,6 @@ public class FullToColumnTransformer { * Creates a LodNode for a chunk in the given world. * @throws IllegalArgumentException thrown if either the chunk or world is null. */ - public static ColumnRenderSource transformFullDataToColumnData(IDhClientLevel level, FullDataSource data) { final DhSectionPos pos = data.getSectionPos(); final byte dataDetail = data.getDataDetail();