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