diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java index 6175ae415..c47122656 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/FullDataMetaFile.java @@ -40,7 +40,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I //TODO: Atm can't find a better way to store when genQueue is checked. public boolean genQueueChecked = false; - private boolean markedNeedUpdate = false; + private volatile boolean markedNeedUpdate = false; public AbstractFullDataSourceLoader fullDataSourceLoader; public Class dataType; @@ -57,6 +57,9 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I @Override public void debugRender(DebugRenderer r) { IFullDataSource cached = cachedFullDataSource.get(); + if (markedNeedUpdate) + r.renderBox(new DebugRenderer.Box(pos, 0, 512, 0.05f, Color.red)); + Color c = Color.black; if (cached != null) { if (cached instanceof CompleteFullDataSource) { @@ -69,7 +72,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I } else if (doesFileExist) { c = Color.RED; } - //r.renderBox(pos, 50, 200, 0.05f, c); + //r.renderBox(new DebugRenderer.Box(pos, 0, 256, 0.05f, c)); } //TODO: use ConcurrentAppendSingleSwapContainer instead of below: @@ -168,9 +171,11 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I private void makeUpdateCompletionStage(CompletableFuture completer, CompletableFuture currentStage) { - markedNeedUpdate = false; currentStage.thenCompose( - (fullDataSource) -> this.fullDataSourceProvider.onDataFileUpdate(fullDataSource, this, this::_updateAndWriteDataSource, this::_applyWriteQueueToFullDataSource)) + (fullDataSource) -> { + markedNeedUpdate = false; + return this.fullDataSourceProvider.onDataFileUpdate(fullDataSource, this, this::_updateAndWriteDataSource, this::_applyWriteQueueToFullDataSource); + }) .whenComplete((fullDataSource, ex) -> { if (ex instanceof CompletionException) { @@ -186,11 +191,25 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I if (fullDataSource != null) { new DataObjTracker(fullDataSource); } - LOGGER.info("Updated file "+this.file); + //LOGGER.info("Updated file "+this.file); + if (pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) + DebugRenderer.makeParticle( + new DebugRenderer.BoxParticle( + new DebugRenderer.Box(this.pos, 0, 256f, 0.05f, Color.green), + 0.5, 512f + ) + ); + this.cachedFullDataSource = new SoftReference<>(fullDataSource); inCrit = false; dataSourceLoadFutureRef.set(null); completer.complete(fullDataSource); + + if (this.markedNeedUpdate) + { + // trigger another update + this.loadOrGetCachedDataSourceAsync(); + } }); } @@ -413,7 +432,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile implements I public CompletableFuture flushAndSaveAsync() { debugPhantomLifeCycleCheck(); - boolean isEmpty = this.writeQueueRef.get().queue.isEmpty(); + boolean isEmpty = this.writeQueueRef.get().queue.isEmpty() && !markedNeedUpdate; if (!isEmpty) { // This will flush the data to disk. diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java index 74e780ba2..87d13cfed 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java @@ -1,12 +1,14 @@ package com.seibel.distanthorizons.core.file.fullDatafile; 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.dataObjects.fullData.sources.interfaces.IIncompleteFullDataSource; import com.seibel.distanthorizons.core.file.metaData.BaseMetaData; import com.seibel.distanthorizons.core.generation.WorldGenerationQueue; import com.seibel.distanthorizons.core.generation.tasks.IWorldGenTaskTracker; import com.seibel.distanthorizons.core.generation.tasks.WorldGenResult; +import com.seibel.distanthorizons.core.level.DhLevel; import com.seibel.distanthorizons.core.level.IDhServerLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhLodPos; @@ -69,15 +71,15 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler { boolean oldQueueExists = this.worldGenQueueRef.compareAndSet(null, newWorldGenQueue); LodUtil.assertTrue(oldQueueExists, "previous world gen queue is still here!"); - + LOGGER.info("Set world gen queue for level {} to start.", this.level); for (FullDataMetaFile metaFile : this.fileBySectionPos.values()) { - metaFile.genQueueChecked = false; // unset it so it can be checked again IFullDataSource data = metaFile.getCachedDataSourceNowOrNull(); - if (data instanceof IIncompleteFullDataSource) { - // need manual marking for update. - metaFile.markNeedUpdate(); + if (data instanceof CompleteFullDataSource) { + continue; } + metaFile.genQueueChecked = false; // unset it so it can be checked again + metaFile.markNeedUpdate(); } flushAndSave(); // Trigger an update to the meta files } @@ -113,7 +115,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler if (targetDataDetailLevel > maxSectDataDetailLevel) { ArrayList existingFiles = new ArrayList<>(); byte sectDetailLevel = (byte) (DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL + maxSectDataDetailLevel); - pos.forEachChildAtLevel(sectDetailLevel, this::getOrMakeFile); + pos.forEachChildAtLevel(sectDetailLevel, p -> existingFiles.add(getOrMakeFile(p))); return sampleFromFiles(dataSource, existingFiles).thenApply(IIncompleteFullDataSource::tryPromotingToCompleteDataSource) .exceptionally((e) -> { @@ -249,6 +251,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler private void fireOnGenPosSuccessListeners(DhSectionPos pos) { + if (true) return; //LOGGER.info("gen task completed for pos: ["+pos+"]."); /* // save the full data source @@ -328,7 +331,8 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler { if (chunkSizedFullDataSource.getLodPos().overlapsExactly(this.loadedTargetFullDataSource.getSectionPos().getSectionBBoxPos())) { - GeneratedFullDataFileHandler.this.write(this.loadedTargetFullDataSource.getSectionPos(), chunkSizedFullDataSource); + ((DhLevel)level).saveWrites(chunkSizedFullDataSource); + //GeneratedFullDataFileHandler.this.write(this.loadedTargetFullDataSource.getSectionPos(), chunkSizedFullDataSource); } }; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java index 56bd88a42..4cd17c38e 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/renderfile/RenderMetaDataFile.java @@ -5,6 +5,7 @@ import com.seibel.distanthorizons.core.file.metaData.AbstractMetaDataContainerFi import com.seibel.distanthorizons.core.file.metaData.BaseMetaData; import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; import com.seibel.distanthorizons.core.pos.DhLodPos; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderLoader; @@ -14,6 +15,7 @@ import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataInputStream; import org.apache.logging.log4j.Logger; +import java.awt.*; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -87,6 +89,13 @@ public class RenderMetaDataFile extends AbstractMetaDataContainerFile CompletableFuture readSourceFuture = this.getCachedDataSourceAsync(); if (readSourceFuture != null) { + if (chunkDataView.getLodPos().detailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) + DebugRenderer.makeParticle( + new DebugRenderer.BoxParticle( + new DebugRenderer.Box(chunkDataView.getLodPos(), 0, 256f, 0.05f, Color.blue), + 0.5, 512f + ) + ); readSourceFuture.thenAccept((renderSource) -> renderSource.fastWrite(chunkDataView, level)); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java index 89a9e2b35..2aa8bb43d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java @@ -84,6 +84,7 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable public WorldGenerationQueue(IDhApiWorldGenerator generator) { + LOGGER.info("Creating world gen queue"); this.generator = generator; this.maxGranularity = generator.getMaxGenerationGranularity(); this.minGranularity = generator.getMinGenerationGranularity(); @@ -104,6 +105,7 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable throw new IllegalArgumentException(IDhApiWorldGenerator.class.getSimpleName() + ": max granularity smaller than min granularity!"); } DebugRenderer.register(this); + LOGGER.info("Created world gen queue"); } @@ -156,13 +158,9 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable public void runCurrentGenTasksUntilBusy(DhBlockPos2D targetPos) { + generator.preGeneratorTaskStart(); try { - if (this.generator == null) - { - throw new IllegalStateException("generator is null"); - } - // the generator is shutting down, don't attempt to generate anything if (this.generatorClosingFuture != null) { @@ -496,6 +494,7 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable public CompletableFuture startClosing(boolean cancelCurrentGeneration, boolean alsoInterruptRunning) { + LOGGER.info("Closing world gen queue"); this.queueingThread.shutdownNow(); @@ -578,10 +577,7 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable { LOGGER.warn("Failed to close generation queue: ", e); } - - LOGGER.info("Finished closing "+WorldGenerationQueue.class.getSimpleName()); - DebugRenderer.unregister(this); } @@ -627,10 +623,10 @@ public class WorldGenerationQueue implements Closeable, IDebugRenderable public void debugRender(DebugRenderer r) { CheckingTasks.forEach((t) -> { DhLodPos pos = t.pos; - r.renderBox(pos, -32f, 128f, 0.05f, Color.blue); + r.renderBox(new DebugRenderer.Box(pos, -32f, 128f, 0.05f, Color.blue)); }); this.inProgressGenTasksByLodPos.forEach((pos, t) -> { - r.renderBox(pos, -30f, 128f, 0.05f, Color.red); + r.renderBox(new DebugRenderer.Box(pos, -32f, 128f, 0.05f, Color.red)); }); } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java index c4803a7ee..9e63773a9 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java @@ -84,7 +84,7 @@ public class DhClientLevel extends DhLevel implements IDhClientLevel } @Override - protected void saveWrites(ChunkSizedFullDataAccessor data) { + public void saveWrites(ChunkSizedFullDataAccessor data) { clientside.saveWrites(data); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java index 4dfa0573c..0d9f20703 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java @@ -3,6 +3,7 @@ package com.seibel.distanthorizons.core.level; import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.file.fullDatafile.IFullDataSourceProvider; +import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhBlockPos; @@ -18,6 +19,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapp import com.seibel.distanthorizons.coreapi.util.math.Mat4f; import org.apache.logging.log4j.Logger; +import java.awt.*; import java.util.concurrent.CompletableFuture; /** The level used on a singleplayer world */ @@ -143,7 +145,7 @@ public class DhClientServerLevel extends DhLevel implements IDhClientLevel, IDhS } @Override - protected void saveWrites(ChunkSizedFullDataAccessor data) { + public void saveWrites(ChunkSizedFullDataAccessor data) { clientside.saveWrites(data); } @@ -171,6 +173,13 @@ 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, 0, 256f, 0.05f, Color.red), + 0.5, 512f + ) + ); clientside.reloadPos(pos); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhLevel.java index 0811d7f14..1f4f3301a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhLevel.java @@ -14,7 +14,7 @@ public abstract class DhLevel implements IDhLevel { this.chunkToLodBuilder = new ChunkToLodBuilder(); } - protected abstract void saveWrites(ChunkSizedFullDataAccessor data); + public abstract void saveWrites(ChunkSizedFullDataAccessor data); @Override diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java index b0fc81c85..8434d4c8b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java @@ -35,7 +35,7 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel } @Override - protected void saveWrites(ChunkSizedFullDataAccessor data) { + public void saveWrites(ChunkSizedFullDataAccessor data) { DhLodPos pos = data.getLodPos().convertToDetailLevel(CompleteFullDataSource.SECTION_SIZE_OFFSET); getFileHandler().write(new DhSectionPos(pos.detailLevel, pos.x, pos.z), data); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java b/core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java index 17f2f7de9..81e5be59c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java @@ -20,7 +20,6 @@ import java.util.concurrent.atomic.AtomicReference; public class ServerLevelModule { private static class WorldGenState { - public final IDhApiWorldGenerator chunkGenerator; public final WorldGenerationQueue worldGenerationQueue; WorldGenState(IDhServerLevel level) { @@ -33,9 +32,7 @@ public class ServerLevelModule { // since core world generator's should have the lowest override priority WorldGeneratorInjector.INSTANCE.bind(level.getLevelWrapper(), worldGenerator); } - this.chunkGenerator = worldGenerator; - - this.worldGenerationQueue = new WorldGenerationQueue(this.chunkGenerator); + this.worldGenerationQueue = new WorldGenerationQueue(worldGenerator); } CompletableFuture closeAsync(boolean doInterrupt) @@ -46,13 +43,17 @@ public class ServerLevelModule { LOGGER.error("Error closing generation queue", ex); return null; } - ).thenRun(this.chunkGenerator::close) + ).thenRun(this.worldGenerationQueue::close) .exceptionally(ex -> { LOGGER.error("Error closing world gen", ex); return null; }); } + + public void tick(DhBlockPos2D targetPosForGeneration) { + worldGenerationQueue.runCurrentGenTasksUntilBusy(targetPosForGeneration); + } } private static final Logger LOGGER = DhLoggerBuilder.getLogger(); @@ -87,8 +88,8 @@ public class ServerLevelModule { LOGGER.warn("Failed to start world gen due to concurrency"); newWgs.closeAsync(false); } - dataFileHandler.setGenerationQueue(newWgs.worldGenerationQueue); dataFileHandler.addWorldGenCompleteListener(parent); + dataFileHandler.setGenerationQueue(newWgs.worldGenerationQueue); } public void stopWorldGen() @@ -125,8 +126,7 @@ public class ServerLevelModule { if (worldGenState != null) { // queue new world generation requests - worldGenState.chunkGenerator.preGeneratorTaskStart();//new DhBlockPos2D(MC_CLIENT.getPlayerBlockPos() - worldGenState.worldGenerationQueue.runCurrentGenTasksUntilBusy(targetPosForGeneration); + worldGenState.tick(targetPosForGeneration); } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java index 754a5c4d5..5d057bd45 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodRenderSection.java @@ -81,9 +81,7 @@ public class LodRenderSection implements IDebugRenderable if (canRenderNow() && isRenderingEnabled) color = Color.green; } - float yOffset = Objects.hashCode(this) / (float) Integer.MAX_VALUE * 16f + 16f; - - r.renderBox(this.pos, yOffset, yOffset, 0.1f, color); + r.renderBox(new DebugRenderer.Box(this.pos, 400, 8f, Objects.hashCode(this), 0.1f, color)); } @@ -109,6 +107,7 @@ public class LodRenderSection implements IDebugRenderable { this.renderSourceLoadFuture = null; this.renderSource = renderSource; + this.lastNs = -1; if (this.reloadRenderSourceOnceLoaded) { this.reloadRenderSourceOnceLoaded = false; @@ -136,6 +135,13 @@ public class LodRenderSection implements IDebugRenderable public void reload(ILodRenderSourceProvider renderDataProvider) { + if (pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL) + DebugRenderer.makeParticle( + new DebugRenderer.BoxParticle( + new DebugRenderer.Box(pos, 0, 256f, 0.05f, Color.cyan), + 0.5, 512f + ) + ); this.renderSourceProvider = renderDataProvider; if (this.renderSourceProvider == null) { @@ -201,14 +207,14 @@ public class LodRenderSection implements IDebugRenderable private boolean isInBuildBufferTimeout() { if (this.lastNs == -1) return false; - return true; + //return true; - //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 inTimeout; + 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 inTimeout; } /** @return true if this section is loaded and set to render */ @@ -228,6 +234,13 @@ public class LodRenderSection implements IDebugRenderable { boolean didSwapped = false; if (canBuildBuffer()) { + 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 + ) + ); ColumnRenderSource[] adjacentSources = new ColumnRenderSource[ELodDirection.ADJ_DIRECTIONS.length]; for (ELodDirection direction : ELodDirection.ADJ_DIRECTIONS) { try { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java index 13c99549a..a880a77b3 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java @@ -19,6 +19,8 @@ import com.seibel.distanthorizons.coreapi.util.math.Mat4f; 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.*; @@ -26,6 +28,7 @@ import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.*; +import java.util.concurrent.PriorityBlockingQueue; public class DebugRenderer { public static DebugRenderer INSTANCE = new DebugRenderer(); @@ -67,17 +70,117 @@ public class DebugRenderer { 3, 7, }; + public static final class Box { + public final Vec3f a; + public final Vec3f b; + public final Color color; + + public Box(Vec3f a, Vec3f b, Color color) { + this.a = a; + this.b = b; + this.color = color; + } + + public Box(Vec3f a, Vec3f b, Color color, Vec3f margin) { + this.a = a; + this.a.add(margin); + this.b = b; + this.b.subtract(margin); + this.color = color; + } + + public Box(DhLodPos pos, float minY, float maxY, float marginPercent, Color color) { + DhBlockPos2D blockMin = pos.getCornerBlockPos(); + DhBlockPos2D blockMax = blockMin.add(pos.getBlockWidth(), pos.getBlockWidth()); + float edge = pos.getBlockWidth() * marginPercent; + Vec3f a = new Vec3f(blockMin.x + edge, minY, blockMin.z + edge); + Vec3f b = new Vec3f(blockMax.x - edge, maxY, blockMax.z - edge); + this.a = a; + this.b = b; + this.color = color; + } + + public Box(DhLodPos pos, float y, float yDiff, Object hash, float marginPercent, Color color) { + float hashY = ((float)hash.hashCode() / Integer.MAX_VALUE) * yDiff; + DhBlockPos2D blockMin = pos.getCornerBlockPos(); + DhBlockPos2D blockMax = blockMin.add(pos.getBlockWidth(), pos.getBlockWidth()); + float edge = pos.getBlockWidth() * marginPercent; + Vec3f a = new Vec3f(blockMin.x + edge, hashY, blockMin.z + edge); + Vec3f b = new Vec3f(blockMax.x - edge, hashY, blockMax.z - edge); + this.a = a; + this.b = b; + this.color = color; + } + + public Box(DhSectionPos pos, float minY, float maxY, float marginPercent, Color color) { + this(pos.getSectionBBoxPos(), minY, maxY, marginPercent, color); + } + + public Box(DhSectionPos pos, float y, float yDiff, Object hash, float marginPercent, Color color) { + this(pos.getSectionBBoxPos(), y, yDiff, hash, marginPercent, color); + } + } + ShaderProgram basicShader; GLVertexBuffer boxBuffer; GLElementBuffer boxOutlineBuffer; VertexAttribute va; boolean init = false; + private final LinkedList> renderers = new LinkedList<>(); + + public static final class BoxParticle implements Comparable { + private final Box box; + private final long startTime; + private final long duration; + private final float yChange; + + public BoxParticle(Box box, long startTime, long duration, float yChange) { + this.box = box; + this.startTime = startTime; + this.duration = duration; + this.yChange = yChange; + } + + public BoxParticle(Box box, long ns, float yChange) { + this(box, System.nanoTime(), ns, 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) { + return Long.compare(startTime, o.startTime); + } + + Box getBox() { + long now = System.nanoTime(); + float percent = (now - startTime) / (float)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); + } + + boolean isDead(long time) { + return time - startTime > duration; + } + } + + private final PriorityBlockingQueue particles = new PriorityBlockingQueue<>(); + public static void unregister(IDebugRenderable r) { if (INSTANCE == null) return; INSTANCE.removeRenderer(r); } + public static void makeParticle(BoxParticle particle) { + if (INSTANCE == null) return; + if (!Config.Client.Advanced.Debugging.debugWireframeRendering.get()) return; + INSTANCE.particles.add(particle); + } + private void removeRenderer(IDebugRenderable r) { synchronized (renderers) { Iterator> it = renderers.iterator(); @@ -126,8 +229,6 @@ public class DebugRenderer { boxOutlineBuffer.uploadBuffer(buffer, EGpuUploadMethod.DATA, box_outline_indices.length * Integer.BYTES, GL32.GL_STATIC_DRAW); } - private final LinkedList> renderers = new LinkedList<>(); - public void addRenderer(IDebugRenderable r) { if (!Config.Client.Advanced.Debugging.debugWireframeRendering.get()) return; synchronized (renderers) { @@ -143,34 +244,13 @@ public class DebugRenderer { private Mat4f transform_this_frame; private Vec3f camf; - public void renderBox(DhLodPos pos, float minY, float maxY, float marginPercent, Color color) { - DhBlockPos2D blockMin = pos.getCornerBlockPos(); - DhBlockPos2D blockMax = blockMin.add(pos.getBlockWidth(), pos.getBlockWidth()); - float edge = pos.getBlockWidth() * marginPercent; - renderBox(blockMin.x + edge, minY, blockMin.z + edge, blockMax.x - edge, maxY, blockMax.z - edge, color); - } - - public void renderBox(DhLodPos pos, float minY, float maxY, Color color) { - renderBox(pos, minY, maxY, 0, color); - } - - public void renderBox(DhSectionPos sectPos, float minY, float maxY, Color color) { - renderBox(sectPos.getSectionBBoxPos(), minY, maxY, 0, color); - } - - public void renderBox(DhSectionPos sectPos, float minY, float maxY, float marginPercent, Color color) { - renderBox(sectPos.getSectionBBoxPos(), minY, maxY, marginPercent, color); - } - - public void renderBox(float x, float y, float z, float x2, float y2, float z2, Color color) { - Vec3f boxPos = new Vec3f(x - camf.x, y - camf.y, z - camf.z); - Mat4f boxTransform = Mat4f.createTranslateMatrix(boxPos.x, boxPos.y, boxPos.z); - boxTransform.multiply(Mat4f.createScaleMatrix(x2-x, y2-y, z2-z)); + 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"), color); + basicShader.setUniform(basicShader.getUniformLocation("uColor"), box.color); GL32.glDrawElements(GL32.GL_LINES, box_outline_indices.length, GL32.GL_UNSIGNED_INT, 0); } @@ -213,6 +293,13 @@ public class DebugRenderer { } } + 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(); }