From 69202b86cd0e7bb88287024cb9bb7a958f99872f Mon Sep 17 00:00:00 2001 From: TomTheFurry Date: Mon, 25 Jul 2022 13:38:33 +0800 Subject: [PATCH] Fix and port batch generator to new Generator API. Now if we just fix up forge, and there's no bugs (impossible), then there's enough implemented to finally have something shown! Yay! --- .../lod/common/wrappers/WrapperFactory.java | 18 +- .../BatchGenerationEnvironment.java | 407 ++++++++---------- .../worldGeneration/GenerationEvent.java | 136 +++--- .../wrappers/worldGeneration/Rolling.java | 2 +- .../step/StepStructureStart.java | 3 +- core | 2 +- 6 files changed, 255 insertions(+), 313 deletions(-) diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/WrapperFactory.java b/common/src/main/java/com/seibel/lod/common/wrappers/WrapperFactory.java index 146836fe1..e5a7df83d 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/WrapperFactory.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/WrapperFactory.java @@ -21,8 +21,8 @@ package com.seibel.lod.common.wrappers; import com.seibel.lod.common.wrappers.block.BlockStateWrapper; import com.seibel.lod.common.wrappers.world.BiomeWrapper; -import com.seibel.lod.core.builders.lodBuilding.LodBuilder; -import com.seibel.lod.core.objects.lod.LodDimension; +import com.seibel.lod.core.a7.level.ILevel; +import com.seibel.lod.core.a7.level.IServerLevel; import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory; import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper; @@ -40,10 +40,16 @@ public class WrapperFactory implements IWrapperFactory { public static final WrapperFactory INSTANCE = new WrapperFactory(); - public AbstractBatchGenerationEnvionmentWrapper createBatchGenerator(LodBuilder newLodBuilder, - LodDimension newLodDimension, ILevelWrapper worldWrapper) - { - return new BatchGenerationEnvironment(worldWrapper, newLodBuilder, newLodDimension); + @Override + public AbstractBatchGenerationEnvionmentWrapper createBatchGenerator(ILevel targetLevel) { + if (targetLevel instanceof IServerLevel) + { + return new BatchGenerationEnvironment((IServerLevel) targetLevel); + } + else + { + throw new IllegalArgumentException("The target level must be a server-side level."); + } } @Override diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index aa3a29d07..886f93eb0 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -30,6 +30,9 @@ import com.seibel.lod.core.logging.ConfigBasedSpamLogger; import com.seibel.lod.core.builders.lodBuilding.LodBuilderConfig; import com.seibel.lod.core.enums.config.EDistanceGenerationMode; import com.seibel.lod.core.enums.config.ELightGenerationMode; +import com.seibel.lod.core.objects.DHChunkPos; +import com.seibel.lod.core.util.EventTimer; +import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.gridList.ArrayGridList; import com.seibel.lod.core.util.LodThreadFactory; import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; @@ -37,6 +40,8 @@ import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper; import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; import java.util.concurrent.CompletableFuture; @@ -74,6 +79,7 @@ import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.lighting.LevelLightEngine; import org.apache.logging.log4j.LogManager; +import org.checkerframework.checker.units.qual.C; /* Total: 3.135214124s @@ -102,121 +108,56 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv () -> Config.Client.Advanced.Debugging.DebugSwitch.logWorldGenLoadEvent.get()); //TODO: Make actual proper support for StarLight - - public static class PrefEvent - { - long beginNano = 0; - long emptyNano = 0; - long structStartNano = 0; - long structRefNano = 0; - long biomeNano = 0; - long noiseNano = 0; - long surfaceNano = 0; - long carverNano = 0; - long featureNano = 0; - long lightNano = 0; - long endNano = 0; - - @Override - public String toString() - { - return "beginNano: " + beginNano + ",\n" + - "emptyNano: " + emptyNano + ",\n" + - "structStartNano: " + structStartNano + ",\n" + - "structRefNano: " + structRefNano + ",\n" + - "biomeNano: " + biomeNano + ",\n" + - "noiseNano: " + noiseNano + ",\n" + - "surfaceNano: " + surfaceNano + ",\n" + - "carverNano: " + carverNano + ",\n" + - "featureNano: " + featureNano + ",\n" + - "lightNano: " + lightNano + ",\n" + - "endNano: " + endNano + "\n"; - } - } - + public static class PerfCalculator { + private static final String[] TIME_NAMES = { + "total", + "setup", + "structStart", + "structRef", + "biome", + "noise", + "surface", + "carver", + "feature", + "light", + "cleanup", + //"lodCreation" (No longer used) + }; + public static final int SIZE = 50; - Rolling totalTime = new Rolling(SIZE); - Rolling emptyTime = new Rolling(SIZE); - Rolling structStartTime = new Rolling(SIZE); - Rolling structRefTime = new Rolling(SIZE); - Rolling biomeTime = new Rolling(SIZE); - Rolling noiseTime = new Rolling(SIZE); - Rolling surfaceTime = new Rolling(SIZE); - Rolling carverTime = new Rolling(SIZE); - Rolling featureTime = new Rolling(SIZE); - Rolling lightTime = new Rolling(SIZE); - Rolling lodTime = new Rolling(SIZE); - - public void recordEvent(PrefEvent e) + ArrayList times = new ArrayList<>(); + + public PerfCalculator() { - long preTime = e.beginNano; - totalTime.add(e.endNano - preTime); - if (e.emptyNano != 0) + for(int i = 0; i < 11; i++) { - emptyTime.add(e.emptyNano - preTime); - preTime = e.emptyNano; + times.add(new Rolling(SIZE)); } - if (e.structStartNano != 0) + } + + public void recordEvent(EventTimer event) + { + for (EventTimer.Event e : event.events) { - structStartTime.add(e.structStartNano - preTime); - preTime = e.structStartNano; - } - if (e.structRefNano != 0) - { - structRefTime.add(e.structRefNano - preTime); - preTime = e.structRefNano; - } - if (e.biomeNano != 0) - { - biomeTime.add(e.biomeNano - preTime); - preTime = e.biomeNano; - } - if (e.noiseNano != 0) - { - noiseTime.add(e.noiseNano - preTime); - preTime = e.noiseNano; - } - if (e.surfaceNano != 0) - { - surfaceTime.add(e.surfaceNano - preTime); - preTime = e.surfaceNano; - } - if (e.carverNano != 0) - { - carverTime.add(e.carverNano - preTime); - preTime = e.carverNano; - } - if (e.featureNano != 0) - { - featureTime.add(e.featureNano - preTime); - preTime = e.featureNano; - } - if (e.lightNano != 0) - { - lightTime.add(e.lightNano - preTime); - preTime = e.lightNano; - } - if (e.endNano != 0) - { - lodTime.add(e.endNano - preTime); + String name = e.name; + int index = Arrays.asList(TIME_NAMES).indexOf(name); + if(index == -1) continue; + times.get(index).add(e.timeNs); } + times.get(0).add(event.getTotalTimeNs()); } public String toString() { - return "Total: " + Duration.ofNanos((long) totalTime.getAverage()) + ", Empty/LoadChunk: " - + Duration.ofNanos((long) emptyTime.getAverage()) + ", StructStart: " - + Duration.ofNanos((long) structStartTime.getAverage()) + ", StructRef: " - + Duration.ofNanos((long) structRefTime.getAverage()) + ", Biome: " - + Duration.ofNanos((long) biomeTime.getAverage()) + ", Noise: " - + Duration.ofNanos((long) noiseTime.getAverage()) + ", Surface: " - + Duration.ofNanos((long) surfaceTime.getAverage()) + ", Carver: " - + Duration.ofNanos((long) carverTime.getAverage()) + ", Feature: " - + Duration.ofNanos((long) featureTime.getAverage()) + ", Light: " - + Duration.ofNanos((long) lightTime.getAverage()) + ", Lod: " - + Duration.ofNanos((long) lodTime.getAverage()); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < times.size(); i++) + { + if (times.get(i).getAverage() == 0) continue; + sb.append(TIME_NAMES[i]).append(": ").append(times.get(i).getAverage()).append("\n"); + } + return sb.toString(); } } @@ -273,23 +214,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv executors = Executors.newFixedThreadPool(newThreadCount, new LodThreadFactory("Gen-Worker-Thread", Thread.MIN_PRIORITY)); } - - public boolean tryAddPoint(int px, int pz, int range, Steps target, boolean genAllDetails, double runTimeRatio) - { - int boxSize = range * 2 + 1; - int x = Math.floorDiv(px, boxSize) * boxSize + range; - int z = Math.floorDiv(pz, boxSize) * boxSize + range; - - for (GenerationEvent event : events) - { - if (event.tooClose(x, z, range)) - return false; - } - // System.out.println(x + ", "+z); - events.add(new GenerationEvent(new ChunkPos(x, z), range, this, target, genAllDetails, runTimeRatio)); - return true; - } - + public void updateAllFutures() { if (unknownExceptionCount > 0) { @@ -297,36 +222,32 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv unknownExceptionCount = 0; } } - + // Update all current out standing jobs Iterator iter = events.iterator(); while (iter.hasNext()) { GenerationEvent event = iter.next(); - if (event.isCompleted()) + if (event.future.isDone()) { - try - { - event.join(); - } - catch (Throwable e) - { - EVENT_LOGGER.error("Batching World Generator: Event {} gotten an exception", event); - EVENT_LOGGER.error("Exception: ", e); - unknownExceptionCount++; - lastExceptionTriggerTime = System.nanoTime(); - } - finally - { - iter.remove(); + if (event.future.isCompletedExceptionally() && !event.future.isCancelled()) { + try { + event.future.get(); // Should throw exception + LodUtil.assertNotReach(); + } catch (Exception e) { + unknownExceptionCount++; + lastExceptionTriggerTime = System.nanoTime(); + EVENT_LOGGER.error("Batching World Generator: Event {} gotten an exception", event); + EVENT_LOGGER.error("Exception: ", e); + } } + iter.remove(); } else if (event.hasTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)) { EVENT_LOGGER.error("Batching World Generator: " + event + " timed out and terminated!"); - EVENT_LOGGER.info("Dump PrefEvent: " + event.pEvent); - try - { + EVENT_LOGGER.info("Dump PrefEvent: " + event.timer); + try { if (!event.terminate()) EVENT_LOGGER.error("Failed to terminate the stuck generation event!"); } @@ -336,13 +257,14 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv } } } + if (unknownExceptionCount > EXCEPTION_COUNTER_TRIGGER) { EVENT_LOGGER.error("Too many exceptions in Batching World Generator! Disabling the generator."); unknownExceptionCount = 0; Config.Client.WorldGenerator.enableDistantGeneration.set(false); } } - + public BatchGenerationEnvironment(IServerLevel serverlevel) { super(serverlevel); @@ -400,19 +322,19 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv } - public void generateLodFromList(GenerationEvent e) + public ArrayGridList generateLodFromList(GenerationEvent e) { - EVENT_LOGGER.debug("Lod Generate Event: " + e.pos); - e.pEvent.beginNano = System.nanoTime(); + EVENT_LOGGER.debug("Lod Generate Event: " + e.minPos); ArrayGridList referencedChunks; ArrayGridList genChunks; EDistanceGenerationMode generationMode; LightedWorldGenRegion region; WorldGenLevelLightEngine lightEngine; LightGetterAdaptor adaptor; - int refRange = e.range + RANGE_TO_RANGE_EMPTY_EXTENSION; - int refOffsetX = e.pos.x - refRange; - int refOffsetZ = e.pos.z - refRange; + int refSize = e.size+2; // +2 for the border referenced chunks + int refPosX = e.minPos.x - 1; // -1 for the border referenced chunks + int refPosZ = e.minPos.z - 1; // -1 for the border referenced chunks + try { adaptor = new LightGetterAdaptor(params.level); @@ -439,109 +361,118 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv return target; }; - referencedChunks = new ArrayGridList<>(refRange*2+1, - (x,z) -> generator.generate(x + refOffsetX,z + refOffsetZ) + referencedChunks = new ArrayGridList<>(refSize, + (x,z) -> generator.generate(x + refPosX,z + refPosZ) ); - e.pEvent.emptyNano = System.nanoTime(); e.refreshTimeout(); region = new LightedWorldGenRegion(params.level, lightEngine, referencedChunks, - ChunkStatus.STRUCTURE_STARTS, refRange, e.lightMode, generator); + ChunkStatus.STRUCTURE_STARTS, refSize/2, e.lightMode, generator); adaptor.setRegion(region); e.tParam.makeStructFeat(region, params); genChunks = new ArrayGridList<>(referencedChunks, RANGE_TO_RANGE_EMPTY_EXTENSION, referencedChunks.gridSize - RANGE_TO_RANGE_EMPTY_EXTENSION); generateDirect(e, genChunks, e.target, region); + e.timer.nextEvent("cleanup"); } catch (StepStructureStart.StructStartCorruptedException f) { e.tParam.markAsInvalid(); - return; + throw (RuntimeException)f.getCause(); } - switch (e.target) - { - case Empty: - case StructureStart: - case StructureReference: - generationMode = EDistanceGenerationMode.NONE; - break; - case Biomes: - generationMode = EDistanceGenerationMode.BIOME_ONLY; - case Noise: - generationMode = EDistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT; - break; - case Surface: - case Carvers: - generationMode = EDistanceGenerationMode.SURFACE; - break; - case Features: - generationMode = EDistanceGenerationMode.FEATURES; - break; - case Light: - case LiquidCarvers: - default: - return; - } - - for (int oy = 0; oy < genChunks.gridSize; oy++) - { - for (int ox = 0; ox < genChunks.gridSize; ox++) - { - ChunkAccess target = genChunks.get(ox, oy); - ChunkWrapper wrappedChunk = new ChunkWrapper(target, region); - if (!wrappedChunk.isLightCorrect()) { - throw new RuntimeException("The generated chunk somehow has isLightCorrect() returning false"); - } - - boolean isFull = target.getStatus() == ChunkStatus.FULL || target instanceof LevelChunk; - #if POST_MC_1_18_1 - boolean isPartial = target.isOldNoiseGeneration(); - #endif - if (isFull) - { - LOAD_LOGGER.info("Detected full existing chunk at {}", target.getPos()); - ChunkSizedData data = LodDataBuilder.createChunkData(wrappedChunk); - if (data != null) - { - //params.lodLevel.submitChunkData(data); - } +// switch (e.target) +// { +// case Empty: +// case StructureStart: +// case StructureReference: +// generationMode = EDistanceGenerationMode.NONE; +// break; +// case Biomes: +// generationMode = EDistanceGenerationMode.BIOME_ONLY; +// case Noise: +// generationMode = EDistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT; +// break; +// case Surface: +// case Carvers: +// generationMode = EDistanceGenerationMode.SURFACE; +// break; +// case Features: +// generationMode = EDistanceGenerationMode.FEATURES; +// break; +// case Light: +// case LiquidCarvers: +// default: +// throw new IllegalArgumentException("Unknown/Unsupported target: " + e.target); +// } +// for (int oy = 0; oy < genChunks.gridSize; oy++) +// { +// for (int ox = 0; ox < genChunks.gridSize; ox++) +// { +// ChunkAccess target = genChunks.get(ox, oy); +// ChunkWrapper wrappedChunk = new ChunkWrapper(target, region); +// if (!wrappedChunk.isLightCorrect()) { +// throw new RuntimeException("The generated chunk somehow has isLightCorrect() returning false"); +// } +// +// boolean isFull = target.getStatus() == ChunkStatus.FULL || target instanceof LevelChunk; +// #if POST_MC_1_18_1 +// boolean isPartial = target.isOldNoiseGeneration(); +// #endif +// if (isFull) +// { +// LOAD_LOGGER.info("Detected full existing chunk at {}", target.getPos()); +// ChunkSizedData data = LodDataBuilder.createChunkData(wrappedChunk); +// if (data != null) +// { +// params.lodLevel.submitChunkData(data); +// } +// +// //FIXME: Fix this +// params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk, +// new LodBuilderConfig(EDistanceGenerationMode.FULL), true, e.genAllDetails); +// } +// #if POST_MC_1_18_1 +// else if (isPartial) +// { +// LOAD_LOGGER.info("Detected old existing chunk at {}", target.getPos()); +// params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk, +// new LodBuilderConfig(generationMode), true, e.genAllDetails); +// } +// #endif +// else if (target.getStatus() == ChunkStatus.EMPTY && generationMode == EDistanceGenerationMode.NONE) +// { +// params.lodBuilder.generateLodNodeFromChunk(params.lodDim,wrappedChunk, +// LodBuilderConfig.getFillVoidConfig(), true, e.genAllDetails); +// } +// else +// { +// params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk, +// new LodBuilderConfig(generationMode), true, e.genAllDetails); +// } +// if (e.lightMode == ELightGenerationMode.FANCY || isFull) +// { +// lightEngine.retainData(target.getPos(), false); +// } +// +// } +// } - //FIXME: Fix this - //params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk, - // new LodBuilderConfig(EDistanceGenerationMode.FULL), true, e.genAllDetails); - } - #if POST_MC_1_18_1 - else if (isPartial) - { - LOAD_LOGGER.info("Detected old existing chunk at {}", target.getPos()); - //params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk, - // new LodBuilderConfig(generationMode), true, e.genAllDetails); - } - #endif - else if (target.getStatus() == ChunkStatus.EMPTY && generationMode == EDistanceGenerationMode.NONE) - { - //params.lodBuilder.generateLodNodeFromChunk(params.lodDim,wrappedChunk, - // LodBuilderConfig.getFillVoidConfig(), true, e.genAllDetails); - } - else - { - //params.lodBuilder.generateLodNodeFromChunk(params.lodDim, wrappedChunk, - // new LodBuilderConfig(generationMode), true, e.genAllDetails); - } - if (e.lightMode == ELightGenerationMode.FANCY || isFull) - { - lightEngine.retainData(target.getPos(), false); - } - + ArrayGridList result = new ArrayGridList<>(e.size); + for (int oy = 0; oy < e.size; oy++) + { + for (int ox = 0; ox < e.size; ox++) + { + result.set(ox, oy, new ChunkWrapper(genChunks.get(ox, oy), region)); } } - e.pEvent.endNano = System.nanoTime(); + e.timer.complete(); e.refreshTimeout(); if (PREF_LOGGER.canMaybeLog()) { - e.tParam.perf.recordEvent(e.pEvent); - PREF_LOGGER.infoInc("{}", e.tParam.perf); + e.tParam.perf.recordEvent(e.timer); + PREF_LOGGER.infoInc("{}", e.timer); } + return result; } public void generateDirect(GenerationEvent e, ArrayGridList subRange, Steps step, @@ -559,39 +490,41 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv }); if (step == Steps.Empty) return; + e.timer.nextEvent("structStart"); stepStructureStart.generateGroup(e.tParam, region, subRange); - e.pEvent.structStartNano = System.nanoTime(); e.refreshTimeout(); if (step == Steps.StructureStart) return; + e.timer.nextEvent("structRef"); stepStructureReference.generateGroup(e.tParam, region, subRange); - e.pEvent.structRefNano = System.nanoTime(); e.refreshTimeout(); if (step == Steps.StructureReference) return; + e.timer.nextEvent("biome"); stepBiomes.generateGroup(e.tParam, region, subRange); - e.pEvent.biomeNano = System.nanoTime(); e.refreshTimeout(); if (step == Steps.Biomes) return; + e.timer.nextEvent("noise"); stepNoise.generateGroup(e.tParam, region, subRange); - e.pEvent.noiseNano = System.nanoTime(); e.refreshTimeout(); if (step == Steps.Noise) return; + e.timer.nextEvent("surface"); stepSurface.generateGroup(e.tParam, region, subRange); - e.pEvent.surfaceNano = System.nanoTime(); e.refreshTimeout(); if (step == Steps.Surface) return; + e.timer.nextEvent("carver"); if (step == Steps.Carvers) return; + e.timer.nextEvent("feature"); stepFeatures.generateGroup(e.tParam, region, subRange); - e.pEvent.featureNano = System.nanoTime(); e.refreshTimeout(); } finally { + e.timer.nextEvent("light"); switch (region.lightMode) { case FANCY: @@ -611,7 +544,6 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv }); break; } - e.pEvent.lightNano = System.nanoTime(); e.refreshTimeout(); } } @@ -641,6 +573,9 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv @Override public CompletableFuture> generateChunks(int minX, int minZ, int genSize, Steps targetStep, double runTimeRatio) { - return null; // TODO: Implement generateChunks + // TODO: Check event overlap via e.tooClose() + GenerationEvent e = GenerationEvent.startEvent(new DHChunkPos(minX, minZ), genSize, this, targetStep, runTimeRatio); + events.add(e); + return e.future; } } \ No newline at end of file diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/GenerationEvent.java b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/GenerationEvent.java index 31fa659df..1fe3649de 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/GenerationEvent.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/GenerationEvent.java @@ -20,86 +20,92 @@ package com.seibel.lod.common.wrappers.worldGeneration; import java.lang.invoke.MethodHandles; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment.PrefEvent; import com.seibel.lod.core.config.Config; import com.seibel.lod.core.enums.config.ELightGenerationMode; import com.seibel.lod.core.logging.DhLoggerBuilder; +import com.seibel.lod.core.objects.DHChunkPos; +import com.seibel.lod.core.util.EventTimer; import com.seibel.lod.core.util.LodUtil; +import com.seibel.lod.core.util.gridList.ArrayGridList; +import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper.Steps; -import net.minecraft.world.level.ChunkPos; import org.apache.logging.log4j.Logger; //======================= Main Event class====================== public final class GenerationEvent { private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName()); - private static int generationFutureDebugIDs = 0; - final ThreadedParameters tParam; - final ChunkPos pos; - final int range; - final Future future; - long creationNanotime; final int id; + final ThreadedParameters tParam; + final DHChunkPos minPos; + final int size; final Steps target; final ELightGenerationMode lightMode; - final PrefEvent pEvent = new PrefEvent(); - final boolean genAllDetails; - final double runTimeRatio; - - public GenerationEvent(ChunkPos pos, int range, BatchGenerationEnvironment generationGroup, - Steps target, boolean genAllDetails, double runTimeRatio) + EventTimer timer = null; + long inQueueTime; + long timeoutTime = -1; + public CompletableFuture> future = null; + + public GenerationEvent(DHChunkPos minPos, int size, BatchGenerationEnvironment generationGroup, + Steps target, double runTimeRatio) { - creationNanotime = System.nanoTime(); - this.pos = pos; - this.range = range; - id = generationFutureDebugIDs++; + inQueueTime = System.nanoTime(); + this.id = generationFutureDebugIDs++; + this.minPos = minPos; + this.size = size; this.target = target; this.tParam = ThreadedParameters.getOrMake(generationGroup.params); - ELightGenerationMode mode = Config.Client.WorldGenerator.lightGenerationMode.get(); - - this.lightMode = mode; - this.genAllDetails = genAllDetails; + this.lightMode = Config.Client.WorldGenerator.lightGenerationMode.get(); this.runTimeRatio = runTimeRatio; - - future = generationGroup.executors.submit(() -> - { - long startTime = System.nanoTime(); - BatchGenerationEnvironment.isDistantGeneratorThread.set(true); - try { - generationGroup.generateLodFromList(this); - } finally { - BatchGenerationEnvironment.isDistantGeneratorThread.remove(); - if (!Thread.interrupted() && runTimeRatio < 1.0) { - long endTime = System.nanoTime(); - try { - long deltaMs = TimeUnit.NANOSECONDS.toMillis(endTime - startTime); - Thread.sleep((long) (deltaMs/runTimeRatio - deltaMs)); - } catch (InterruptedException ignored) { - } - } - } - }); + } - - public boolean isCompleted() + + public static GenerationEvent startEvent(DHChunkPos minPos, int size, BatchGenerationEnvironment generationGroup, + Steps target, double runTimeRatio) + { + if (size % 2 == 0) size += 1; // size must be odd for vanilla world gen region to work + GenerationEvent event = new GenerationEvent(minPos, size, generationGroup, target, runTimeRatio); + event.future = CompletableFuture.supplyAsync(() -> + { + long runStartTime = System.nanoTime(); + event.timeoutTime = runStartTime; + event.inQueueTime = runStartTime - event.inQueueTime; + event.timer = new EventTimer("setup"); + BatchGenerationEnvironment.isDistantGeneratorThread.set(true); + try { + return generationGroup.generateLodFromList(event); + } finally { + BatchGenerationEnvironment.isDistantGeneratorThread.remove(); + if (!Thread.interrupted() && runTimeRatio < 1.0) { + long endTime = System.nanoTime(); + try { + long deltaMs = TimeUnit.NANOSECONDS.toMillis(endTime - runStartTime); + Thread.sleep((long) (deltaMs/runTimeRatio - deltaMs)); + } catch (InterruptedException ignored) {} + } + } + }, generationGroup.executors); + return event; + } + + public boolean isComplete() { return future.isDone(); } - + public boolean hasTimeout(int duration, TimeUnit unit) { long currentTime = System.nanoTime(); - long delta = currentTime - creationNanotime; + long delta = currentTime - timeoutTime; return (delta > TimeUnit.NANOSECONDS.convert(duration, unit)); } - + public boolean terminate() { LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN======================="); @@ -108,36 +114,30 @@ public final class GenerationEvent return future.isCancelled(); } - public void join() + public boolean tooClose(int minX, int minZ, int w) { - try - { - future.get(); - } - catch (InterruptedException | ExecutionException e) - { - throw new RuntimeException(e.getCause()==null? e : e.getCause()); - } - } - - public boolean tooClose(int cx, int cz, int cr) - { - int distX = Math.abs(cx - pos.x); - int distZ = Math.abs(cz - pos.z); - int minRange = cr + range + 1; // Need one to account for the center - minRange += 1 + 1; // Account for required empty chunks - return distX < minRange && distZ < minRange; + int aMinX = minPos.x; + int aMinZ = minPos.z; + int aSize = size; + // Account for required empty chunks in the border + aSize += 1; + w+= 1; + // Do a AABB to AABB intersection test + return (aMinX + aSize >= minX && + aMinX <= minX + w && + aMinZ + aSize >= minZ && + aMinZ <= minZ + w); } public void refreshTimeout() { - creationNanotime = System.nanoTime(); + timeoutTime = System.nanoTime(); LodUtil.checkInterruptsUnchecked(); } @Override public String toString() { - return id + ":" + range + "@" + pos + "(" + target + ")"; + return id + ":" + size + "@" + minPos + "(" + target + ")"; } } \ No newline at end of file diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/Rolling.java b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/Rolling.java index c2f93d752..a219c1f42 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/Rolling.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/Rolling.java @@ -48,6 +48,6 @@ public class Rolling public double getAverage() { - return total / size; + return size==0 ? 0 : total / size; } } \ No newline at end of file diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/step/StepStructureStart.java b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/step/StepStructureStart.java index ae6e45934..f7e9b99a2 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/step/StepStructureStart.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/step/StepStructureStart.java @@ -87,7 +87,8 @@ public final class StepStructureStart { } catch (ArrayIndexOutOfBoundsException e) { // There's a rare issue with StructStart where it throws ArrayIndexOutOfBounds // This means the structFeat is corrupted (For some reason) and I need to reset it. - // TODO: Figure out in the future why this happens even though I am using new structFeat + // TODO: Figure out in the future why this happens even though I am using new structFeat - OLD + // TODO: Is this still a problem? throw new StepStructureStart.StructStartCorruptedException(e); } #endif diff --git a/core b/core index 5f486b625..973be4032 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 5f486b625846c76d62d44e910f1018f8bee040e4 +Subproject commit 973be40324bdc6699ecada4fb3451eee93007b10