From af8dea9d9f6efbe00a6f3dce4afe8a442002b406 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Nov 2025 08:17:01 -0600 Subject: [PATCH 01/33] Start world gen refactoring --- .../common/wrappers/DependencySetup.java | 2 +- ...oneCheck.java => WorldGenThreadCheck.java} | 11 +- .../common/wrappers/WrapperFactory.java | 4 +- .../BatchGenerationEnvironment.java | 173 +++++++++--------- .../worldGeneration/GenerationEvent.java | 31 ++-- ...ameters.java => GlobalWorldGenParams.java} | 20 +- .../wrappers/worldGeneration/Rolling.java | 56 ------ ...ameters.java => ThreadWorldGenParams.java} | 41 +++-- .../step/AbstractWorldGenStep.java | 4 +- .../worldGeneration/step/StepBiomes.java | 6 +- .../worldGeneration/step/StepFeatures.java | 4 +- .../worldGeneration/step/StepNoise.java | 7 +- .../step/StepStructureReference.java | 6 +- .../step/StepStructureStart.java | 9 +- .../worldGeneration/step/StepSurface.java | 6 +- coreSubProjects | 2 +- .../fabric/mixins/server/MixinLevelTicks.java | 4 +- .../mixins/server/MixinTracingExecutor.java | 5 +- .../server/MixinUtilBackgroundThread.java | 9 +- .../mixins/server/MixinLevelTicks.java | 4 +- .../mixins/server/MixinTracingExecutor.java | 4 +- .../server/MixinUtilBackgroundThread.java | 10 +- 22 files changed, 178 insertions(+), 240 deletions(-) rename common/src/main/java/com/seibel/distanthorizons/common/wrappers/{DependencySetupDoneCheck.java => WorldGenThreadCheck.java} (71%) rename common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/{GlobalParameters.java => GlobalWorldGenParams.java} (90%) delete mode 100644 common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/Rolling.java rename common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/{ThreadedParameters.java => ThreadWorldGenParams.java} (71%) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java index c7b851f36..9260196fd 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java @@ -56,7 +56,7 @@ public class DependencySetup SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE); SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE); SingletonInjector.INSTANCE.bind(IKeyedClientLevelManager.class, KeyedClientLevelManager.INSTANCE); - DependencySetupDoneCheck.isDone = true; + WorldGenThreadCheck.isSetup = true; } public static void createServerBindings() diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetupDoneCheck.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WorldGenThreadCheck.java similarity index 71% rename from common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetupDoneCheck.java rename to common/src/main/java/com/seibel/distanthorizons/common/wrappers/WorldGenThreadCheck.java index c508d5321..224ed8c69 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetupDoneCheck.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WorldGenThreadCheck.java @@ -19,18 +19,21 @@ package com.seibel.distanthorizons.common.wrappers; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; + import java.util.function.Supplier; -public class DependencySetupDoneCheck +public class WorldGenThreadCheck { - // TODO move to DependencySetup - public static boolean isDone = false; + public static boolean isSetup = false; + /** * This is used so we can override some MC logic when running * in DH's world generator. * Specifically so we can redirect threads to run on DH threads instead * of MC threads. */ - public static Supplier getIsCurrentThreadDistantGeneratorThread = (() -> { return false; }); + //public static Supplier isCurrentThreadDhWorldGenThread = (() -> { return false; }); + public static Supplier isCurrentThreadDhWorldGenThread = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread; // TODO can we just do this? } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java index b692b9c11..ce789634a 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java @@ -38,7 +38,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrappe import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; -import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper; import net.minecraft.client.multiplayer.ClientLevel; #if MC_VER > MC_1_17_1 import net.minecraft.core.Holder; @@ -67,7 +67,7 @@ public class WrapperFactory implements IWrapperFactory //==============// @Override - public AbstractBatchGenerationEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel) + public IBatchGeneratorEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel) { if (targetLevel instanceof IDhServerLevel) { diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index fc7967440..19a3c9d65 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -36,11 +36,12 @@ import com.seibel.distanthorizons.core.util.ExceptionUtil; import com.seibel.distanthorizons.core.util.objects.EventTimer; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; +import com.seibel.distanthorizons.core.util.objects.RollingAverage; import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; -import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import java.io.IOException; @@ -57,7 +58,7 @@ import java.util.stream.StreamSupport; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck; +import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepBiomes; import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepFeatures; import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepNoise; @@ -93,30 +94,18 @@ import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStatus; #endif -/* -Total: 3.135214124s -===================================== -Empty Chunks: 0.000558328s -StructureStart Step: 0.025177207s -StructureReference Step: 0.00189559s -Biome Step: 0.13789155s -Noise Step: 1.570347555s -Surface Step: 0.741238194s -Carver Step: 0.000009923s -Feature Step: 0.389072425s -Lod Generation: 0.269023348s -*/ -public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnvironmentWrapper +public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironmentWrapper { + public static final DhLogger LOGGER = new DhLoggerBuilder() + .name("LOD World Gen") + .fileLevelConfig(Config.Common.Logging.logWorldGenEventToFile) + .build(); + public static final DhLogger PREF_LOGGER = new DhLoggerBuilder() .name("LOD World Gen") .fileLevelConfig(Config.Common.Logging.logWorldGenPerformanceToFile) .maxCountPerSecond(1) .build(); - public static final DhLogger EVENT_LOGGER = new DhLoggerBuilder() - .name("LOD World Gen") - .fileLevelConfig(Config.Common.Logging.logWorldGenEventToFile) - .build(); public static final DhLogger CHUNK_LOAD_LOGGER = new DhLoggerBuilder() .name("LOD World Gen") .fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile) @@ -132,6 +121,10 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv private static final IModChecker MOD_CHECKER = SingletonInjector.INSTANCE.get(IModChecker.class); + @NotNull + public static final ImmutableMap WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP; + public static final int MAX_WORLD_GEN_CHUNK_BORDER_NEEDED; + private final IDhServerLevel serverLevel; @@ -147,7 +140,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv //=================Generation Step=================== public final LinkedBlockingQueue generationEventList = new LinkedBlockingQueue<>(); - public final GlobalParameters params; + public final GlobalWorldGenParams params; public final StepStructureStart stepStructureStart = new StepStructureStart(this); public final StepStructureReference stepStructureReference = new StepStructureReference(this); public final StepBiomes stepBiomes = new StepBiomes(this); @@ -176,8 +169,8 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv return cache; } - public static ThreadLocal isDistantGeneratorThread = new ThreadLocal<>(); - public static boolean isCurrentThreadDistantGeneratorThread() { return (isDistantGeneratorThread.get() != null); } + public static ThreadLocal isDhWorldGenThreadRef = new ThreadLocal<>(); + public static boolean isCurrentThreadDistantGeneratorThread() { return (isDhWorldGenThreadRef.get() != null); } @@ -185,31 +178,27 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv // constructors // //==============// - @NotNull - public static final ImmutableMap WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP; - public static final int MAX_WORLD_GEN_CHUNK_BORDER_NEEDED; - static { - DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread; + // TODO can this be handled directly? + WorldGenThreadCheck.isCurrentThreadDhWorldGenThread = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread; - boolean isTerraFirmaCraft = false; + boolean isTerraFirmaCraftPresent = false; try { Class.forName("net.dries007.tfc.world.TFCChunkGenerator"); - isTerraFirmaCraft = true; + isTerraFirmaCraftPresent = true; + LOGGER.info("TerraFirmaCraft detected."); } - catch (ClassNotFoundException e) - { - //Ignore - } - EVENT_LOGGER.info("DH TerraFirmaCraft detection: " + isTerraFirmaCraft); + catch (ClassNotFoundException ignore) { } + + ImmutableMap.Builder builder = ImmutableMap.builder(); builder.put(EDhApiWorldGenerationStep.EMPTY, 1); builder.put(EDhApiWorldGenerationStep.STRUCTURE_START, 0); builder.put(EDhApiWorldGenerationStep.STRUCTURE_REFERENCE, 0); - builder.put(EDhApiWorldGenerationStep.BIOMES, isTerraFirmaCraft ? 1 : 0); - builder.put(EDhApiWorldGenerationStep.NOISE, isTerraFirmaCraft ? 1 : 0); + builder.put(EDhApiWorldGenerationStep.BIOMES, isTerraFirmaCraftPresent ? 1 : 0); + builder.put(EDhApiWorldGenerationStep.NOISE, isTerraFirmaCraftPresent ? 1 : 0); builder.put(EDhApiWorldGenerationStep.SURFACE, 0); builder.put(EDhApiWorldGenerationStep.CARVERS, 0); builder.put(EDhApiWorldGenerationStep.LIQUID_CARVERS, 0); @@ -227,42 +216,43 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv public BatchGenerationEnvironment(IDhServerLevel serverLevel) { - super(serverLevel); this.serverLevel = serverLevel; - EVENT_LOGGER.info("================WORLD_GEN_STEP_INITING============="); + LOGGER.info("================WORLD_GEN_STEP_INITING============="); serverLevel.getServerLevelWrapper().getDimensionType(); ChunkGenerator generator = ((ServerLevelWrapper) (serverLevel.getServerLevelWrapper())).getLevel().getChunkSource().getGenerator(); - if (!(generator instanceof NoiseBasedChunkGenerator || - generator instanceof DebugLevelSource || - generator instanceof FlatLevelSource)) + boolean isMcGenerator = + generator instanceof NoiseBasedChunkGenerator + || generator instanceof DebugLevelSource + || generator instanceof FlatLevelSource; + if (!isMcGenerator) { if (generator.getClass().toString().equals("class com.terraforged.mod.chunk.TFChunkGenerator")) { - EVENT_LOGGER.info("TerraForge Chunk Generator detected: [" + generator.getClass() + "], Distant Generation will try its best to support it."); - EVENT_LOGGER.info("If it does crash, turn Distant Generation off or set it to to [" + EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY + "]."); + LOGGER.info("TerraForge Chunk Generator detected: [" + generator.getClass() + "], Distant Generation will try its best to support it."); + LOGGER.info("If it does crash, turn Distant Generation off or set it to to [" + EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY + "]."); } else if (generator.getClass().toString().equals("class net.dries007.tfc.world.TFCChunkGenerator")) { - EVENT_LOGGER.info("TerraFirmaCraft Chunk Generator detected: [" + generator.getClass() + "], Distant Generation will try its best to support it."); - EVENT_LOGGER.info("If it does crash, turn Distant Generation off or set it to to [" + EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY + "]."); + LOGGER.info("TerraFirmaCraft Chunk Generator detected: [" + generator.getClass() + "], Distant Generation will try its best to support it."); + LOGGER.info("If it does crash, turn Distant Generation off or set it to to [" + EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY + "]."); } else { - EVENT_LOGGER.warn("Unknown Chunk Generator detected: [" + generator.getClass() + "], Distant Generation May Fail!"); - EVENT_LOGGER.warn("If it does crash, disable Distant Generation or set the Generation Mode to [" + EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY + "]."); + LOGGER.warn("Unknown Chunk Generator detected: [" + generator.getClass() + "], Distant Generation May Fail!"); + LOGGER.warn("If it does crash, disable Distant Generation or set the Generation Mode to [" + EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY + "]."); } } if (MOD_CHECKER.isModLoaded("c2me")) { - EVENT_LOGGER.info("C2ME detected: DH's pre-existing chunk accessing will use methods handled by C2ME."); + LOGGER.info("C2ME detected: DH's pre-existing chunk accessing will use methods handled by C2ME."); this.pullExistingChunkUsingMcAsyncMethod = true; } - this.params = new GlobalParameters(serverLevel); + this.params = new GlobalWorldGenParams(serverLevel); } @@ -283,7 +273,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv // operation to be done synchronously if (!this.unsafeThreadingRecorded && !future.isDone()) { - EVENT_LOGGER.warn( + LOGGER.warn( "Unsafe MultiThreading in Distant Horizons Chunk Generator. \n" + "This can happen if world generation is run on one of Minecraft's thread pools " + "instead of the thread DH provided. \n" + @@ -328,7 +318,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv { this.unknownExceptionCount++; this.lastExceptionTriggerTime = System.nanoTime(); - EVENT_LOGGER.error("Batching World Generator event ["+event+"] threw an exception: "+e.getMessage(), e); + LOGGER.error("Batching World Generator event ["+event+"] threw an exception: "+e.getMessage(), e); } } @@ -338,7 +328,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv if (this.unknownExceptionCount > EXCEPTION_COUNTER_TRIGGER) { - EVENT_LOGGER.error("Too many exceptions in Batching World Generator! Disabling the generator."); + LOGGER.error("Too many exceptions in Batching World Generator! Disabling the generator."); this.unknownExceptionCount = 0; Config.Common.WorldGenerator.enableDistantGeneration.set(false); } @@ -355,12 +345,12 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv /** @throws RejectedExecutionException if the given {@link Executor} is cancelled. */ public CompletableFuture generateLodFromListAsync(GenerationEvent genEvent, Executor executor) throws RejectedExecutionException, InterruptedException { - EVENT_LOGGER.debug("Lod Generate Event: " + genEvent.minPos); + LOGGER.debug("Lod Generate Event: " + genEvent.minPos); // Minecraft's generation events expect odd chunk width areas (3x3, 7x7, or 11x11), // but DH submits square generation events (4x4). // We handle this later, although that handling would need to change if the gen size ever changes. - LodUtil.assertTrue(genEvent.size % 2 == 0, "Generation events are expected to be an evan number of chunks wide."); + LodUtil.assertTrue(genEvent.widthInChunks % 2 == 0, "Generation events are expected to be an evan number of chunks wide."); if (genEvent.generatorMode == EDhApiDistantGeneratorMode.INTERNAL_SERVER) { @@ -369,7 +359,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv int borderSize = MAX_WORLD_GEN_CHUNK_BORDER_NEEDED; // genEvent.size - 1 converts the even width size to an odd number for MC compatability - int refSize = (genEvent.size - 1) + (borderSize * 2); + int refSize = (genEvent.widthInChunks - 1) + (borderSize * 2); int refPosX = genEvent.minPos.getX() - borderSize; int refPosZ = genEvent.minPos.getZ() - borderSize; @@ -391,7 +381,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv // futures to handle getting empty chunks CompletableFuture[] readFutures = // the extra radius of 8 is to account for structure references which need a chunk radius of 8 - getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.size, 8) + getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 8) .map((chunkPos) -> this.createEmptyOrPreExistingChunkAsync(chunkPos.x, chunkPos.z, chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, generatedChunkByDhPos)) .toArray(CompletableFuture[]::new); @@ -523,7 +513,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv // submit generated chunks // //=========================// - Iterator iterator = getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.size, 0).iterator(); + Iterator iterator = getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); while (iterator.hasNext()) { ChunkPos pos = iterator.next(); @@ -546,12 +536,12 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv boolean isShutdownException = ExceptionUtil.isShutdownException(e); if (!isShutdownException) { - EVENT_LOGGER.error("Completion error during world gen for min chunk pos ["+genEvent.minPos+"], error: ["+e.getMessage()+"].", e); + LOGGER.error("Completion error during world gen for min chunk pos ["+genEvent.minPos+"], error: ["+e.getMessage()+"].", e); } } catch (Exception e) { - EVENT_LOGGER.error("Unexpected error during world gen for min chunk pos ["+genEvent.minPos+"], error: ["+e.getMessage()+"].", e); + LOGGER.error("Unexpected error during world gen for min chunk pos ["+genEvent.minPos+"], error: ["+e.getMessage()+"].", e); } }, executor); } @@ -652,7 +642,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv // this shouldn't happen, if anything is null it should be // ioWorker.storage // but just in case - EVENT_LOGGER.error("Unexpected issue pulling pre-existing chunk ["+chunkPos+"], falling back to async chunk pulling. This may cause server-tick lag.", e); + LOGGER.error("Unexpected issue pulling pre-existing chunk ["+chunkPos+"], falling back to async chunk pulling. This may cause server-tick lag.", e); this.pullExistingChunkUsingMcAsyncMethod = true; // try again now using the async method @@ -665,7 +655,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv if (!this.pullExistingChunkUsingMcAsyncMethod) { // this shouldn't happen, but just in case - EVENT_LOGGER.info("Unable to pull pre-existing chunk using synchronous method. Falling back to async method. this may cause server-tick lag."); + LOGGER.info("Unable to pull pre-existing chunk using synchronous method. Falling back to async method. this may cause server-tick lag."); this.pullExistingChunkUsingMcAsyncMethod = true; } @@ -798,7 +788,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv // request each chunk pos from the server CompletableFuture[] requestFutures = - getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.size, 0) + getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0) .map(chunkPos -> { return requestChunkFromServerAsync(this.params.level, chunkPos, true) @@ -859,7 +849,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv // cleanup // release the generated chunks - Iterator iterator = getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.size, 0).iterator(); + Iterator iterator = getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); while (iterator.hasNext()) { ChunkPos chunkPos = iterator.next(); @@ -896,7 +886,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv catch (InterruptedException e) { // interrupted, release chunk to server - Iterator iterator = getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.size, 0).iterator(); + Iterator iterator = getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); while (iterator.hasNext()) { ChunkPos chunkPos = iterator.next(); @@ -978,7 +968,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv } catch (Exception e) { - EVENT_LOGGER.warn("Failed to release chunk back to internal server. Error: ["+e.getMessage()+"]", e); + LOGGER.warn("Failed to release chunk back to internal server. Error: ["+e.getMessage()+"]", e); } }); } @@ -1124,14 +1114,11 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv @Override - public int getEventCount() { return this.generationEventList.size(); } - - @Override - public void stop() + public void close() { - EVENT_LOGGER.info(BatchGenerationEnvironment.class.getSimpleName() + " shutting down..."); + LOGGER.info(BatchGenerationEnvironment.class.getSimpleName() + " shutting down..."); - EVENT_LOGGER.info("Canceling in progress generation event futures..."); + LOGGER.info("Canceling in progress generation event futures..."); Iterator iter = this.generationEventList.iterator(); while (iter.hasNext()) { @@ -1151,11 +1138,11 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv catch (ClosedChannelException ignore) { /* world generator is being shut down */ } catch (IOException e) { - EVENT_LOGGER.error("Failed to close region file storage cache, error: ["+e.getMessage()+"].", e); + LOGGER.error("Failed to close region file storage cache, error: ["+e.getMessage()+"].", e); } } - EVENT_LOGGER.info(BatchGenerationEnvironment.class.getSimpleName() + " shutdown complete."); + LOGGER.info(BatchGenerationEnvironment.class.getSimpleName() + " shutdown complete."); } @Override @@ -1290,14 +1277,20 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv //"lodCreation" (No longer used) }; - public static final int SIZE = 50; - ArrayList times = new ArrayList<>(); + public static final int ROLLING_AVG_SIZE = 50; + ArrayList rollingAverageList = new ArrayList<>(); + + + + //=============// + // constructor // + //=============// public PerfCalculator() { - for (int i = 0; i < 11; i++) + for (int i = 0; i < TIME_NAMES.length; i++) { - times.add(new Rolling(SIZE)); + this.rollingAverageList.add(new RollingAverage(ROLLING_AVG_SIZE)); } } @@ -1307,21 +1300,29 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv { String name = e.name; int index = Arrays.asList(TIME_NAMES).indexOf(name); - if (index == -1) continue; - times.get(index).add(e.timeNs); + if (index == -1) + { + continue; + } + + this.rollingAverageList.get(index).add(e.timeNs); } - times.get(0).add(event.getTotalTimeNs()); + this.rollingAverageList.get(0).add(event.getTotalTimeNs()); } public String toString() { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < times.size(); i++) + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < this.rollingAverageList.size(); i++) { - if (times.get(i).getAverage() == 0) continue; - sb.append(TIME_NAMES[i]).append(": ").append(times.get(i).getAverage()).append("\n"); + if (this.rollingAverageList.get(i).getAverage() == 0) + { + continue; + } + + builder.append(TIME_NAMES[i]).append(": ").append(this.rollingAverageList.get(i).getAverageRoundedString()).append("\n"); } - return sb.toString(); + return builder.toString(); } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java index 193fad255..3189919ad 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java @@ -19,7 +19,6 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration; -import java.lang.invoke.MethodHandles; import java.util.concurrent.*; import java.util.function.Consumer; @@ -34,18 +33,19 @@ import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.logging.DhLogger; -import org.jetbrains.annotations.Nullable; public final class GenerationEvent { private static final DhLogger LOGGER = new DhLoggerBuilder().build();; - private static int generationFutureDebugIDs = 0; + + private static int generationFutureDebugIDs = 0; // TODO make atomic int? + public final int id; - public final ThreadedParameters threadedParam; + public final ThreadWorldGenParams threadedParam; public final DhChunkPos minPos; /** the number of chunks wide this event is */ - public final int size; + public final int widthInChunks; public final EDhApiWorldGenerationStep targetGenerationStep; public final EDhApiDistantGeneratorMode generatorMode; public EventTimer timer = null; @@ -56,17 +56,21 @@ public final class GenerationEvent + //=============// + // constructor // + //=============// + public GenerationEvent( - DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup, + DhChunkPos minPos, int widthInChunks, BatchGenerationEnvironment generationGroup, EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetGenerationStep, Consumer resultConsumer) { this.inQueueTime = System.nanoTime(); this.id = generationFutureDebugIDs++; this.minPos = minPos; - this.size = size; + this.widthInChunks = widthInChunks; this.generatorMode = generatorMode; this.targetGenerationStep = targetGenerationStep; - this.threadedParam = ThreadedParameters.getOrMake(generationGroup.params); + this.threadedParam = ThreadWorldGenParams.getOrMake(generationGroup.params); this.resultConsumer = resultConsumer; } @@ -90,17 +94,18 @@ public final class GenerationEvent generationEvent.inQueueTime = runStartTime - generationEvent.inQueueTime; generationEvent.timer = new EventTimer("setup"); - BatchGenerationEnvironment.isDistantGeneratorThread.set(true); + BatchGenerationEnvironment.isDhWorldGenThreadRef.set(true); genEnvironment.generateLodFromListAsync(generationEvent, (runnable) -> { worldGeneratorThreadPool.execute(() -> { + // TODO why not just always set this each time? boolean alreadyMarked = BatchGenerationEnvironment.isCurrentThreadDistantGeneratorThread(); if (!alreadyMarked) { - BatchGenerationEnvironment.isDistantGeneratorThread.set(true); + BatchGenerationEnvironment.isDhWorldGenThreadRef.set(true); } try @@ -115,7 +120,7 @@ public final class GenerationEvent { if (!alreadyMarked) { - BatchGenerationEnvironment.isDistantGeneratorThread.set(false); + BatchGenerationEnvironment.isDhWorldGenThreadRef.set(false); } } }); @@ -129,7 +134,7 @@ public final class GenerationEvent } finally { - BatchGenerationEnvironment.isDistantGeneratorThread.remove(); + BatchGenerationEnvironment.isDhWorldGenThreadRef.remove(); } }); } @@ -194,6 +199,6 @@ public final class GenerationEvent } @Override - public String toString() { return this.id + ":" + this.size + "@" + this.minPos + "(" + this.targetGenerationStep + ")"; } + public String toString() { return this.id + ":" + this.widthInChunks + "@" + this.minPos + "(" + this.targetGenerationStep + ")"; } } \ No newline at end of file diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalParameters.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java similarity index 90% rename from common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalParameters.java rename to common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java index a9c90a45f..c4dc9dcf9 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalParameters.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java @@ -27,14 +27,12 @@ import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.chunk.ChunkGenerator; #if MC_VER >= MC_1_18_2 import net.minecraft.world.level.chunk.storage.ChunkScanAccess; #endif -import net.minecraft.world.level.levelgen.WorldGenSettings; #if MC_VER < MC_1_19_2 import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; #else @@ -47,7 +45,7 @@ import net.minecraft.core.registries.Registries; #endif import net.minecraft.world.level.storage.WorldData; -public final class GlobalParameters +public final class GlobalWorldGenParams { public final ChunkGenerator generator; public final IDhServerLevel lodLevel; @@ -55,7 +53,7 @@ public final class GlobalParameters public final Registry biomes; public final RegistryAccess registry; public final long worldSeed; - public final DataFixer fixerUpper; + public final DataFixer dataFixer; #if MC_VER < MC_1_19_2 public final StructureManager structures; @@ -72,10 +70,16 @@ public final class GlobalParameters #if MC_VER >= MC_1_18_2 public final BiomeManager biomeManager; - public final ChunkScanAccess chunkScanner; // FIXME: Figure out if this is actually needed + public final ChunkScanAccess chunkScanner; #endif - public GlobalParameters(IDhServerLevel lodLevel) + + + //=============// + // constructor // + //=============// + + public GlobalWorldGenParams(IDhServerLevel lodLevel) { this.lodLevel = lodLevel; @@ -102,9 +106,11 @@ public final class GlobalParameters this.biomeManager = new BiomeManager(this.level, BiomeManager.obfuscateSeed(this.worldSeed)); this.chunkScanner = this.level.getChunkSource().chunkScanner(); #endif + this.structures = server.getStructureManager(); this.generator = this.level.getChunkSource().getGenerator(); - this.fixerUpper = server.getFixerUpper(); + this.dataFixer = server.getFixerUpper(); + #if MC_VER >= MC_1_19_2 this.randomState = this.level.getChunkSource().randomState(); #endif diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/Rolling.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/Rolling.java deleted file mode 100644 index 64a37a287..000000000 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/Rolling.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of the Distant Horizons mod - * licensed under the GNU LGPL v3 License. - * - * Copyright (C) 2020 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - - -package com.seibel.distanthorizons.common.wrappers.worldGeneration; - -//FIXME: Move this outside the WorldGenerationStep thingy -public class Rolling -{ - - private final int size; - private double total = 0d; - private int index = 0; - private final double[] samples; - - public Rolling(int size) - { - this.size = size; - samples = new double[size]; - for (int i = 0; i < size; i++) - { - samples[i] = 0d; - } - } - - public void add(double x) - { - total -= samples[index]; - samples[index] = x; - total += x; - if (++index == size) - index = 0; // cheaper than modulus - } - - public double getAverage() - { - return size == 0 ? 0 : total / size; - } - -} \ No newline at end of file diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadedParameters.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java similarity index 71% rename from common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadedParameters.java rename to common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java index 88001881b..c34d02687 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadedParameters.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java @@ -29,9 +29,10 @@ import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.levelgen.structure.StructureCheck; #endif -public final class ThreadedParameters +public final class ThreadWorldGenParams { - private static final ThreadLocal LOCAL_PARAM = new ThreadLocal<>(); + private static final ThreadLocal LOCAL_PARAM = new ThreadLocal<>(); + final ServerLevel level; public WorldGenStructFeatManager structFeat = null; @@ -41,26 +42,32 @@ public final class ThreadedParameters boolean isValid = true; public final PerfCalculator perf = new PerfCalculator(); - private static GlobalParameters previousGlobalParameters = null; + private static GlobalWorldGenParams previousGlobalWorldGenParams = null; - public static ThreadedParameters getOrMake(GlobalParameters param) + //=============// + // constructor // + //=============// + + public static ThreadWorldGenParams getOrMake(GlobalWorldGenParams globalParams) { - ThreadedParameters tParam = LOCAL_PARAM.get(); - if (tParam != null && tParam.isValid && tParam.level == param.level) + ThreadWorldGenParams threadParam = LOCAL_PARAM.get(); + if (threadParam != null + && threadParam.isValid + && threadParam.level == globalParams.level) { - return tParam; + return threadParam; } - tParam = new ThreadedParameters(param); - LOCAL_PARAM.set(tParam); - return tParam; + threadParam = new ThreadWorldGenParams(globalParams); + LOCAL_PARAM.set(threadParam); + return threadParam; } - private ThreadedParameters(GlobalParameters param) + private ThreadWorldGenParams(GlobalWorldGenParams param) { - previousGlobalParameters = param; + previousGlobalWorldGenParams = param; this.level = param.level; #if MC_VER < MC_1_18_2 @@ -70,20 +77,18 @@ public final class ThreadedParameters #else this.structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures, param.level.dimension(), param.generator, param.randomState, level, param.generator.getBiomeSource(), param.worldSeed, - param.fixerUpper); + param.dataFixer); #endif } - public void markAsInvalid() { isValid = false; } - - public void makeStructFeat(WorldGenLevel genLevel, GlobalParameters param) + public void makeStructFeat(WorldGenLevel genLevel, GlobalWorldGenParams param) { #if MC_VER < MC_1_19_4 - structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel #if MC_VER >= MC_1_18_2 , structCheck #endif ); + this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel #if MC_VER >= MC_1_18_2 , this.structCheck #endif ); #else - structFeat = new WorldGenStructFeatManager(param.worldOptions, genLevel, structCheck); + this.structFeat = new WorldGenStructFeatManager(param.worldOptions, genLevel, this.structCheck); #endif } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/AbstractWorldGenStep.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/AbstractWorldGenStep.java index fb8b41977..7915596ed 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/AbstractWorldGenStep.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/AbstractWorldGenStep.java @@ -1,7 +1,7 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.step; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; import net.minecraft.world.level.chunk.ChunkAccess; @@ -19,7 +19,7 @@ import net.minecraft.world.level.chunk.status.ChunkStatus; public abstract class AbstractWorldGenStep { public abstract void generateGroup( - ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion, + ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers); public abstract ChunkStatus getChunkStatus(); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java index 8a0bcb819..ed185b4a8 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java @@ -23,13 +23,11 @@ import java.util.ArrayList; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; -import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ProtoChunk; #if MC_VER >= MC_1_18_2 import net.minecraft.world.level.levelgen.blending.Blender; @@ -66,7 +64,7 @@ public final class StepBiomes extends AbstractWorldGenStep @Override public void generateGroup( - ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion, + ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers) { ArrayList chunksToDo = this.getChunksToGenerate(chunkWrappers); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java index ffe8fe346..b9920546d 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java @@ -21,7 +21,7 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.step; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; @@ -67,7 +67,7 @@ public final class StepFeatures extends AbstractWorldGenStep @Override public void generateGroup( - ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion, + ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers) { for (ChunkWrapper chunkWrapper : chunkWrappers) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java index 49a1b5bcf..4994ea365 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java @@ -20,18 +20,15 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.step; import java.util.ArrayList; -import java.util.List; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException; -import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ProtoChunk; #if MC_VER >= MC_1_18_2 import net.minecraft.world.level.levelgen.blending.Blender; @@ -68,7 +65,7 @@ public final class StepNoise extends AbstractWorldGenStep @Override public void generateGroup( - ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion, + ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers) { ArrayList chunksToDo = new ArrayList<>(); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java index cba8dc7cc..e743027ac 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java @@ -20,15 +20,13 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.step; import java.util.ArrayList; -import java.util.List; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; -import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ProtoChunk; @@ -64,7 +62,7 @@ public final class StepStructureReference extends AbstractWorldGenStep @Override public void generateGroup( - ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion, + ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers) { ArrayList chunksToDo = new ArrayList(); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java index ce5ff81f4..c9df513ad 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java @@ -20,21 +20,16 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.step; import java.util.ArrayList; -import java.util.List; import java.util.concurrent.locks.ReentrantLock; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.world.level.Level; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ProtoChunk; import com.seibel.distanthorizons.core.logging.DhLogger; #if MC_VER <= MC_1_20_4 @@ -71,7 +66,7 @@ public final class StepStructureStart extends AbstractWorldGenStep @Override public void generateGroup( - ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion, + ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers) { ArrayList chunksToDo = this.getChunksToGenerate(chunkWrappers); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java index 4f6ef551a..8a2c0ab4e 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java @@ -20,15 +20,13 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.step; import java.util.ArrayList; -import java.util.List; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; -import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ProtoChunk; @@ -64,7 +62,7 @@ public final class StepSurface extends AbstractWorldGenStep @Override public void generateGroup( - ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion, + ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers) { ArrayList chunksToDo = new ArrayList<>(); diff --git a/coreSubProjects b/coreSubProjects index 3f287388d..2537c4a25 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 3f287388d5523f1cdf4eda7f1826aa74e4f2bc56 +Subproject commit 2537c4a25925781219567a01eb05acc592a84572 diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinLevelTicks.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinLevelTicks.java index 68db84b96..8a40f05bb 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinLevelTicks.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinLevelTicks.java @@ -13,7 +13,7 @@ public class MixinLevelTicks #else -import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck; +import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; import net.minecraft.world.ticks.LevelTicks; import net.minecraft.world.ticks.ScheduledTick; @@ -28,7 +28,7 @@ public class MixinLevelTicks { // TODO put in a common location private static boolean isWorldGenThread() - { return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); } + { return WorldGenThreadCheck.isSetup && WorldGenThreadCheck.isCurrentThreadDhWorldGenThread.get(); } diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinTracingExecutor.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinTracingExecutor.java index 8d9637a0a..dd10c7588 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinTracingExecutor.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinTracingExecutor.java @@ -35,10 +35,9 @@ public class MixinTracingExecutor } #else -import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck; +import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService; import net.minecraft.TracingExecutor; -import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -57,7 +56,7 @@ public class MixinTracingExecutor { // TODO put in a common location private static boolean isWorldGenThread() - { return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); } + { return WorldGenThreadCheck.isSetup && WorldGenThreadCheck.isCurrentThreadDhWorldGenThread.get(); } // replaced with TracingExecutor in MC 1.21.3+ diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinUtilBackgroundThread.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinUtilBackgroundThread.java index f8c5c7642..3e297fb4b 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinUtilBackgroundThread.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinUtilBackgroundThread.java @@ -19,17 +19,12 @@ package com.seibel.distanthorizons.fabric.mixins.server; -import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck; +import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.Util; -import java.util.concurrent.ExecutorService; - #if MC_VER < MC_1_16_5 #elif MC_VER < MC_1_21_3 import java.util.function.Supplier; @@ -47,7 +42,7 @@ import java.util.function.Supplier; public class MixinUtilBackgroundThread { private static boolean isWorldGenThread() - { return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); } + { return WorldGenThreadCheck.isSetup && WorldGenThreadCheck.isCurrentThreadDhWorldGenThread.get(); } #if MC_VER < MC_1_21_3 diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinLevelTicks.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinLevelTicks.java index c01c8b503..8eb434908 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinLevelTicks.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinLevelTicks.java @@ -13,7 +13,7 @@ public class MixinLevelTicks #else -import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck; +import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; import net.minecraft.world.ticks.LevelTicks; import net.minecraft.world.ticks.ScheduledTick; import org.spongepowered.asm.mixin.Mixin; @@ -26,7 +26,7 @@ public class MixinLevelTicks { // TODO put in a common location private static boolean isWorldGenThread() - { return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); } + { return WorldGenThreadCheck.isSetup && WorldGenThreadCheck.isCurrentThreadDhWorldGenThread.get(); } diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinTracingExecutor.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinTracingExecutor.java index 100d2e90e..f7f1eea53 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinTracingExecutor.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinTracingExecutor.java @@ -35,7 +35,7 @@ public class MixinTracingExecutor } #else -import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck; +import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService; import net.minecraft.TracingExecutor; import org.spongepowered.asm.mixin.Mixin; @@ -57,7 +57,7 @@ public class MixinTracingExecutor { // TODO put in a common location private static boolean isWorldGenThread() - { return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); } + { return WorldGenThreadCheck.isSetup && WorldGenThreadCheck.isCurrentThreadDhWorldGenThread.get(); } // Util.backgroundExecutor().forName("init_biomes") diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java index a6f488cc7..91d08f79a 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java @@ -19,16 +19,10 @@ package com.seibel.distanthorizons.neoforge.mixins.server; -import java.util.concurrent.ExecutorService; -import java.util.function.Supplier; - import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck; +import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; import net.minecraft.Util; @@ -43,7 +37,7 @@ import net.minecraft.Util; public class MixinUtilBackgroundThread { private static boolean isWorldGenThread() - { return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); } + { return WorldGenThreadCheck.isSetup && WorldGenThreadCheck.isCurrentThreadDhWorldGenThread.get(); } From 91da0bf252e5f5c375197806c7f7b7dad602f8d2 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Nov 2025 09:25:55 -0600 Subject: [PATCH 02/33] replace and simplify WorldGenThreadCheck --- .../common/wrappers/DependencySetup.java | 1 - .../common/wrappers/WorldGenThreadCheck.java | 39 ------------ .../BatchGenerationEnvironment.java | 60 +++++++++---------- .../worldGeneration/GenerationEvent.java | 2 +- .../worldGeneration/GlobalWorldGenParams.java | 30 +++++++--- .../worldGeneration/ThreadWorldGenParams.java | 38 ++++++++---- coreSubProjects | 2 +- .../fabric/mixins/server/MixinLevelTicks.java | 11 +--- .../mixins/server/MixinTracingExecutor.java | 9 +-- .../server/MixinUtilBackgroundThread.java | 17 +++--- .../server/MixinUtilBackgroundThread.java | 26 ++++---- .../neoforge/NeoforgeServerProxy.java | 5 +- .../mixins/server/MixinLevelTicks.java | 10 +--- .../mixins/server/MixinTracingExecutor.java | 9 +-- .../server/MixinUtilBackgroundThread.java | 12 ++-- 15 files changed, 118 insertions(+), 153 deletions(-) delete mode 100644 common/src/main/java/com/seibel/distanthorizons/common/wrappers/WorldGenThreadCheck.java diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java index 9260196fd..b8fb6a99f 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/DependencySetup.java @@ -56,7 +56,6 @@ public class DependencySetup SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE); SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE); SingletonInjector.INSTANCE.bind(IKeyedClientLevelManager.class, KeyedClientLevelManager.INSTANCE); - WorldGenThreadCheck.isSetup = true; } public static void createServerBindings() diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WorldGenThreadCheck.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WorldGenThreadCheck.java deleted file mode 100644 index 224ed8c69..000000000 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WorldGenThreadCheck.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of the Distant Horizons mod - * licensed under the GNU LGPL v3 License. - * - * Copyright (C) 2020 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.seibel.distanthorizons.common.wrappers; - -import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; - -import java.util.function.Supplier; - -public class WorldGenThreadCheck -{ - public static boolean isSetup = false; - - /** - * This is used so we can override some MC logic when running - * in DH's world generator. - * Specifically so we can redirect threads to run on DH threads instead - * of MC threads. - */ - //public static Supplier isCurrentThreadDhWorldGenThread = (() -> { return false; }); - public static Supplier isCurrentThreadDhWorldGenThread = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread; // TODO can we just do this? - -} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 19a3c9d65..b14868c2e 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -58,7 +58,6 @@ import java.util.stream.StreamSupport; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepBiomes; import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepFeatures; import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepNoise; @@ -126,6 +125,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm public static final int MAX_WORLD_GEN_CHUNK_BORDER_NEEDED; + private final IDhServerLevel serverLevel; /** @@ -137,20 +137,19 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm - //=================Generation Step=================== - public final LinkedBlockingQueue generationEventList = new LinkedBlockingQueue<>(); public final GlobalWorldGenParams params; + public final StepStructureStart stepStructureStart = new StepStructureStart(this); public final StepStructureReference stepStructureReference = new StepStructureReference(this); public final StepBiomes stepBiomes = new StepBiomes(this); public final StepNoise stepNoise = new StepNoise(this); public final StepSurface stepSurface = new StepSurface(this); public final StepFeatures stepFeatures = new StepFeatures(this); + public boolean unsafeThreadingRecorded = false; public static final long EXCEPTION_TIMER_RESET_TIME = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); public static final int EXCEPTION_COUNTER_TRIGGER = 20; - public static final int RANGE_TO_RANGE_EMPTY_EXTENSION = 1; public int unknownExceptionCount = 0; public long lastExceptionTriggerTime = 0; @@ -170,7 +169,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm } public static ThreadLocal isDhWorldGenThreadRef = new ThreadLocal<>(); - public static boolean isCurrentThreadDistantGeneratorThread() { return (isDhWorldGenThreadRef.get() != null); } + public static boolean isThisDhWorldGenThread() { return (isDhWorldGenThreadRef.get() != null); } @@ -180,9 +179,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm static { - // TODO can this be handled directly? - WorldGenThreadCheck.isCurrentThreadDhWorldGenThread = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread; - boolean isTerraFirmaCraftPresent = false; try { @@ -218,7 +214,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm { this.serverLevel = serverLevel; - LOGGER.info("================WORLD_GEN_STEP_INITING============="); + LOGGER.info("Creating Batch Generator"); serverLevel.getServerLevelWrapper().getDimensionType(); @@ -345,8 +341,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm /** @throws RejectedExecutionException if the given {@link Executor} is cancelled. */ public CompletableFuture generateLodFromListAsync(GenerationEvent genEvent, Executor executor) throws RejectedExecutionException, InterruptedException { - LOGGER.debug("Lod Generate Event: " + genEvent.minPos); - // Minecraft's generation events expect odd chunk width areas (3x3, 7x7, or 11x11), // but DH submits square generation events (4x4). // We handle this later, although that handling would need to change if the gen size ever changes. @@ -561,13 +555,13 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm * otherwise this will return an empty chunk. */ private CompletableFuture createEmptyOrPreExistingChunkAsync( - int x, int z, + int chunkX, int chunkZ, Map chunkSkyLightingByDhPos, Map chunkBlockLightingByDhPos, Map generatedChunkByDhPos) { - ChunkPos chunkPos = new ChunkPos(x, z); - DhChunkPos dhChunkPos = new DhChunkPos(x, z); + ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); + DhChunkPos dhChunkPos = new DhChunkPos(chunkX, chunkZ); if (generatedChunkByDhPos.containsKey(dhChunkPos)) { @@ -1110,9 +1104,29 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm } private static ArrayGridList GetCutoutFrom(ArrayGridList total, int border) { return new ArrayGridList<>(total, border, total.gridSize - border); } private static ArrayGridList GetCutoutFrom(ArrayGridList total, EDhApiWorldGenerationStep step) { return GetCutoutFrom(total, WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP.get(step)); } - //private static ArrayGridList GetCutoutFrom(ArrayGridList total, EDhApiWorldGenerationStep step) { return GetCutoutFrom(total, 0); } + + @Override + public CompletableFuture generateChunks( + int minX, int minZ, int genSize, + EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetStep, + ExecutorService worldGeneratorThreadPool, Consumer resultConsumer) + { + //System.out.println("GenerationEvent: "+genSize+"@"+minX+","+minZ+" "+targetStep); + + // TODO: Check event overlap via e.tooClose() + GenerationEvent genEvent = GenerationEvent.startEvent(new DhChunkPos(minX, minZ), genSize, this, generatorMode, targetStep, resultConsumer, worldGeneratorThreadPool); + this.generationEventList.add(genEvent); + return genEvent.future; + } + + + + //================// + // base overrides // + //================// + @Override public void close() { @@ -1145,20 +1159,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm LOGGER.info(BatchGenerationEnvironment.class.getSimpleName() + " shutdown complete."); } - @Override - public CompletableFuture generateChunks( - int minX, int minZ, int genSize, - EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetStep, - ExecutorService worldGeneratorThreadPool, Consumer resultConsumer) - { - //System.out.println("GenerationEvent: "+genSize+"@"+minX+","+minZ+" "+targetStep); - - // TODO: Check event overlap via e.tooClose() - GenerationEvent genEvent = GenerationEvent.startEvent(new DhChunkPos(minX, minZ), genSize, this, generatorMode, targetStep, resultConsumer, worldGeneratorThreadPool); - this.generationEventList.add(genEvent); - return genEvent.future; - } - //================// @@ -1174,7 +1174,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm { if (Thread.interrupted()) { - throw new InterruptedException(BatchGenerationEnvironment.class.getSimpleName() + " task interrupted."); + throw new InterruptedException("["+BatchGenerationEnvironment.class.getSimpleName()+"] task interrupted."); } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java index 3189919ad..c05945921 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java @@ -102,7 +102,7 @@ public final class GenerationEvent worldGeneratorThreadPool.execute(() -> { // TODO why not just always set this each time? - boolean alreadyMarked = BatchGenerationEnvironment.isCurrentThreadDistantGeneratorThread(); + boolean alreadyMarked = BatchGenerationEnvironment.isThisDhWorldGenThread(); if (!alreadyMarked) { BatchGenerationEnvironment.isDhWorldGenThreadRef.set(true); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java index c4dc9dcf9..c640685f6 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java @@ -36,15 +36,29 @@ import net.minecraft.world.level.chunk.storage.ChunkScanAccess; #if MC_VER < MC_1_19_2 import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; #else -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; -import net.minecraft.world.level.levelgen.RandomState; -#if MC_VER >= MC_1_19_4 -import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.core.registries.Registries; -#endif #endif import net.minecraft.world.level.storage.WorldData; +#if MC_VER < MC_1_19_4 +#elif MC_VER < MC_1_21_3 +import net.minecraft.core.registries.Registries; +#else +import net.minecraft.core.registries.Registries; +#endif + +#if MC_VER < MC_1_19_4 +import net.minecraft.world.level.levelgen.WorldGenSettings; +#else +import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import net.minecraft.world.level.levelgen.RandomState; +#endif + +/** + * Handles parameters that are relevant for the entire MC world. + * + * @see ThreadWorldGenParams + */ public final class GlobalWorldGenParams { public final ChunkGenerator generator; @@ -87,7 +101,7 @@ public final class GlobalWorldGenParams MinecraftServer server = this.level.getServer(); WorldData worldData = server.getWorldData(); this.registry = server.registryAccess(); - + #if MC_VER < MC_1_19_4 this.worldGenSettings = worldData.worldGenSettings(); this.biomes = registry.registryOrThrow(Registry.BIOME_REGISTRY); @@ -116,4 +130,6 @@ public final class GlobalWorldGenParams #endif } + + } \ No newline at end of file diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java index c34d02687..23b783247 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java @@ -31,17 +31,20 @@ import net.minecraft.world.level.levelgen.structure.StructureCheck; public final class ThreadWorldGenParams { - private static final ThreadLocal LOCAL_PARAM = new ThreadLocal<>(); + private static final ThreadLocal LOCAL_PARAM_REF = new ThreadLocal<>(); final ServerLevel level; public WorldGenStructFeatManager structFeat = null; + #if MC_VER >= MC_1_18_2 public StructureCheck structCheck; #endif + boolean isValid = true; public final PerfCalculator perf = new PerfCalculator(); + // used for some older MC versions private static GlobalWorldGenParams previousGlobalWorldGenParams = null; @@ -52,7 +55,7 @@ public final class ThreadWorldGenParams public static ThreadWorldGenParams getOrMake(GlobalWorldGenParams globalParams) { - ThreadWorldGenParams threadParam = LOCAL_PARAM.get(); + ThreadWorldGenParams threadParam = LOCAL_PARAM_REF.get(); if (threadParam != null && threadParam.isValid && threadParam.level == globalParams.level) @@ -61,7 +64,7 @@ public final class ThreadWorldGenParams } threadParam = new ThreadWorldGenParams(globalParams); - LOCAL_PARAM.set(threadParam); + LOCAL_PARAM_REF.set(threadParam); return threadParam; } @@ -70,45 +73,54 @@ public final class ThreadWorldGenParams previousGlobalWorldGenParams = param; this.level = param.level; + #if MC_VER < MC_1_18_2 - this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, level); + this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, this.level); #elif MC_VER < MC_1_19_2 this.structCheck = this.createStructureCheck(param); #else this.structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures, - param.level.dimension(), param.generator, param.randomState, level, param.generator.getBiomeSource(), param.worldSeed, + param.level.dimension(), param.generator, param.randomState, this.level, param.generator.getBiomeSource(), param.worldSeed, param.dataFixer); #endif } + //==========// + // builders // + //==========// + public void makeStructFeat(WorldGenLevel genLevel, GlobalWorldGenParams param) { - #if MC_VER < MC_1_19_4 - this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel #if MC_VER >= MC_1_18_2 , this.structCheck #endif ); + #if MC_VER < MC_1_18_2 + this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel); + #elif MC_VER < MC_1_19_4 + this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel, this.structCheck); #else this.structFeat = new WorldGenStructFeatManager(param.worldOptions, genLevel, this.structCheck); #endif } - - #if MC_VER >= MC_1_18_2 && MC_VER < MC_1_19_2 + #if MC_VER < MC_1_18_2 + #elif MC_VER < MC_1_19_2 public void recreateStructureCheck() { - if (previousGlobalParameters != null) + if (previousGlobalWorldGenParams != null) { - this.structCheck = createStructureCheck(previousGlobalParameters); + this.structCheck = this.createStructureCheck(previousGlobalWorldGenParams); } } - private StructureCheck createStructureCheck(GlobalParameters param) + private StructureCheck createStructureCheck(GlobalWorldGenParams param) { return new StructureCheck(param.chunkScanner, param.registry, param.structures, param.level.dimension(), param.generator, this.level, param.generator.getBiomeSource(), param.worldSeed, - param.fixerUpper); + param.dataFixer); } #else public void recreateStructureCheck() { /* do nothing */ } #endif + + } \ No newline at end of file diff --git a/coreSubProjects b/coreSubProjects index 2537c4a25..1b4f9e894 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 2537c4a25925781219567a01eb05acc592a84572 +Subproject commit 1b4f9e89428f06a222925137906352f7484c61a7 diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinLevelTicks.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinLevelTicks.java index 8a40f05bb..4df7a270f 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinLevelTicks.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinLevelTicks.java @@ -13,8 +13,7 @@ public class MixinLevelTicks #else -import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; - +import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import net.minecraft.world.ticks.LevelTicks; import net.minecraft.world.ticks.ScheduledTick; @@ -26,18 +25,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(LevelTicks.class) // available in 1.18.2+, but only needed in 1.21.4+ public class MixinLevelTicks { - // TODO put in a common location - private static boolean isWorldGenThread() - { return WorldGenThreadCheck.isSetup && WorldGenThreadCheck.isCurrentThreadDhWorldGenThread.get(); } - - - @Inject(method = "schedule", at = @At(value = "HEAD"), cancellable = true) private void onChunkSave(ScheduledTick tick, CallbackInfo ci) { // In MC 1.21.4 an error check was added to log attempting to schedule ticks for unloaded chunks // this caused a lot of unnecessary errors when generating sand (FallingBlock.class). - if (isWorldGenThread()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { ci.cancel(); } diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinTracingExecutor.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinTracingExecutor.java index dd10c7588..a35e4e759 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinTracingExecutor.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinTracingExecutor.java @@ -19,6 +19,7 @@ package com.seibel.distanthorizons.fabric.mixins.server; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import org.spongepowered.asm.mixin.Mixin; #if MC_VER < MC_1_21_3 @@ -35,7 +36,6 @@ public class MixinTracingExecutor } #else -import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService; import net.minecraft.TracingExecutor; import org.spongepowered.asm.mixin.injection.At; @@ -54,16 +54,11 @@ import java.util.concurrent.Executor; @Mixin(TracingExecutor.class) public class MixinTracingExecutor { - // TODO put in a common location - private static boolean isWorldGenThread() - { return WorldGenThreadCheck.isSetup && WorldGenThreadCheck.isCurrentThreadDhWorldGenThread.get(); } - - // replaced with TracingExecutor in MC 1.21.3+ @Inject(method = "forName(Ljava/lang/String;)Ljava/util/concurrent/Executor;", at = @At("HEAD"), cancellable = true) private void forName(String executorName, CallbackInfoReturnable ci) { - if (isWorldGenThread()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { // run this task on the current DH thread instead of a new MC thread ci.setReturnValue(new RunOnThisThreadExecutorService()); diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinUtilBackgroundThread.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinUtilBackgroundThread.java index 3e297fb4b..80ea7f5df 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinUtilBackgroundThread.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinUtilBackgroundThread.java @@ -19,14 +19,19 @@ package com.seibel.distanthorizons.fabric.mixins.server; -import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService; import org.spongepowered.asm.mixin.Mixin; import net.minecraft.Util; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + #if MC_VER < MC_1_16_5 #elif MC_VER < MC_1_21_3 +import java.util.concurrent.ExecutorService; import java.util.function.Supplier; #else #endif @@ -41,15 +46,11 @@ import java.util.function.Supplier; @Mixin(Util.class) public class MixinUtilBackgroundThread { - private static boolean isWorldGenThread() - { return WorldGenThreadCheck.isSetup && WorldGenThreadCheck.isCurrentThreadDhWorldGenThread.get(); } - - #if MC_VER < MC_1_21_3 @Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true) private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable ci) { - if (isWorldGenThread()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { // run this task on the current DH thread instead of a new MC thread ci.setReturnValue(new RunOnThisThreadExecutorService()); @@ -65,7 +66,7 @@ public class MixinUtilBackgroundThread at = @At("HEAD"), cancellable = true) private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable ci) { - if (isWorldGenThread()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { //ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered"); ci.setReturnValue(r); @@ -81,7 +82,7 @@ public class MixinUtilBackgroundThread at = @At("HEAD"), cancellable = true) private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier r, CallbackInfoReturnable> ci) { - if (isWorldGenThread()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { //ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered"); ci.setReturnValue(r); diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinUtilBackgroundThread.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinUtilBackgroundThread.java index 194114ad0..dfaf7de41 100644 --- a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinUtilBackgroundThread.java +++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinUtilBackgroundThread.java @@ -22,12 +22,15 @@ package com.seibel.distanthorizons.forge.mixins.server; import java.util.concurrent.ExecutorService; import java.util.function.Supplier; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck; import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService; import net.minecraft.Util; @@ -35,17 +38,17 @@ import net.minecraft.Util; @Mixin(Util.class) public class MixinUtilBackgroundThread { - private static boolean shouldApplyOverride() - { - return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); - } + @Unique + private static final DhLogger LOGGER = new DhLoggerBuilder().name("MixinUtilBackgroundThread").build(); + + @Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true) private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable ci) { - if (shouldApplyOverride()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { - //ApiShared.LOGGER.info("util backgroundExecutor triggered"); + //LOGGER.info("util backgroundExecutor triggered"); ci.setReturnValue(new RunOnThisThreadExecutorService()); } } @@ -55,21 +58,22 @@ public class MixinUtilBackgroundThread at = @At("HEAD"), cancellable = true) private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable ci) { - if (shouldApplyOverride()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { - //ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered"); + //LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered"); ci.setReturnValue(r); } } #endif + #if MC_VER >= MC_1_18_2 @Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/util/function/Supplier;)Ljava/util/function/Supplier;", at = @At("HEAD"), cancellable = true) private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier r, CallbackInfoReturnable> ci) { - if (shouldApplyOverride()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { - //ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered"); + //LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered"); ci.setReturnValue(r); } } diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeServerProxy.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeServerProxy.java index da9fbf0b8..a91dcc863 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeServerProxy.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeServerProxy.java @@ -30,8 +30,7 @@ import java.util.function.Supplier; #if MC_VER < MC_1_20_6 import net.neoforged.neoforge.event.TickEvent; -#else -import net.neoforged.neoforge.event.tick.ServerTickEvent; +#else #endif @@ -52,7 +51,7 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy public NeoforgeServerProxy(boolean isDedicated) { this.isDedicated = isDedicated; - isGenerationThreadChecker = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread; + isGenerationThreadChecker = BatchGenerationEnvironment::isThisDhWorldGenThread; } @Override diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinLevelTicks.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinLevelTicks.java index 8eb434908..15c5c8423 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinLevelTicks.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinLevelTicks.java @@ -13,7 +13,7 @@ public class MixinLevelTicks #else -import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import net.minecraft.world.ticks.LevelTicks; import net.minecraft.world.ticks.ScheduledTick; import org.spongepowered.asm.mixin.Mixin; @@ -24,18 +24,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(LevelTicks.class) // available in 1.18.2+, but only needed in 1.21.4+ public class MixinLevelTicks { - // TODO put in a common location - private static boolean isWorldGenThread() - { return WorldGenThreadCheck.isSetup && WorldGenThreadCheck.isCurrentThreadDhWorldGenThread.get(); } - - - @Inject(method = "schedule", at = @At(value = "HEAD"), cancellable = true) private void onChunkSave(ScheduledTick tick, CallbackInfo ci) { // In MC 1.21.4 an error check was added to log attempting to schedule ticks for unloaded chunks // this caused a lot of unnecessary errors when generating sand (FallingBlock.class). - if (isWorldGenThread()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { ci.cancel(); } diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinTracingExecutor.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinTracingExecutor.java index f7f1eea53..51abf0a5f 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinTracingExecutor.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinTracingExecutor.java @@ -35,7 +35,7 @@ public class MixinTracingExecutor } #else -import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService; import net.minecraft.TracingExecutor; import org.spongepowered.asm.mixin.Mixin; @@ -55,11 +55,6 @@ import java.util.concurrent.Executor; @Mixin(TracingExecutor.class) public class MixinTracingExecutor { - // TODO put in a common location - private static boolean isWorldGenThread() - { return WorldGenThreadCheck.isSetup && WorldGenThreadCheck.isCurrentThreadDhWorldGenThread.get(); } - - // Util.backgroundExecutor().forName("init_biomes") // needed for world gen @@ -67,7 +62,7 @@ public class MixinTracingExecutor @Inject(method = "forName(Ljava/lang/String;)Ljava/util/concurrent/Executor;", at = @At("HEAD"), cancellable = true) private void forName(String executorName, CallbackInfoReturnable ci) { - if (isWorldGenThread()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { // run this task on the current DH thread instead of a new MC thread ci.setReturnValue(new RunOnThisThreadExecutorService()); diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java index 91d08f79a..33e38e235 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java @@ -19,11 +19,10 @@ package com.seibel.distanthorizons.neoforge.mixins.server; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService; import org.spongepowered.asm.mixin.Mixin; -import com.seibel.distanthorizons.common.wrappers.WorldGenThreadCheck; - import net.minecraft.Util; /** @@ -36,16 +35,13 @@ import net.minecraft.Util; @Mixin(Util.class) public class MixinUtilBackgroundThread { - private static boolean isWorldGenThread() - { return WorldGenThreadCheck.isSetup && WorldGenThreadCheck.isCurrentThreadDhWorldGenThread.get(); } - #if MC_VER < MC_1_21_3 @Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true) private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable ci) { - if (isWorldGenThread()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { // run this task on the current DH thread instead of a new MC thread ci.setReturnValue(new RunOnThisThreadExecutorService()); @@ -61,7 +57,7 @@ public class MixinUtilBackgroundThread at = @At("HEAD"), cancellable = true) private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable ci) { - if (isWorldGenThread()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { //ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered"); ci.setReturnValue(r); @@ -77,7 +73,7 @@ public class MixinUtilBackgroundThread at = @At("HEAD"), cancellable = true) private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier r, CallbackInfoReturnable> ci) { - if (isWorldGenThread()) + if (BatchGenerationEnvironment.isThisDhWorldGenThread()) { //ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered"); ci.setReturnValue(r); From 738aff8ec6971a171b2c2d6a6fa2ec8570e3ac24 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Nov 2025 09:30:13 -0600 Subject: [PATCH 03/33] remove performance recording in batch gen --- .../BatchGenerationEnvironment.java | 102 ------------------ .../worldGeneration/GenerationEvent.java | 4 +- .../worldGeneration/ThreadWorldGenParams.java | 2 - coreSubProjects | 2 +- 4 files changed, 2 insertions(+), 108 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index b14868c2e..52353eefb 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -33,10 +33,8 @@ import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.util.ExceptionUtil; -import com.seibel.distanthorizons.core.util.objects.EventTimer; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; -import com.seibel.distanthorizons.core.util.objects.RollingAverage; import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; @@ -100,11 +98,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm .fileLevelConfig(Config.Common.Logging.logWorldGenEventToFile) .build(); - public static final DhLogger PREF_LOGGER = new DhLoggerBuilder() - .name("LOD World Gen") - .fileLevelConfig(Config.Common.Logging.logWorldGenPerformanceToFile) - .maxCountPerSecond(1) - .build(); public static final DhLogger CHUNK_LOAD_LOGGER = new DhLoggerBuilder() .name("LOD World Gen") .fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile) @@ -494,13 +487,9 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm { throw new CompletionException(e); } - - genEvent.timer.nextEvent("cleanup"); } } - genEvent.timer.nextEvent("cleanup"); - //=========================// @@ -516,13 +505,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm genEvent.resultConsumer.accept(wrappedChunk); } - genEvent.timer.complete(); genEvent.refreshTimeout(); - if (PREF_LOGGER.canLog()) - { - genEvent.threadedParam.perf.recordEvent(genEvent.timer); - PREF_LOGGER.debug(genEvent.timer.toString()); - } } catch (CompletionException | UncheckedInterruptedException e) { @@ -769,7 +752,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm private CompletableFuture generateChunksViaInternalServerAsync(GenerationEvent genEvent) throws InterruptedException { - genEvent.timer.nextEvent("requestFromServer"); LinkedBlockingQueue runnableQueue = new LinkedBlockingQueue<>(); Map chunkWrappersByDhPos = Collections.synchronizedMap(new HashMap<>()); @@ -815,7 +797,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm .whenCompleteAsync((voidObj, throwable) -> { // generate chunk lighting using DH's lighting engine - genEvent.timer.nextEvent("light"); int maxSkyLight = this.serverLevel.getServerLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT; ArrayList generatedChunks = new ArrayList<>(chunkWrappersByDhPos.values()); @@ -832,7 +813,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm this.serverLevel.updateBeaconBeamsForChunk(iChunkWrapper, generatedChunks); } - genEvent.timer.nextEvent("cleanup"); for (IChunkWrapper iChunkWrapper : generatedChunks) { genEvent.resultConsumer.accept(iChunkWrapper); @@ -850,13 +830,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm releaseChunkToServer(this.params.level, chunkPos, true); } - genEvent.timer.complete(); genEvent.refreshTimeout(); - if (PREF_LOGGER.canLog()) - { - genEvent.threadedParam.perf.recordEvent(genEvent.timer); - PREF_LOGGER.debug(genEvent.timer.toString()); - } }); processGeneratedChunksFuture.whenCompleteAsync((unused, throwable) -> { }, runnableQueue::add); // trigger wakeup @@ -996,7 +970,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm return; } - genEvent.timer.nextEvent("structStart"); throwIfThreadInterrupted(); this.stepStructureStart.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.STRUCTURE_START)); genEvent.refreshTimeout(); @@ -1005,7 +978,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm return; } - genEvent.timer.nextEvent("structRef"); throwIfThreadInterrupted(); this.stepStructureReference.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.STRUCTURE_REFERENCE)); genEvent.refreshTimeout(); @@ -1014,7 +986,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm return; } - genEvent.timer.nextEvent("biome"); throwIfThreadInterrupted(); this.stepBiomes.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.BIOMES)); genEvent.refreshTimeout(); @@ -1023,7 +994,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm return; } - genEvent.timer.nextEvent("noise"); throwIfThreadInterrupted(); this.stepNoise.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.NOISE)); genEvent.refreshTimeout(); @@ -1032,7 +1002,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm return; } - genEvent.timer.nextEvent("surface"); throwIfThreadInterrupted(); this.stepSurface.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.SURFACE)); genEvent.refreshTimeout(); @@ -1041,7 +1010,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm return; } - genEvent.timer.nextEvent("carver"); throwIfThreadInterrupted(); // caves can generally be ignored since they aren't generally visible from far away if (step == EDhApiWorldGenerationStep.CARVERS) @@ -1049,15 +1017,12 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm return; } - genEvent.timer.nextEvent("feature"); throwIfThreadInterrupted(); this.stepFeatures.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.FEATURES)); genEvent.refreshTimeout(); } finally { - genEvent.timer.nextEvent("light"); - // generate lighting using DH's lighting engine int maxSkyLight = this.serverLevel.getServerLevelWrapper().hasSkyLight() ? 15 : 0; @@ -1260,72 +1225,5 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm } } - 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 ROLLING_AVG_SIZE = 50; - ArrayList rollingAverageList = new ArrayList<>(); - - - - //=============// - // constructor // - //=============// - - public PerfCalculator() - { - for (int i = 0; i < TIME_NAMES.length; i++) - { - this.rollingAverageList.add(new RollingAverage(ROLLING_AVG_SIZE)); - } - } - - public void recordEvent(EventTimer event) - { - for (EventTimer.Event e : event.events) - { - String name = e.name; - int index = Arrays.asList(TIME_NAMES).indexOf(name); - if (index == -1) - { - continue; - } - - this.rollingAverageList.get(index).add(e.timeNs); - } - this.rollingAverageList.get(0).add(event.getTotalTimeNs()); - } - - public String toString() - { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < this.rollingAverageList.size(); i++) - { - if (this.rollingAverageList.get(i).getAverage() == 0) - { - continue; - } - - builder.append(TIME_NAMES[i]).append(": ").append(this.rollingAverageList.get(i).getAverageRoundedString()).append("\n"); - } - return builder.toString(); - } - - } - } \ No newline at end of file diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java index c05945921..3d6ec4c0d 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java @@ -25,10 +25,10 @@ import java.util.function.Consumer; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep; import com.seibel.distanthorizons.core.util.ExceptionUtil; +import com.seibel.distanthorizons.core.util.PerfRecorder; import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhChunkPos; -import com.seibel.distanthorizons.core.util.objects.EventTimer; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; @@ -48,7 +48,6 @@ public final class GenerationEvent public final int widthInChunks; public final EDhApiWorldGenerationStep targetGenerationStep; public final EDhApiDistantGeneratorMode generatorMode; - public EventTimer timer = null; public long inQueueTime; public long timeoutTime = -1; public final CompletableFuture future = new CompletableFuture<>(); @@ -92,7 +91,6 @@ public final class GenerationEvent long runStartTime = System.nanoTime(); generationEvent.timeoutTime = runStartTime; generationEvent.inQueueTime = runStartTime - generationEvent.inQueueTime; - generationEvent.timer = new EventTimer("setup"); BatchGenerationEnvironment.isDhWorldGenThreadRef.set(true); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java index 23b783247..60cf1b698 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java @@ -20,7 +20,6 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment.PerfCalculator; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.WorldGenStructFeatManager; import net.minecraft.server.level.ServerLevel; @@ -42,7 +41,6 @@ public final class ThreadWorldGenParams #endif boolean isValid = true; - public final PerfCalculator perf = new PerfCalculator(); // used for some older MC versions private static GlobalWorldGenParams previousGlobalWorldGenParams = null; diff --git a/coreSubProjects b/coreSubProjects index 1b4f9e894..33a55dc7c 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 1b4f9e89428f06a222925137906352f7484c61a7 +Subproject commit 33a55dc7cdae68979d304b335eef103e0bc4a65f From ce2aa6602aca9540136b4f1a19243231aa2f082f Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Nov 2025 09:48:35 -0600 Subject: [PATCH 04/33] remove unused items from world gen event --- .../BatchGenerationEnvironment.java | 34 ++++++------- .../worldGeneration/GenerationEvent.java | 50 +++++-------------- 2 files changed, 28 insertions(+), 56 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 52353eefb..166c2d769 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -418,7 +418,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm .findFirst() .orElseGet(() -> regionChunks.getFirst()); - genEvent.refreshTimeout(); DhLitWorldGenRegion region = new DhLitWorldGenRegion( centerX, centerZ, centerChunk, @@ -504,8 +503,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm ChunkWrapper wrappedChunk = chunkWrappersByDhPos.get(dhPos); genEvent.resultConsumer.accept(wrappedChunk); } - - genEvent.refreshTimeout(); } catch (CompletionException | UncheckedInterruptedException e) { @@ -533,6 +530,11 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // new ChunkPos(genMinX + (width - 1) + extraRadius, genMinZ + (width - 1) + extraRadius) //); } + + + + // get existing chunk // + /** * If the given chunk pos already exists in the world, that chunk will be returned, * otherwise this will return an empty chunk. @@ -750,6 +752,8 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm + // internal server generation // + private CompletableFuture generateChunksViaInternalServerAsync(GenerationEvent genEvent) throws InterruptedException { LinkedBlockingQueue runnableQueue = new LinkedBlockingQueue<>(); @@ -829,8 +833,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm ChunkPos chunkPos = iterator.next(); releaseChunkToServer(this.params.level, chunkPos, true); } - - genEvent.refreshTimeout(); }); processGeneratedChunksFuture.whenCompleteAsync((unused, throwable) -> { }, runnableQueue::add); // trigger wakeup @@ -941,6 +943,10 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm }); } + + + // direct generation // + public void generateDirect( GenerationEvent genEvent, ArrayGridList chunkWrappersToGenerate, DhLitWorldGenRegion region) throws InterruptedException @@ -972,7 +978,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm throwIfThreadInterrupted(); this.stepStructureStart.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.STRUCTURE_START)); - genEvent.refreshTimeout(); if (step == EDhApiWorldGenerationStep.STRUCTURE_START) { return; @@ -980,7 +985,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm throwIfThreadInterrupted(); this.stepStructureReference.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.STRUCTURE_REFERENCE)); - genEvent.refreshTimeout(); if (step == EDhApiWorldGenerationStep.STRUCTURE_REFERENCE) { return; @@ -988,7 +992,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm throwIfThreadInterrupted(); this.stepBiomes.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.BIOMES)); - genEvent.refreshTimeout(); if (step == EDhApiWorldGenerationStep.BIOMES) { return; @@ -996,7 +999,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm throwIfThreadInterrupted(); this.stepNoise.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.NOISE)); - genEvent.refreshTimeout(); if (step == EDhApiWorldGenerationStep.NOISE) { return; @@ -1004,7 +1006,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm throwIfThreadInterrupted(); this.stepSurface.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.SURFACE)); - genEvent.refreshTimeout(); if (step == EDhApiWorldGenerationStep.SURFACE) { return; @@ -1019,7 +1020,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm throwIfThreadInterrupted(); this.stepFeatures.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.FEATURES)); - genEvent.refreshTimeout(); } finally { @@ -1063,8 +1063,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm this.serverLevel.updateBeaconBeamsForChunk(centerChunk, iChunkWrapperList); } - - genEvent.refreshTimeout(); } } private static ArrayGridList GetCutoutFrom(ArrayGridList total, int border) { return new ArrayGridList<>(total, border, total.gridSize - border); } @@ -1074,14 +1072,14 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm @Override public CompletableFuture generateChunks( - int minX, int minZ, int genSize, + int minX, int minZ, int chunkWidthCount, EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetStep, ExecutorService worldGeneratorThreadPool, Consumer resultConsumer) { - //System.out.println("GenerationEvent: "+genSize+"@"+minX+","+minZ+" "+targetStep); - - // TODO: Check event overlap via e.tooClose() - GenerationEvent genEvent = GenerationEvent.startEvent(new DhChunkPos(minX, minZ), genSize, this, generatorMode, targetStep, resultConsumer, worldGeneratorThreadPool); + GenerationEvent genEvent = GenerationEvent.startEvent( + new DhChunkPos(minX, minZ), chunkWidthCount, this, + generatorMode, targetStep, resultConsumer, + worldGeneratorThreadPool); this.generationEventList.add(genEvent); return genEvent.future; } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java index 3d6ec4c0d..313ae3ca9 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java @@ -25,11 +25,8 @@ import java.util.function.Consumer; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep; import com.seibel.distanthorizons.core.util.ExceptionUtil; -import com.seibel.distanthorizons.core.util.PerfRecorder; -import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhChunkPos; -import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.logging.DhLogger; @@ -48,8 +45,6 @@ public final class GenerationEvent public final int widthInChunks; public final EDhApiWorldGenerationStep targetGenerationStep; public final EDhApiDistantGeneratorMode generatorMode; - public long inQueueTime; - public long timeoutTime = -1; public final CompletableFuture future = new CompletableFuture<>(); public final Consumer resultConsumer; @@ -59,11 +54,10 @@ public final class GenerationEvent // constructor // //=============// - public GenerationEvent( + private GenerationEvent( DhChunkPos minPos, int widthInChunks, BatchGenerationEnvironment generationGroup, EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetGenerationStep, Consumer resultConsumer) { - this.inQueueTime = System.nanoTime(); this.id = generationFutureDebugIDs++; this.minPos = minPos; this.widthInChunks = widthInChunks; @@ -75,12 +69,16 @@ public final class GenerationEvent + //=======// + // start // + //=======// + public static GenerationEvent startEvent( - DhChunkPos minPos, int size, BatchGenerationEnvironment genEnvironment, + DhChunkPos minPos, int widthInChunks, BatchGenerationEnvironment genEnvironment, EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep target, Consumer resultConsumer, ExecutorService worldGeneratorThreadPool) { - GenerationEvent generationEvent = new GenerationEvent(minPos, size, genEnvironment, generatorMode, target, resultConsumer); + GenerationEvent generationEvent = new GenerationEvent(minPos, widthInChunks, genEnvironment, generatorMode, target, resultConsumer); try { @@ -88,10 +86,6 @@ public final class GenerationEvent { try { - long runStartTime = System.nanoTime(); - generationEvent.timeoutTime = runStartTime; - generationEvent.inQueueTime = runStartTime - generationEvent.inQueueTime; - BatchGenerationEnvironment.isDhWorldGenThreadRef.set(true); @@ -168,35 +162,15 @@ public final class GenerationEvent } } - public boolean isComplete() { return this.future.isDone(); } - public boolean hasTimeout(int duration, TimeUnit unit) - { - if (this.timeoutTime == -1) - { - return false; - } - - long currentTime = System.nanoTime(); - long delta = currentTime - this.timeoutTime; - return (delta > TimeUnit.NANOSECONDS.convert(duration, unit)); - } - public boolean terminate() - { - LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN======================="); - ThreadPoolUtil.WORLD_GEN_THREAD_FACTORY.dumpAllThreadStacks(); - this.future.cancel(true); - return this.future.isCancelled(); - } - - public void refreshTimeout() - { - this.timeoutTime = System.nanoTime(); - UncheckedInterruptedException.throwIfInterrupted(); - } + //================// + // base overrides // + //================// @Override public String toString() { return this.id + ":" + this.widthInChunks + "@" + this.minPos + "(" + this.targetGenerationStep + ")"; } + + } \ No newline at end of file From 3c11a2dc335354304e897ba54a54cf6bd342cdac Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Nov 2025 10:29:00 -0600 Subject: [PATCH 05/33] Update .editorconfig --- .editorconfig | 172 +++++++++++++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 72 deletions(-) diff --git a/.editorconfig b/.editorconfig index c9290aae9..932e24503 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,12 +16,35 @@ ij_formatter_off_tag = @formatter:off ij_formatter_on_tag = @formatter:on ij_formatter_tags_enabled = true ij_smart_tabs = false -ij_visual_guides = none +ij_visual_guides = ij_wrap_on_typing = false +[*.dcl] +ij_declarative_keep_indents_on_empty_lines = false + +[*.gsh] +ij_glsl_space_after_colon = true +ij_glsl_space_after_comma = true +ij_glsl_space_after_for_semicolon = true +ij_glsl_space_after_quest = true +ij_glsl_space_before_colon = true +ij_glsl_space_before_comma = false +ij_glsl_space_before_for_semicolon = false +ij_glsl_space_before_quest = true +ij_glsl_spaces_around_additive_operators = true +ij_glsl_spaces_around_assignment_operators = true +ij_glsl_spaces_around_bitwise_operators = true +ij_glsl_spaces_around_equality_operators = true +ij_glsl_spaces_around_logical_operators = true +ij_glsl_spaces_around_multiplicative_operators = true +ij_glsl_spaces_around_relational_operators = true +ij_glsl_spaces_around_shift_operators = true +ij_glsl_spaces_within_brackets = false +ij_glsl_spaces_within_parentheses = false + [*.java] indent_style = tab -ij_smart_tabs = true +ij_continuation_indent_size = 4 ij_java_align_consecutive_assignments = false ij_java_align_consecutive_variable_declarations = false ij_java_align_group_field_declarations = false @@ -30,21 +53,21 @@ ij_java_align_multiline_array_initializer_expression = false ij_java_align_multiline_assignment = false ij_java_align_multiline_binary_operation = false ij_java_align_multiline_chained_methods = false -ij_java_align_multiline_deconstruction_list_components = false +ij_java_align_multiline_deconstruction_list_components = true ij_java_align_multiline_extends_list = false -ij_java_align_multiline_for = false +ij_java_align_multiline_for = true ij_java_align_multiline_method_parentheses = false ij_java_align_multiline_parameters = false ij_java_align_multiline_parameters_in_calls = false ij_java_align_multiline_parenthesized_expression = false -ij_java_align_multiline_records = false +ij_java_align_multiline_records = true ij_java_align_multiline_resources = false ij_java_align_multiline_ternary_operation = false ij_java_align_multiline_text_blocks = false ij_java_align_multiline_throws_list = false ij_java_align_subsequent_simple_methods = false ij_java_align_throws_keyword = false -ij_java_align_types_in_multi_catch = false +ij_java_align_types_in_multi_catch = true ij_java_annotation_parameter_wrap = off ij_java_array_initializer_new_line_after_left_brace = false ij_java_array_initializer_right_brace_on_new_line = false @@ -61,17 +84,17 @@ ij_java_blank_lines_after_package = 1 ij_java_blank_lines_around_class = 1 ij_java_blank_lines_around_field = 0 ij_java_blank_lines_around_field_in_interface = 0 -ij_java_blank_lines_around_initializer = 0 -ij_java_blank_lines_around_method = 0 -ij_java_blank_lines_around_method_in_interface = 0 -ij_java_blank_lines_before_class_end = 1 +ij_java_blank_lines_around_initializer = 1 +ij_java_blank_lines_around_method = 1 +ij_java_blank_lines_around_method_in_interface = 1 +ij_java_blank_lines_before_class_end = 0 ij_java_blank_lines_before_imports = 1 ij_java_blank_lines_before_method_body = 0 ij_java_blank_lines_before_package = 1 ij_java_block_brace_style = next_line ij_java_block_comment_add_space = false ij_java_block_comment_at_first_column = true -ij_java_builder_methods = none +ij_java_builder_methods = ij_java_call_parameters_new_line_after_left_paren = false ij_java_call_parameters_right_paren_on_new_line = false ij_java_call_parameters_wrap = normal @@ -86,7 +109,7 @@ ij_java_do_not_indent_top_level_class_members = false ij_java_do_not_wrap_after_single_annotation = false ij_java_do_not_wrap_after_single_annotation_in_parameter = false ij_java_do_while_brace_force = never -ij_java_doc_add_blank_line_after_description = true +ij_java_doc_add_blank_line_after_description = false ij_java_doc_add_blank_line_after_param_comments = false ij_java_doc_add_blank_line_after_return = false ij_java_doc_add_p_tag_on_empty_lines = false @@ -97,25 +120,29 @@ ij_java_doc_enable_formatting = true ij_java_doc_enable_leading_asterisks = true ij_java_doc_indent_on_continuation = false ij_java_doc_keep_empty_lines = true -ij_java_doc_keep_empty_parameter_tag = true +ij_java_doc_keep_empty_parameter_tag = false ij_java_doc_keep_empty_return_tag = false -ij_java_doc_keep_empty_throws_tag = true -ij_java_doc_keep_invalid_tags = true +ij_java_doc_keep_empty_throws_tag = false +ij_java_doc_keep_invalid_tags = false ij_java_doc_param_description_on_new_line = false ij_java_doc_preserve_line_breaks = false ij_java_doc_use_throws_not_exception_tag = true ij_java_else_on_new_line = true ij_java_enum_constants_wrap = off +ij_java_enum_field_annotation_wrap = off ij_java_extends_keyword_wrap = normal ij_java_extends_list_wrap = normal ij_java_field_annotation_wrap = off +ij_java_field_name_prefix = +ij_java_field_name_suffix = ij_java_finally_on_new_line = true -ij_java_for_brace_force = always +ij_java_for_brace_force = never ij_java_for_statement_new_line_after_left_paren = false ij_java_for_statement_right_paren_on_new_line = false ij_java_for_statement_wrap = off ij_java_generate_final_locals = false ij_java_generate_final_parameters = false +ij_java_generate_use_type_annotation_before_type = true ij_java_if_brace_force = never ij_java_imports_layout = *,|,javax.**,java.**,|,$* ij_java_indent_case_from_switch = true @@ -126,13 +153,13 @@ ij_java_keep_blank_lines_between_package_declaration_and_header = 2 ij_java_keep_blank_lines_in_code = 10 ij_java_keep_blank_lines_in_declarations = 10 ij_java_keep_builder_methods_indents = false -ij_java_keep_control_statement_in_one_line = true -ij_java_keep_first_column_comment = true +ij_java_keep_control_statement_in_one_line = false +ij_java_keep_first_column_comment = false ij_java_keep_indents_on_empty_lines = true ij_java_keep_line_breaks = true -ij_java_keep_multiple_expressions_in_one_line = true +ij_java_keep_multiple_expressions_in_one_line = false ij_java_keep_simple_blocks_in_one_line = false -ij_java_keep_simple_classes_in_one_line = true +ij_java_keep_simple_classes_in_one_line = false ij_java_keep_simple_lambdas_in_one_line = true ij_java_keep_simple_methods_in_one_line = true ij_java_label_indent_absolute = false @@ -141,11 +168,13 @@ ij_java_lambda_brace_style = end_of_line ij_java_layout_static_imports_separately = true ij_java_line_comment_add_space = false ij_java_line_comment_add_space_on_reformat = false -ij_java_line_comment_at_first_column = false +ij_java_line_comment_at_first_column = true +ij_java_local_variable_name_prefix = +ij_java_local_variable_name_suffix = ij_java_method_annotation_wrap = off ij_java_method_brace_style = next_line ij_java_method_call_chain_wrap = normal -ij_java_method_parameters_new_line_after_left_paren = true +ij_java_method_parameters_new_line_after_left_paren = false ij_java_method_parameters_right_paren_on_new_line = false ij_java_method_parameters_wrap = normal ij_java_modifier_list_wrap = false @@ -154,18 +183,22 @@ ij_java_names_count_to_use_import_on_demand = 3 ij_java_new_line_after_lparen_in_annotation = false ij_java_new_line_after_lparen_in_deconstruction_pattern = true ij_java_new_line_after_lparen_in_record_header = false +ij_java_new_line_when_body_is_presented = false ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.* ij_java_parameter_annotation_wrap = off +ij_java_parameter_name_prefix = +ij_java_parameter_name_suffix = ij_java_parentheses_expression_new_line_after_left_paren = false ij_java_parentheses_expression_right_paren_on_new_line = false ij_java_place_assignment_sign_on_next_line = false ij_java_prefer_longer_names = true ij_java_prefer_parameters_wrap = false ij_java_record_components_wrap = normal +ij_java_repeat_annotations = ij_java_repeat_synchronized = true ij_java_replace_instanceof_and_cast = false -ij_java_replace_null_check = false -ij_java_replace_sum_lambda_with_method_ref = false +ij_java_replace_null_check = true +ij_java_replace_sum_lambda_with_method_ref = true ij_java_resource_list_new_line_after_left_paren = false ij_java_resource_list_right_paren_on_new_line = false ij_java_resource_list_wrap = on_every_item @@ -181,7 +214,7 @@ ij_java_space_after_quest = true ij_java_space_after_type_cast = true ij_java_space_before_annotation_array_initializer_left_brace = false ij_java_space_before_annotation_parameter_list = false -ij_java_space_before_array_initializer_left_brace = false +ij_java_space_before_array_initializer_left_brace = true ij_java_space_before_catch_keyword = true ij_java_space_before_catch_left_brace = true ij_java_space_before_catch_parentheses = true @@ -207,7 +240,7 @@ ij_java_space_before_opening_angle_bracket_in_type_parameter = false ij_java_space_before_quest = true ij_java_space_before_switch_left_brace = true ij_java_space_before_switch_parentheses = true -ij_java_space_before_synchronized_left_brace = false +ij_java_space_before_synchronized_left_brace = true ij_java_space_before_synchronized_parentheses = true ij_java_space_before_try_left_brace = true ij_java_space_before_try_parentheses = true @@ -216,7 +249,7 @@ ij_java_space_before_while_keyword = true ij_java_space_before_while_left_brace = true ij_java_space_before_while_parentheses = true ij_java_space_inside_one_line_enum_braces = false -ij_java_space_within_empty_array_initializer_braces = true +ij_java_space_within_empty_array_initializer_braces = false ij_java_space_within_empty_method_call_parentheses = false ij_java_space_within_empty_method_parentheses = false ij_java_spaces_around_additive_operators = true @@ -232,9 +265,10 @@ ij_java_spaces_around_relational_operators = true ij_java_spaces_around_shift_operators = true ij_java_spaces_around_type_bounds_in_type_parameters = true ij_java_spaces_around_unary_operator = false +ij_java_spaces_inside_block_braces_when_body_is_present = false ij_java_spaces_within_angle_brackets = false ij_java_spaces_within_annotation_parentheses = false -ij_java_spaces_within_array_initializer_braces = false +ij_java_spaces_within_array_initializer_braces = true ij_java_spaces_within_braces = true ij_java_spaces_within_brackets = false ij_java_spaces_within_cast_parentheses = false @@ -251,9 +285,14 @@ ij_java_spaces_within_synchronized_parentheses = false ij_java_spaces_within_try_parentheses = false ij_java_spaces_within_while_parentheses = false ij_java_special_else_if_treatment = true +ij_java_static_field_name_prefix = +ij_java_static_field_name_suffix = +ij_java_subclass_name_prefix = ij_java_subclass_name_suffix = Impl +ij_java_switch_expressions_wrap = normal ij_java_ternary_operation_signs_on_next_line = false ij_java_ternary_operation_wrap = on_every_item +ij_java_test_name_prefix = ij_java_test_name_suffix = Test ij_java_throws_keyword_wrap = normal ij_java_throws_list_wrap = normal @@ -263,11 +302,12 @@ ij_java_use_relative_indents = false ij_java_use_single_class_imports = true ij_java_variable_annotation_wrap = off ij_java_visibility = public -ij_java_while_brace_force = always +ij_java_while_brace_force = never ij_java_while_on_new_line = true ij_java_wrap_comments = false ij_java_wrap_first_method_in_call_chain = false ij_java_wrap_long_lines = false +ij_java_wrap_semicolon_after_call_chain = false [*.nbtt] indent_style = tab @@ -313,11 +353,9 @@ ij_xml_space_after_tag_name = false ij_xml_space_around_equals_in_attribute = false ij_xml_space_inside_empty_tag = false ij_xml_text_wrap = normal -ij_xml_use_custom_settings = false [{*.bash,*.sh,*.zsh}] -indent_size = 4 -tab_width = 4 +indent_style = tab ij_shell_binary_ops_start_line = false ij_shell_keep_column_alignment_padding = false ij_shell_minify_program = false @@ -325,25 +363,8 @@ ij_shell_redirect_followed_by_space = false ij_shell_switch_cases_indented = false ij_shell_use_unix_line_separator = true -[{*.comp,*.frag,*.fsh,*.geom,*.glsl,*.gsh,*.tesc,*.tese,*.vert,*.vsh}] -ij_glsl_space_after_colon = true -ij_glsl_space_after_comma = true -ij_glsl_space_after_for_semicolon = true -ij_glsl_space_after_quest = true -ij_glsl_space_before_colon = false -ij_glsl_space_before_comma = false -ij_glsl_space_before_for_semicolon = false -ij_glsl_space_before_quest = true -ij_glsl_spaces_around_additive_operators = true -ij_glsl_spaces_around_assignment_operators = true -ij_glsl_spaces_around_bitwise_operators = true -ij_glsl_spaces_around_equality_operators = true -ij_glsl_spaces_around_logical_operators = true -ij_glsl_spaces_around_multiplicative_operators = true -ij_glsl_spaces_around_relational_operators = true -ij_glsl_spaces_around_shift_operators = true -ij_glsl_spaces_within_brackets = false -ij_glsl_spaces_within_parentheses = false +[{*.comp,*.frag,*.fsh,*.geom,*.glsl,*.tesc,*.tese,*.vert,*.vsh}] +ij_glsl_keep_indents_on_empty_lines = false [{*.gant,*.groovy,*.gy}] ij_groovy_align_group_field_declarations = false @@ -536,8 +557,9 @@ ij_groovy_while_on_new_line = false ij_groovy_wrap_chain_calls_after_dot = false ij_groovy_wrap_long_lines = false -[{*.har,*.json,*.png.mcmeta,mcmod.info,pack.mcmeta}] -indent_size = 4 +[{*.har,*.json,*.jsonc,*.png.mcmeta,mcmod.info,pack.mcmeta}] +indent_style = tab +ij_continuation_indent_size = 4 ij_json_array_wrapping = split_into_lines ij_json_keep_blank_lines_in_code = 0 ij_json_keep_indents_on_empty_lines = false @@ -582,6 +604,8 @@ ij_html_space_inside_empty_tag = false ij_html_text_wrap = normal [{*.kt,*.kts}] +indent_style = tab +ij_continuation_indent_size = 4 ij_kotlin_align_in_columns_case_branch = false ij_kotlin_align_multiline_binary_operation = false ij_kotlin_align_multiline_extends_list = false @@ -590,32 +614,34 @@ ij_kotlin_align_multiline_parameters = true ij_kotlin_align_multiline_parameters_in_calls = false ij_kotlin_allow_trailing_comma = false ij_kotlin_allow_trailing_comma_on_call_site = false -ij_kotlin_assignment_wrap = off +ij_kotlin_assignment_wrap = normal ij_kotlin_blank_lines_after_class_header = 0 ij_kotlin_blank_lines_around_block_when_branches = 0 ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1 ij_kotlin_block_comment_add_space = false ij_kotlin_block_comment_at_first_column = true -ij_kotlin_call_parameters_new_line_after_left_paren = false -ij_kotlin_call_parameters_right_paren_on_new_line = false -ij_kotlin_call_parameters_wrap = off +ij_kotlin_call_parameters_new_line_after_left_paren = true +ij_kotlin_call_parameters_right_paren_on_new_line = true +ij_kotlin_call_parameters_wrap = on_every_item ij_kotlin_catch_on_new_line = false ij_kotlin_class_annotation_wrap = split_into_lines -ij_kotlin_continuation_indent_for_chained_calls = true -ij_kotlin_continuation_indent_for_expression_bodies = true -ij_kotlin_continuation_indent_in_argument_lists = true -ij_kotlin_continuation_indent_in_elvis = true -ij_kotlin_continuation_indent_in_if_conditions = true -ij_kotlin_continuation_indent_in_parameter_lists = true -ij_kotlin_continuation_indent_in_supertype_lists = true +ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL +ij_kotlin_continuation_indent_for_chained_calls = false +ij_kotlin_continuation_indent_for_expression_bodies = false +ij_kotlin_continuation_indent_in_argument_lists = false +ij_kotlin_continuation_indent_in_elvis = false +ij_kotlin_continuation_indent_in_if_conditions = false +ij_kotlin_continuation_indent_in_parameter_lists = false +ij_kotlin_continuation_indent_in_supertype_lists = false ij_kotlin_else_on_new_line = false ij_kotlin_enum_constants_wrap = off -ij_kotlin_extends_list_wrap = off +ij_kotlin_extends_list_wrap = normal ij_kotlin_field_annotation_wrap = split_into_lines ij_kotlin_finally_on_new_line = false -ij_kotlin_if_rparen_on_new_line = false +ij_kotlin_if_rparen_on_new_line = true ij_kotlin_import_nested_classes = false ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^ +ij_kotlin_indent_before_arrow_on_new_line = true ij_kotlin_insert_whitespaces_in_simple_one_line_method = true ij_kotlin_keep_blank_lines_before_right_brace = 2 ij_kotlin_keep_blank_lines_in_code = 2 @@ -629,10 +655,10 @@ ij_kotlin_line_comment_add_space = false ij_kotlin_line_comment_add_space_on_reformat = false ij_kotlin_line_comment_at_first_column = true ij_kotlin_method_annotation_wrap = split_into_lines -ij_kotlin_method_call_chain_wrap = off -ij_kotlin_method_parameters_new_line_after_left_paren = false -ij_kotlin_method_parameters_right_paren_on_new_line = false -ij_kotlin_method_parameters_wrap = off +ij_kotlin_method_call_chain_wrap = normal +ij_kotlin_method_parameters_new_line_after_left_paren = true +ij_kotlin_method_parameters_right_paren_on_new_line = true +ij_kotlin_method_parameters_wrap = on_every_item ij_kotlin_name_count_to_use_star_import = 5 ij_kotlin_name_count_to_use_star_import_for_members = 3 ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.** @@ -662,7 +688,7 @@ ij_kotlin_spaces_around_when_arrow = true ij_kotlin_variable_annotation_wrap = off ij_kotlin_while_on_new_line = false ij_kotlin_wrap_elvis_expressions = 1 -ij_kotlin_wrap_expression_body_functions = 0 +ij_kotlin_wrap_expression_body_functions = 1 ij_kotlin_wrap_first_method_in_call_chain = false [{*.markdown,*.md}] @@ -687,13 +713,15 @@ ij_markdown_wrap_text_inside_blockquotes = true ij_toml_keep_indents_on_empty_lines = false [{*.yaml,*.yml}] -indent_size = 4 ij_yaml_align_values_properties = do_not_align ij_yaml_autoinsert_sequence_marker = true ij_yaml_block_mapping_on_new_line = false ij_yaml_indent_sequence_value = true ij_yaml_keep_indents_on_empty_lines = false ij_yaml_keep_line_breaks = true +ij_yaml_line_comment_add_space = false +ij_yaml_line_comment_add_space_on_reformat = false +ij_yaml_line_comment_at_first_column = true ij_yaml_sequence_on_new_line = false ij_yaml_space_before_colon = false ij_yaml_spaces_within_braces = true From a709ab60715433942c810771c9f4ec97d4cf413c Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Nov 2025 11:02:13 -0600 Subject: [PATCH 06/33] move internal server into its own file --- .../BatchGenerationEnvironment.java | 352 ++---------------- .../worldGeneration/ChunkPosGenStream.java | 88 +++++ .../worldGeneration/GenerationEvent.java | 63 ++-- .../InternalServerGenerator.java | 262 +++++++++++++ coreSubProjects | 2 +- 5 files changed, 420 insertions(+), 347 deletions(-) create mode 100644 common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ChunkPosGenStream.java create mode 100644 common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 166c2d769..f7ad847f5 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -24,6 +24,7 @@ import com.google.common.collect.ImmutableMap; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.internalServer.InternalServerGenerator; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.*; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.generation.DhLightingEngine; @@ -49,9 +50,6 @@ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; -import java.util.function.Function; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -99,27 +97,22 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm .build(); public static final DhLogger CHUNK_LOAD_LOGGER = new DhLoggerBuilder() - .name("LOD World Gen") + .name("LOD Chunk Loading") .fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile) .build(); - #if MC_VER < MC_1_21_5 - private static final TicketType DH_SERVER_GEN_TICKET = TicketType.create("dh_server_gen_ticket", Comparator.comparingLong(ChunkPos::toLong)); - #elif MC_VER < MC_1_21_9 - private static final TicketType DH_SERVER_GEN_TICKET = new TicketType(/* timeout, 0 = disabled*/0L, /* persist */ false, TicketType.TicketUse.LOADING); - #else - private static final TicketType DH_SERVER_GEN_TICKET = new TicketType(/* timeout, 0 = disabled*/0L, /* flags */TicketType.FLAG_LOADING); - #endif - private static final IModChecker MOD_CHECKER = SingletonInjector.INSTANCE.get(IModChecker.class); @NotNull public static final ImmutableMap WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP; public static final int MAX_WORLD_GEN_CHUNK_BORDER_NEEDED; + public static final long EXCEPTION_TIMER_RESET_TIME = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); + public static final int EXCEPTION_COUNTER_TRIGGER = 20; - private final IDhServerLevel serverLevel; + + private final IDhServerLevel dhServerLevel; /** * will be true if C2ME is installed (since they require us to @@ -128,9 +121,11 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm */ private boolean pullExistingChunkUsingMcAsyncMethod = false; + public final InternalServerGenerator internalServerGenerator; - public final LinkedBlockingQueue generationEventList = new LinkedBlockingQueue<>(); + + public final LinkedBlockingQueue generationEventQueue = new LinkedBlockingQueue<>(); public final GlobalWorldGenParams params; public final StepStructureStart stepStructureStart = new StepStructureStart(this); @@ -141,8 +136,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm public final StepFeatures stepFeatures = new StepFeatures(this); public boolean unsafeThreadingRecorded = false; - public static final long EXCEPTION_TIMER_RESET_TIME = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); - public static final int EXCEPTION_COUNTER_TRIGGER = 20; public int unknownExceptionCount = 0; public long lastExceptionTriggerTime = 0; @@ -203,15 +196,13 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm MAX_WORLD_GEN_CHUNK_BORDER_NEEDED = 0; } - public BatchGenerationEnvironment(IDhServerLevel serverLevel) + public BatchGenerationEnvironment(IDhServerLevel dhServerLevel) { - this.serverLevel = serverLevel; + this.dhServerLevel = dhServerLevel; + this.params = new GlobalWorldGenParams(dhServerLevel); + this.internalServerGenerator = new InternalServerGenerator(this.params, this.dhServerLevel); - LOGGER.info("Creating Batch Generator"); - - serverLevel.getServerLevelWrapper().getDimensionType(); - - ChunkGenerator generator = ((ServerLevelWrapper) (serverLevel.getServerLevelWrapper())).getLevel().getChunkSource().getGenerator(); + ChunkGenerator generator = ((ServerLevelWrapper) (dhServerLevel.getServerLevelWrapper())).getLevel().getChunkSource().getGenerator(); boolean isMcGenerator = generator instanceof NoiseBasedChunkGenerator || generator instanceof DebugLevelSource @@ -241,7 +232,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm this.pullExistingChunkUsingMcAsyncMethod = true; } - this.params = new GlobalWorldGenParams(serverLevel); } @@ -290,7 +280,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // Update all current out standing jobs - Iterator iter = this.generationEventList.iterator(); + Iterator iter = this.generationEventQueue.iterator(); while (iter.hasNext()) { GenerationEvent event = iter.next(); @@ -339,11 +329,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // We handle this later, although that handling would need to change if the gen size ever changes. LodUtil.assertTrue(genEvent.widthInChunks % 2 == 0, "Generation events are expected to be an evan number of chunks wide."); - if (genEvent.generatorMode == EDhApiDistantGeneratorMode.INTERNAL_SERVER) - { - return this.generateChunksViaInternalServerAsync(genEvent); - } - int borderSize = MAX_WORLD_GEN_CHUNK_BORDER_NEEDED; // genEvent.size - 1 converts the even width size to an odd number for MC compatability int refSize = (genEvent.widthInChunks - 1) + (borderSize * 2); @@ -368,7 +353,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // futures to handle getting empty chunks CompletableFuture[] readFutures = // the extra radius of 8 is to account for structure references which need a chunk radius of 8 - getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 8) + ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 8) .map((chunkPos) -> this.createEmptyOrPreExistingChunkAsync(chunkPos.x, chunkPos.z, chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, generatedChunkByDhPos)) .toArray(CompletableFuture[]::new); @@ -452,7 +437,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm else if (chunk != null) { // wrap the chunk - ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.serverLevel.getLevelWrapper()); + ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper()); chunkWrapperList.set(relX, relZ, chunkWrapper); // try setting the wrapper's lighting @@ -495,7 +480,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // submit generated chunks // //=========================// - Iterator iterator = getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); + Iterator iterator = ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); while (iterator.hasNext()) { ChunkPos pos = iterator.next(); @@ -519,17 +504,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm } }, executor); } - /** @param extraRadius in both the positive and negative directions */ - private static Stream getChunkPosToGenerateStream(int genMinX, int genMinZ, int width, int extraRadius) - { - return StreamSupport.stream(new InclusiveChunkPosStream(genMinX, genMinZ, width, extraRadius), false); - - // method this is replacing - //return ChunkPos.rangeClosed( - // new ChunkPos(genMinX - extraRadius, genMinZ - extraRadius), - // new ChunkPos(genMinX + (width - 1) + extraRadius, genMinZ + (width - 1) + extraRadius) - //); - } @@ -682,7 +656,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm } catch (Exception e) { - CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load or make chunk [" + chunkPos + "]. Error: [" + e.getMessage() + "].", e); + CHUNK_LOAD_LOGGER.warn("Couldn't load or make chunk [" + chunkPos + "]. Error: [" + e.getMessage() + "].", e); return CompletableFuture.completedFuture(null); } } @@ -752,199 +726,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm - // internal server generation // - - private CompletableFuture generateChunksViaInternalServerAsync(GenerationEvent genEvent) throws InterruptedException - { - LinkedBlockingQueue runnableQueue = new LinkedBlockingQueue<>(); - - Map chunkWrappersByDhPos = Collections.synchronizedMap(new HashMap<>()); - - - - //===================================// - // create generation queue runnables // - //===================================// - - // request each chunk pos from the server - CompletableFuture[] requestFutures = - getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0) - .map(chunkPos -> - { - return requestChunkFromServerAsync(this.params.level, chunkPos, true) - .whenCompleteAsync((chunk, throwable) -> - { - // unwrap the CompletionException if necessary - Throwable actualThrowable = throwable; - while (actualThrowable instanceof CompletionException) - { - actualThrowable = actualThrowable.getCause(); - } - - if (throwable != null) - { - CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load chunk [" + chunkPos + "] from server, error: [" + actualThrowable.getMessage() + "].", actualThrowable); - } - - if (chunk != null) - { - ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.serverLevel.getLevelWrapper()); - chunkWrappersByDhPos.put(new DhChunkPos(chunkPos.x, chunkPos.z), chunkWrapper); - } - }, runnableQueue::add); - }) - .toArray(CompletableFuture[]::new); - - // handle each generated chunk - CompletableFuture processGeneratedChunksFuture = - CompletableFuture.allOf(requestFutures) - .whenCompleteAsync((voidObj, throwable) -> - { - // generate chunk lighting using DH's lighting engine - int maxSkyLight = this.serverLevel.getServerLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT; - - ArrayList generatedChunks = new ArrayList<>(chunkWrappersByDhPos.values()); - for (IChunkWrapper iChunkWrapper : generatedChunks) - { - ((ChunkWrapper) iChunkWrapper).recalculateDhHeightMapsIfNeeded(); - - // pre-generated chunks should have lighting but new ones won't - if (!iChunkWrapper.isDhBlockLightingCorrect()) - { - DhLightingEngine.INSTANCE.bakeChunkBlockLighting(iChunkWrapper, generatedChunks, maxSkyLight); - } - - this.serverLevel.updateBeaconBeamsForChunk(iChunkWrapper, generatedChunks); - } - - for (IChunkWrapper iChunkWrapper : generatedChunks) - { - genEvent.resultConsumer.accept(iChunkWrapper); - } - }, runnableQueue::add) - .whenCompleteAsync((unused, throwable) -> - { - // cleanup - // release the generated chunks - - Iterator iterator = getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); - while (iterator.hasNext()) - { - ChunkPos chunkPos = iterator.next(); - releaseChunkToServer(this.params.level, chunkPos, true); - } - }); - - processGeneratedChunksFuture.whenCompleteAsync((unused, throwable) -> { }, runnableQueue::add); // trigger wakeup - - - - //===============// - // run each step // - //===============// - - while (!processGeneratedChunksFuture.isDone()) - { - try - { - Runnable command = runnableQueue.poll(1, TimeUnit.SECONDS); - if (command != null) - { - command.run(); - } - } - catch (InterruptedException e) - { - // interrupted, release chunk to server - Iterator iterator = getChunkPosToGenerateStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); - while (iterator.hasNext()) - { - ChunkPos chunkPos = iterator.next(); - releaseChunkToServer(this.params.level, chunkPos, true); - } - - throw e; - } - } - - return processGeneratedChunksFuture; - } - /** @param generateUpToFeatures if false this generate the chunk up to "FULL" status */ - private static CompletableFuture requestChunkFromServerAsync(ServerLevel level, ChunkPos pos, boolean generateUpToFeatures) - { - return CompletableFuture.supplyAsync(() -> - { - int chunkLevel; - #if MC_VER <= MC_1_19_4 - // 33 is equivalent to FULL Chunk - chunkLevel = generateUpToFeatures ? 33 + ChunkStatus.getDistance(ChunkStatus.FEATURES) : 33; - #else - // 33 is equivalent to FULL Chunk - chunkLevel = generateUpToFeatures ? ChunkLevel.byStatus(ChunkStatus.FEATURES) : 33; - #endif - - #if MC_VER < MC_1_21_5 - level.getChunkSource().distanceManager.addTicket(DH_SERVER_GEN_TICKET, pos, chunkLevel, pos); - #else - level.getChunkSource().addTicketWithRadius(DH_SERVER_GEN_TICKET, pos, 0); - #endif - level.getChunkSource().distanceManager.runAllUpdates(level.getChunkSource().chunkMap); // probably not the most optimal to run updates here, but fast enough - ChunkHolder holder = level.getChunkSource().chunkMap.getUpdatingChunkIfPresent(pos.toLong()); - if (holder == null) - { - throw new IllegalStateException("No chunk holder after ticket has been added"); - } - - #if MC_VER <= MC_1_20_4 - return holder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) - .thenApply(result -> result.left().orElseThrow(() -> new RuntimeException(result.right().get().toString()))); // can throw if the server is shutting down - #elif MC_VER <= MC_1_20_6 - return holder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) - .thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.toString()))); // can throw if the server is shutting down - #else - return holder.scheduleChunkGenerationTask(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) - .thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.getError()))); // can throw if the server is shutting down - #endif - - }, level.getChunkSource().chunkMap.mainThreadExecutor).thenCompose(Function.identity()); - } - /** @param chunkWasGeneratedUpToFeatures if false this assumes the chunk was generated to "FULL" status */ - private static void releaseChunkToServer(ServerLevel level, ChunkPos pos, boolean chunkWasGeneratedUpToFeatures) - { - level.getChunkSource().chunkMap.mainThreadExecutor.execute(() -> - { - try - { - int chunkLevel; - #if MC_VER <= MC_1_19_4 - // 33 is equivalent to FULL Chunk - chunkLevel = chunkWasGeneratedUpToFeatures ? 33 + ChunkStatus.getDistance(ChunkStatus.FEATURES) : 33; - #else - // 33 is equivalent to FULL Chunk - chunkLevel = chunkWasGeneratedUpToFeatures ? ChunkLevel.byStatus(ChunkStatus.FEATURES) : 33; - #endif - - #if MC_VER < MC_1_21_5 - level.getChunkSource().distanceManager.removeTicket(DH_SERVER_GEN_TICKET, pos, chunkLevel, pos); - #else - level.getChunkSource().removeTicketWithRadius(DH_SERVER_GEN_TICKET, pos, 0); - #endif - - // mitigate OOM issues in vanilla chunk system: see https://github.com/pop4959/Chunky/pull/383 - level.getChunkSource().chunkMap.tick(() -> false); - #if MC_VER > MC_1_16_5 - level.entityManager.tick(); - #endif - } - catch (Exception e) - { - LOGGER.warn("Failed to release chunk back to internal server. Error: ["+e.getMessage()+"]", e); - } - }); - } - - - // direct generation // public void generateDirect( @@ -1025,7 +806,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm { // generate lighting using DH's lighting engine - int maxSkyLight = this.serverLevel.getServerLevelWrapper().hasSkyLight() ? 15 : 0; + int maxSkyLight = this.dhServerLevel.getServerLevelWrapper().hasSkyLight() ? 15 : 0; // only light generated chunks, // attempting to light un-generated chunks will cause lighting issues on bordering generated chunks @@ -1061,7 +842,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm DhLightingEngine.INSTANCE.bakeChunkBlockLighting(centerChunk, iChunkWrapperList, maxSkyLight); } - this.serverLevel.updateBeaconBeamsForChunk(centerChunk, iChunkWrapperList); + this.dhServerLevel.updateBeaconBeamsForChunk(centerChunk, iChunkWrapperList); } } } @@ -1070,8 +851,10 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm + // queue task // + @Override - public CompletableFuture generateChunks( + public CompletableFuture queueGenEvent( int minX, int minZ, int chunkWidthCount, EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetStep, ExecutorService worldGeneratorThreadPool, Consumer resultConsumer) @@ -1080,7 +863,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm new DhChunkPos(minX, minZ), chunkWidthCount, this, generatorMode, targetStep, resultConsumer, worldGeneratorThreadPool); - this.generationEventList.add(genEvent); + this.generationEventQueue.add(genEvent); return genEvent.future; } @@ -1093,17 +876,19 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm @Override public void close() { - LOGGER.info(BatchGenerationEnvironment.class.getSimpleName() + " shutting down..."); + LOGGER.info("Closing [" +BatchGenerationEnvironment.class.getSimpleName() + "]"); - LOGGER.info("Canceling in progress generation event futures..."); - Iterator iter = this.generationEventList.iterator(); - while (iter.hasNext()) + + // cancel in-progress tasks + Iterator genEventIter = this.generationEventQueue.iterator(); + while (genEventIter.hasNext()) { - GenerationEvent event = iter.next(); + GenerationEvent event = genEventIter.next(); event.future.cancel(true); - iter.remove(); + genEventIter.remove(); } + // clear the chunk cache RegionFileStorageExternalCache regionStorage = this.regionFileStorageCacheRef.get(); if (regionStorage != null) @@ -1118,8 +903,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm LOGGER.error("Failed to close region file storage cache, error: ["+e.getMessage()+"].", e); } } - - LOGGER.info(BatchGenerationEnvironment.class.getSimpleName() + " shutdown complete."); } @@ -1153,75 +936,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm ChunkAccess getChunk(int chunkPosX, int chunkPosZ); } - private static class InclusiveChunkPosStream extends Spliterators.AbstractSpliterator - { - private final int minX; - private final int minZ; - - private final int maxX; - private final int maxZ; - - - /** current X pos */ - int x; - /** current Z pos */ - private int z; - - - - //=============// - // constructor // - //=============// - - protected InclusiveChunkPosStream(int genMinX, int genMinZ, int width, int extraRadius) - { - super(getCount(width, extraRadius), Spliterator.SIZED); - - this.minX = genMinX - extraRadius; - this.minZ = genMinZ - extraRadius; - - this.maxX = genMinX + (width - 1) + extraRadius; - this.maxZ = genMinZ + (width - 1) + extraRadius; - - // X starts at 1 minus the minX so we can immediately re-add 1 in the tryAdvance() loop - this.x = this.minX - 1; - this.z = this.minZ; - } - private static int getCount(int width, int extraRadius) - { - int widthPlusExtra = width + (extraRadius * 2); - return widthPlusExtra * widthPlusExtra; - } - - - - //=================// - // iterator method // - //=================// - - public boolean tryAdvance(Consumer consumer) - { - if (this.x == this.maxX && this.z == this.maxZ) - { - // the last returned position was the final valid position - return false; - } - - if (this.x == this.maxX) - { - // we reached the max X position, loop back around in the next Z row - this.x = this.minX; - this.z++; - } - else - { - this.x++; - } - - consumer.accept(new ChunkPos(this.x, this.z)); - return true; - } - } } \ No newline at end of file diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ChunkPosGenStream.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ChunkPosGenStream.java new file mode 100644 index 000000000..b923ff1a6 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ChunkPosGenStream.java @@ -0,0 +1,88 @@ +package com.seibel.distanthorizons.common.wrappers.worldGeneration; + +import net.minecraft.world.level.ChunkPos; + +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.Consumer; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +public class ChunkPosGenStream +{ + + /** @param extraRadius in both the positive and negative directions */ + public static Stream getStream(int genMinX, int genMinZ, int width, int extraRadius) + { return StreamSupport.stream(new InclusiveChunkPosIterator(genMinX, genMinZ, width, extraRadius), false); } + public static class InclusiveChunkPosIterator extends Spliterators.AbstractSpliterator + { + private final int minX; + private final int minZ; + + private final int maxX; + private final int maxZ; + + + /** current X pos */ + int x; + /** current Z pos */ + private int z; + + + + //=============// + // constructor // + //=============// + + protected InclusiveChunkPosIterator(int genMinX, int genMinZ, int width, int extraRadius) + { + super(getCount(width, extraRadius), Spliterator.SIZED); + + this.minX = genMinX - extraRadius; + this.minZ = genMinZ - extraRadius; + + this.maxX = genMinX + (width - 1) + extraRadius; + this.maxZ = genMinZ + (width - 1) + extraRadius; + + // X starts at 1 minus the minX so we can immediately re-add 1 in the tryAdvance() loop + this.x = this.minX - 1; + this.z = this.minZ; + } + private static int getCount(int width, int extraRadius) + { + int widthPlusExtra = width + (extraRadius * 2); + return widthPlusExtra * widthPlusExtra; + } + + + + //=================// + // iterator method // + //=================// + + @Override + public boolean tryAdvance(Consumer consumer) + { + if (this.x == this.maxX && this.z == this.maxZ) + { + // the last returned position was the final valid position + return false; + } + + if (this.x == this.maxX) + { + // we reached the max X position, loop back around in the next Z row + this.x = this.minX; + this.z++; + } + else + { + this.x++; + } + + consumer.accept(new ChunkPos(this.x, this.z)); + return true; + } + } + +} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java index 313ae3ca9..f898655c0 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java @@ -59,6 +59,7 @@ public final class GenerationEvent EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetGenerationStep, Consumer resultConsumer) { this.id = generationFutureDebugIDs++; + this.minPos = minPos; this.widthInChunks = widthInChunks; this.generatorMode = generatorMode; @@ -78,7 +79,7 @@ public final class GenerationEvent EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep target, Consumer resultConsumer, ExecutorService worldGeneratorThreadPool) { - GenerationEvent generationEvent = new GenerationEvent(minPos, widthInChunks, genEnvironment, generatorMode, target, resultConsumer); + GenerationEvent genEvent = new GenerationEvent(minPos, widthInChunks, genEnvironment, generatorMode, target, resultConsumer); try { @@ -89,40 +90,48 @@ public final class GenerationEvent BatchGenerationEnvironment.isDhWorldGenThreadRef.set(true); - genEnvironment.generateLodFromListAsync(generationEvent, (runnable) -> + if (genEvent.generatorMode == EDhApiDistantGeneratorMode.INTERNAL_SERVER) { - worldGeneratorThreadPool.execute(() -> + genEnvironment.internalServerGenerator.generateChunksViaInternalServer(genEvent); + genEvent.future.complete(null); + } + else + { + genEnvironment.generateLodFromListAsync(genEvent, (runnable) -> { - // TODO why not just always set this each time? - boolean alreadyMarked = BatchGenerationEnvironment.isThisDhWorldGenThread(); - if (!alreadyMarked) - { - BatchGenerationEnvironment.isDhWorldGenThreadRef.set(true); - } - - try - { - runnable.run(); - } - catch (Throwable throwable) - { - handleWorldGenThrowable(generationEvent, throwable); - } - finally + worldGeneratorThreadPool.execute(() -> { + // TODO why not just always set this each time? + boolean alreadyMarked = BatchGenerationEnvironment.isThisDhWorldGenThread(); if (!alreadyMarked) { - BatchGenerationEnvironment.isDhWorldGenThreadRef.set(false); + BatchGenerationEnvironment.isDhWorldGenThreadRef.set(true); } - } + + try + { + runnable.run(); + } + catch (Throwable throwable) + { + handleWorldGenThrowable(genEvent, throwable); + } + finally + { + if (!alreadyMarked) + { + BatchGenerationEnvironment.isDhWorldGenThreadRef.set(false); + } + } + }); }); - }); - - generationEvent.future.complete(null); + + genEvent.future.complete(null); + } } catch (Throwable initialThrowable) { - handleWorldGenThrowable(generationEvent, initialThrowable); + handleWorldGenThrowable(genEvent, initialThrowable); } finally { @@ -132,10 +141,10 @@ public final class GenerationEvent } catch (RejectedExecutionException e) { - generationEvent.future.completeExceptionally(e); + genEvent.future.completeExceptionally(e); } - return generationEvent; + return genEvent; } /** There's probably a better way to handle this, but it'll work for now */ private static void handleWorldGenThrowable(GenerationEvent generationEvent, Throwable initialThrowable) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java new file mode 100644 index 000000000..3c0f88947 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java @@ -0,0 +1,262 @@ +package com.seibel.distanthorizons.common.wrappers.worldGeneration.internalServer; + +import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.ChunkPosGenStream; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.GenerationEvent; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.GlobalWorldGenParams; +import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.generation.DhLightingEngine; +import com.seibel.distanthorizons.core.level.IDhServerLevel; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkLevel; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.TicketType; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.status.ChunkStatus; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +public class InternalServerGenerator +{ + public static final DhLogger LOGGER = new DhLoggerBuilder() + .name("LOD World Gen - Internal Server") + .fileLevelConfig(Config.Common.Logging.logWorldGenEventToFile) + .build(); + + public static final DhLogger CHUNK_LOAD_LOGGER = new DhLoggerBuilder() + .name("LOD Chunk Loading") + .fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile) + .build(); + + #if MC_VER < MC_1_21_5 + private static final TicketType DH_SERVER_GEN_TICKET = TicketType.create("dh_server_gen_ticket", Comparator.comparingLong(ChunkPos::toLong)); + #elif MC_VER < MC_1_21_9 + private static final TicketType DH_SERVER_GEN_TICKET = new TicketType(/* timeout, 0 = disabled*/0L, /* persist */ false, TicketType.TicketUse.LOADING); + #else + private static final TicketType DH_SERVER_GEN_TICKET = new TicketType(/* timeout, 0 = disabled*/0L, /* flags */TicketType.FLAG_LOADING); + #endif + + + private final GlobalWorldGenParams params; + private final IDhServerLevel dhServerLevel; + + + + //=============// + // constructor // + //=============// + + public InternalServerGenerator(GlobalWorldGenParams params, IDhServerLevel dhServerLevel) + { + this.params = params; + this.dhServerLevel = dhServerLevel; + } + + + + //============// + // generation // + //============// + + public void generateChunksViaInternalServer(GenerationEvent genEvent) throws InterruptedException + { + LinkedBlockingQueue runnableQueue = new LinkedBlockingQueue<>(); + + Map chunkWrappersByDhPos = Collections.synchronizedMap(new HashMap<>()); + + + + //===================================// + // create generation queue runnables // + //===================================// + + // request each chunk pos from the server + CompletableFuture[] requestFutures = + ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0) + .map(chunkPos -> + { + return requestChunkFromServerAsync(this.params.level, chunkPos, true) + .whenCompleteAsync((chunk, throwable) -> + { + // unwrap the CompletionException if necessary + Throwable actualThrowable = throwable; + while (actualThrowable instanceof CompletionException) + { + actualThrowable = actualThrowable.getCause(); + } + + if (throwable != null) + { + CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load chunk [" + chunkPos + "] from server, error: [" + actualThrowable.getMessage() + "].", actualThrowable); + } + + if (chunk != null) + { + ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper()); + chunkWrappersByDhPos.put(new DhChunkPos(chunkPos.x, chunkPos.z), chunkWrapper); + } + }, runnableQueue::add); + }) + .toArray(CompletableFuture[]::new); + + // handle each generated chunk + CompletableFuture processGeneratedChunksFuture = + CompletableFuture.allOf(requestFutures) + .whenCompleteAsync((voidObj, throwable) -> + { + // generate chunk lighting using DH's lighting engine + int maxSkyLight = this.dhServerLevel.getServerLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT; + + ArrayList generatedChunks = new ArrayList<>(chunkWrappersByDhPos.values()); + for (IChunkWrapper iChunkWrapper : generatedChunks) + { + ((ChunkWrapper) iChunkWrapper).recalculateDhHeightMapsIfNeeded(); + + // pre-generated chunks should have lighting but new ones won't + if (!iChunkWrapper.isDhBlockLightingCorrect()) + { + DhLightingEngine.INSTANCE.bakeChunkBlockLighting(iChunkWrapper, generatedChunks, maxSkyLight); + } + + this.dhServerLevel.updateBeaconBeamsForChunk(iChunkWrapper, generatedChunks); + } + + for (IChunkWrapper iChunkWrapper : generatedChunks) + { + genEvent.resultConsumer.accept(iChunkWrapper); + } + }, runnableQueue::add) + .whenCompleteAsync((unused, throwable) -> + { + // cleanup + // release the generated chunks + + Iterator iterator = ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); + while (iterator.hasNext()) + { + ChunkPos chunkPos = iterator.next(); + releaseChunkFromServer(this.params.level, chunkPos, true); + } + }); + + processGeneratedChunksFuture.whenCompleteAsync((unused, throwable) -> { }, runnableQueue::add); // trigger wakeup + + + + //===============// + // run each step // + //===============// + + while (!processGeneratedChunksFuture.isDone()) + { + try + { + Runnable command = runnableQueue.poll(1, TimeUnit.SECONDS); + if (command != null) + { + command.run(); + } + } + catch (InterruptedException e) + { + // interrupted, release chunk to server + Iterator iterator = ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); + while (iterator.hasNext()) + { + ChunkPos chunkPos = iterator.next(); + releaseChunkFromServer(this.params.level, chunkPos, true); + } + + throw e; + } + } + } + /** @param generateUpToFeatures if false this generate the chunk up to "FULL" status */ + private static CompletableFuture requestChunkFromServerAsync(ServerLevel level, ChunkPos pos, boolean generateUpToFeatures) + { + return CompletableFuture.supplyAsync(() -> + { + int chunkLevel; + #if MC_VER <= MC_1_19_4 + // 33 is equivalent to FULL Chunk + chunkLevel = generateUpToFeatures ? 33 + ChunkStatus.getDistance(ChunkStatus.FEATURES) : 33; + #else + // 33 is equivalent to FULL Chunk + chunkLevel = generateUpToFeatures ? ChunkLevel.byStatus(ChunkStatus.FEATURES) : 33; + #endif + + #if MC_VER < MC_1_21_5 + level.getChunkSource().distanceManager.addTicket(DH_SERVER_GEN_TICKET, pos, chunkLevel, pos); + #else + level.getChunkSource().addTicketWithRadius(DH_SERVER_GEN_TICKET, pos, 0); + #endif + level.getChunkSource().distanceManager.runAllUpdates(level.getChunkSource().chunkMap); // probably not the most optimal to run updates here, but fast enough + ChunkHolder holder = level.getChunkSource().chunkMap.getUpdatingChunkIfPresent(pos.toLong()); + if (holder == null) + { + throw new IllegalStateException("No chunk holder after ticket has been added"); + } + + #if MC_VER <= MC_1_20_4 + return holder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) + .thenApply(result -> result.left().orElseThrow(() -> new RuntimeException(result.right().get().toString()))); // can throw if the server is shutting down + #elif MC_VER <= MC_1_20_6 + return holder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) + .thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.toString()))); // can throw if the server is shutting down + #else + return holder.scheduleChunkGenerationTask(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) + .thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.getError()))); // can throw if the server is shutting down + #endif + + }, level.getChunkSource().chunkMap.mainThreadExecutor) + .thenCompose(Function.identity()); + } + /** @param chunkWasGeneratedUpToFeatures if false this assumes the chunk was generated to "FULL" status */ + private static void releaseChunkFromServer(ServerLevel level, ChunkPos pos, boolean chunkWasGeneratedUpToFeatures) + { + level.getChunkSource().chunkMap.mainThreadExecutor.execute(() -> + { + try + { + int chunkLevel; + #if MC_VER <= MC_1_19_4 + // 33 is equivalent to FULL Chunk + chunkLevel = chunkWasGeneratedUpToFeatures ? 33 + ChunkStatus.getDistance(ChunkStatus.FEATURES) : 33; + #else + // 33 is equivalent to FULL Chunk + chunkLevel = chunkWasGeneratedUpToFeatures ? ChunkLevel.byStatus(ChunkStatus.FEATURES) : 33; + #endif + + #if MC_VER < MC_1_21_5 + level.getChunkSource().distanceManager.removeTicket(DH_SERVER_GEN_TICKET, pos, chunkLevel, pos); + #else + level.getChunkSource().removeTicketWithRadius(DH_SERVER_GEN_TICKET, pos, 0); + #endif + + // mitigate OOM issues in vanilla chunk system: see https://github.com/pop4959/Chunky/pull/383 + level.getChunkSource().chunkMap.tick(() -> false); + #if MC_VER > MC_1_16_5 + level.entityManager.tick(); + #endif + } + catch (Exception e) + { + LOGGER.warn("Failed to release chunk back to internal server. Error: ["+e.getMessage()+"]", e); + } + }); + } + + + +} diff --git a/coreSubProjects b/coreSubProjects index 33a55dc7c..47a4d1535 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 33a55dc7cdae68979d304b335eef103e0bc4a65f +Subproject commit 47a4d1535f1ad38850bf8db1230184c5e5314bcd From ab4a9cbb55af7dac72d6ffb0156e370606e26f7e Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Nov 2025 11:27:01 -0600 Subject: [PATCH 07/33] Remove world gen step duplicate code --- .../step/AbstractWorldGenStep.java | 10 +- .../worldGeneration/step/StepBiomes.java | 7 +- .../worldGeneration/step/StepFeatures.java | 13 +-- .../worldGeneration/step/StepNoise.java | 17 +-- .../step/StepStructureReference.java | 20 +--- .../step/StepStructureStart.java | 104 +++++++++--------- .../worldGeneration/step/StepSurface.java | 29 ++--- 7 files changed, 80 insertions(+), 120 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/AbstractWorldGenStep.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/AbstractWorldGenStep.java index 7915596ed..dad094c37 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/AbstractWorldGenStep.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/AbstractWorldGenStep.java @@ -27,26 +27,26 @@ public abstract class AbstractWorldGenStep /** @return the list of chunks that have an earlier status and can be generated */ - protected ArrayList getChunksToGenerate(List chunkWrappers) + protected ArrayList getChunkWrappersToGenerate(List chunkWrappers) { - ArrayList chunksToGenerate = new ArrayList<>(); + ArrayList chunkWrappersToGenerate = new ArrayList<>(chunkWrappers.size()); for (ChunkWrapper chunkWrapper : chunkWrappers) { ChunkAccess chunk = chunkWrapper.getChunk(); if (chunkWrapper.getStatus().isOrAfter(this.getChunkStatus())) { - // this chunk has already generated this step + // this chunk has already been generated up to this step continue; } else if (chunk instanceof ProtoChunk) { chunkWrapper.trySetStatus(this.getChunkStatus()); - chunksToGenerate.add(chunk); + chunkWrappersToGenerate.add(chunkWrapper); } } - return chunksToGenerate; + return chunkWrappersToGenerate; } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java index ed185b4a8..17d05ad84 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java @@ -67,9 +67,12 @@ public final class StepBiomes extends AbstractWorldGenStep ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers) { - ArrayList chunksToDo = this.getChunksToGenerate(chunkWrappers); - for (ChunkAccess chunk : chunksToDo) + ArrayList chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers); + for (ChunkWrapper chunkWrapper : chunksToDo) { + ChunkAccess chunk = chunkWrapper.getChunk(); + + #if MC_VER < MC_1_18_2 this.environment.params.generator.createBiomes(this.environment.params.biomes, chunk); #elif MC_VER < MC_1_19_2 diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java index b9920546d..fecc60e9e 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java @@ -37,6 +37,7 @@ import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStatus; #endif +import java.util.ArrayList; import java.util.ConcurrentModificationException; @@ -70,18 +71,10 @@ public final class StepFeatures extends AbstractWorldGenStep ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers) { - for (ChunkWrapper chunkWrapper : chunkWrappers) + ArrayList chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers); + for (ChunkWrapper chunkWrapper : chunksToDo) { ChunkAccess chunk = chunkWrapper.getChunk(); - if (chunkWrapper.getStatus().isOrAfter(STATUS)) - { - // this chunk has already generated this step - continue; - } - else if (chunk instanceof ProtoChunk) - { - chunkWrapper.trySetStatus(STATUS); - } try diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java index 4994ea365..d421543a2 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java @@ -68,21 +68,11 @@ public final class StepNoise extends AbstractWorldGenStep ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers) { - ArrayList chunksToDo = new ArrayList<>(); - - for (ChunkWrapper chunkWrapper : chunkWrappers) + ArrayList chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers); + for (ChunkWrapper chunkWrapper : chunksToDo) { ChunkAccess chunk = chunkWrapper.getChunk(); - if (chunkWrapper.getStatus().isOrAfter(STATUS)) - { - continue; - } - chunkWrapper.trySetStatus(STATUS); - chunksToDo.add(chunk); - } - - for (ChunkAccess chunk : chunksToDo) - { + #if MC_VER < MC_1_17_1 this.environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk); #elif MC_VER < MC_1_18_2 @@ -114,7 +104,6 @@ public final class StepNoise extends AbstractWorldGenStep tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk)); #endif - UncheckedInterruptedException.throwIfInterrupted(); } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java index e743027ac..a96965c48 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java @@ -65,26 +65,10 @@ public final class StepStructureReference extends AbstractWorldGenStep ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers) { - ArrayList chunksToDo = new ArrayList(); - - for (ChunkWrapper chunkWrapper : chunkWrappers) + ArrayList chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers); + for (ChunkWrapper chunkWrapper : chunksToDo) { ChunkAccess chunk = chunkWrapper.getChunk(); - if (chunkWrapper.getStatus().isOrAfter(STATUS)) - { - // this chunk has already generated this step - continue; - } - else if (chunk instanceof ProtoChunk) - { - chunkWrapper.trySetStatus(STATUS); - chunksToDo.add(chunk); - } - } - - for (ChunkAccess chunk : chunksToDo) - { - // System.out.println("StepStructureReference: "+chunk.getPos()); this.environment.params.generator.createReferences(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk); } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java index c9df513ad..d94318267 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java @@ -69,71 +69,75 @@ public final class StepStructureStart extends AbstractWorldGenStep ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers) { - ArrayList chunksToDo = this.getChunksToGenerate(chunkWrappers); + ArrayList chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers); #if MC_VER < MC_1_19_2 - if (this.environment.params.worldGenSettings.generateFeatures()) - { + if (!this.environment.params.worldGenSettings.generateFeatures()) #elif MC_VER < MC_1_19_4 - if (this.environment.params.worldGenSettings.generateStructures()) - { + if (!this.environment.params.worldGenSettings.generateStructures()) #else - if (this.environment.params.worldOptions.generateStructures()) - { + if (!this.environment.params.worldOptions.generateStructures()) #endif - for (ChunkAccess chunk : chunksToDo) + { + return; + } + + + + for (ChunkWrapper chunkWrapper : chunksToDo) + { + ChunkAccess chunk = chunkWrapper.getChunk(); + + // hopefully this shouldn't cause any performance issues (this step is generally quite quick so hopefully it should be fine) + // and should prevent some concurrency issues + STRUCTURE_PLACEMENT_LOCK.lock(); + + #if MC_VER < MC_1_19_2 + this.environment.params.generator.createStructures(this.environment.params.registry, tParams.structFeat, chunk, this.environment.params.structures, + this.environment.params.worldSeed); + #elif MC_VER < MC_1_19_4 + this.environment.params.generator.createStructures(this.environment.params.registry, this.environment.params.randomState, tParams.structFeat, chunk, this.environment.params.structures, + this.environment.params.worldSeed); + #elif MC_VER <= MC_1_21_3 + this.environment.params.generator.createStructures(this.environment.params.registry, + this.environment.params.level.getChunkSource().getGeneratorState(), + tParams.structFeat, chunk, this.environment.params.structures); + #else + this.environment.params.generator.createStructures(this.environment.params.registry, + this.environment.params.level.getChunkSource().getGeneratorState(), + tParams.structFeat, chunk, this.environment.params.structures, + this.environment.params.level.dimension()); + #endif + + #if MC_VER >= MC_1_18_2 + try { - // hopefully this shouldn't cause any performance issues (this step is generally quite quick so hopefully it should be fine) - // and should prevent some concurrency issues - STRUCTURE_PLACEMENT_LOCK.lock(); + tParams.structCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts()); + } + catch (ArrayIndexOutOfBoundsException firstEx) + { + // 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 - OLD - #if MC_VER < MC_1_19_2 - this.environment.params.generator.createStructures(this.environment.params.registry, tParams.structFeat, chunk, this.environment.params.structures, - this.environment.params.worldSeed); - #elif MC_VER < MC_1_19_4 - this.environment.params.generator.createStructures(this.environment.params.registry, this.environment.params.randomState, tParams.structFeat, chunk, this.environment.params.structures, - this.environment.params.worldSeed); - #elif MC_VER <= MC_1_21_3 - this.environment.params.generator.createStructures(this.environment.params.registry, - this.environment.params.level.getChunkSource().getGeneratorState(), - tParams.structFeat, chunk, this.environment.params.structures); - #else - this.environment.params.generator.createStructures(this.environment.params.registry, - this.environment.params.level.getChunkSource().getGeneratorState(), - tParams.structFeat, chunk, this.environment.params.structures, - this.environment.params.level.dimension()); - #endif + // reset the structureStart + tParams.recreateStructureCheck(); - #if MC_VER >= MC_1_18_2 try { + // try running the structure logic again tParams.structCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts()); } - catch (ArrayIndexOutOfBoundsException firstEx) + catch (ArrayIndexOutOfBoundsException secondEx) { - // 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 - OLD - - // reset the structureStart - tParams.recreateStructureCheck(); - - try - { - // try running the structure logic again - tParams.structCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts()); - } - catch (ArrayIndexOutOfBoundsException secondEx) - { - // the structure logic failed again, log it and move on - LOGGER.error("Unable to create structure starts for " + chunk.getPos() + ". This is an error with MC's world generation. Ignoring and continuing generation. Error: " + secondEx.getMessage()); // don't log the full stack trace since it is long and will generally end up in MC's code - } + // the structure logic failed again, log it and move on + LOGGER.error("Unable to create structure starts for " + chunk.getPos() + ". This is an error with MC's world generation. Ignoring and continuing generation. Error: " + secondEx.getMessage()); // don't log the full stack trace since it is long and will generally end up in MC's code } - - #endif - - STRUCTURE_PLACEMENT_LOCK.unlock(); } + + #endif + + STRUCTURE_PLACEMENT_LOCK.unlock(); } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java index 8a2c0ab4e..f56521085 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java @@ -65,34 +65,21 @@ public final class StepSurface extends AbstractWorldGenStep ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion, ArrayGridList chunkWrappers) { - ArrayList chunksToDo = new ArrayList<>(); - - for (ChunkWrapper chunkWrapper : chunkWrappers) + ArrayList chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers); + for (ChunkWrapper chunkWrapper : chunksToDo) { ChunkAccess chunk = chunkWrapper.getChunk(); - if (chunkWrapper.getStatus().isOrAfter(STATUS)) - { - // this chunk has already generated this step - continue; - } - else if (chunk instanceof ProtoChunk) - { - chunkWrapper.trySetStatus(STATUS); - chunksToDo.add(chunk); - } - } - - for (ChunkAccess chunk : chunksToDo) - { - // System.out.println("StepSurface: "+chunk.getPos()); + #if MC_VER < MC_1_18_2 - environment.params.generator.buildSurfaceAndBedrock(worldGenRegion, chunk); + this.environment.params.generator.buildSurfaceAndBedrock(worldGenRegion, chunk); #elif MC_VER < MC_1_19_2 - environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk); + this.environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk); #else - environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), environment.params.randomState, chunk); + this.environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), this.environment.params.randomState, chunk); #endif } } + + } \ No newline at end of file From e026cf104cbafa075409801f254c81fed734d0e0 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Nov 2025 11:59:49 -0600 Subject: [PATCH 08/33] remove unneeded lambda --- .../BatchGenerationEnvironment.java | 249 +++++++++--------- .../worldGeneration/GenerationEvent.java | 55 ++-- 2 files changed, 142 insertions(+), 162 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index f7ad847f5..79bdb7d26 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -319,10 +319,8 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // world generation // //==================// - // TODO this is already being run on a generator thread, - // why are we passing in an executor? /** @throws RejectedExecutionException if the given {@link Executor} is cancelled. */ - public CompletableFuture generateLodFromListAsync(GenerationEvent genEvent, Executor executor) throws RejectedExecutionException, InterruptedException + public void generateEvent(GenerationEvent genEvent) throws RejectedExecutionException { // Minecraft's generation events expect odd chunk width areas (3x3, 7x7, or 11x11), // but DH submits square generation events (4x4). @@ -361,148 +359,145 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // also allows file IO to run in parallel so no one thread is waiting on disk IO (this is only an issue when C2ME is present) CompletableFuture.allOf(readFutures).join(); - // future chain for generation - return CompletableFuture.runAsync(() -> + + try { - try + // offset 1 chunk in both X and Z direction so we can generate an even number of chunks wide + // while still submitting an odd number width to MC's internal generators + for (int xOffset = 0; xOffset < 2; xOffset++) { - // offset 1 chunk in both X and Z direction so we can generate an even number of chunks wide - // while still submitting an odd number width to MC's internal generators - for (int xOffset = 0; xOffset < 2; xOffset++) + // final is so the offset can be used in lambdas + final int xOffsetFinal = xOffset; + for (int zOffset = 0; zOffset < 2; zOffset++) { - // final is so the offset can be used in lambdas - final int xOffsetFinal = xOffset; - for (int zOffset = 0; zOffset < 2; zOffset++) + final int zOffsetFinal = zOffset; + + + + //================// + // variable setup // + //================// + + int radius = refSize / 2; + int centerX = refPosX + radius + xOffset; + int centerZ = refPosZ + radius + zOffset; + + // get/create the list of chunks we're going to generate + IEmptyChunkRetrievalFunc fallbackFunc = + (chunkPosX, chunkPosZ) -> Objects.requireNonNull( + generatedChunkByDhPos.get(new DhChunkPos(chunkPosX, chunkPosZ)), + () -> String.format("Requested chunk [%d, %d] unavailable during world generation", chunkPosX, chunkPosZ)); + + ArrayGridList regionChunks = new ArrayGridList<>( + refSize, + (relX, relZ) -> fallbackFunc.getChunk( + relX + refPosX + xOffsetFinal, + relZ + refPosZ + zOffsetFinal)); + + ChunkAccess centerChunk = regionChunks.stream() + .filter((chunk) -> chunk.getPos().x == centerX && chunk.getPos().z == centerZ) + .findFirst() + .orElseGet(() -> regionChunks.getFirst()); + + DhLitWorldGenRegion region = new DhLitWorldGenRegion( + centerX, centerZ, + centerChunk, + this.params.level, dummyLightEngine, regionChunks, + ChunkStatus.STRUCTURE_STARTS, radius, + // this method shouldn't be necessary since we're passing in a pre-populated + // list of chunks, but just in case + fallbackFunc + ); + lightGetterAdaptor.setRegion(region); + genEvent.threadedParam.makeStructFeat(region, this.params); + + + + //=============================// + // create chunk wrappers // + // and process existing chunks // + //=============================// + + ArrayGridList chunkWrapperList = new ArrayGridList<>(regionChunks.gridSize); + regionChunks.forEachPos((relX, relZ) -> { - final int zOffsetFinal = zOffset; + // ArrayGridList's use relative positions and don't have a center position + // so we need to use the offsetFinal to select the correct position + DhChunkPos chunkPos = new DhChunkPos(relX + refPosX + xOffsetFinal, relZ + refPosZ + zOffsetFinal); + ChunkAccess chunk = regionChunks.get(relX, relZ); - - - //================// - // variable setup // - //================// - - int radius = refSize / 2; - int centerX = refPosX + radius + xOffset; - int centerZ = refPosZ + radius + zOffset; - - // get/create the list of chunks we're going to generate - IEmptyChunkRetrievalFunc fallbackFunc = - (chunkPosX, chunkPosZ) -> Objects.requireNonNull( - generatedChunkByDhPos.get(new DhChunkPos(chunkPosX, chunkPosZ)), - () -> String.format("Requested chunk [%d, %d] unavailable during world generation", chunkPosX, chunkPosZ)); - - ArrayGridList regionChunks = new ArrayGridList<>( - refSize, - (relX, relZ) -> fallbackFunc.getChunk( - relX + refPosX + xOffsetFinal, - relZ + refPosZ + zOffsetFinal)); - - ChunkAccess centerChunk = regionChunks.stream() - .filter((chunk) -> chunk.getPos().x == centerX && chunk.getPos().z == centerZ) - .findFirst() - .orElseGet(() -> regionChunks.getFirst()); - - DhLitWorldGenRegion region = new DhLitWorldGenRegion( - centerX, centerZ, - centerChunk, - this.params.level, dummyLightEngine, regionChunks, - ChunkStatus.STRUCTURE_STARTS, radius, - // this method shouldn't be necessary since we're passing in a pre-populated - // list of chunks, but just in case - fallbackFunc - ); - lightGetterAdaptor.setRegion(region); - genEvent.threadedParam.makeStructFeat(region, this.params); - - - - //=============================// - // create chunk wrappers // - // and process existing chunks // - //=============================// - - ArrayGridList chunkWrapperList = new ArrayGridList<>(regionChunks.gridSize); - regionChunks.forEachPos((relX, relZ) -> + if (chunkWrappersByDhPos.containsKey(chunkPos)) { - // ArrayGridList's use relative positions and don't have a center position - // so we need to use the offsetFinal to select the correct position - DhChunkPos chunkPos = new DhChunkPos(relX + refPosX + xOffsetFinal, relZ + refPosZ + zOffsetFinal); - ChunkAccess chunk = regionChunks.get(relX, relZ); + chunkWrapperList.set(relX, relZ, chunkWrappersByDhPos.get(chunkPos)); + } + else if (chunk != null) + { + // wrap the chunk + ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper()); + chunkWrapperList.set(relX, relZ, chunkWrapper); - if (chunkWrappersByDhPos.containsKey(chunkPos)) + // try setting the wrapper's lighting + if (chunkBlockLightingByDhPos.containsKey(chunkWrapper.getChunkPos())) { - chunkWrapperList.set(relX, relZ, chunkWrappersByDhPos.get(chunkPos)); + chunkWrapper.setBlockLightStorage(chunkBlockLightingByDhPos.get(chunkWrapper.getChunkPos())); + chunkWrapper.setSkyLightStorage(chunkSkyLightingByDhPos.get(chunkWrapper.getChunkPos())); + chunkWrapper.setIsDhBlockLightCorrect(true); + chunkWrapper.setIsDhSkyLightCorrect(true); } - else if (chunk != null) - { - // wrap the chunk - ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper()); - chunkWrapperList.set(relX, relZ, chunkWrapper); - - // try setting the wrapper's lighting - if (chunkBlockLightingByDhPos.containsKey(chunkWrapper.getChunkPos())) - { - chunkWrapper.setBlockLightStorage(chunkBlockLightingByDhPos.get(chunkWrapper.getChunkPos())); - chunkWrapper.setSkyLightStorage(chunkSkyLightingByDhPos.get(chunkWrapper.getChunkPos())); - chunkWrapper.setIsDhBlockLightCorrect(true); - chunkWrapper.setIsDhSkyLightCorrect(true); - } - - chunkWrappersByDhPos.put(chunkPos, chunkWrapper); - } - else //if (chunk == null) - { - LodUtil.assertNotReach("Programmer Error: No chunk found in grid list, position offset is likely wrong."); - } - }); - - - - //=================// - // generate chunks // - //=================// - - try - { - this.generateDirect(genEvent, chunkWrapperList, region); + + chunkWrappersByDhPos.put(chunkPos, chunkWrapper); } - catch (InterruptedException e) + else //if (chunk == null) { - throw new CompletionException(e); + LodUtil.assertNotReach("Programmer Error: No chunk found in grid list, position offset is likely wrong."); } + }); + + + + //=================// + // generate chunks // + //=================// + + try + { + this.generateDirect(genEvent, chunkWrapperList, region); + } + catch (InterruptedException e) + { + throw new CompletionException(e); } } - - - - //=========================// - // submit generated chunks // - //=========================// - - Iterator iterator = ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); - while (iterator.hasNext()) - { - ChunkPos pos = iterator.next(); - DhChunkPos dhPos = new DhChunkPos(pos.x, pos.z); - ChunkWrapper wrappedChunk = chunkWrappersByDhPos.get(dhPos); - genEvent.resultConsumer.accept(wrappedChunk); - } } - catch (CompletionException | UncheckedInterruptedException e) + + + + //=========================// + // submit generated chunks // + //=========================// + + Iterator iterator = ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); + while (iterator.hasNext()) { - // interrupts mean the world generator is being shut down, no need to log that - boolean isShutdownException = ExceptionUtil.isShutdownException(e); - if (!isShutdownException) - { - LOGGER.error("Completion error during world gen for min chunk pos ["+genEvent.minPos+"], error: ["+e.getMessage()+"].", e); - } + ChunkPos pos = iterator.next(); + DhChunkPos dhPos = new DhChunkPos(pos.x, pos.z); + ChunkWrapper wrappedChunk = chunkWrappersByDhPos.get(dhPos); + genEvent.resultConsumer.accept(wrappedChunk); } - catch (Exception e) + } + catch (CompletionException | UncheckedInterruptedException e) + { + // interrupts mean the world generator is being shut down, no need to log that + boolean isShutdownException = ExceptionUtil.isShutdownException(e); + if (!isShutdownException) { - LOGGER.error("Unexpected error during world gen for min chunk pos ["+genEvent.minPos+"], error: ["+e.getMessage()+"].", e); + LOGGER.error("Completion error during world gen for min chunk pos ["+genEvent.minPos+"], error: ["+e.getMessage()+"].", e); } - }, executor); + } + catch (Exception e) + { + LOGGER.error("Unexpected error during world gen for min chunk pos ["+genEvent.minPos+"], error: ["+e.getMessage()+"].", e); + } } @@ -859,7 +854,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetStep, ExecutorService worldGeneratorThreadPool, Consumer resultConsumer) { - GenerationEvent genEvent = GenerationEvent.startEvent( + GenerationEvent genEvent = GenerationEvent.start( new DhChunkPos(minX, minZ), chunkWidthCount, this, generatorMode, targetStep, resultConsumer, worldGeneratorThreadPool); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java index f898655c0..7158abac2 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java @@ -20,6 +20,7 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode; @@ -35,17 +36,18 @@ public final class GenerationEvent { private static final DhLogger LOGGER = new DhLoggerBuilder().build();; - private static int generationFutureDebugIDs = 0; // TODO make atomic int? + private static final AtomicInteger DEBUG_ID_REF = new AtomicInteger(0); + /** can be used for troubleshooting */ public final int id; + public final ThreadWorldGenParams threadedParam; public final DhChunkPos minPos; - /** the number of chunks wide this event is */ public final int widthInChunks; public final EDhApiWorldGenerationStep targetGenerationStep; public final EDhApiDistantGeneratorMode generatorMode; - public final CompletableFuture future = new CompletableFuture<>(); + public final CompletableFuture future; public final Consumer resultConsumer; @@ -58,13 +60,14 @@ public final class GenerationEvent DhChunkPos minPos, int widthInChunks, BatchGenerationEnvironment generationGroup, EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetGenerationStep, Consumer resultConsumer) { - this.id = generationFutureDebugIDs++; + this.id = DEBUG_ID_REF.getAndIncrement(); this.minPos = minPos; this.widthInChunks = widthInChunks; - this.generatorMode = generatorMode; this.targetGenerationStep = targetGenerationStep; + this.generatorMode = generatorMode; this.threadedParam = ThreadWorldGenParams.getOrMake(generationGroup.params); + this.future = new CompletableFuture<>(); this.resultConsumer = resultConsumer; } @@ -74,7 +77,7 @@ public final class GenerationEvent // start // //=======// - public static GenerationEvent startEvent( + public static GenerationEvent start( DhChunkPos minPos, int widthInChunks, BatchGenerationEnvironment genEnvironment, EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep target, Consumer resultConsumer, ExecutorService worldGeneratorThreadPool) @@ -97,36 +100,18 @@ public final class GenerationEvent } else { - genEnvironment.generateLodFromListAsync(genEvent, (runnable) -> + try { - worldGeneratorThreadPool.execute(() -> - { - // TODO why not just always set this each time? - boolean alreadyMarked = BatchGenerationEnvironment.isThisDhWorldGenThread(); - if (!alreadyMarked) - { - BatchGenerationEnvironment.isDhWorldGenThreadRef.set(true); - } - - try - { - runnable.run(); - } - catch (Throwable throwable) - { - handleWorldGenThrowable(genEvent, throwable); - } - finally - { - if (!alreadyMarked) - { - BatchGenerationEnvironment.isDhWorldGenThreadRef.set(false); - } - } - }); - }); - - genEvent.future.complete(null); + genEnvironment.generateEvent(genEvent); + } + catch (Throwable throwable) + { + handleWorldGenThrowable(genEvent, throwable); + } + finally + { + genEvent.future.complete(null); + } } } catch (Throwable initialThrowable) From b7253b654915deebad0dac40f55b3a0ad0362bb7 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 22 Nov 2025 12:23:54 -0600 Subject: [PATCH 09/33] refactor chunk file handling --- .../BatchGenerationEnvironment.java | 286 +-------------- .../ChunkCompoundTagParser.java} | 212 +++-------- .../chunkFileHandling/ChunkFileReader.java | 339 ++++++++++++++++++ .../chunkFileHandling/CompoundTagUtil.java | 137 +++++++ .../RegionFileStorageExternalCache.java | 32 +- .../step/StepStructureStart.java | 2 + 6 files changed, 543 insertions(+), 465 deletions(-) rename common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/{mimicObject/ChunkFileReader.java => chunkFileHandling/ChunkCompoundTagParser.java} (83%) create mode 100644 common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java create mode 100644 common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/CompoundTagUtil.java diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 79bdb7d26..5583cc481 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -24,9 +24,9 @@ import com.google.common.collect.ImmutableMap; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling.ChunkFileReader; import com.seibel.distanthorizons.common.wrappers.worldGeneration.internalServer.InternalServerGenerator; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.*; -import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.generation.DhLightingEngine; import com.seibel.distanthorizons.core.level.IDhServerLevel; import com.seibel.distanthorizons.core.config.Config; @@ -39,20 +39,14 @@ import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; -import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; -import java.io.IOException; -import java.nio.channels.ClosedByInterruptException; -import java.nio.channels.ClosedChannelException; import java.util.*; import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepBiomes; import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepFeatures; @@ -61,16 +55,12 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepStruc import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepStructureStart; import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepSurface; -import net.minecraft.server.level.*; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.*; -import net.minecraft.world.level.chunk.storage.IOWorker; -import net.minecraft.world.level.chunk.storage.RegionFileStorage; import net.minecraft.world.level.levelgen.DebugLevelSource; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; -import net.minecraft.nbt.CompoundTag; #if MC_VER <= MC_1_17_1 #elif MC_VER <= MC_1_19_2 @@ -96,13 +86,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm .fileLevelConfig(Config.Common.Logging.logWorldGenEventToFile) .build(); - public static final DhLogger CHUNK_LOAD_LOGGER = new DhLoggerBuilder() - .name("LOD Chunk Loading") - .fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile) - .build(); - - private static final IModChecker MOD_CHECKER = SingletonInjector.INSTANCE.get(IModChecker.class); - @NotNull public static final ImmutableMap WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP; public static final int MAX_WORLD_GEN_CHUNK_BORDER_NEEDED; @@ -114,14 +97,8 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm private final IDhServerLevel dhServerLevel; - /** - * will be true if C2ME is installed (since they require us to - * pull chunks using their async method), or if there - * was an issue with the sync pulling method. - */ - private boolean pullExistingChunkUsingMcAsyncMethod = false; - public final InternalServerGenerator internalServerGenerator; + public final ChunkFileReader chunkFileReader; @@ -139,21 +116,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm public int unknownExceptionCount = 0; public long lastExceptionTriggerTime = 0; - private final AtomicReference regionFileStorageCacheRef = new AtomicReference<>(); - public RegionFileStorageExternalCache getOrCreateRegionFileCache(RegionFileStorage storage) - { - RegionFileStorageExternalCache cache = this.regionFileStorageCacheRef.get(); - if (cache == null) - { - cache = new RegionFileStorageExternalCache(storage); - if (!this.regionFileStorageCacheRef.compareAndSet(null, cache)) - { - cache = this.regionFileStorageCacheRef.get(); - } - } - return cache; - } - public static ThreadLocal isDhWorldGenThreadRef = new ThreadLocal<>(); public static boolean isThisDhWorldGenThread() { return (isDhWorldGenThreadRef.get() != null); } @@ -201,6 +163,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm this.dhServerLevel = dhServerLevel; this.params = new GlobalWorldGenParams(dhServerLevel); this.internalServerGenerator = new InternalServerGenerator(this.params, this.dhServerLevel); + this.chunkFileReader = new ChunkFileReader(this.params); ChunkGenerator generator = ((ServerLevelWrapper) (dhServerLevel.getServerLevelWrapper())).getLevel().getChunkSource().getGenerator(); boolean isMcGenerator = @@ -226,12 +189,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm } } - if (MOD_CHECKER.isModLoaded("c2me")) - { - LOGGER.info("C2ME detected: DH's pre-existing chunk accessing will use methods handled by C2ME."); - this.pullExistingChunkUsingMcAsyncMethod = true; - } - } @@ -352,7 +309,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm CompletableFuture[] readFutures = // the extra radius of 8 is to account for structure references which need a chunk radius of 8 ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 8) - .map((chunkPos) -> this.createEmptyOrPreExistingChunkAsync(chunkPos.x, chunkPos.z, chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, generatedChunkByDhPos)) + .map((chunkPos) -> this.chunkFileReader.createEmptyOrPreExistingChunkAsync(chunkPos.x, chunkPos.z, chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, generatedChunkByDhPos)) .toArray(CompletableFuture[]::new); // join to prevent an issue where DH queues too many tasks or something(?) @@ -502,225 +459,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm - // get existing chunk // - - /** - * If the given chunk pos already exists in the world, that chunk will be returned, - * otherwise this will return an empty chunk. - */ - private CompletableFuture createEmptyOrPreExistingChunkAsync( - int chunkX, int chunkZ, - Map chunkSkyLightingByDhPos, - Map chunkBlockLightingByDhPos, - Map generatedChunkByDhPos) - { - ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - DhChunkPos dhChunkPos = new DhChunkPos(chunkX, chunkZ); - - if (generatedChunkByDhPos.containsKey(dhChunkPos)) - { - return CompletableFuture.completedFuture(generatedChunkByDhPos.get(dhChunkPos)); - } - - return this.getChunkNbtDataAsync(chunkPos) - .thenApply((chunkData) -> - { - ChunkAccess newChunk = this.loadOrMakeChunk(chunkPos, chunkData); - - if (Config.Common.LodBuilding.pullLightingForPregeneratedChunks.get()) - { - // attempt to get chunk lighting - ChunkFileReader.CombinedChunkLightStorage combinedLights = ChunkFileReader.readLight(newChunk, chunkData); - if (combinedLights != null) - { - chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage); - chunkBlockLightingByDhPos.put(dhChunkPos, combinedLights.blockLightStorage); - } - } - - return newChunk; - }) - // separate handle so we can cleanly handle missing chunks and/or thrown errors - .handle((newChunk, throwable) -> - { - if (newChunk != null) - { - return newChunk; - } - else - { - return CreateEmptyChunk(this.params.level, chunkPos); - } - }) - .thenApply((newChunk) -> - { - generatedChunkByDhPos.put(dhChunkPos, newChunk); - return newChunk; - }); - } - // TODO FIXME this method can be called up to 25 times for the same chunk position, why? - private CompletableFuture getChunkNbtDataAsync(ChunkPos chunkPos) - { - ServerLevel level = this.params.level; - - //if (true) - // return CompletableFuture.completedFuture(null); - - // TODO disabling drastically reduces GC overhead (2Gb/s -> 1GB/s) - - try - { - IOWorker ioWorker = level.getChunkSource().chunkMap.worker; - - #if MC_VER <= MC_1_18_2 - return CompletableFuture.completedFuture(ioWorker.load(chunkPos)); - #else - - // storage will be null if C2ME is installed - if (!this.pullExistingChunkUsingMcAsyncMethod && ioWorker.storage != null) - { - try - { - RegionFileStorage storage = this.params.level.getChunkSource().chunkMap.worker.storage; - RegionFileStorageExternalCache cache = this.getOrCreateRegionFileCache(storage); - return CompletableFuture.completedFuture(cache.read(chunkPos)); - } - catch (NullPointerException e) - { - // this shouldn't happen, if anything is null it should be - // ioWorker.storage - // but just in case - LOGGER.error("Unexpected issue pulling pre-existing chunk ["+chunkPos+"], falling back to async chunk pulling. This may cause server-tick lag.", e); - this.pullExistingChunkUsingMcAsyncMethod = true; - - // try again now using the async method - return this.getChunkNbtDataAsync(chunkPos); - } - } - else - { - // log if we unexpectedly weren't able to run the sync chunk pulling - if (!this.pullExistingChunkUsingMcAsyncMethod) - { - // this shouldn't happen, but just in case - LOGGER.info("Unable to pull pre-existing chunk using synchronous method. Falling back to async method. this may cause server-tick lag."); - this.pullExistingChunkUsingMcAsyncMethod = true; - } - - //GET_CHUNK_COUNT_REF.incrementAndGet(); - - // When running in vanilla MC on versions before 1.21.4, - // DH would attempt to run loadAsync on this same thread via a threading mixin, - // to prevent causing lag on the server thread. - // However, if a mod like C2ME is installed this will run on a C2ME thread instead. - return ioWorker.loadAsync(chunkPos) - .thenApply(optional -> - { - // Debugging note: - // If there are reports of extreme memory use when C2ME is installed, that probably means - // this method is queuing a lot of tasks (1,000+), which causes C2ME to explode. - - //GET_CHUNK_COUNT_REF.decrementAndGet(); - //PREF_LOGGER.info("chunk getter count ["+F3Screen.NUMBER_FORMAT.format(GET_CHUNK_COUNT_REF.get())+"]"); - return optional.orElse(null); - }) - .exceptionally((throwable) -> - { - // unwrap the CompletionException if necessary - Throwable actualThrowable = throwable; - while (actualThrowable instanceof CompletionException completionException) - { - actualThrowable = completionException.getCause(); - } - - boolean isShutdownException = ExceptionUtil.isShutdownException(actualThrowable); - if (!isShutdownException) - { - CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load or make chunk ["+chunkPos+"], error: ["+actualThrowable.getMessage()+"].", actualThrowable); - } - - return null; - }); - } - #endif - } - catch (ClosedByInterruptException ignore) - { - // this just means the world generator is being shut down - return CompletableFuture.completedFuture(null); - } - catch (Exception e) - { - CHUNK_LOAD_LOGGER.warn("Couldn't load or make chunk [" + chunkPos + "]. Error: [" + e.getMessage() + "].", e); - return CompletableFuture.completedFuture(null); - } - } - private ChunkAccess loadOrMakeChunk(ChunkPos chunkPos, CompoundTag chunkData) - { - ServerLevel level = this.params.level; - - if (chunkData == null) - { - return CreateEmptyChunk(level, chunkPos); - } - else - { - try - { - CHUNK_LOAD_LOGGER.debug("DistantHorizons: Loading chunk [" + chunkPos + "] from disk."); - - @Nullable - ChunkAccess chunk = ChunkFileReader.read(level, chunkPos, chunkData); - if (chunk != null) - { - if (Config.Common.LodBuilding.assumePreExistingChunksAreFinished.get()) - { - // Sometimes the chunk status is wrong - // (this might be an issue with some versions of chunky) - // which can cause issues with some world gen steps re-running and locking up - ChunkWrapper.trySetStatus(chunk, ChunkStatus.FULL); - } - } - else - { - chunk = CreateEmptyChunk(level, chunkPos); - } - return chunk; - } - catch (Exception e) - { - CHUNK_LOAD_LOGGER.error( - "DistantHorizons: couldn't load or make chunk at [" + chunkPos + "]." + - "Please try optimizing your world to fix this issue. \n" + - "World optimization can be done from the singleplayer world selection screen.\n" + - "Error: [" + e.getMessage() + "]." - , e); - - return CreateEmptyChunk(level, chunkPos); - } - } - } - private static ProtoChunk CreateEmptyChunk(ServerLevel level, ChunkPos chunkPos) - { - #if MC_VER <= MC_1_16_5 - return new ProtoChunk(chunkPos, UpgradeData.EMPTY); - #elif MC_VER <= MC_1_17_1 - return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level); - #elif MC_VER <= MC_1_19_2 - return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null); - #elif MC_VER <= MC_1_19_4 - return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null); - #elif MC_VER < MC_1_21_3 - return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null); - #elif MC_VER < MC_1_21_9 - return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().lookupOrThrow(Registries.BIOME), null); - #else - return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, PalettedContainerFactory.create(level.registryAccess()), null); - #endif - } - - - // direct generation // public void generateDirect( @@ -884,20 +622,8 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm } - // clear the chunk cache - RegionFileStorageExternalCache regionStorage = this.regionFileStorageCacheRef.get(); - if (regionStorage != null) - { - try - { - regionStorage.close(); - } - catch (ClosedChannelException ignore) { /* world generator is being shut down */ } - catch (IOException e) - { - LOGGER.error("Failed to close region file storage cache, error: ["+e.getMessage()+"].", e); - } - } + this.chunkFileReader.close(); + } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkFileReader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java similarity index 83% rename from common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkFileReader.java rename to common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java index b9aa41169..d7b73644c 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkFileReader.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java @@ -17,14 +17,15 @@ * along with this program. If not, see . */ -package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject; +package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling; import com.mojang.serialization.Codec; import com.mojang.serialization.Dynamic; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; +import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; @@ -34,22 +35,19 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; -import it.unimi.dsi.fastutil.shorts.ShortList; import net.minecraft.core.Registry; #if MC_VER >= MC_1_19_4 -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; #endif + import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.*; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.*; @@ -86,14 +84,16 @@ import net.minecraft.world.level.chunk.status.ChunkType; #endif import net.minecraft.world.level.material.Fluid; -import org.jetbrains.annotations.Nullable; -public class ChunkFileReader +public class ChunkCompoundTagParser { private static final AtomicBoolean ZERO_CHUNK_POS_ERROR_LOGGED_REF = new AtomicBoolean(false); - private static final DhLogger LOGGER = BatchGenerationEnvironment.CHUNK_LOAD_LOGGER; + public static final DhLogger LOGGER = new DhLoggerBuilder() + .name("LOD Chunk Reader") + .fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile) + .build(); #if MC_VER >= MC_1_21_9 @@ -121,7 +121,7 @@ public class ChunkFileReader // read chunk // //============// - public static LevelChunk read(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData) + public static LevelChunk createFromTag(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData) { #if MC_VER < MC_1_18_2 CompoundTag tagLevel = chunkData.getCompound("Level"); @@ -129,8 +129,8 @@ public class ChunkFileReader CompoundTag tagLevel = chunkData; #endif - int chunkX = tagGetInt(tagLevel,"xPos"); - int chunkZ = tagGetInt(tagLevel, "zPos"); + int chunkX = CompoundTagUtil.getInt(tagLevel,"xPos"); + int chunkZ = CompoundTagUtil.getInt(tagLevel, "zPos"); ChunkPos actualPos = new ChunkPos(chunkX, chunkZ); if (!Objects.equals(chunkPos, actualPos)) @@ -165,18 +165,25 @@ public class ChunkFileReader chunkType = readChunkType(tagLevel); #if MC_VER < MC_1_18_2 - if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK) - return null; + if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK) + { + return null; + } #elif MC_VER < MC_1_21_6 BlendingData blendingData = readBlendingData(tagLevel); #if MC_VER < MC_1_19_2 if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || !blendingData.oldNoise())) + { return null; + } #else if (chunkType == #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType.PROTOCHUNK #else ChunkType.PROTOCHUNK #endif && blendingData == null) + { return null; + } #endif + #else // ignore blending data, there appears to be an issue with parsing it in 1.21.6 @@ -188,31 +195,31 @@ public class ChunkFileReader } #endif - long inhabitedTime = tagGetLong(tagLevel, "InhabitedTime"); + long inhabitedTime = CompoundTagUtil.getLong(tagLevel, "InhabitedTime"); //================== Read params for making the LevelChunk ================== UpgradeData upgradeData = UpgradeData.EMPTY; // commented out 2025-06-04 as a test to see if the upgrade data // is actually necessary for DH or if it can be ignored - // (if it can't be ignored we'll need to handle null responses from tagGetCompoundTag()) + // (if it can't be ignored we'll need to handle null responses from CompoundTagUtil.getCompoundTag()) // //#if MC_VER < MC_1_17_1 //upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10) - // ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA)) + // ? new UpgradeData(CompoundTagUtil.getCompoundTag(tagLevel, TAG_UPGRADE_DATA)) // : UpgradeData.EMPTY; //#elif MC_VER < MC_1_21_5 //upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10) - // ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level) + // ? new UpgradeData(CompoundTagUtil.getCompoundTag(tagLevel, TAG_UPGRADE_DATA), level) // : UpgradeData.EMPTY; //#else //upgradeData = tagLevel.contains(TAG_UPGRADE_DATA) - // ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level) + // ? new UpgradeData(CompoundTagUtil.getCompoundTag(tagLevel, TAG_UPGRADE_DATA), level) // : UpgradeData.EMPTY; //#endif - boolean isLightOn = tagGetBoolean(tagLevel, "isLightOn"); + boolean isLightOn = CompoundTagUtil.getBoolean(tagLevel, "isLightOn"); #if MC_VER < MC_1_18_2 ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer( level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY)#if MC_VER >= MC_1_17_1 , level #endif , @@ -301,10 +308,10 @@ public class ChunkFileReader int sectionYIndex = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYIndex]; - ListTag tagSections = tagGetListTag(chunkData, "Sections", 10); + ListTag tagSections = CompoundTagUtil.getListTag(chunkData, "Sections", 10); if (tagSections == null || tagSections.isEmpty()) { - tagSections = tagGetListTag(chunkData, "sections", 10); + tagSections = CompoundTagUtil.getListTag(chunkData, "sections", 10); } @@ -312,13 +319,13 @@ public class ChunkFileReader { for (int j = 0; j < tagSections.size(); ++j) { - CompoundTag tagSection = tagGetCompoundTag(tagSections, j); + CompoundTag tagSection = CompoundTagUtil.getCompoundTag(tagSections, j); if (tagSection == null) { continue; } - final int sectionYPos = tagGetByte(tagSection, "Y"); + final int sectionYPos = CompoundTagUtil.getByte(tagSection, "Y"); #if MC_VER < MC_1_18_2 if (tagSection.contains("Palette", 9) && tagSection.contains("BlockStates", 12)) @@ -353,11 +360,11 @@ public class ChunkFileReader if (containsBlockStates) { #if MC_VER < MC_1_20_6 - blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states")) + blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "block_states")) .promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string)) .getOrThrow(false, (message) -> logParsingWarningOnce(message)); #else - blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states")) + blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "block_states")) .promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string)) .getOrThrow((message) -> logErrorAndReturnException(message)); #endif @@ -389,11 +396,11 @@ public class ChunkFileReader if (containsBiomes) { #if MC_VER < MC_1_20_6 - biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes")) + biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "biomes")) .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) .getOrThrow(false, (message) -> logParsingWarningOnce(message)); #else - biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes")) + biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "biomes")) .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) .getOrThrow((message) -> logErrorAndReturnException(message)); #endif @@ -434,7 +441,7 @@ public class ChunkFileReader #else ChunkType #endif readChunkType(CompoundTag tagLevel) { - String statusString = tagGetString(tagLevel,"Status"); + String statusString = CompoundTagUtil.getString(tagLevel,"Status"); if (statusString != null) { ChunkStatus chunkStatus = ChunkStatus.byName(statusString); @@ -452,7 +459,7 @@ public class ChunkFileReader } private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData) { - CompoundTag tagHeightmaps = tagGetCompoundTag(chunkData, "Heightmaps"); + CompoundTag tagHeightmaps = CompoundTagUtil.getCompoundTag(chunkData, "Heightmaps"); if (tagHeightmaps != null) { for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter()) @@ -482,18 +489,18 @@ public class ChunkFileReader // DH probably doesn't need any chunk post-processing data //private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData) //{ - // ListTag tagPostProcessings = tagGetListTag(chunkData,"PostProcessing", 9); + // ListTag tagPostProcessings = CompoundTagUtil.getListTag(chunkData,"PostProcessing", 9); // if (tagPostProcessings != null) // { // for (int i = 0; i < tagPostProcessings.size(); ++i) // { - // ListTag listTag3 = tagGetListTag(tagPostProcessings, i); + // ListTag listTag3 = CompoundTagUtil.getListTag(tagPostProcessings, i); // for (int j = 0; j < listTag3.size(); ++j) // { // #if MC_VER < MC_1_21_3 // chunk.addPackedPostProcess(listTag3.getShort(j), i); // #else - // chunk.addPackedPostProcess(ShortList.of(tagGetShort(listTag3, j)), i); + // chunk.addPackedPostProcess(ShortList.of(CompoundTagUtil.getShort(listTag3, j)), i); // #endif // } // } @@ -547,9 +554,7 @@ public class ChunkFileReader // read chunk lighting // //=====================// - /** - * https://minecraft.wiki/w/Chunk_format - */ + /** https://minecraft.wiki/w/Chunk_format */ public static CombinedChunkLightStorage readLight(ChunkAccess chunk, CompoundTag chunkData) { #if MC_VER <= MC_1_17_1 @@ -612,8 +617,8 @@ public class ChunkFileReader // if null all lights = 0 - byte[] blockLightNibbleArray = tagGetByteArray(chunkSectionCompoundTag, "BlockLight"); - byte[] skyLightNibbleArray = tagGetByteArray(chunkSectionCompoundTag, "SkyLight"); + byte[] blockLightNibbleArray = CompoundTagUtil.getByteArray(chunkSectionCompoundTag, "BlockLight"); + byte[] skyLightNibbleArray = CompoundTagUtil.getByteArray(chunkSectionCompoundTag, "SkyLight"); if (blockLightNibbleArray != null && skyLightNibbleArray != null) @@ -725,137 +730,6 @@ public class ChunkFileReader - //====================// - // tag helper methods // - //====================// - - // TODO move into separate file (this file is getting long) - // these tag helpers are to simplify tag accessing between MC versions - - /** defaults to "false" if the tag isn't present */ - private static boolean tagGetBoolean(CompoundTag tag, String key) - { - #if MC_VER < MC_1_21_5 - return tag.getBoolean(key); - #else - return tag.getBoolean(key).orElse(false); - #endif - } - - /** defaults to "0" if the tag isn't present */ - private static byte tagGetByte(CompoundTag tag, String key) - { - #if MC_VER < MC_1_21_5 - return tag.getByte(key); - #else - return tag.getByte(key).orElse((byte)0); - #endif - } - - /** defaults to "0" if the tag isn't present */ - private static short tagGetShort(ListTag tag, int index) - { - #if MC_VER < MC_1_21_5 - return tag.getShort(index); - #else - return tag.getShort(index).orElse((short)0); - #endif - } - - /** defaults to "0" if the tag isn't present */ - private static int tagGetInt(CompoundTag tag, String key) - { - #if MC_VER < MC_1_21_5 - return tag.getInt(key); - #else - return tag.getInt(key).orElse(0); - #endif - } - - /** defaults to "0" if the tag isn't present */ - private static long tagGetLong(CompoundTag tag, String key) - { - #if MC_VER < MC_1_21_5 - return tag.getInt(key); - #else - return tag.getLong(key).orElse(0L); - #endif - } - - - - /** defaults to null if the tag isn't present */ - @Nullable - private static String tagGetString(CompoundTag tag, String key) - { - #if MC_VER < MC_1_21_5 - return tag.getString(key); - #else - return tag.getString(key).orElse(null); - #endif - } - - /** defaults to null if the tag isn't present */ - @Nullable - private static byte[] tagGetByteArray(CompoundTag tag, String key) - { - #if MC_VER < MC_1_21_5 - return tag.getByteArray(key); - #else - return tag.getByteArray(key).orElse(null); - #endif - } - - - - /** defaults to null if the tag isn't present */ - @Nullable - private static CompoundTag tagGetCompoundTag(CompoundTag tag, String key) - { - #if MC_VER < MC_1_21_5 - return tag.getCompound(key); - #else - return tag.getCompound(key).orElse(null); - #endif - } - /** defaults to null if the tag isn't present */ - @Nullable - private static CompoundTag tagGetCompoundTag(ListTag tag, int index) - { - #if MC_VER < MC_1_21_5 - return tag.getCompound(index); - #else - return tag.getCompound(index).orElse(null); - #endif - } - - /** - * defaults to null if the tag isn't present - * @param elementType unused after MC 1.21.5 - */ - @Nullable - private static ListTag tagGetListTag(CompoundTag tag, String key, int elementType) - { - #if MC_VER < MC_1_21_5 - return tag.getList(key, elementType); - #else - return tag.getList(key).orElse(null); - #endif - } - - /** defaults to null if the tag isn't present */ - @Nullable - private static ListTag tagGetListTag(ListTag tag, int index) - { - #if MC_VER < MC_1_21_5 - return tag.getList(index); - #else - return tag.getList(index).orElse(null); - #endif - } - - - //================// // helper classes // //================// diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java new file mode 100644 index 000000000..688688f88 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java @@ -0,0 +1,339 @@ +package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling; + +import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.GlobalWorldGenParams; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.RegionFileStorageExternalCache; +import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.util.ExceptionUtil; +import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; +import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.PalettedContainerFactory; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.storage.IOWorker; +import net.minecraft.world.level.chunk.storage.RegionFileStorage; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.channels.ClosedByInterruptException; +import java.nio.channels.ClosedChannelException; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.atomic.AtomicReference; + +public class ChunkFileReader implements AutoCloseable +{ + + public static final DhLogger LOGGER = new DhLoggerBuilder() + .name("LOD World Gen") + .fileLevelConfig(Config.Common.Logging.logWorldGenEventToFile) + .build(); + + public static final DhLogger CHUNK_LOAD_LOGGER = new DhLoggerBuilder() + .name("LOD Chunk Loading") + .fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile) + .build(); + + private static final IModChecker MOD_CHECKER = SingletonInjector.INSTANCE.get(IModChecker.class); + + public final GlobalWorldGenParams params; + + /** + * will be true if C2ME is installed (since they require us to + * pull chunks using their async method), or if there + * was an issue with the sync pulling method. + */ + private boolean pullExistingChunkUsingMcAsyncMethod = false; + + private final AtomicReference regionFileStorageCacheRef = new AtomicReference<>(); + public RegionFileStorageExternalCache getOrCreateRegionFileCache(RegionFileStorage storage) + { + RegionFileStorageExternalCache cache = this.regionFileStorageCacheRef.get(); + if (cache == null) + { + cache = new RegionFileStorageExternalCache(storage); + if (!this.regionFileStorageCacheRef.compareAndSet(null, cache)) + { + cache = this.regionFileStorageCacheRef.get(); + } + } + return cache; + } + + + + //=============// + // constructor // + //=============// + + public ChunkFileReader(GlobalWorldGenParams params) + { + this.params = params; + + if (MOD_CHECKER.isModLoaded("c2me")) + { + LOGGER.info("C2ME detected: DH's pre-existing chunk accessing will use methods handled by C2ME."); + this.pullExistingChunkUsingMcAsyncMethod = true; + } + + } + + + + //=============// + // constructor // + //=============// + + /** + * If the given chunk pos already exists in the world, that chunk will be returned, + * otherwise this will return an empty chunk. + */ + public CompletableFuture createEmptyOrPreExistingChunkAsync( + int chunkX, int chunkZ, + Map chunkSkyLightingByDhPos, + Map chunkBlockLightingByDhPos, + Map generatedChunkByDhPos) + { + ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); + DhChunkPos dhChunkPos = new DhChunkPos(chunkX, chunkZ); + + if (generatedChunkByDhPos.containsKey(dhChunkPos)) + { + return CompletableFuture.completedFuture(generatedChunkByDhPos.get(dhChunkPos)); + } + + return this.getChunkNbtDataAsync(chunkPos) + .thenApply((CompoundTag chunkData) -> + { + ChunkAccess newChunk = this.loadOrMakeChunk(chunkPos, chunkData); + + if (Config.Common.LodBuilding.pullLightingForPregeneratedChunks.get()) + { + // attempt to get chunk lighting + ChunkCompoundTagParser.CombinedChunkLightStorage combinedLights = ChunkCompoundTagParser.readLight(newChunk, chunkData); + if (combinedLights != null) + { + chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage); + chunkBlockLightingByDhPos.put(dhChunkPos, combinedLights.blockLightStorage); + } + } + + return newChunk; + }) + // separate handle so we can cleanly handle missing chunks and/or thrown errors + .handle((newChunk, throwable) -> + { + if (newChunk != null) + { + return newChunk; + } + else + { + return CreateEmptyChunk(this.params.level, chunkPos); + } + }) + .thenApply((newChunk) -> + { + generatedChunkByDhPos.put(dhChunkPos, newChunk); + return newChunk; + }); + } + // TODO FIXME this method can be called up to 25 times for the same chunk position, why? + private CompletableFuture getChunkNbtDataAsync(ChunkPos chunkPos) + { + ServerLevel level = this.params.level; + + //if (true) + // return CompletableFuture.completedFuture(null); + + // TODO disabling drastically reduces GC overhead (2Gb/s -> 1GB/s) + + try + { + IOWorker ioWorker = level.getChunkSource().chunkMap.worker; + + #if MC_VER <= MC_1_18_2 + return CompletableFuture.completedFuture(ioWorker.load(chunkPos)); + #else + + // storage will be null if C2ME is installed + if (!this.pullExistingChunkUsingMcAsyncMethod + && ioWorker.storage != null) + { + try + { + RegionFileStorage storage = this.params.level.getChunkSource().chunkMap.worker.storage; + RegionFileStorageExternalCache cache = this.getOrCreateRegionFileCache(storage); + return CompletableFuture.completedFuture(cache.read(chunkPos)); + } + catch (NullPointerException e) + { + // this shouldn't happen, if anything is null it should be + // ioWorker.storage + // but just in case + LOGGER.error("Unexpected issue pulling pre-existing chunk ["+chunkPos+"], falling back to async chunk pulling. This may cause server-tick lag.", e); + this.pullExistingChunkUsingMcAsyncMethod = true; + + // try again now using the async method + return this.getChunkNbtDataAsync(chunkPos); + } + } + else + { + // log if we unexpectedly weren't able to run the sync chunk pulling + if (!this.pullExistingChunkUsingMcAsyncMethod) + { + // this shouldn't happen, but just in case + LOGGER.info("Unable to pull pre-existing chunk using synchronous method. Falling back to async method. this may cause server-tick lag."); + this.pullExistingChunkUsingMcAsyncMethod = true; + } + + //GET_CHUNK_COUNT_REF.incrementAndGet(); + + // When running in vanilla MC on versions before 1.21.4, + // DH would attempt to run loadAsync on this same thread via a threading mixin, + // to prevent causing lag on the server thread. + // However, if a mod like C2ME is installed this will run on a C2ME thread instead. + return ioWorker.loadAsync(chunkPos) + .thenApply(optional -> + { + // Debugging note: + // If there are reports of extreme memory use when C2ME is installed, that probably means + // this method is queuing a lot of tasks (1,000+), which causes C2ME to explode. + + //GET_CHUNK_COUNT_REF.decrementAndGet(); + //PREF_LOGGER.info("chunk getter count ["+F3Screen.NUMBER_FORMAT.format(GET_CHUNK_COUNT_REF.get())+"]"); + return optional.orElse(null); + }) + .exceptionally((throwable) -> + { + // unwrap the CompletionException if necessary + Throwable actualThrowable = throwable; + while (actualThrowable instanceof CompletionException completionException) + { + actualThrowable = completionException.getCause(); + } + + boolean isShutdownException = ExceptionUtil.isShutdownException(actualThrowable); + if (!isShutdownException) + { + CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load or make chunk ["+chunkPos+"], error: ["+actualThrowable.getMessage()+"].", actualThrowable); + } + + return null; + }); + } + #endif + } + catch (ClosedByInterruptException ignore) + { + // this just means the world generator is being shut down + return CompletableFuture.completedFuture(null); + } + catch (Exception e) + { + CHUNK_LOAD_LOGGER.warn("Couldn't load or make chunk [" + chunkPos + "]. Error: [" + e.getMessage() + "].", e); + return CompletableFuture.completedFuture(null); + } + } + private ChunkAccess loadOrMakeChunk(ChunkPos chunkPos, CompoundTag chunkTagData) + { + ServerLevel level = this.params.level; + + if (chunkTagData == null) + { + return CreateEmptyChunk(level, chunkPos); + } + else + { + try + { + CHUNK_LOAD_LOGGER.debug("DistantHorizons: Loading chunk [" + chunkPos + "] from disk."); + + @Nullable + ChunkAccess chunk = ChunkCompoundTagParser.createFromTag(level, chunkPos, chunkTagData); + if (chunk != null) + { + if (Config.Common.LodBuilding.assumePreExistingChunksAreFinished.get()) + { + // Sometimes the chunk status is wrong + // (this might be an issue with some versions of chunky) + // which can cause issues with some world gen steps re-running and locking up + ChunkWrapper.trySetStatus(chunk, ChunkStatus.FULL); + } + } + else + { + chunk = CreateEmptyChunk(level, chunkPos); + } + return chunk; + } + catch (Exception e) + { + CHUNK_LOAD_LOGGER.error( + "DistantHorizons: couldn't load or make chunk at [" + chunkPos + "]." + + "Please try optimizing your world to fix this issue. \n" + + "World optimization can be done from the singleplayer world selection screen.\n" + + "Error: [" + e.getMessage() + "]." + , e); + + return CreateEmptyChunk(level, chunkPos); + } + } + } + private static ProtoChunk CreateEmptyChunk(ServerLevel level, ChunkPos chunkPos) + { + #if MC_VER <= MC_1_16_5 + return new ProtoChunk(chunkPos, UpgradeData.EMPTY); + #elif MC_VER <= MC_1_17_1 + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level); + #elif MC_VER <= MC_1_19_2 + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null); + #elif MC_VER <= MC_1_19_4 + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null); + #elif MC_VER < MC_1_21_3 + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null); + #elif MC_VER < MC_1_21_9 + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().lookupOrThrow(Registries.BIOME), null); + #else + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, PalettedContainerFactory.create(level.registryAccess()), null); + #endif + } + + + + //================// + // base overrides // + //================// + + @Override + public void close() + { + RegionFileStorageExternalCache regionStorage = this.regionFileStorageCacheRef.get(); + if (regionStorage != null) + { + try + { + regionStorage.close(); + } + catch (ClosedChannelException ignore) { /* world generator is being shut down */ } + catch (IOException e) + { + LOGGER.error("Failed to close region file storage cache, error: ["+e.getMessage()+"].", e); + } + } + } + + + +} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/CompoundTagUtil.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/CompoundTagUtil.java new file mode 100644 index 000000000..9e442cfd1 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/CompoundTagUtil.java @@ -0,0 +1,137 @@ +package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import org.jetbrains.annotations.Nullable; + +/** + * these tag helpers are usedd to simplify tag accessing between MC versions + */ +public class CompoundTagUtil +{ + + /** defaults to "false" if the tag isn't present */ + public static boolean getBoolean(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getBoolean(key); + #else + return tag.getBoolean(key).orElse(false); + #endif + } + + /** defaults to "0" if the tag isn't present */ + public static byte getByte(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getByte(key); + #else + return tag.getByte(key).orElse((byte)0); + #endif + } + + /** defaults to "0" if the tag isn't present */ + public static short getShort(ListTag tag, int index) + { + #if MC_VER < MC_1_21_5 + return tag.getShort(index); + #else + return tag.getShort(index).orElse((short)0); + #endif + } + + /** defaults to "0" if the tag isn't present */ + public static int getInt(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getInt(key); + #else + return tag.getInt(key).orElse(0); + #endif + } + + /** defaults to "0" if the tag isn't present */ + public static long getLong(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getInt(key); + #else + return tag.getLong(key).orElse(0L); + #endif + } + + + + /** defaults to null if the tag isn't present */ + @Nullable + public static String getString(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getString(key); + #else + return tag.getString(key).orElse(null); + #endif + } + + /** defaults to null if the tag isn't present */ + @Nullable + public static byte[] getByteArray(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getByteArray(key); + #else + return tag.getByteArray(key).orElse(null); + #endif + } + + + + /** defaults to null if the tag isn't present */ + @Nullable + public static CompoundTag getCompoundTag(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getCompound(key); + #else + return tag.getCompound(key).orElse(null); + #endif + } + /** defaults to null if the tag isn't present */ + @Nullable + public static CompoundTag getCompoundTag(ListTag tag, int index) + { + #if MC_VER < MC_1_21_5 + return tag.getCompound(index); + #else + return tag.getCompound(index).orElse(null); + #endif + } + + /** + * defaults to null if the tag isn't present + * @param elementType unused after MC 1.21.5 + */ + @Nullable + public static ListTag getListTag(CompoundTag tag, String key, int elementType) + { + #if MC_VER < MC_1_21_5 + return tag.getList(key, elementType); + #else + return tag.getList(key).orElse(null); + #endif + } + + /** defaults to null if the tag isn't present */ + @Nullable + public static ListTag getListTag(ListTag tag, int index) + { + #if MC_VER < MC_1_21_5 + return tag.getList(index); + #else + return tag.getList(index).orElse(null); + #endif + } + + + +} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/RegionFileStorageExternalCache.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/RegionFileStorageExternalCache.java index 3b8fb6980..d7b2df37d 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/RegionFileStorageExternalCache.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/RegionFileStorageExternalCache.java @@ -1,6 +1,6 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling.ChunkFileReader; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtIo; @@ -55,7 +55,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable public RegionFileStorageExternalCache(RegionFileStorage storage) { this.storage = storage; } @Nullable - public RegionFile getRegionFile(ChunkPos pos) throws IOException + public RegionFile getRegionFile(ChunkPos chunkPos) throws IOException { if (this.storage == null) { @@ -70,8 +70,8 @@ public class RegionFileStorageExternalCache implements AutoCloseable - long posLong = ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ()); - RegionFile rFile = null; + long chunkPosLong = ChunkPos.asLong(chunkPos.getRegionX(), chunkPos.getRegionZ()); + RegionFile regionFile = null; // Check vanilla cache int retryCount = 0; @@ -85,7 +85,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable this.getRegionFileLock.lock(); #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 - rFile = this.storage.getRegionFile(pos); + regionFile = this.storage.getRegionFile(chunkPos); // keeping the region cache size low helps prevent concurrency issues if (this.storage.regionCache.size() > 150) // max 256 @@ -97,7 +97,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable } } #else - rFile = this.storage.regionCache.getOrDefault(posLong, null); + regionFile = this.storage.regionCache.getOrDefault(chunkPosLong, null); #endif break; @@ -139,19 +139,19 @@ public class RegionFileStorageExternalCache implements AutoCloseable if (retryCount >= maxRetryCount) { - BatchGenerationEnvironment.CHUNK_LOAD_LOGGER.warn("Concurrency issue detected when getting region file for chunk at [" + pos + "]."); + ChunkFileReader.CHUNK_LOAD_LOGGER.warn("Concurrency issue detected when getting region file for chunk at [" + chunkPos + "]."); } - if (rFile != null) + if (regionFile != null) { - return rFile; + return regionFile; } // Then check our custom cache for (RegionFileCache cache : this.regionFileCache) { - if (cache.pos == posLong) + if (cache.pos == chunkPosLong) { return cache.file; } @@ -170,22 +170,22 @@ public class RegionFileStorageExternalCache implements AutoCloseable return null; } - Path regionFilePath = storageFolderPath.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca"); + Path regionFilePath = storageFolderPath.resolve("r." + chunkPos.getRegionX() + "." + chunkPos.getRegionZ() + ".mca"); #if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 - rFile = new RegionFile(regionFilePath.toFile(), storageFolderPath.toFile(), false); + regionFile = new RegionFile(regionFilePath.toFile(), storageFolderPath.toFile(), false); #elif MC_VER <= MC_1_20_4 - rFile = new RegionFile(regionFilePath, storageFolderPath, false); + regionFile = new RegionFile(regionFilePath, storageFolderPath, false); #else - rFile = new RegionFile(new RegionStorageInfo("level", null, "level type"), regionFilePath, storageFolderPath, false); + regionFile = new RegionFile(new RegionStorageInfo("level", null, "level type"), regionFilePath, storageFolderPath, false); #endif - this.regionFileCache.add(new RegionFileCache(ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ()), rFile)); + this.regionFileCache.add(new RegionFileCache(ChunkPos.asLong(chunkPos.getRegionX(), chunkPos.getRegionZ()), regionFile)); while (this.regionFileCache.size() > MAX_CACHE_SIZE) { this.regionFileCache.poll().file.close(); } - return rFile; + return regionFile; } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java index d94318267..5485e757a 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java @@ -71,6 +71,8 @@ public final class StepStructureStart extends AbstractWorldGenStep { ArrayList chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers); + // TODO should be put in wrapped environment so we can skip some other world gen steps + // SURFACE wouldn't need structure generation either #if MC_VER < MC_1_19_2 if (!this.environment.params.worldGenSettings.generateFeatures()) #elif MC_VER < MC_1_19_4 From 5652a9328c9caba36bd6e205f1fe9882b136e09d Mon Sep 17 00:00:00 2001 From: James Seibel Date: Mon, 24 Nov 2025 14:43:56 -0600 Subject: [PATCH 10/33] add/replace ZStd stream with block compression --- coreSubProjects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreSubProjects b/coreSubProjects index 47a4d1535..22f5608f9 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 47a4d1535f1ad38850bf8db1230184c5e5314bcd +Subproject commit 22f5608f9a2bcd07099750a9b01e75502501fc43 From 2aa8d9f48953f74faaa00e0fc5a9c38ad48b043d Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 26 Nov 2025 13:52:51 -0600 Subject: [PATCH 11/33] update neoforge reference 1.21.10 6 -> 55 --- versionProperties/1.21.10.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versionProperties/1.21.10.properties b/versionProperties/1.21.10.properties index 02238be09..2b33746c4 100644 --- a/versionProperties/1.21.10.properties +++ b/versionProperties/1.21.10.properties @@ -41,7 +41,7 @@ fabric_api_version=0.135.0+1.21.10 # (Neo)Forge loader forge_version= -neoforge_version=21.10.6-beta +neoforge_version=21.10.55-beta neoforge_version_range=[21.10.6-beta,) # (Neo)Forge mod versions From 986a6cdc197f7dd6bc86cfa758bf5f112245c91a Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 26 Nov 2025 13:53:10 -0600 Subject: [PATCH 12/33] Update coreSubProjects --- coreSubProjects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreSubProjects b/coreSubProjects index 22f5608f9..5a4ddafbb 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 22f5608f9a2bcd07099750a9b01e75502501fc43 +Subproject commit 5a4ddafbbbd7f7b92f7cd64565f6008d5581fdc2 From 350d72b6ec0f27fafe4edefe6bdd15f3da5dd669 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 26 Nov 2025 13:55:47 -0600 Subject: [PATCH 13/33] Update .editorconfig --- .editorconfig | 174 +++++++++++++++++++++----------------------------- 1 file changed, 73 insertions(+), 101 deletions(-) diff --git a/.editorconfig b/.editorconfig index 932e24503..0c9c384c3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,40 +11,17 @@ insert_final_newline = false max_line_length = 1000 tab_width = 4 trim_trailing_whitespace = false -ij_continuation_indent_size = 8 +ij_continuation_indent_size = 4 ij_formatter_off_tag = @formatter:off ij_formatter_on_tag = @formatter:on ij_formatter_tags_enabled = true ij_smart_tabs = false -ij_visual_guides = +ij_visual_guides = none ij_wrap_on_typing = false -[*.dcl] -ij_declarative_keep_indents_on_empty_lines = false - -[*.gsh] -ij_glsl_space_after_colon = true -ij_glsl_space_after_comma = true -ij_glsl_space_after_for_semicolon = true -ij_glsl_space_after_quest = true -ij_glsl_space_before_colon = true -ij_glsl_space_before_comma = false -ij_glsl_space_before_for_semicolon = false -ij_glsl_space_before_quest = true -ij_glsl_spaces_around_additive_operators = true -ij_glsl_spaces_around_assignment_operators = true -ij_glsl_spaces_around_bitwise_operators = true -ij_glsl_spaces_around_equality_operators = true -ij_glsl_spaces_around_logical_operators = true -ij_glsl_spaces_around_multiplicative_operators = true -ij_glsl_spaces_around_relational_operators = true -ij_glsl_spaces_around_shift_operators = true -ij_glsl_spaces_within_brackets = false -ij_glsl_spaces_within_parentheses = false - [*.java] indent_style = tab -ij_continuation_indent_size = 4 +ij_smart_tabs = true ij_java_align_consecutive_assignments = false ij_java_align_consecutive_variable_declarations = false ij_java_align_group_field_declarations = false @@ -53,21 +30,21 @@ ij_java_align_multiline_array_initializer_expression = false ij_java_align_multiline_assignment = false ij_java_align_multiline_binary_operation = false ij_java_align_multiline_chained_methods = false -ij_java_align_multiline_deconstruction_list_components = true +ij_java_align_multiline_deconstruction_list_components = false ij_java_align_multiline_extends_list = false -ij_java_align_multiline_for = true +ij_java_align_multiline_for = false ij_java_align_multiline_method_parentheses = false ij_java_align_multiline_parameters = false ij_java_align_multiline_parameters_in_calls = false ij_java_align_multiline_parenthesized_expression = false -ij_java_align_multiline_records = true +ij_java_align_multiline_records = false ij_java_align_multiline_resources = false ij_java_align_multiline_ternary_operation = false ij_java_align_multiline_text_blocks = false ij_java_align_multiline_throws_list = false ij_java_align_subsequent_simple_methods = false ij_java_align_throws_keyword = false -ij_java_align_types_in_multi_catch = true +ij_java_align_types_in_multi_catch = false ij_java_annotation_parameter_wrap = off ij_java_array_initializer_new_line_after_left_brace = false ij_java_array_initializer_right_brace_on_new_line = false @@ -84,17 +61,17 @@ ij_java_blank_lines_after_package = 1 ij_java_blank_lines_around_class = 1 ij_java_blank_lines_around_field = 0 ij_java_blank_lines_around_field_in_interface = 0 -ij_java_blank_lines_around_initializer = 1 -ij_java_blank_lines_around_method = 1 -ij_java_blank_lines_around_method_in_interface = 1 -ij_java_blank_lines_before_class_end = 0 +ij_java_blank_lines_around_initializer = 0 +ij_java_blank_lines_around_method = 0 +ij_java_blank_lines_around_method_in_interface = 0 +ij_java_blank_lines_before_class_end = 1 ij_java_blank_lines_before_imports = 1 ij_java_blank_lines_before_method_body = 0 ij_java_blank_lines_before_package = 1 ij_java_block_brace_style = next_line ij_java_block_comment_add_space = false ij_java_block_comment_at_first_column = true -ij_java_builder_methods = +ij_java_builder_methods = none ij_java_call_parameters_new_line_after_left_paren = false ij_java_call_parameters_right_paren_on_new_line = false ij_java_call_parameters_wrap = normal @@ -109,7 +86,7 @@ ij_java_do_not_indent_top_level_class_members = false ij_java_do_not_wrap_after_single_annotation = false ij_java_do_not_wrap_after_single_annotation_in_parameter = false ij_java_do_while_brace_force = never -ij_java_doc_add_blank_line_after_description = false +ij_java_doc_add_blank_line_after_description = true ij_java_doc_add_blank_line_after_param_comments = false ij_java_doc_add_blank_line_after_return = false ij_java_doc_add_p_tag_on_empty_lines = false @@ -120,29 +97,25 @@ ij_java_doc_enable_formatting = true ij_java_doc_enable_leading_asterisks = true ij_java_doc_indent_on_continuation = false ij_java_doc_keep_empty_lines = true -ij_java_doc_keep_empty_parameter_tag = false +ij_java_doc_keep_empty_parameter_tag = true ij_java_doc_keep_empty_return_tag = false -ij_java_doc_keep_empty_throws_tag = false -ij_java_doc_keep_invalid_tags = false +ij_java_doc_keep_empty_throws_tag = true +ij_java_doc_keep_invalid_tags = true ij_java_doc_param_description_on_new_line = false ij_java_doc_preserve_line_breaks = false ij_java_doc_use_throws_not_exception_tag = true ij_java_else_on_new_line = true ij_java_enum_constants_wrap = off -ij_java_enum_field_annotation_wrap = off ij_java_extends_keyword_wrap = normal ij_java_extends_list_wrap = normal ij_java_field_annotation_wrap = off -ij_java_field_name_prefix = -ij_java_field_name_suffix = ij_java_finally_on_new_line = true -ij_java_for_brace_force = never +ij_java_for_brace_force = always ij_java_for_statement_new_line_after_left_paren = false ij_java_for_statement_right_paren_on_new_line = false ij_java_for_statement_wrap = off ij_java_generate_final_locals = false ij_java_generate_final_parameters = false -ij_java_generate_use_type_annotation_before_type = true ij_java_if_brace_force = never ij_java_imports_layout = *,|,javax.**,java.**,|,$* ij_java_indent_case_from_switch = true @@ -153,13 +126,13 @@ ij_java_keep_blank_lines_between_package_declaration_and_header = 2 ij_java_keep_blank_lines_in_code = 10 ij_java_keep_blank_lines_in_declarations = 10 ij_java_keep_builder_methods_indents = false -ij_java_keep_control_statement_in_one_line = false -ij_java_keep_first_column_comment = false +ij_java_keep_control_statement_in_one_line = true +ij_java_keep_first_column_comment = true ij_java_keep_indents_on_empty_lines = true ij_java_keep_line_breaks = true -ij_java_keep_multiple_expressions_in_one_line = false +ij_java_keep_multiple_expressions_in_one_line = true ij_java_keep_simple_blocks_in_one_line = false -ij_java_keep_simple_classes_in_one_line = false +ij_java_keep_simple_classes_in_one_line = true ij_java_keep_simple_lambdas_in_one_line = true ij_java_keep_simple_methods_in_one_line = true ij_java_label_indent_absolute = false @@ -168,13 +141,11 @@ ij_java_lambda_brace_style = end_of_line ij_java_layout_static_imports_separately = true ij_java_line_comment_add_space = false ij_java_line_comment_add_space_on_reformat = false -ij_java_line_comment_at_first_column = true -ij_java_local_variable_name_prefix = -ij_java_local_variable_name_suffix = +ij_java_line_comment_at_first_column = false ij_java_method_annotation_wrap = off ij_java_method_brace_style = next_line ij_java_method_call_chain_wrap = normal -ij_java_method_parameters_new_line_after_left_paren = false +ij_java_method_parameters_new_line_after_left_paren = true ij_java_method_parameters_right_paren_on_new_line = false ij_java_method_parameters_wrap = normal ij_java_modifier_list_wrap = false @@ -183,22 +154,18 @@ ij_java_names_count_to_use_import_on_demand = 3 ij_java_new_line_after_lparen_in_annotation = false ij_java_new_line_after_lparen_in_deconstruction_pattern = true ij_java_new_line_after_lparen_in_record_header = false -ij_java_new_line_when_body_is_presented = false ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.* ij_java_parameter_annotation_wrap = off -ij_java_parameter_name_prefix = -ij_java_parameter_name_suffix = ij_java_parentheses_expression_new_line_after_left_paren = false ij_java_parentheses_expression_right_paren_on_new_line = false ij_java_place_assignment_sign_on_next_line = false ij_java_prefer_longer_names = true ij_java_prefer_parameters_wrap = false ij_java_record_components_wrap = normal -ij_java_repeat_annotations = ij_java_repeat_synchronized = true ij_java_replace_instanceof_and_cast = false -ij_java_replace_null_check = true -ij_java_replace_sum_lambda_with_method_ref = true +ij_java_replace_null_check = false +ij_java_replace_sum_lambda_with_method_ref = false ij_java_resource_list_new_line_after_left_paren = false ij_java_resource_list_right_paren_on_new_line = false ij_java_resource_list_wrap = on_every_item @@ -214,7 +181,7 @@ ij_java_space_after_quest = true ij_java_space_after_type_cast = true ij_java_space_before_annotation_array_initializer_left_brace = false ij_java_space_before_annotation_parameter_list = false -ij_java_space_before_array_initializer_left_brace = true +ij_java_space_before_array_initializer_left_brace = false ij_java_space_before_catch_keyword = true ij_java_space_before_catch_left_brace = true ij_java_space_before_catch_parentheses = true @@ -240,7 +207,7 @@ ij_java_space_before_opening_angle_bracket_in_type_parameter = false ij_java_space_before_quest = true ij_java_space_before_switch_left_brace = true ij_java_space_before_switch_parentheses = true -ij_java_space_before_synchronized_left_brace = true +ij_java_space_before_synchronized_left_brace = false ij_java_space_before_synchronized_parentheses = true ij_java_space_before_try_left_brace = true ij_java_space_before_try_parentheses = true @@ -249,7 +216,7 @@ ij_java_space_before_while_keyword = true ij_java_space_before_while_left_brace = true ij_java_space_before_while_parentheses = true ij_java_space_inside_one_line_enum_braces = false -ij_java_space_within_empty_array_initializer_braces = false +ij_java_space_within_empty_array_initializer_braces = true ij_java_space_within_empty_method_call_parentheses = false ij_java_space_within_empty_method_parentheses = false ij_java_spaces_around_additive_operators = true @@ -265,10 +232,9 @@ ij_java_spaces_around_relational_operators = true ij_java_spaces_around_shift_operators = true ij_java_spaces_around_type_bounds_in_type_parameters = true ij_java_spaces_around_unary_operator = false -ij_java_spaces_inside_block_braces_when_body_is_present = false ij_java_spaces_within_angle_brackets = false ij_java_spaces_within_annotation_parentheses = false -ij_java_spaces_within_array_initializer_braces = true +ij_java_spaces_within_array_initializer_braces = false ij_java_spaces_within_braces = true ij_java_spaces_within_brackets = false ij_java_spaces_within_cast_parentheses = false @@ -285,14 +251,9 @@ ij_java_spaces_within_synchronized_parentheses = false ij_java_spaces_within_try_parentheses = false ij_java_spaces_within_while_parentheses = false ij_java_special_else_if_treatment = true -ij_java_static_field_name_prefix = -ij_java_static_field_name_suffix = -ij_java_subclass_name_prefix = ij_java_subclass_name_suffix = Impl -ij_java_switch_expressions_wrap = normal ij_java_ternary_operation_signs_on_next_line = false ij_java_ternary_operation_wrap = on_every_item -ij_java_test_name_prefix = ij_java_test_name_suffix = Test ij_java_throws_keyword_wrap = normal ij_java_throws_list_wrap = normal @@ -302,12 +263,11 @@ ij_java_use_relative_indents = false ij_java_use_single_class_imports = true ij_java_variable_annotation_wrap = off ij_java_visibility = public -ij_java_while_brace_force = never +ij_java_while_brace_force = always ij_java_while_on_new_line = true ij_java_wrap_comments = false ij_java_wrap_first_method_in_call_chain = false ij_java_wrap_long_lines = false -ij_java_wrap_semicolon_after_call_chain = false [*.nbtt] indent_style = tab @@ -353,9 +313,11 @@ ij_xml_space_after_tag_name = false ij_xml_space_around_equals_in_attribute = false ij_xml_space_inside_empty_tag = false ij_xml_text_wrap = normal +ij_xml_use_custom_settings = false [{*.bash,*.sh,*.zsh}] -indent_style = tab +indent_size = 4 +tab_width = 4 ij_shell_binary_ops_start_line = false ij_shell_keep_column_alignment_padding = false ij_shell_minify_program = false @@ -363,8 +325,25 @@ ij_shell_redirect_followed_by_space = false ij_shell_switch_cases_indented = false ij_shell_use_unix_line_separator = true -[{*.comp,*.frag,*.fsh,*.geom,*.glsl,*.tesc,*.tese,*.vert,*.vsh}] -ij_glsl_keep_indents_on_empty_lines = false +[{*.comp,*.frag,*.fsh,*.geom,*.glsl,*.gsh,*.tesc,*.tese,*.vert,*.vsh}] +ij_glsl_space_after_colon = true +ij_glsl_space_after_comma = true +ij_glsl_space_after_for_semicolon = true +ij_glsl_space_after_quest = true +ij_glsl_space_before_colon = false +ij_glsl_space_before_comma = false +ij_glsl_space_before_for_semicolon = false +ij_glsl_space_before_quest = true +ij_glsl_spaces_around_additive_operators = true +ij_glsl_spaces_around_assignment_operators = true +ij_glsl_spaces_around_bitwise_operators = true +ij_glsl_spaces_around_equality_operators = true +ij_glsl_spaces_around_logical_operators = true +ij_glsl_spaces_around_multiplicative_operators = true +ij_glsl_spaces_around_relational_operators = true +ij_glsl_spaces_around_shift_operators = true +ij_glsl_spaces_within_brackets = false +ij_glsl_spaces_within_parentheses = false [{*.gant,*.groovy,*.gy}] ij_groovy_align_group_field_declarations = false @@ -557,9 +536,8 @@ ij_groovy_while_on_new_line = false ij_groovy_wrap_chain_calls_after_dot = false ij_groovy_wrap_long_lines = false -[{*.har,*.json,*.jsonc,*.png.mcmeta,mcmod.info,pack.mcmeta}] -indent_style = tab -ij_continuation_indent_size = 4 +[{*.har,*.json,*.png.mcmeta,mcmod.info,pack.mcmeta}] +indent_size = 4 ij_json_array_wrapping = split_into_lines ij_json_keep_blank_lines_in_code = 0 ij_json_keep_indents_on_empty_lines = false @@ -604,8 +582,6 @@ ij_html_space_inside_empty_tag = false ij_html_text_wrap = normal [{*.kt,*.kts}] -indent_style = tab -ij_continuation_indent_size = 4 ij_kotlin_align_in_columns_case_branch = false ij_kotlin_align_multiline_binary_operation = false ij_kotlin_align_multiline_extends_list = false @@ -614,34 +590,32 @@ ij_kotlin_align_multiline_parameters = true ij_kotlin_align_multiline_parameters_in_calls = false ij_kotlin_allow_trailing_comma = false ij_kotlin_allow_trailing_comma_on_call_site = false -ij_kotlin_assignment_wrap = normal +ij_kotlin_assignment_wrap = off ij_kotlin_blank_lines_after_class_header = 0 ij_kotlin_blank_lines_around_block_when_branches = 0 ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1 ij_kotlin_block_comment_add_space = false ij_kotlin_block_comment_at_first_column = true -ij_kotlin_call_parameters_new_line_after_left_paren = true -ij_kotlin_call_parameters_right_paren_on_new_line = true -ij_kotlin_call_parameters_wrap = on_every_item +ij_kotlin_call_parameters_new_line_after_left_paren = false +ij_kotlin_call_parameters_right_paren_on_new_line = false +ij_kotlin_call_parameters_wrap = off ij_kotlin_catch_on_new_line = false ij_kotlin_class_annotation_wrap = split_into_lines -ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL -ij_kotlin_continuation_indent_for_chained_calls = false -ij_kotlin_continuation_indent_for_expression_bodies = false -ij_kotlin_continuation_indent_in_argument_lists = false -ij_kotlin_continuation_indent_in_elvis = false -ij_kotlin_continuation_indent_in_if_conditions = false -ij_kotlin_continuation_indent_in_parameter_lists = false -ij_kotlin_continuation_indent_in_supertype_lists = false +ij_kotlin_continuation_indent_for_chained_calls = true +ij_kotlin_continuation_indent_for_expression_bodies = true +ij_kotlin_continuation_indent_in_argument_lists = true +ij_kotlin_continuation_indent_in_elvis = true +ij_kotlin_continuation_indent_in_if_conditions = true +ij_kotlin_continuation_indent_in_parameter_lists = true +ij_kotlin_continuation_indent_in_supertype_lists = true ij_kotlin_else_on_new_line = false ij_kotlin_enum_constants_wrap = off -ij_kotlin_extends_list_wrap = normal +ij_kotlin_extends_list_wrap = off ij_kotlin_field_annotation_wrap = split_into_lines ij_kotlin_finally_on_new_line = false -ij_kotlin_if_rparen_on_new_line = true +ij_kotlin_if_rparen_on_new_line = false ij_kotlin_import_nested_classes = false ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^ -ij_kotlin_indent_before_arrow_on_new_line = true ij_kotlin_insert_whitespaces_in_simple_one_line_method = true ij_kotlin_keep_blank_lines_before_right_brace = 2 ij_kotlin_keep_blank_lines_in_code = 2 @@ -655,10 +629,10 @@ ij_kotlin_line_comment_add_space = false ij_kotlin_line_comment_add_space_on_reformat = false ij_kotlin_line_comment_at_first_column = true ij_kotlin_method_annotation_wrap = split_into_lines -ij_kotlin_method_call_chain_wrap = normal -ij_kotlin_method_parameters_new_line_after_left_paren = true -ij_kotlin_method_parameters_right_paren_on_new_line = true -ij_kotlin_method_parameters_wrap = on_every_item +ij_kotlin_method_call_chain_wrap = off +ij_kotlin_method_parameters_new_line_after_left_paren = false +ij_kotlin_method_parameters_right_paren_on_new_line = false +ij_kotlin_method_parameters_wrap = off ij_kotlin_name_count_to_use_star_import = 5 ij_kotlin_name_count_to_use_star_import_for_members = 3 ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.** @@ -688,7 +662,7 @@ ij_kotlin_spaces_around_when_arrow = true ij_kotlin_variable_annotation_wrap = off ij_kotlin_while_on_new_line = false ij_kotlin_wrap_elvis_expressions = 1 -ij_kotlin_wrap_expression_body_functions = 1 +ij_kotlin_wrap_expression_body_functions = 0 ij_kotlin_wrap_first_method_in_call_chain = false [{*.markdown,*.md}] @@ -713,15 +687,13 @@ ij_markdown_wrap_text_inside_blockquotes = true ij_toml_keep_indents_on_empty_lines = false [{*.yaml,*.yml}] +indent_size = 4 ij_yaml_align_values_properties = do_not_align ij_yaml_autoinsert_sequence_marker = true ij_yaml_block_mapping_on_new_line = false ij_yaml_indent_sequence_value = true ij_yaml_keep_indents_on_empty_lines = false ij_yaml_keep_line_breaks = true -ij_yaml_line_comment_add_space = false -ij_yaml_line_comment_add_space_on_reformat = false -ij_yaml_line_comment_at_first_column = true ij_yaml_sequence_on_new_line = false ij_yaml_space_before_colon = false ij_yaml_spaces_within_braces = true From ace1aab42e58f8abfd1dd75f89e198581a8acfbf Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 27 Nov 2025 10:44:47 -0600 Subject: [PATCH 14/33] refactor internal server world gen --- .../BatchGenerationEnvironment.java | 38 ++- .../worldGeneration/ChunkPosGenStream.java | 6 +- .../chunkFileHandling/ChunkFileReader.java | 7 + .../InternalServerGenerator.java | 291 ++++++++++-------- coreSubProjects | 2 +- .../distanthorizons/fabric/FabricMain.java | 3 +- .../wrappers/modAccessor/C2meAccessor.java | 32 ++ .../neoforge/NeoforgeMain.java | 3 + .../wrappers/modAccessor/C2meAccessor.java | 32 ++ versionProperties/1.21.10.properties | 2 +- 10 files changed, 266 insertions(+), 150 deletions(-) create mode 100644 fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/C2meAccessor.java create mode 100644 neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/C2meAccessor.java diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 5583cc481..369d657ab 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -21,6 +21,7 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration; import com.google.common.collect.ImmutableMap; +import com.seibel.distanthorizons.api.DhApi; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; @@ -36,7 +37,10 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.util.ExceptionUtil; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; +import com.seibel.distanthorizons.core.util.objects.RollingAverage; import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException; +import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker; +import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper; @@ -46,6 +50,7 @@ import java.util.*; import java.util.concurrent.*; import java.util.function.Consumer; +import com.seibel.distanthorizons.coreapi.ModInfo; import org.jetbrains.annotations.NotNull; import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepBiomes; @@ -86,6 +91,11 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm .fileLevelConfig(Config.Common.Logging.logWorldGenEventToFile) .build(); + public static final DhLogger RATE_LIMITED_LOGGER = new DhLoggerBuilder() + .name("LOD World Gen") + .maxCountPerSecond(1) + .build(); + @NotNull public static final ImmutableMap WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP; public static final int MAX_WORLD_GEN_CHUNK_BORDER_NEEDED; @@ -284,6 +294,14 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // We handle this later, although that handling would need to change if the gen size ever changes. LodUtil.assertTrue(genEvent.widthInChunks % 2 == 0, "Generation events are expected to be an evan number of chunks wide."); + if (!DhApi.isDhThread() + && ModInfo.IS_DEV_BUILD) + { + throw new IllegalStateException("Batch world generation should be called from one of DH's world gen thread. Current thread: ["+Thread.currentThread().getName()+"]"); + } + + + int borderSize = MAX_WORLD_GEN_CHUNK_BORDER_NEEDED; // genEvent.size - 1 converts the even width size to an odd number for MC compatability int refSize = (genEvent.widthInChunks - 1) + (borderSize * 2); @@ -308,7 +326,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // futures to handle getting empty chunks CompletableFuture[] readFutures = // the extra radius of 8 is to account for structure references which need a chunk radius of 8 - ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 8) + ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 8)// TODO .map((chunkPos) -> this.chunkFileReader.createEmptyOrPreExistingChunkAsync(chunkPos.x, chunkPos.z, chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, generatedChunkByDhPos)) .toArray(CompletableFuture[]::new); @@ -433,7 +451,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // submit generated chunks // //=========================// - Iterator iterator = ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); + Iterator iterator = ChunkPosGenStream.getIterator(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0); while (iterator.hasNext()) { ChunkPos pos = iterator.next(); @@ -478,7 +496,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm if (chunk instanceof ProtoChunk) { ProtoChunk protoChunk = ((ProtoChunk) chunk); - protoChunk.setLightEngine(region.getLightEngine()); } }); @@ -525,13 +542,13 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm return; } - throwIfThreadInterrupted(); - // caves can generally be ignored since they aren't generally visible from far away - if (step == EDhApiWorldGenerationStep.CARVERS) - { - return; - } - +// throwIfThreadInterrupted(); +// // caves can generally be ignored since they aren't generally visible from far away +// if (step == EDhApiWorldGenerationStep.CARVERS) +// { +// return; +// } + throwIfThreadInterrupted(); this.stepFeatures.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.FEATURES)); } @@ -574,6 +591,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm { DhLightingEngine.INSTANCE.bakeChunkBlockLighting(centerChunk, iChunkWrapperList, maxSkyLight); } +// centerChunk.setIsDhBlockLightCorrect(true); this.dhServerLevel.updateBeaconBeamsForChunk(centerChunk, iChunkWrapperList); } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ChunkPosGenStream.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ChunkPosGenStream.java index b923ff1a6..a4e92348c 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ChunkPosGenStream.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ChunkPosGenStream.java @@ -2,6 +2,7 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration; import net.minecraft.world.level.ChunkPos; +import java.util.Iterator; import java.util.Spliterator; import java.util.Spliterators; import java.util.function.Consumer; @@ -11,10 +12,13 @@ import java.util.stream.StreamSupport; public class ChunkPosGenStream { + public static Iterator getIterator(int genMinX, int genMinZ, int width, int extraRadius) + { return getStream(genMinX, genMinZ, width, extraRadius).iterator(); } /** @param extraRadius in both the positive and negative directions */ public static Stream getStream(int genMinX, int genMinZ, int width, int extraRadius) { return StreamSupport.stream(new InclusiveChunkPosIterator(genMinX, genMinZ, width, extraRadius), false); } - public static class InclusiveChunkPosIterator extends Spliterators.AbstractSpliterator + + private static class InclusiveChunkPosIterator extends Spliterators.AbstractSpliterator { private final int minX; private final int minZ; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java index 688688f88..46e0b2343 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java @@ -107,6 +107,13 @@ public class ChunkFileReader implements AutoCloseable ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); DhChunkPos dhChunkPos = new DhChunkPos(chunkX, chunkZ); +// if (true) +// { +// ChunkAccess newChunk = CreateEmptyChunk(this.params.level, chunkPos); +// generatedChunkByDhPos.put(dhChunkPos, newChunk); +// return CompletableFuture.completedFuture(newChunk); +// } + if (generatedChunkByDhPos.containsKey(dhChunkPos)) { return CompletableFuture.completedFuture(generatedChunkByDhPos.get(dhChunkPos)); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java index 3c0f88947..e8f2269dd 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java @@ -1,19 +1,24 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.internalServer; +import com.seibel.distanthorizons.api.DhApi; +import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.ChunkPosGenStream; import com.seibel.distanthorizons.common.wrappers.worldGeneration.GenerationEvent; import com.seibel.distanthorizons.common.wrappers.worldGeneration.GlobalWorldGenParams; +import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.generation.DhLightingEngine; import com.seibel.distanthorizons.core.level.IDhServerLevel; import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; -import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.util.ExceptionUtil; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor; +import com.seibel.distanthorizons.coreapi.ModInfo; import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ChunkLevel; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.TicketType; import net.minecraft.world.level.ChunkPos; @@ -23,8 +28,6 @@ import net.minecraft.world.level.chunk.status.ChunkStatus; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; import java.util.function.Function; public class InternalServerGenerator @@ -39,6 +42,8 @@ public class InternalServerGenerator .fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile) .build(); + private static final IC2meAccessor C2ME_ACCESSOR = ModAccessorInjector.INSTANCE.get(IC2meAccessor.class); + #if MC_VER < MC_1_21_5 private static final TicketType DH_SERVER_GEN_TICKET = TicketType.create("dh_server_gen_ticket", Comparator.comparingLong(ChunkPos::toLong)); #elif MC_VER < MC_1_21_9 @@ -47,6 +52,8 @@ public class InternalServerGenerator private static final TicketType DH_SERVER_GEN_TICKET = new TicketType(/* timeout, 0 = disabled*/0L, /* flags */TicketType.FLAG_LOADING); #endif + private static boolean c2meMissingWarningLogged = false; + private final GlobalWorldGenParams params; private final IDhServerLevel dhServerLevel; @@ -69,183 +76,197 @@ public class InternalServerGenerator // generation // //============// - public void generateChunksViaInternalServer(GenerationEvent genEvent) throws InterruptedException + public void generateChunksViaInternalServer(GenerationEvent genEvent) { - LinkedBlockingQueue runnableQueue = new LinkedBlockingQueue<>(); + this.runValidation(); - Map chunkWrappersByDhPos = Collections.synchronizedMap(new HashMap<>()); - - - - //===================================// - // create generation queue runnables // - //===================================// - - // request each chunk pos from the server - CompletableFuture[] requestFutures = - ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0) - .map(chunkPos -> - { - return requestChunkFromServerAsync(this.params.level, chunkPos, true) - .whenCompleteAsync((chunk, throwable) -> - { - // unwrap the CompletionException if necessary - Throwable actualThrowable = throwable; - while (actualThrowable instanceof CompletionException) - { - actualThrowable = actualThrowable.getCause(); - } - - if (throwable != null) - { - CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load chunk [" + chunkPos + "] from server, error: [" + actualThrowable.getMessage() + "].", actualThrowable); - } - - if (chunk != null) - { - ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper()); - chunkWrappersByDhPos.put(new DhChunkPos(chunkPos.x, chunkPos.z), chunkWrapper); - } - }, runnableQueue::add); - }) - .toArray(CompletableFuture[]::new); - - // handle each generated chunk - CompletableFuture processGeneratedChunksFuture = - CompletableFuture.allOf(requestFutures) - .whenCompleteAsync((voidObj, throwable) -> - { - // generate chunk lighting using DH's lighting engine - int maxSkyLight = this.dhServerLevel.getServerLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT; - - ArrayList generatedChunks = new ArrayList<>(chunkWrappersByDhPos.values()); - for (IChunkWrapper iChunkWrapper : generatedChunks) - { - ((ChunkWrapper) iChunkWrapper).recalculateDhHeightMapsIfNeeded(); - - // pre-generated chunks should have lighting but new ones won't - if (!iChunkWrapper.isDhBlockLightingCorrect()) - { - DhLightingEngine.INSTANCE.bakeChunkBlockLighting(iChunkWrapper, generatedChunks, maxSkyLight); - } - - this.dhServerLevel.updateBeaconBeamsForChunk(iChunkWrapper, generatedChunks); - } - - for (IChunkWrapper iChunkWrapper : generatedChunks) - { - genEvent.resultConsumer.accept(iChunkWrapper); - } - }, runnableQueue::add) - .whenCompleteAsync((unused, throwable) -> - { - // cleanup - // release the generated chunks - - Iterator iterator = ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); - while (iterator.hasNext()) - { - ChunkPos chunkPos = iterator.next(); - releaseChunkFromServer(this.params.level, chunkPos, true); - } - }); - - processGeneratedChunksFuture.whenCompleteAsync((unused, throwable) -> { }, runnableQueue::add); // trigger wakeup - - - - //===============// - // run each step // - //===============// - - while (!processGeneratedChunksFuture.isDone()) + try { - try + //=====================// + // create gen requests // + //=====================// + + ArrayList> getChunkFutureList = new ArrayList<>(); { - Runnable command = runnableQueue.poll(1, TimeUnit.SECONDS); - if (command != null) + Iterator chunkPosIterator = ChunkPosGenStream.getIterator(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0); + while (chunkPosIterator.hasNext()) { - command.run(); + ChunkPos chunkPos = chunkPosIterator.next(); + + CompletableFuture requestChunkFuture = + this.requestChunkFromServerAsync(chunkPos) + // log errors if necessary + .whenCompleteAsync( + (chunk, throwable) -> + { + // unwrap the CompletionException if necessary + Throwable actualThrowable = throwable; + while (actualThrowable instanceof CompletionException) + { + actualThrowable = actualThrowable.getCause(); + } + + if (actualThrowable != null) + { + // ignore expected shutdown exceptions + boolean isShutdownException = + ExceptionUtil.isShutdownException(actualThrowable) + || actualThrowable.getMessage().contains("Unloaded chunk"); + if (!isShutdownException) + { + CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load chunk [" + chunkPos + "] from server, error: [" + actualThrowable.getMessage() + "].", actualThrowable); + } + } + }); + + getChunkFutureList.add(requestChunkFuture); } } - catch (InterruptedException e) + + + + //==============================// + // wait for generation requests // + //==============================// + + // Join-ing each thread will prevent DH from working on anything else + // but will also prevent over-queuing world gen tasks. + // If C2ME is present the CPU will still be well utilized. + + ArrayList chunkWrappers = new ArrayList<>(); + for (int i = 0; i < getChunkFutureList.size(); i++) { - // interrupted, release chunk to server - Iterator iterator = ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0).iterator(); - while (iterator.hasNext()) + CompletableFuture getChunkFuture = getChunkFutureList.get(i); + ChunkAccess chunk = getChunkFuture.join(); + if (chunk != null) { - ChunkPos chunkPos = iterator.next(); - releaseChunkFromServer(this.params.level, chunkPos, true); + ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper()); + chunkWrappers.add(chunkWrapper); + } + } + + + + //==========================// + // process generated chunks // + //==========================// + + int maxSkyLight = this.dhServerLevel.getServerLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT; + for (int i = 0; i < chunkWrappers.size(); i++) + { + ChunkWrapper chunkWrapper = (ChunkWrapper)chunkWrappers.get(i); + chunkWrapper.recalculateDhHeightMapsIfNeeded(); + + // pre-generated chunks should have lighting but new ones won't + if (!chunkWrapper.isDhBlockLightingCorrect()) + { + DhLightingEngine.INSTANCE.bakeChunkBlockLighting(chunkWrapper, chunkWrappers, maxSkyLight); } - throw e; + this.dhServerLevel.updateBeaconBeamsForChunk(chunkWrapper, chunkWrappers); + genEvent.resultConsumer.accept(chunkWrapper); + } + } + finally + { + // release all chunks from the server to prevent out of memory issues + Iterator chunkPosIterator = ChunkPosGenStream.getIterator(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0); + while (chunkPosIterator.hasNext()) + { + ChunkPos chunkPos = chunkPosIterator.next(); + this.releaseChunkFromServer(this.params.level, chunkPos); } } } - /** @param generateUpToFeatures if false this generate the chunk up to "FULL" status */ - private static CompletableFuture requestChunkFromServerAsync(ServerLevel level, ChunkPos pos, boolean generateUpToFeatures) + private void runValidation() + { + // DH thread check + if (!DhApi.isDhThread() + && ModInfo.IS_DEV_BUILD) + { + throw new IllegalStateException("Internal server generation should be called from one of DH's world gen thread. Current thread: ["+Thread.currentThread().getName()+"]"); + } + + + // C2ME present? + if (C2ME_ACCESSOR == null + && !c2meMissingWarningLogged) + { + c2meMissingWarningLogged = true; + + String c2meWarning = "C2ME missing, \n" + + "low CPU usage and slow world gen speeds expected. \n" + + "DH is set to use MC's internal server for world gen \n" + + "this mode is less efficient unless a mod like C2ME is present." + ; + + if (Config.Common.Logging.Warning.showSlowWorldGenSettingWarnings.get()) + { + String message = + // orange text + "\u00A76" + "Distant Horizons: slow world gen." + "\u00A7r\n" + + c2meWarning; + ClientApi.INSTANCE.showChatMessageNextFrame(message); + } + + LOGGER.warn(c2meWarning); + } + } + private CompletableFuture requestChunkFromServerAsync(ChunkPos chunkPos) { return CompletableFuture.supplyAsync(() -> { - int chunkLevel; - #if MC_VER <= MC_1_19_4 - // 33 is equivalent to FULL Chunk - chunkLevel = generateUpToFeatures ? 33 + ChunkStatus.getDistance(ChunkStatus.FEATURES) : 33; - #else - // 33 is equivalent to FULL Chunk - chunkLevel = generateUpToFeatures ? ChunkLevel.byStatus(ChunkStatus.FEATURES) : 33; - #endif + ServerLevel level = this.params.level; #if MC_VER < MC_1_21_5 + int chunkLevel = 33; // 33 is equivalent to FULL Chunk level.getChunkSource().distanceManager.addTicket(DH_SERVER_GEN_TICKET, pos, chunkLevel, pos); #else - level.getChunkSource().addTicketWithRadius(DH_SERVER_GEN_TICKET, pos, 0); + level.getChunkSource().addTicketWithRadius(DH_SERVER_GEN_TICKET, chunkPos, 0); #endif - level.getChunkSource().distanceManager.runAllUpdates(level.getChunkSource().chunkMap); // probably not the most optimal to run updates here, but fast enough - ChunkHolder holder = level.getChunkSource().chunkMap.getUpdatingChunkIfPresent(pos.toLong()); - if (holder == null) + + // probably not the most optimal to run updates here, but fast enough + level.getChunkSource().distanceManager.runAllUpdates(level.getChunkSource().chunkMap); + + ChunkHolder chunkHolder = level.getChunkSource().chunkMap.getUpdatingChunkIfPresent(chunkPos.toLong()); + if (chunkHolder == null) { - throw new IllegalStateException("No chunk holder after ticket has been added"); + throw new IllegalStateException("No chunk chunkHolder for pos ["+chunkPos+"] after ticket has been added."); } #if MC_VER <= MC_1_20_4 - return holder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) + return chunkHolder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) .thenApply(result -> result.left().orElseThrow(() -> new RuntimeException(result.right().get().toString()))); // can throw if the server is shutting down #elif MC_VER <= MC_1_20_6 - return holder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) + return chunkHolder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) .thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.toString()))); // can throw if the server is shutting down #else - return holder.scheduleChunkGenerationTask(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) + return chunkHolder.scheduleChunkGenerationTask(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) .thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.getError()))); // can throw if the server is shutting down #endif - }, level.getChunkSource().chunkMap.mainThreadExecutor) - .thenCompose(Function.identity()); + }, this.params.level.getChunkSource().chunkMap.mainThreadExecutor) + .thenCompose(Function.identity()); } - /** @param chunkWasGeneratedUpToFeatures if false this assumes the chunk was generated to "FULL" status */ - private static void releaseChunkFromServer(ServerLevel level, ChunkPos pos, boolean chunkWasGeneratedUpToFeatures) + /** + * mitigates out of memory issues in the vanilla chunk system.
+ * See: https://github.com/pop4959/Chunky/pull/383 + */ + private void releaseChunkFromServer(ServerLevel level, ChunkPos pos) { level.getChunkSource().chunkMap.mainThreadExecutor.execute(() -> { try { - int chunkLevel; - #if MC_VER <= MC_1_19_4 - // 33 is equivalent to FULL Chunk - chunkLevel = chunkWasGeneratedUpToFeatures ? 33 + ChunkStatus.getDistance(ChunkStatus.FEATURES) : 33; - #else - // 33 is equivalent to FULL Chunk - chunkLevel = chunkWasGeneratedUpToFeatures ? ChunkLevel.byStatus(ChunkStatus.FEATURES) : 33; - #endif - #if MC_VER < MC_1_21_5 + int chunkLevel = 33; // 33 is equivalent to FULL Chunk level.getChunkSource().distanceManager.removeTicket(DH_SERVER_GEN_TICKET, pos, chunkLevel, pos); #else level.getChunkSource().removeTicketWithRadius(DH_SERVER_GEN_TICKET, pos, 0); #endif - // mitigate OOM issues in vanilla chunk system: see https://github.com/pop4959/Chunky/pull/383 level.getChunkSource().chunkMap.tick(() -> false); + #if MC_VER > MC_1_16_5 level.entityManager.tick(); #endif diff --git a/coreSubProjects b/coreSubProjects index 5a4ddafbb..19b23bea5 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 5a4ddafbbbd7f7b92f7cd64565f6008d5581fdc2 +Subproject commit 19b23bea5fae8efa10b0958e8cf4f89e21716698 diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java index a23e7b7dc..e2fec7267 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java @@ -47,8 +47,6 @@ import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; #endif -import javax.swing.*; -import java.awt.*; import java.util.function.Consumer; /** @@ -110,6 +108,7 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti this.tryCreateModCompatAccessor("starlight", IStarlightAccessor.class, StarlightAccessor::new); this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new); this.tryCreateModCompatAccessor("bclib", IBCLibAccessor.class, BCLibAccessor::new); + this.tryCreateModCompatAccessor("c2me", IC2meAccessor.class, C2meAccessor::new); #if MC_VER >= MC_1_19_4 // 1.19.4 is the lowest version Iris supports DH this.tryCreateModCompatAccessor("iris", IIrisAccessor.class, IrisAccessor::new); diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/C2meAccessor.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/C2meAccessor.java new file mode 100644 index 000000000..313e71ae7 --- /dev/null +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/C2meAccessor.java @@ -0,0 +1,32 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.fabric.wrappers.modAccessor; + +import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor; + +public class C2meAccessor implements IC2meAccessor +{ + @Override + public String getModName() + { + return "c2me"; + } + +} diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java index 37c56f8f6..8559b24d5 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java @@ -30,9 +30,11 @@ import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor; import com.seibel.distanthorizons.coreapi.ModInfo; +import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.C2meAccessor; import com.seibel.distanthorizons.neoforge.wrappers.NeoforgeMinecraftRenderWrapper; import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.ModChecker; import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.OptifineAccessor; @@ -144,6 +146,7 @@ public class NeoforgeMain extends AbstractModInitializer protected void initializeModCompat() { this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new); + this.tryCreateModCompatAccessor("c2me", IC2meAccessor.class, C2meAccessor::new); #if MC_VER < MC_1_20_6 ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/C2meAccessor.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/C2meAccessor.java new file mode 100644 index 000000000..85811c706 --- /dev/null +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/C2meAccessor.java @@ -0,0 +1,32 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.neoforge.wrappers.modAccessor; + +import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor; + +public class C2meAccessor implements IC2meAccessor +{ + @Override + public String getModName() + { + return "c2me"; + } + +} diff --git a/versionProperties/1.21.10.properties b/versionProperties/1.21.10.properties index 2b33746c4..209285e56 100644 --- a/versionProperties/1.21.10.properties +++ b/versionProperties/1.21.10.properties @@ -12,7 +12,7 @@ netty_version=4.1.97.Final # Fabric loader fabric_loader_version=0.17.3 -fabric_api_version=0.135.0+1.21.10 +fabric_api_version=0.138.3+1.21.10 modmenu_version=16.0.0-rc.1 starlight_version_fabric= phosphor_version_fabric= From af3a993042a35e24763fd86a2326574dc4cebb9b Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 27 Nov 2025 18:51:30 -0600 Subject: [PATCH 15/33] massively speed up pre-existing world importing --- .../BatchGenerationEnvironment.java | 97 ++- .../worldGeneration/ThreadWorldGenParams.java | 2 +- .../ChunkCompoundTagParser.java | 658 +++++++++--------- .../chunkFileHandling/ChunkFileReader.java | 13 +- .../chunkFileHandling/CompoundTagUtil.java | 11 + .../worldGeneration/step/StepFeatures.java | 1 - .../worldGeneration/step/StepNoise.java | 1 - .../step/StepStructureReference.java | 1 - .../worldGeneration/step/StepSurface.java | 1 - 9 files changed, 408 insertions(+), 377 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 369d657ab..590550713 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -37,10 +37,7 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.util.ExceptionUtil; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; -import com.seibel.distanthorizons.core.util.objects.RollingAverage; import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException; -import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker; -import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper; @@ -302,6 +299,10 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm + //================// + // variable setup // + //================// + int borderSize = MAX_WORLD_GEN_CHUNK_BORDER_NEEDED; // genEvent.size - 1 converts the even width size to an odd number for MC compatability int refSize = (genEvent.widthInChunks - 1) + (borderSize * 2); @@ -311,29 +312,75 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm LightGetterAdaptor lightGetterAdaptor = new LightGetterAdaptor(this.params.level); DummyLightEngine dummyLightEngine = new DummyLightEngine(lightGetterAdaptor); - - - //====================================// - // offset and generate odd width area // - //====================================// - // reused data between each offset Map chunkSkyLightingByDhPos = Collections.synchronizedMap(new HashMap<>()); Map chunkBlockLightingByDhPos = Collections.synchronizedMap(new HashMap<>()); Map generatedChunkByDhPos = Collections.synchronizedMap(new HashMap<>()); Map chunkWrappersByDhPos = Collections.synchronizedMap(new HashMap<>()); - // futures to handle getting empty chunks - CompletableFuture[] readFutures = - // the extra radius of 8 is to account for structure references which need a chunk radius of 8 - ChunkPosGenStream.getStream(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 8)// TODO - .map((chunkPos) -> this.chunkFileReader.createEmptyOrPreExistingChunkAsync(chunkPos.x, chunkPos.z, chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, generatedChunkByDhPos)) - .toArray(CompletableFuture[]::new); - // join to prevent an issue where DH queues too many tasks or something(?) - // also allows file IO to run in parallel so no one thread is waiting on disk IO (this is only an issue when C2ME is present) - CompletableFuture.allOf(readFutures).join(); + //================================// + // read existing chunks from file // + //================================// + + HashMap> readFutureByDhChunkPos = new HashMap<>(); + + Iterator existingChunkPosIterator = ChunkPosGenStream.getIterator( + genEvent.minPos.getX(), genEvent.minPos.getZ(), + genEvent.widthInChunks, + // 0 radius -> only pull existing chunks from disk + 0); + while (existingChunkPosIterator.hasNext()) + { + ChunkPos chunkPos = existingChunkPosIterator.next(); + DhChunkPos dhChunkPos = new DhChunkPos(chunkPos.x, chunkPos.z); + + CompletableFuture getExistingChunkFuture + // running async allows file IO to run in parallel when C2ME is present + = this.chunkFileReader.createEmptyOrPreExistingChunkAsync( + chunkPos.x, chunkPos.z, + chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, generatedChunkByDhPos); + + readFutureByDhChunkPos.put(dhChunkPos, getExistingChunkFuture); + } + + // normally DH will handle each of these futures serially + // but if C2ME is present these will be completed in parallel + for (CompletableFuture readChunkFuture : readFutureByDhChunkPos.values()) + { + readChunkFuture.join(); + } + + + + //===================================// + // create empty chunks for world gen // + //===================================// + + Iterator emptyChunkPosIterator = ChunkPosGenStream.getIterator( + genEvent.minPos.getX(), genEvent.minPos.getZ(), + genEvent.widthInChunks, + // the extra radius of 8 is to account for structure references which need a chunk radius of 8 + 8); + while (emptyChunkPosIterator.hasNext()) + { + ChunkPos chunkPos = emptyChunkPosIterator.next(); + DhChunkPos dhChunkPos = new DhChunkPos(chunkPos.x, chunkPos.z); + + // create empty chunks outside the generation radius + if (!readFutureByDhChunkPos.containsKey(dhChunkPos)) + { + ChunkAccess chunk = ChunkFileReader.CreateEmptyChunk(this.params.level, chunkPos); + generatedChunkByDhPos.put(dhChunkPos, chunk); + } + } + + + + //=================// + // generate chunks // + //=================// try { @@ -358,14 +405,14 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm int centerZ = refPosZ + radius + zOffset; // get/create the list of chunks we're going to generate - IEmptyChunkRetrievalFunc fallbackFunc = - (chunkPosX, chunkPosZ) -> Objects.requireNonNull( - generatedChunkByDhPos.get(new DhChunkPos(chunkPosX, chunkPosZ)), - () -> String.format("Requested chunk [%d, %d] unavailable during world generation", chunkPosX, chunkPosZ)); + IEmptyChunkRetrievalFunc fallbackChunkGetterFunc = + (chunkPosX, chunkPosZ) -> Objects.requireNonNull( + generatedChunkByDhPos.get(new DhChunkPos(chunkPosX, chunkPosZ)), + () -> String.format("Requested chunk [%d, %d] unavailable during world generation", chunkPosX, chunkPosZ)); ArrayGridList regionChunks = new ArrayGridList<>( refSize, - (relX, relZ) -> fallbackFunc.getChunk( + (relX, relZ) -> fallbackChunkGetterFunc.getChunk( relX + refPosX + xOffsetFinal, relZ + refPosZ + zOffsetFinal)); @@ -381,10 +428,10 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm ChunkStatus.STRUCTURE_STARTS, radius, // this method shouldn't be necessary since we're passing in a pre-populated // list of chunks, but just in case - fallbackFunc + fallbackChunkGetterFunc ); lightGetterAdaptor.setRegion(region); - genEvent.threadedParam.makeStructFeat(region, this.params); + genEvent.threadedParam.makeStructFeatManager(region, this.params); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java index 60cf1b698..cd54bac95 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java @@ -89,7 +89,7 @@ public final class ThreadWorldGenParams // builders // //==========// - public void makeStructFeat(WorldGenLevel genLevel, GlobalWorldGenParams param) + public void makeStructFeatManager(WorldGenLevel genLevel, GlobalWorldGenParams param) { #if MC_VER < MC_1_18_2 this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java index d7b73644c..652096195 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java @@ -88,32 +88,16 @@ import net.minecraft.world.level.material.Fluid; public class ChunkCompoundTagParser { - private static final AtomicBoolean ZERO_CHUNK_POS_ERROR_LOGGED_REF = new AtomicBoolean(false); - public static final DhLogger LOGGER = new DhLoggerBuilder() .name("LOD Chunk Reader") .fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile) .build(); - - #if MC_VER >= MC_1_21_9 - // BLOCK_STATE_CODEC can no longer be statically created since - // it needs a level reference - #elif MC_VER >= MC_1_19_2 - private static final Codec> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); - #elif MC_VER >= MC_1_18_2 - private static final Codec> BLOCK_STATE_CODEC = PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); - #endif - - private static final String TAG_UPGRADE_DATA = "UpgradeData"; - private static final String BLOCK_TICKS_TAG_18 = "block_ticks"; - private static final String FLUID_TICKS_TAG_18 = "fluid_ticks"; - private static final String BLOCK_TICKS_TAG_PRE18 = "TileTicks"; - private static final String FLUID_TICKS_TAG_PRE18 = "LiquidTicks"; + private static final AtomicBoolean ZERO_CHUNK_POS_ERROR_LOGGED_REF = new AtomicBoolean(false); + private static final ConcurrentHashMap LOGGED_ERROR_MESSAGE_MAP = new ConcurrentHashMap<>(); private static boolean lightingSectionErrorLogged = false; - private static final ConcurrentHashMap LOGGED_ERROR_MESSAGE_MAP = new ConcurrentHashMap<>(); @@ -129,11 +113,18 @@ public class ChunkCompoundTagParser CompoundTag tagLevel = chunkData; #endif + + + //=======================// + // validate the chunkPos // + //=======================// + int chunkX = CompoundTagUtil.getInt(tagLevel,"xPos"); int chunkZ = CompoundTagUtil.getInt(tagLevel, "zPos"); - ChunkPos actualPos = new ChunkPos(chunkX, chunkZ); + ChunkPos actualChunkPos = new ChunkPos(chunkX, chunkZ); - if (!Objects.equals(chunkPos, actualPos)) + // confirm chunk pos is correct + if (!Objects.equals(chunkPos, actualChunkPos)) { if (chunkX == 0 && chunkZ == 0) { @@ -144,19 +135,27 @@ public class ChunkCompoundTagParser "This might happen if the world was created using an external program. \n" + "DH will attempt to parse the chunk anyway and won't log this message again.\n" + "If issues arise please try optimizing your world to fix this issue. \n" + - "World optimization can be done from the singleplayer world selection screen."+ - ""); + "World optimization can be done from the singleplayer world selection screen." + + " "); } } else { - // everything is on one line to fix a JDK 17 compiler issue - // if the issue is ever resolved, feel free to make this multi-line for readability - LOGGER.error("Chunk file at ["+chunkPos.toString()+"] is in the wrong location. \nPlease try optimizing your world to fix this issue. \nWorld optimization can be done from the singleplayer world selection screen. \n(Expected pos: ["+chunkPos.toString()+"], actual ["+actualPos.toString()+"])"); + LOGGER.error("Chunk file at ["+chunkPos.toString()+"] is in the wrong location. \n" + + "Please try optimizing your world to fix this issue. \n" + + "World optimization can be done from the singleplayer world selection screen. \n" + + "(Expected pos: ["+chunkPos.toString()+"], actual ["+actualChunkPos.toString()+"])" + + " "); return null; } } + + + //==========================// + // ignore incomplete chunks // + //==========================// + #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType chunkType; #else @@ -169,277 +168,90 @@ public class ChunkCompoundTagParser { return null; } - #elif MC_VER < MC_1_21_6 - - BlendingData blendingData = readBlendingData(tagLevel); - #if MC_VER < MC_1_19_2 - if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || !blendingData.oldNoise())) - { - return null; - } - #else - if (chunkType == #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType.PROTOCHUNK #else ChunkType.PROTOCHUNK #endif && blendingData == null) - { - return null; - } - #endif - + #elif MC_VER < MC_1_19_2 + if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK) + { + return null; + } #else - - // ignore blending data, there appears to be an issue with parsing it in 1.21.6 - BlendingData blendingData = null; - if (chunkType == ChunkType.PROTOCHUNK) { return null; } #endif - long inhabitedTime = CompoundTagUtil.getLong(tagLevel, "InhabitedTime"); - - //================== Read params for making the LevelChunk ================== - - UpgradeData upgradeData = UpgradeData.EMPTY; - // commented out 2025-06-04 as a test to see if the upgrade data - // is actually necessary for DH or if it can be ignored - // (if it can't be ignored we'll need to handle null responses from CompoundTagUtil.getCompoundTag()) - // - //#if MC_VER < MC_1_17_1 - //upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10) - // ? new UpgradeData(CompoundTagUtil.getCompoundTag(tagLevel, TAG_UPGRADE_DATA)) - // : UpgradeData.EMPTY; - //#elif MC_VER < MC_1_21_5 - //upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10) - // ? new UpgradeData(CompoundTagUtil.getCompoundTag(tagLevel, TAG_UPGRADE_DATA), level) - // : UpgradeData.EMPTY; - //#else - //upgradeData = tagLevel.contains(TAG_UPGRADE_DATA) - // ? new UpgradeData(CompoundTagUtil.getCompoundTag(tagLevel, TAG_UPGRADE_DATA), level) - // : UpgradeData.EMPTY; - //#endif - boolean isLightOn = CompoundTagUtil.getBoolean(tagLevel, "isLightOn"); + //===========// + // get ticks // + //===========// + #if MC_VER < MC_1_18_2 ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer( - level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY)#if MC_VER >= MC_1_17_1 , level #endif , + level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), #if MC_VER >= MC_1_17_1 level, #endif chunkPos, level.getLevel().getChunkSource().getGenerator().getBiomeSource(), tagLevel.contains("Biomes", 11) ? tagLevel.getIntArray("Biomes") : null); + String BLOCK_TICKS_TAG_PRE18 = "TileTicks"; TickList blockTicks = tagLevel.contains(BLOCK_TICKS_TAG_PRE18, 9) ? ChunkTickList.create(tagLevel.getList(BLOCK_TICKS_TAG_PRE18, 10), Registry.BLOCK::getKey, Registry.BLOCK::get) : new ProtoTickList(block -> (block == null || block.defaultBlockState().isAir()), chunkPos, - tagLevel.getList("ToBeTicked", 9)#if MC_VER >= MC_1_17_1 , level #endif ); + tagLevel.getList("ToBeTicked", 9) #if MC_VER >= MC_1_17_1 , level #endif ); + String FLUID_TICKS_TAG_PRE18 = "LiquidTicks"; TickList fluidTicks = tagLevel.contains(FLUID_TICKS_TAG_PRE18, 9) ? ChunkTickList.create(tagLevel.getList(FLUID_TICKS_TAG_PRE18, 10), Registry.FLUID::getKey, Registry.FLUID::get) : new ProtoTickList(fluid -> (fluid == null || fluid == Fluids.EMPTY), chunkPos, - tagLevel.getList("LiquidsToBeTicked", 9)#if MC_VER >= MC_1_17_1 , level #endif ); + tagLevel.getList("LiquidsToBeTicked", 9) #if MC_VER >= MC_1_17_1 , level #endif ); #else - #if MC_VER < MC_1_19_4 - LevelChunkTicks blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10), - string -> Registry.BLOCK.getOptional(ResourceLocation.tryParse(string)), chunkPos); - LevelChunkTicks fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10), - string -> Registry.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos); - #elif MC_VER < MC_1_21_4 - LevelChunkTicks blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10), - (string -> BuiltInRegistries.BLOCK.getOptional(ResourceLocation.tryParse(string))), chunkPos); - LevelChunkTicks fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10), - string -> BuiltInRegistries.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos); - #else - // do we need the ticks for what we're doing? - LevelChunkTicks blockTicks = new LevelChunkTicks<>(); - LevelChunkTicks fluidTicks = new LevelChunkTicks<>(); - #endif + // ticks shouldn't be needed so ignore them for MC versions after 1.18.2 + LevelChunkTicks blockTicks = new LevelChunkTicks<>(); + LevelChunkTicks fluidTicks = new LevelChunkTicks<>(); #endif + + + //=====================// + // get misc properties // + //=====================// + LevelChunkSection[] levelChunkSections = readSections(level, chunkPos, tagLevel); + long inhabitedTime = CompoundTagUtil.getLong(tagLevel, "InhabitedTime"); + boolean isLightOn = CompoundTagUtil.getBoolean(tagLevel, "isLightOn"); + + + + //============// + // make chunk // + //============// - // ====================== Make the chunk ========================= #if MC_VER < MC_1_18_2 - LevelChunk chunk = new LevelChunk((Level) level.getLevel(), chunkPos, chunkBiomeContainer, upgradeData, blockTicks, + LevelChunk chunk = new LevelChunk((Level) level.getLevel(), chunkPos, chunkBiomeContainer, UpgradeData.EMPTY, blockTicks, fluidTicks, inhabitedTime, levelChunkSections, null); #else - LevelChunk chunk = new LevelChunk((Level) level, chunkPos, upgradeData, blockTicks, - fluidTicks, inhabitedTime, levelChunkSections, null, blendingData); + LevelChunk chunk = new LevelChunk((Level) level, chunkPos, UpgradeData.EMPTY, blockTicks, + fluidTicks, inhabitedTime, levelChunkSections, null, null); #endif + // Set some states after object creation chunk.setLightCorrect(isLightOn); readHeightmaps(chunk, chunkData); - //readPostPocessings(chunk, chunkData); + return chunk; } - private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData) - { - #if MC_VER < MC_1_21_9 - // BLOCK_STATE_CODEC is created statically - // TODO clean up this code separation - #else - final Codec> BLOCK_STATE_CODEC = PalettedContainerFactory.create(level.registryAccess()).blockStatesContainerCodec(); - #endif - - - #if MC_VER >= MC_1_18_2 - #if MC_VER < MC_1_19_4 - Registry biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); - #elif MC_VER < MC_1_21_3 - Registry biomes = level.registryAccess().registryOrThrow(Registries.BIOME); - #else - Registry biomes = level.registryAccess().lookupOrThrow(Registries.BIOME); - #endif - #if MC_VER < MC_1_18_2 - Codec> biomeCodec = PalettedContainer.codec( - biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS)); - #elif MC_VER < MC_1_19_2 - Codec>> biomeCodec = PalettedContainer.codec( - biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS)); - #elif MC_VER < MC_1_21_3 - Codec>> biomeCodec = PalettedContainer.codecRW( - biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS)); - #elif MC_VER < MC_1_21_9 - Codec>> biomeCodec = PalettedContainer.codecRW( - biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS)); - #else - Codec>> biomeCodec = PalettedContainer.codecRW( - biomes.holderByNameCodec(), PalettedContainerFactory.create(level.registryAccess()).biomeStrategy(), biomes.getOrThrow(Biomes.PLAINS)); - #endif - #endif - - int sectionYIndex = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif - LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYIndex]; - - ListTag tagSections = CompoundTagUtil.getListTag(chunkData, "Sections", 10); - if (tagSections == null || tagSections.isEmpty()) - { - tagSections = CompoundTagUtil.getListTag(chunkData, "sections", 10); - } - - - if (tagSections != null) - { - for (int j = 0; j < tagSections.size(); ++j) - { - CompoundTag tagSection = CompoundTagUtil.getCompoundTag(tagSections, j); - if (tagSection == null) - { - continue; - } - - final int sectionYPos = CompoundTagUtil.getByte(tagSection, "Y"); - - #if MC_VER < MC_1_18_2 - if (tagSection.contains("Palette", 9) && tagSection.contains("BlockStates", 12)) - { - LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4); - levelChunkSection.getStates().read(tagSection.getList("Palette", 10), - tagSection.getLongArray("BlockStates")); - levelChunkSection.recalcBlockCounts(); - if (!levelChunkSection.isEmpty()) - chunkSections[#if MC_VER < MC_1_17_1 sectionYPos #else level.getSectionIndexFromSectionY(sectionYPos) #endif ] - = levelChunkSection; - } - #else - int sectionId = level.getSectionIndexFromSectionY(sectionYPos); - if (sectionId >= 0 && sectionId < chunkSections.length) - { - PalettedContainer blockStateContainer; - #if MC_VER < MC_1_18_2 - PalettedContainer biomeContainer; - #else - PalettedContainer> biomeContainer; - #endif - - - boolean containsBlockStates; - #if MC_VER < MC_1_21_5 - containsBlockStates = tagSection.contains("block_states", 10); - #else - containsBlockStates = tagSection.contains("block_states"); - #endif - - if (containsBlockStates) - { - #if MC_VER < MC_1_20_6 - blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "block_states")) - .promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string)) - .getOrThrow(false, (message) -> logParsingWarningOnce(message)); - #else - blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "block_states")) - .promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string)) - .getOrThrow((message) -> logErrorAndReturnException(message)); - #endif - } - else - { - #if MC_VER < MC_1_21_9 - blockStateContainer = new PalettedContainer(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - #else - blockStateContainer = PalettedContainerFactory.create(level.registryAccess()).createForBlockStates(); - #endif - } - - - #if MC_VER < MC_1_18_2 - biomeContainer = tagSection.contains("biomes", 10) - ? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, (message) -> logWarningOnce(message)) - : new PalettedContainer(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); - #else - - - boolean containsBiomes; - #if MC_VER < MC_1_21_5 - containsBiomes = tagSection.contains("biomes", 10); - #else - containsBiomes = tagSection.contains("biomes"); - #endif - - if (containsBiomes) - { - #if MC_VER < MC_1_20_6 - biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "biomes")) - .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) - .getOrThrow(false, (message) -> logParsingWarningOnce(message)); - #else - biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "biomes")) - .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) - .getOrThrow((message) -> logErrorAndReturnException(message)); - #endif - } - else - { - #if MC_VER < MC_1_21_3 - biomeContainer = new PalettedContainer>( - biomes.asHolderIdMap(), - biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); - #elif MC_VER < MC_1_21_9 - biomeContainer = new PalettedContainer>(biomes.asHolderIdMap(), - biomes.getOrThrow(Biomes.PLAINS), - PalettedContainer.Strategy.SECTION_BIOMES); - #else - biomeContainer = PalettedContainerFactory.create(level.registryAccess()).createForBiomes(); - #endif - - } - - #endif - - #if MC_VER < MC_1_20_1 - chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer); - #else - chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer); - #endif - } - #endif - - } - } - return chunkSections; - } + + + + //==========================// + // chunk type // + // (incomplete chunk check) // + //==========================// + private static #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType #elif MC_VER < MC_1_21_1 ChunkType - #else ChunkType #endif - readChunkType(CompoundTag tagLevel) + #else ChunkType #endif + readChunkType(CompoundTag tagLevel) { String statusString = CompoundTagUtil.getString(tagLevel,"Status"); if (statusString != null) @@ -457,104 +269,277 @@ public class ChunkCompoundTagParser return ChunkType.PROTOCHUNK; #endif } + + + + //=================// + // chunk sections // + // (Blocks/biomes) // + //=================// + + /** handles both blocks and biomes */ + private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData) + { + int sectionYIndex = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif + LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYIndex]; + + ListTag tagSections = CompoundTagUtil.getListTag(chunkData, "Sections", 10); + // try lower-case "sections" if capital "Sections" is missing + if (tagSections == null + || tagSections.isEmpty()) + { + tagSections = CompoundTagUtil.getListTag(chunkData, "sections", 10); + } + + + if (tagSections != null) + { + for (int j = 0; j < tagSections.size(); ++j) + { + CompoundTag tagSection = CompoundTagUtil.getCompoundTag(tagSections, j); + if (tagSection == null) + { + continue; + } + + final int sectionYPos = CompoundTagUtil.getByte(tagSection, "Y"); + + + + //===================// + // get blocks/biomes // + //===================// + + #if MC_VER < MC_1_18_2 + if (tagSection.contains("Palette", 9) + && tagSection.contains("BlockStates", 12)) + { + LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4); + levelChunkSection.getStates().read(tagSection.getList("Palette", 10), tagSection.getLongArray("BlockStates")); + levelChunkSection.recalcBlockCounts(); + if (!levelChunkSection.isEmpty()) + { + int sectionIndex; + #if MC_VER < MC_1_17_1 + sectionIndex = sectionYPos; + #else + sectionIndex = level.getSectionIndexFromSectionY(sectionYPos); + #endif + + chunkSections[sectionIndex] = levelChunkSection; + } + } + + #else + + int sectionId = level.getSectionIndexFromSectionY(sectionYPos); + if (sectionId >= 0 + && sectionId < chunkSections.length) + { + //========// + // blocks // + //========// + + PalettedContainer blockStateContainer; + + boolean containsBlockStates = CompoundTagUtil.contains(tagSection, "block_states", 10); + if (containsBlockStates) + { + Codec> blockStateCodec = getBlockStateCodec(level); + + #if MC_VER < MC_1_20_6 + blockStateContainer = blockStateCodec + .parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "block_states")) + .promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string)) + .getOrThrow(false, (message) -> logParsingWarningOnce(message)); + #else + blockStateContainer = blockStateCodec + .parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "block_states")) + .promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string)) + .getOrThrow((message) -> logErrorAndReturnException(message)); + #endif + } + else + { + #if MC_VER < MC_1_21_9 + blockStateContainer = new PalettedContainer(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + #else + blockStateContainer = PalettedContainerFactory.create(level.registryAccess()).createForBlockStates(); + #endif + } + + + + //========// + // biomes // + //========// + + Registry biomeRegistry = getBiomeRegistry(level); + + #if MC_VER < MC_1_18_2 + Codec> biomeCodec; + #else + Codec>> biomeCodec; + #endif + biomeCodec = getBiomeCodec(level, biomeRegistry); + + #if MC_VER < MC_1_18_2 + PalettedContainer biomeContainer; + #else + PalettedContainer> biomeContainer; + #endif + + #if MC_VER < MC_1_18_2 + biomeContainer = tagSection.contains("biomeRegistry", 10) + ? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomeRegistry")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, (message) -> logWarningOnce(message)) + : new PalettedContainer(biomeRegistry, biomeRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); + #else + { + CompoundTag biomeTag = CompoundTagUtil.getCompoundTag(tagSection, "biomeRegistry"); + if (biomeTag == null) + { + biomeTag = CompoundTagUtil.getCompoundTag(tagSection, "biomes"); + } + + if (biomeTag != null) + { + #if MC_VER < MC_1_20_6 + biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, biomeTag) + .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) + .getOrThrow(false, (message) -> logParsingWarningOnce(message)); + #else + biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, biomeTag) + .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) + .getOrThrow((message) -> logErrorAndReturnException(message)); + #endif + } + else + { + // no biomes found, use the default (probably plains) + + #if MC_VER < MC_1_21_3 + biomeContainer = new PalettedContainer>( + biomeRegistry.asHolderIdMap(), + biomeRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); + #elif MC_VER < MC_1_21_9 + biomeContainer = new PalettedContainer>(biomeRegistry.asHolderIdMap(), + biomeRegistry.getOrThrow(Biomes.PLAINS), + PalettedContainer.Strategy.SECTION_BIOMES); + #else + biomeContainer = PalettedContainerFactory.create(level.registryAccess()).createForBiomes(); + #endif + } + } + #endif + + #if MC_VER < MC_1_20_1 + chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer); + #else + chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer); + #endif + } + #endif + + } + } + + return chunkSections; + } + + private static Codec> getBlockStateCodec(LevelAccessor level) + { + #if MC_VER <= MC_1_18_2 + return PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); + #elif MC_VER <= MC_1_19_2 + return PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); + #else + return PalettedContainerFactory.create(level.registryAccess()).blockStatesContainerCodec(); + #endif + } + + private static Registry getBiomeRegistry(LevelAccessor level) + { + #if MC_VER < MC_1_18_2 + // not needed + return null; + #elif MC_VER < MC_1_19_4 + return level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); + #elif MC_VER < MC_1_21_3 + return level.registryAccess().registryOrThrow(Registries.BIOME); + #else + return level.registryAccess().lookupOrThrow(Registries.BIOME); + #endif + } + private static + #if MC_VER < MC_1_18_2 Codec> + #else Codec>> + #endif + getBiomeCodec(LevelAccessor level, Registry biomeRegistry) + { + #if MC_VER < MC_1_18_2 + Codec> biomeCodec = PalettedContainer.codec( + biomeRegistry, biomeRegistry.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getOrThrow(Biomes.PLAINS)); + #elif MC_VER < MC_1_19_2 + return PalettedContainer.codec( + biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getHolderOrThrow(Biomes.PLAINS)); + #elif MC_VER < MC_1_21_3 + return PalettedContainer.codecRW( + biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getHolderOrThrow(Biomes.PLAINS)); + #elif MC_VER < MC_1_21_9 + return PalettedContainer.codecRW( + biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getOrThrow(Biomes.PLAINS)); + #else + return PalettedContainer.codecRW( + biomeRegistry.holderByNameCodec(), PalettedContainerFactory.create(level.registryAccess()).biomeStrategy(), biomeRegistry.getOrThrow(Biomes.PLAINS)); + #endif + } + + + + //============// + // heightmaps // + //============// + private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData) { CompoundTag tagHeightmaps = CompoundTagUtil.getCompoundTag(chunkData, "Heightmaps"); - if (tagHeightmaps != null) + if (tagHeightmaps == null) { - for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter()) - { - String heightmap = type.getSerializationKey(); - #if MC_VER < MC_1_21_5 - if (tagHeightmaps.contains(heightmap, 12)) - { - chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap)); - } - #else - if (tagHeightmaps.contains(heightmap)) - { - Optional optionalHeightmap = tagHeightmaps.getLongArray(heightmap); - if (optionalHeightmap.isPresent()) - { - chunk.setHeightmap(type, optionalHeightmap.get()); - } - } - #endif - } - - Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter()); + return; } - } - // commented out as a test as of 2025-06-04 to see if this is actually necessary for DH - // DH probably doesn't need any chunk post-processing data - //private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData) - //{ - // ListTag tagPostProcessings = CompoundTagUtil.getListTag(chunkData,"PostProcessing", 9); - // if (tagPostProcessings != null) - // { - // for (int i = 0; i < tagPostProcessings.size(); ++i) - // { - // ListTag listTag3 = CompoundTagUtil.getListTag(tagPostProcessings, i); - // for (int j = 0; j < listTag3.size(); ++j) - // { - // #if MC_VER < MC_1_21_3 - // chunk.addPackedPostProcess(listTag3.getShort(j), i); - // #else - // chunk.addPackedPostProcess(ShortList.of(CompoundTagUtil.getShort(listTag3, j)), i); - // #endif - // } - // } - // } - //} - #if MC_VER >= MC_1_18_2 - private static BlendingData readBlendingData(CompoundTag chunkData) - { - BlendingData blendingData = null; - boolean containsBlendingData; - #if MC_VER < MC_1_21_5 - containsBlendingData = chunkData.contains("blending_data", 10); - #else - containsBlendingData = chunkData.contains("blending_data"); - #endif - - if (containsBlendingData) + for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter()) { - @SuppressWarnings({"unchecked", "rawtypes"}) - Dynamic blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data")); + String heightmapKey = type.getSerializationKey(); - try + #if MC_VER < MC_1_21_5 + if (tagHeightmaps.contains(heightmapKey, 12)) { - #if MC_VER < MC_1_21_3 - blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logParsingWarningOnce(message)).orElse(null); - #else - // blending data appears to have changed as of 1.21.6 causing a class cast exception here due to it being wrapped in a Java.Optional - blendingData = BlendingData.unpack(BlendingData.Packed.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logParsingWarningOnce(message)).orElse(null)); - #endif + chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmapKey)); } - catch (Exception e) + #else + if (tagHeightmaps.contains(heightmapKey)) { - String message = e.getMessage(); - if (message == null || message.trim().isEmpty()) + Optional optionalHeightmap = tagHeightmaps.getLongArray(heightmapKey); + if (optionalHeightmap.isPresent()) { - message = "Failed to parse blending data"; + chunk.setHeightmap(type, optionalHeightmap.get()); } - - logParsingWarningOnce(message, e); } + #endif } - return blendingData; + + Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter()); } - #endif - //=====================// - // read chunk lighting // - //=====================// + //================// + // chunk lighting // + //================// - /** https://minecraft.wiki/w/Chunk_format */ + /** source: https://minecraft.wiki/w/Chunk_format */ public static CombinedChunkLightStorage readLight(ChunkAccess chunk, CompoundTag chunkData) { #if MC_VER <= MC_1_17_1 @@ -746,5 +731,6 @@ public class ChunkCompoundTagParser } } + + } - diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java index 46e0b2343..e12f64042 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java @@ -107,13 +107,6 @@ public class ChunkFileReader implements AutoCloseable ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); DhChunkPos dhChunkPos = new DhChunkPos(chunkX, chunkZ); -// if (true) -// { -// ChunkAccess newChunk = CreateEmptyChunk(this.params.level, chunkPos); -// generatedChunkByDhPos.put(dhChunkPos, newChunk); -// return CompletableFuture.completedFuture(newChunk); -// } - if (generatedChunkByDhPos.containsKey(dhChunkPos)) { return CompletableFuture.completedFuture(generatedChunkByDhPos.get(dhChunkPos)); @@ -155,7 +148,6 @@ public class ChunkFileReader implements AutoCloseable return newChunk; }); } - // TODO FIXME this method can be called up to 25 times for the same chunk position, why? private CompletableFuture getChunkNbtDataAsync(ChunkPos chunkPos) { ServerLevel level = this.params.level; @@ -265,8 +257,6 @@ public class ChunkFileReader implements AutoCloseable { try { - CHUNK_LOAD_LOGGER.debug("DistantHorizons: Loading chunk [" + chunkPos + "] from disk."); - @Nullable ChunkAccess chunk = ChunkCompoundTagParser.createFromTag(level, chunkPos, chunkTagData); if (chunk != null) @@ -298,7 +288,8 @@ public class ChunkFileReader implements AutoCloseable } } } - private static ProtoChunk CreateEmptyChunk(ServerLevel level, ChunkPos chunkPos) + + public static ProtoChunk CreateEmptyChunk(ServerLevel level, ChunkPos chunkPos) { #if MC_VER <= MC_1_16_5 return new ProtoChunk(chunkPos, UpgradeData.EMPTY); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/CompoundTagUtil.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/CompoundTagUtil.java index 9e442cfd1..f175815c8 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/CompoundTagUtil.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/CompoundTagUtil.java @@ -134,4 +134,15 @@ public class CompoundTagUtil + public static boolean contains(CompoundTag tag, String key, int index) + { + #if MC_VER < MC_1_21_5 + return tag.contains(key, index); + #else + return tag.contains(key); + #endif + } + + + } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java index fecc60e9e..141c0e64c 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java @@ -27,7 +27,6 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.levelgen.Heightmap; import com.seibel.distanthorizons.core.logging.DhLogger; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java index d421543a2..3aad819cb 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java @@ -27,7 +27,6 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGen import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; -import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException; import net.minecraft.world.level.chunk.ChunkAccess; #if MC_VER >= MC_1_18_2 diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java index a96965c48..70fdb6f6f 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java @@ -28,7 +28,6 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGen import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ProtoChunk; #if MC_VER <= MC_1_20_4 import net.minecraft.world.level.chunk.ChunkStatus; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java index f56521085..a13ba63f2 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java @@ -28,7 +28,6 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGen import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ProtoChunk; #if MC_VER <= MC_1_20_4 import net.minecraft.world.level.chunk.ChunkStatus; From f50613e20c363b33822bccf2fab89519f1a0d2f8 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 27 Nov 2025 18:56:58 -0600 Subject: [PATCH 16/33] world gen var renaming --- .../BatchGenerationEnvironment.java | 16 ++++++++-------- .../worldGeneration/GenerationEvent.java | 2 +- .../worldGeneration/ThreadWorldGenParams.java | 8 ++++---- .../worldGeneration/step/StepBiomes.java | 6 +++--- .../worldGeneration/step/StepFeatures.java | 2 +- .../wrappers/worldGeneration/step/StepNoise.java | 6 +++--- .../step/StepStructureReference.java | 2 +- .../worldGeneration/step/StepStructureStart.java | 10 +++++----- .../worldGeneration/step/StepSurface.java | 2 +- 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 590550713..28568d7e7 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -110,7 +110,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm public final LinkedBlockingQueue generationEventQueue = new LinkedBlockingQueue<>(); - public final GlobalWorldGenParams params; + public final GlobalWorldGenParams globalParams; public final StepStructureStart stepStructureStart = new StepStructureStart(this); public final StepStructureReference stepStructureReference = new StepStructureReference(this); @@ -168,9 +168,9 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm public BatchGenerationEnvironment(IDhServerLevel dhServerLevel) { this.dhServerLevel = dhServerLevel; - this.params = new GlobalWorldGenParams(dhServerLevel); - this.internalServerGenerator = new InternalServerGenerator(this.params, this.dhServerLevel); - this.chunkFileReader = new ChunkFileReader(this.params); + this.globalParams = new GlobalWorldGenParams(dhServerLevel); + this.internalServerGenerator = new InternalServerGenerator(this.globalParams, this.dhServerLevel); + this.chunkFileReader = new ChunkFileReader(this.globalParams); ChunkGenerator generator = ((ServerLevelWrapper) (dhServerLevel.getServerLevelWrapper())).getLevel().getChunkSource().getGenerator(); boolean isMcGenerator = @@ -309,7 +309,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm int refPosX = genEvent.minPos.getX() - borderSize; int refPosZ = genEvent.minPos.getZ() - borderSize; - LightGetterAdaptor lightGetterAdaptor = new LightGetterAdaptor(this.params.level); + LightGetterAdaptor lightGetterAdaptor = new LightGetterAdaptor(this.globalParams.level); DummyLightEngine dummyLightEngine = new DummyLightEngine(lightGetterAdaptor); // reused data between each offset @@ -371,7 +371,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // create empty chunks outside the generation radius if (!readFutureByDhChunkPos.containsKey(dhChunkPos)) { - ChunkAccess chunk = ChunkFileReader.CreateEmptyChunk(this.params.level, chunkPos); + ChunkAccess chunk = ChunkFileReader.CreateEmptyChunk(this.globalParams.level, chunkPos); generatedChunkByDhPos.put(dhChunkPos, chunk); } } @@ -424,14 +424,14 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm DhLitWorldGenRegion region = new DhLitWorldGenRegion( centerX, centerZ, centerChunk, - this.params.level, dummyLightEngine, regionChunks, + this.globalParams.level, dummyLightEngine, regionChunks, ChunkStatus.STRUCTURE_STARTS, radius, // this method shouldn't be necessary since we're passing in a pre-populated // list of chunks, but just in case fallbackChunkGetterFunc ); lightGetterAdaptor.setRegion(region); - genEvent.threadedParam.makeStructFeatManager(region, this.params); + genEvent.threadedParam.makeStructFeatManager(region, this.globalParams); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java index 7158abac2..351f22c52 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java @@ -66,7 +66,7 @@ public final class GenerationEvent this.widthInChunks = widthInChunks; this.targetGenerationStep = targetGenerationStep; this.generatorMode = generatorMode; - this.threadedParam = ThreadWorldGenParams.getOrMake(generationGroup.params); + this.threadedParam = ThreadWorldGenParams.getOrMake(generationGroup.globalParams); this.future = new CompletableFuture<>(); this.resultConsumer = resultConsumer; } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java index cd54bac95..2ea22d04e 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java @@ -34,7 +34,7 @@ public final class ThreadWorldGenParams final ServerLevel level; - public WorldGenStructFeatManager structFeat = null; + public WorldGenStructFeatManager structFeatManager = null; #if MC_VER >= MC_1_18_2 public StructureCheck structCheck; @@ -92,11 +92,11 @@ public final class ThreadWorldGenParams public void makeStructFeatManager(WorldGenLevel genLevel, GlobalWorldGenParams param) { #if MC_VER < MC_1_18_2 - this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel); + this.structFeatManager = new WorldGenStructFeatManager(param.worldGenSettings, genLevel); #elif MC_VER < MC_1_19_4 - this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel, this.structCheck); + this.structFeatManager = new WorldGenStructFeatManager(param.worldGenSettings, genLevel, this.structCheck); #else - this.structFeat = new WorldGenStructFeatManager(param.worldOptions, genLevel, this.structCheck); + this.structFeatManager = new WorldGenStructFeatManager(param.worldOptions, genLevel, this.structCheck); #endif } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java index 17d05ad84..34cd8343d 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java @@ -104,10 +104,10 @@ public final class StepBiomes extends AbstractWorldGenStep ); #else chunk = this.environment.confirmFutureWasRunSynchronously( - this.environment.params.generator.createBiomes( - this.environment.params.randomState, + this.environment.globalParams.generator.createBiomes( + this.environment.globalParams.randomState, Blender.of(worldGenRegion), - tParams.structFeat.forWorldGenRegion(worldGenRegion), + tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk) ); #endif diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java index 141c0e64c..fae6a935a 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java @@ -84,7 +84,7 @@ public final class StepFeatures extends AbstractWorldGenStep #else if (worldGenRegion.hasChunk(chunkWrapper.getChunkPos().getX(), chunkWrapper.getChunkPos().getZ())) { - this.environment.params.generator.applyBiomeDecoration(worldGenRegion, chunk, tParams.structFeat.forWorldGenRegion(worldGenRegion)); + this.environment.globalParams.generator.applyBiomeDecoration(worldGenRegion, chunk, tParams.structFeatManager.forWorldGenRegion(worldGenRegion)); } else { diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java index 3aad819cb..036bdc7f6 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java @@ -97,10 +97,10 @@ public final class StepNoise extends AbstractWorldGenStep chunk)); #else chunk = this.environment.confirmFutureWasRunSynchronously( - this.environment.params.generator.fillFromNoise( + this.environment.globalParams.generator.fillFromNoise( Blender.of(worldGenRegion), - this.environment.params.randomState, - tParams.structFeat.forWorldGenRegion(worldGenRegion), + this.environment.globalParams.randomState, + tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk)); #endif } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java index 70fdb6f6f..714019300 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java @@ -68,7 +68,7 @@ public final class StepStructureReference extends AbstractWorldGenStep for (ChunkWrapper chunkWrapper : chunksToDo) { ChunkAccess chunk = chunkWrapper.getChunk(); - this.environment.params.generator.createReferences(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk); + this.environment.globalParams.generator.createReferences(worldGenRegion, tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk); } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java index 5485e757a..9d1eb1c42 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java @@ -78,7 +78,7 @@ public final class StepStructureStart extends AbstractWorldGenStep #elif MC_VER < MC_1_19_4 if (!this.environment.params.worldGenSettings.generateStructures()) #else - if (!this.environment.params.worldOptions.generateStructures()) + if (!this.environment.globalParams.worldOptions.generateStructures()) #endif { return; @@ -105,10 +105,10 @@ public final class StepStructureStart extends AbstractWorldGenStep this.environment.params.level.getChunkSource().getGeneratorState(), tParams.structFeat, chunk, this.environment.params.structures); #else - this.environment.params.generator.createStructures(this.environment.params.registry, - this.environment.params.level.getChunkSource().getGeneratorState(), - tParams.structFeat, chunk, this.environment.params.structures, - this.environment.params.level.dimension()); + this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry, + this.environment.globalParams.level.getChunkSource().getGeneratorState(), + tParams.structFeatManager, chunk, this.environment.globalParams.structures, + this.environment.globalParams.level.dimension()); #endif #if MC_VER >= MC_1_18_2 diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java index a13ba63f2..b7f460c2b 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java @@ -74,7 +74,7 @@ public final class StepSurface extends AbstractWorldGenStep #elif MC_VER < MC_1_19_2 this.environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk); #else - this.environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), this.environment.params.randomState, chunk); + this.environment.globalParams.generator.buildSurface(worldGenRegion, tParams.structFeatManager.forWorldGenRegion(worldGenRegion), this.environment.globalParams.randomState, chunk); #endif } } From f318b52280d8f90edd131888e0d0c0ac6ed852c6 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 27 Nov 2025 22:12:46 -0600 Subject: [PATCH 17/33] Fix compiling for older MC versions --- .../worldGeneration/GlobalWorldGenParams.java | 5 +++ .../worldGeneration/ThreadWorldGenParams.java | 2 +- .../ChunkCompoundTagParser.java | 33 ++++++++++++------- .../chunkFileHandling/ChunkFileReader.java | 23 +++++++++++-- .../InternalServerGenerator.java | 13 +++++--- .../worldGeneration/step/StepBiomes.java | 22 ++++++------- .../worldGeneration/step/StepFeatures.java | 2 +- .../worldGeneration/step/StepNoise.java | 16 ++++----- .../step/StepStructureStart.java | 18 +++++----- .../worldGeneration/step/StepSurface.java | 4 +-- .../server/MixinUtilBackgroundThread.java | 9 +++++ 11 files changed, 98 insertions(+), 49 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java index c640685f6..e1b112ec2 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java @@ -33,9 +33,14 @@ import net.minecraft.world.level.chunk.ChunkGenerator; #if MC_VER >= MC_1_18_2 import net.minecraft.world.level.chunk.storage.ChunkScanAccess; #endif + #if MC_VER < MC_1_19_2 import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; +#elif MC_VER < MC_1_19_2 +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; #else +import net.minecraft.world.level.levelgen.RandomState; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; #endif import net.minecraft.world.level.storage.WorldData; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java index 2ea22d04e..5c6b20a71 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java @@ -73,7 +73,7 @@ public final class ThreadWorldGenParams this.level = param.level; #if MC_VER < MC_1_18_2 - this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, this.level); + this.structFeatManager = new WorldGenStructFeatManager(param.worldGenSettings, this.level); #elif MC_VER < MC_1_19_2 this.structCheck = this.createStructureCheck(param); #else diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java index 652096195..826992cce 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java @@ -20,6 +20,7 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling; import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; @@ -56,6 +57,11 @@ import net.minecraft.world.level.chunk.storage.ChunkSerializer; #else #endif +#if MC_VER < MC_1_21_9 +import net.minecraft.world.level.block.Blocks; +#else +#endif + import net.minecraft.world.level.levelgen.Heightmap; #if MC_VER >= MC_1_18_2 import net.minecraft.world.level.levelgen.blending.BlendingData; @@ -168,7 +174,7 @@ public class ChunkCompoundTagParser { return null; } - #elif MC_VER < MC_1_19_2 + #elif MC_VER < MC_1_20_6 if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK) { return null; @@ -376,7 +382,7 @@ public class ChunkCompoundTagParser Registry biomeRegistry = getBiomeRegistry(level); - #if MC_VER < MC_1_18_2 + #if MC_VER < MC_1_19_2 Codec> biomeCodec; #else Codec>> biomeCodec; @@ -401,12 +407,13 @@ public class ChunkCompoundTagParser biomeTag = CompoundTagUtil.getCompoundTag(tagSection, "biomes"); } - if (biomeTag != null) + if (biomeTag != null + && !biomeTag.isEmpty()) { - #if MC_VER < MC_1_20_6 - biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, biomeTag) - .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) - .getOrThrow(false, (message) -> logParsingWarningOnce(message)); + #if MC_VER < MC_1_20_6 + biomeContainer = new PalettedContainer>( + biomeRegistry.asHolderIdMap(), + biomeRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); #else biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, biomeTag) .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) @@ -448,9 +455,11 @@ public class ChunkCompoundTagParser private static Codec> getBlockStateCodec(LevelAccessor level) { - #if MC_VER <= MC_1_18_2 + #if MC_VER < MC_1_18_2 + return null; // unused for older MC versions + #elif MC_VER < MC_1_19_2 return PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); - #elif MC_VER <= MC_1_19_2 + #elif MC_VER <= MC_1_21_8 return PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); #else return PalettedContainerFactory.create(level.registryAccess()).blockStatesContainerCodec(); @@ -471,13 +480,15 @@ public class ChunkCompoundTagParser #endif } private static - #if MC_VER < MC_1_18_2 Codec> + #if MC_VER < MC_1_19_2 Codec> #else Codec>> #endif getBiomeCodec(LevelAccessor level, Registry biomeRegistry) { #if MC_VER < MC_1_18_2 - Codec> biomeCodec = PalettedContainer.codec( + return null; // unused for older MC versions + #elif MC_VER < MC_1_19_2 + return PalettedContainer.codec( biomeRegistry, biomeRegistry.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getOrThrow(Biomes.PLAINS)); #elif MC_VER < MC_1_19_2 return PalettedContainer.codec( diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java index e12f64042..c652c3401 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java @@ -11,16 +11,16 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.util.ExceptionUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; + import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.PalettedContainerFactory; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.chunk.storage.RegionFileStorage; + import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -31,6 +31,25 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.atomic.AtomicReference; +#if MC_VER <= MC_1_17_1 +import net.minecraft.world.level.chunk.ChunkStatus; +#elif MC_VER <= MC_1_19_2 +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.core.Registry; +#elif MC_VER <= MC_1_19_4 +import net.minecraft.core.registries.Registries; +import net.minecraft.world.level.chunk.ChunkStatus; +#elif MC_VER <= MC_1_20_6 +import net.minecraft.core.registries.Registries; +import net.minecraft.world.level.chunk.ChunkStatus; +#elif MC_VER <= MC_1_21_10 +import net.minecraft.core.registries.Registries; +import net.minecraft.world.level.chunk.status.ChunkStatus; +#else +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.PalettedContainerFactory; +#endif + public class ChunkFileReader implements AutoCloseable { diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java index e8f2269dd..4eaf32f17 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java @@ -23,7 +23,12 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.TicketType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.ChunkAccess; + +#if MC_VER <= MC_1_20_4 +import net.minecraft.world.level.chunk.ChunkStatus; +#else import net.minecraft.world.level.chunk.status.ChunkStatus; +#endif import java.util.*; import java.util.concurrent.CompletableFuture; @@ -220,7 +225,7 @@ public class InternalServerGenerator #if MC_VER < MC_1_21_5 int chunkLevel = 33; // 33 is equivalent to FULL Chunk - level.getChunkSource().distanceManager.addTicket(DH_SERVER_GEN_TICKET, pos, chunkLevel, pos); + level.getChunkSource().distanceManager.addTicket(DH_SERVER_GEN_TICKET, chunkPos, chunkLevel, chunkPos); #else level.getChunkSource().addTicketWithRadius(DH_SERVER_GEN_TICKET, chunkPos, 0); #endif @@ -235,13 +240,13 @@ public class InternalServerGenerator } #if MC_VER <= MC_1_20_4 - return chunkHolder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) + return chunkHolder.getOrScheduleFuture(ChunkStatus.FULL, level.getChunkSource().chunkMap) .thenApply(result -> result.left().orElseThrow(() -> new RuntimeException(result.right().get().toString()))); // can throw if the server is shutting down #elif MC_VER <= MC_1_20_6 - return chunkHolder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) + return chunkHolder.getOrScheduleFuture(ChunkStatus.FULL, level.getChunkSource().chunkMap) .thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.toString()))); // can throw if the server is shutting down #else - return chunkHolder.scheduleChunkGenerationTask(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) + return chunkHolder.scheduleChunkGenerationTask(ChunkStatus.FULL, level.getChunkSource().chunkMap) .thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.getError()))); // can throw if the server is shutting down #endif diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java index 34cd8343d..5d04bc004 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java @@ -74,32 +74,32 @@ public final class StepBiomes extends AbstractWorldGenStep #if MC_VER < MC_1_18_2 - this.environment.params.generator.createBiomes(this.environment.params.biomes, chunk); + this.environment.globalParams.generator.createBiomes(this.environment.globalParams.biomes, chunk); #elif MC_VER < MC_1_19_2 chunk = this.environment.confirmFutureWasRunSynchronously( - this.environment.params.generator.createBiomes( - this.environment.params.biomes, + this.environment.globalParams.generator.createBiomes( + this.environment.globalParams.biomes, Runnable::run, Blender.of(worldGenRegion), - tParams.structFeat.forWorldGenRegion(worldGenRegion), + tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk) ); #elif MC_VER < MC_1_19_4 chunk = this.environment.confirmFutureWasRunSynchronously( - this.environment.params.generator.createBiomes( - this.environment.params.biomes, + this.environment.globalParams.generator.createBiomes( + this.environment.globalParams.biomes, Runnable::run, - this.environment.params.randomState, Blender.of(worldGenRegion), - tParams.structFeat.forWorldGenRegion(worldGenRegion), + this.environment.globalParams.randomState, Blender.of(worldGenRegion), + tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk) ); #elif MC_VER < MC_1_21_1 chunk = this.environment.confirmFutureWasRunSynchronously( - this.environment.params.generator.createBiomes( + this.environment.globalParams.generator.createBiomes( Runnable::run, - this.environment.params.randomState, + this.environment.globalParams.randomState, Blender.of(worldGenRegion), - tParams.structFeat.forWorldGenRegion(worldGenRegion), + tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk) ); #else diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java index fae6a935a..20407770e 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java @@ -80,7 +80,7 @@ public final class StepFeatures extends AbstractWorldGenStep { #if MC_VER < MC_1_18_2 worldGenRegion.setOverrideCenter(chunk.getPos()); - environment.params.generator.applyBiomeDecoration(worldGenRegion, tParams.structFeat); + environment.globalParams.generator.applyBiomeDecoration(worldGenRegion, tParams.structFeatManager); #else if (worldGenRegion.hasChunk(chunkWrapper.getChunkPos().getX(), chunkWrapper.getChunkPos().getZ())) { diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java index 036bdc7f6..04cd3d356 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java @@ -73,27 +73,27 @@ public final class StepNoise extends AbstractWorldGenStep ChunkAccess chunk = chunkWrapper.getChunk(); #if MC_VER < MC_1_17_1 - this.environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk); + this.environment.globalParams.generator.fillFromNoise(worldGenRegion, tParams.structFeatManager, chunk); #elif MC_VER < MC_1_18_2 chunk = this.environment.confirmFutureWasRunSynchronously( - this.environment.params.generator.fillFromNoise( + this.environment.globalParams.generator.fillFromNoise( Runnable::run, - tParams.structFeat.forWorldGenRegion(worldGenRegion), + tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk)); #elif MC_VER < MC_1_19_2 chunk = this.environment.confirmFutureWasRunSynchronously( - this.environment.params.generator.fillFromNoise( + this.environment.globalParams.generator.fillFromNoise( Runnable::run, Blender.of(worldGenRegion), - tParams.structFeat.forWorldGenRegion(worldGenRegion), + tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk)); #elif MC_VER < MC_1_21_1 chunk = this.environment.confirmFutureWasRunSynchronously( - this.environment.params.generator.fillFromNoise( + this.environment.globalParams.generator.fillFromNoise( Runnable::run, Blender.of(worldGenRegion), - this.environment.params.randomState, - tParams.structFeat.forWorldGenRegion(worldGenRegion), + this.environment.globalParams.randomState, + tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk)); #else chunk = this.environment.confirmFutureWasRunSynchronously( diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java index 9d1eb1c42..70c2d1431 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java @@ -74,9 +74,9 @@ public final class StepStructureStart extends AbstractWorldGenStep // TODO should be put in wrapped environment so we can skip some other world gen steps // SURFACE wouldn't need structure generation either #if MC_VER < MC_1_19_2 - if (!this.environment.params.worldGenSettings.generateFeatures()) + if (!this.environment.globalParams.worldGenSettings.generateFeatures()) #elif MC_VER < MC_1_19_4 - if (!this.environment.params.worldGenSettings.generateStructures()) + if (!this.environment.globalParams.worldGenSettings.generateStructures()) #else if (!this.environment.globalParams.worldOptions.generateStructures()) #endif @@ -95,15 +95,15 @@ public final class StepStructureStart extends AbstractWorldGenStep STRUCTURE_PLACEMENT_LOCK.lock(); #if MC_VER < MC_1_19_2 - this.environment.params.generator.createStructures(this.environment.params.registry, tParams.structFeat, chunk, this.environment.params.structures, - this.environment.params.worldSeed); + this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry, tParams.structFeatManager, chunk, this.environment.globalParams.structures, + this.environment.globalParams.worldSeed); #elif MC_VER < MC_1_19_4 - this.environment.params.generator.createStructures(this.environment.params.registry, this.environment.params.randomState, tParams.structFeat, chunk, this.environment.params.structures, - this.environment.params.worldSeed); + this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry, this.environment.globalParams.randomState, tParams.structFeatManager, chunk, this.environment.globalParams.structures, + this.environment.globalParams.worldSeed); #elif MC_VER <= MC_1_21_3 - this.environment.params.generator.createStructures(this.environment.params.registry, - this.environment.params.level.getChunkSource().getGeneratorState(), - tParams.structFeat, chunk, this.environment.params.structures); + this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry, + this.environment.globalParams.level.getChunkSource().getGeneratorState(), + tParams.structFeatManager, chunk, this.environment.globalParams.structures); #else this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry, this.environment.globalParams.level.getChunkSource().getGeneratorState(), diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java index b7f460c2b..6e9a2d606 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java @@ -70,9 +70,9 @@ public final class StepSurface extends AbstractWorldGenStep ChunkAccess chunk = chunkWrapper.getChunk(); #if MC_VER < MC_1_18_2 - this.environment.params.generator.buildSurfaceAndBedrock(worldGenRegion, chunk); + this.environment.globalParams.generator.buildSurfaceAndBedrock(worldGenRegion, chunk); #elif MC_VER < MC_1_19_2 - this.environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk); + this.environment.globalParams.generator.buildSurface(worldGenRegion, tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk); #else this.environment.globalParams.generator.buildSurface(worldGenRegion, tParams.structFeatManager.forWorldGenRegion(worldGenRegion), this.environment.globalParams.randomState, chunk); #endif diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java index 33e38e235..0974498ee 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinUtilBackgroundThread.java @@ -25,6 +25,15 @@ import org.spongepowered.asm.mixin.Mixin; import net.minecraft.Util; +#if MC_VER < MC_1_21_3 +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.concurrent.ExecutorService; +import java.util.function.Supplier; +#endif + /** * This is needed for DH's world gen so we can run * world gen on our own threads instead of using MC thread pools. From 7047d0afdf377083e984dad09927a5525c7e4642 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 27 Nov 2025 22:16:48 -0600 Subject: [PATCH 18/33] fix 1.21.10 compiling --- .../worldGeneration/chunkFileHandling/ChunkFileReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java index c652c3401..aaede6f57 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java @@ -42,7 +42,7 @@ import net.minecraft.world.level.chunk.ChunkStatus; #elif MC_VER <= MC_1_20_6 import net.minecraft.core.registries.Registries; import net.minecraft.world.level.chunk.ChunkStatus; -#elif MC_VER <= MC_1_21_10 +#elif MC_VER <= MC_1_21_9 import net.minecraft.core.registries.Registries; import net.minecraft.world.level.chunk.status.ChunkStatus; #else From d7eabcf3a6c5b33372ee7810b0c27a820a1014a5 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Fri, 28 Nov 2025 09:39:22 -0600 Subject: [PATCH 19/33] don't render thick snow layers --- .../common/wrappers/block/BlockStateWrapper.java | 13 +++++++------ coreSubProjects | 2 +- .../distanthorizons/fabric/FabricClientProxy.java | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java index 216f7452e..8829c8bb0 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java @@ -274,7 +274,7 @@ public class BlockStateWrapper implements IBlockStateWrapper HashSet baseIgnoredBlock = new HashSet<>(); baseIgnoredBlock.add(AIR_STRING); - rendererIgnoredBlocks = getBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper); + rendererIgnoredBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper); return rendererIgnoredBlocks; } /** @@ -291,7 +291,7 @@ public class BlockStateWrapper implements IBlockStateWrapper HashSet baseIgnoredBlock = new HashSet<>(); baseIgnoredBlock.add(AIR_STRING); - rendererIgnoredCaveBlocks = getBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper); + rendererIgnoredCaveBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper); return rendererIgnoredCaveBlocks; } @@ -302,7 +302,7 @@ public class BlockStateWrapper implements IBlockStateWrapper // lod builder helpers // - private static HashSet getBlockWrappers(ConfigEntry config, HashSet baseResourceLocations, ILevelWrapper levelWrapper) + private static HashSet getAllBlockWrappers(ConfigEntry config, HashSet baseResourceLocations, ILevelWrapper levelWrapper) { // get the base blocks HashSet blockStringList = new HashSet<>(); @@ -318,9 +318,9 @@ public class BlockStateWrapper implements IBlockStateWrapper blockStringList.addAll(Arrays.asList(ignoreBlockCsv.split(","))); } - return getBlockWrappers(blockStringList, levelWrapper); + return getAllBlockWrappers(blockStringList, levelWrapper); } - private static HashSet getBlockWrappers(HashSet blockResourceLocationSet, ILevelWrapper levelWrapper) + private static HashSet getAllBlockWrappers(HashSet blockResourceLocationSet, ILevelWrapper levelWrapper) { // deserialize each of the given resource locations HashSet blockStateWrappers = new HashSet<>(); @@ -587,7 +587,8 @@ public class BlockStateWrapper implements IBlockStateWrapper // we need the final string for the concurrent hash map later final String finalResourceStateString = resourceStateString; - if (finalResourceStateString.equals(AIR_STRING) || finalResourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case + if (finalResourceStateString.equals(AIR_STRING) + || finalResourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case { return AIR; } diff --git a/coreSubProjects b/coreSubProjects index 19b23bea5..f43e2fa44 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 19b23bea5fae8efa10b0958e8cf4f89e21716698 +Subproject commit f43e2fa441ed5df5fda298a978d50afc0c15496a diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java index 30cc79c5e..fee42ffd6 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java @@ -223,7 +223,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy // render event // //==============// - // TODO wait for fabric to re-add their rendering API + #if MC_VER < MC_1_21_9 WorldRenderEvents.AFTER_SETUP.register((renderContext) -> { From 7f0eeb9f15e4a7d3dfa66bc32948e2f6aba0c5df Mon Sep 17 00:00:00 2001 From: James Seibel Date: Fri, 28 Nov 2025 10:48:55 -0600 Subject: [PATCH 20/33] ignore chunk updates during internal server generation --- .../InternalServerGenerator.java | 33 ++++++++++++++++--- coreSubProjects | 2 +- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java index 4eaf32f17..bfa3805a8 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java @@ -1,20 +1,22 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.internalServer; import com.seibel.distanthorizons.api.DhApi; -import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.ChunkPosGenStream; import com.seibel.distanthorizons.common.wrappers.worldGeneration.GenerationEvent; import com.seibel.distanthorizons.common.wrappers.worldGeneration.GlobalWorldGenParams; import com.seibel.distanthorizons.core.api.internal.ClientApi; +import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.generation.DhLightingEngine; import com.seibel.distanthorizons.core.level.IDhServerLevel; import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.util.ExceptionUtil; import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.util.TimerUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor; import com.seibel.distanthorizons.coreapi.ModInfo; @@ -49,6 +51,15 @@ public class InternalServerGenerator private static final IC2meAccessor C2ME_ACCESSOR = ModAccessorInjector.INSTANCE.get(IC2meAccessor.class); + /** + * Used to revert the ignore logic in {@link SharedApi} so + * that given chunk pos can be handled again. + * A timer is used so we don't have to inject into MC's code and it works sell enough + * most of the time. + * If a chunk does get through due the timeout not being long enough that isn't the end of the world. + */ + private static final int MS_TO_IGNORE_CHUNK_AFTER_COMPLETION = 5_000; + #if MC_VER < MC_1_21_5 private static final TicketType DH_SERVER_GEN_TICKET = TicketType.create("dh_server_gen_ticket", Comparator.comparingLong(ChunkPos::toLong)); #elif MC_VER < MC_1_21_9 @@ -62,6 +73,7 @@ public class InternalServerGenerator private final GlobalWorldGenParams params; private final IDhServerLevel dhServerLevel; + private final Timer chunkSaveIgnoreTimer = TimerUtil.CreateTimer("ChunkSaveIgnoreTimer"); @@ -223,6 +235,9 @@ public class InternalServerGenerator { ServerLevel level = this.params.level; + // ignore chunk update events for this position + SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.addPosToIgnore(new DhChunkPos(chunkPos.x, chunkPos.z)); + #if MC_VER < MC_1_21_5 int chunkLevel = 33; // 33 is equivalent to FULL Chunk level.getChunkSource().distanceManager.addTicket(DH_SERVER_GEN_TICKET, chunkPos, chunkLevel, chunkPos); @@ -257,7 +272,7 @@ public class InternalServerGenerator * mitigates out of memory issues in the vanilla chunk system.
* See: https://github.com/pop4959/Chunky/pull/383 */ - private void releaseChunkFromServer(ServerLevel level, ChunkPos pos) + private void releaseChunkFromServer(ServerLevel level, ChunkPos chunkPos) { level.getChunkSource().chunkMap.mainThreadExecutor.execute(() -> { @@ -265,9 +280,9 @@ public class InternalServerGenerator { #if MC_VER < MC_1_21_5 int chunkLevel = 33; // 33 is equivalent to FULL Chunk - level.getChunkSource().distanceManager.removeTicket(DH_SERVER_GEN_TICKET, pos, chunkLevel, pos); + level.getChunkSource().distanceManager.removeTicket(DH_SERVER_GEN_TICKET, chunkPos, chunkLevel, chunkPos); #else - level.getChunkSource().removeTicketWithRadius(DH_SERVER_GEN_TICKET, pos, 0); + level.getChunkSource().removeTicketWithRadius(DH_SERVER_GEN_TICKET, chunkPos, 0); #endif level.getChunkSource().chunkMap.tick(() -> false); @@ -275,6 +290,16 @@ public class InternalServerGenerator #if MC_VER > MC_1_16_5 level.entityManager.tick(); #endif + + + // give MC a few seconds to save the chunk before + // we can process update events there again + this.chunkSaveIgnoreTimer.schedule(new TimerTask() + { + @Override + public void run() { SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.removePosToIgnore(new DhChunkPos(chunkPos.x, chunkPos.z)); } + }, MS_TO_IGNORE_CHUNK_AFTER_COMPLETION); + } catch (Exception e) { diff --git a/coreSubProjects b/coreSubProjects index f43e2fa44..7e46adf46 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit f43e2fa441ed5df5fda298a978d50afc0c15496a +Subproject commit 7e46adf46938642c9f6f9cf7dd741246a2e32e55 From 13a4505d7dcd5e6fa2be4d0c92619ed73262bcd5 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Fri, 28 Nov 2025 15:54:06 -0600 Subject: [PATCH 21/33] Fix biome blending using underground biomes --- .../common/wrappers/block/AbstractDhTintGetter.java | 6 +++--- coreSubProjects | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/AbstractDhTintGetter.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/AbstractDhTintGetter.java index cb7a334ac..1d7ccb579 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/AbstractDhTintGetter.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/AbstractDhTintGetter.java @@ -124,10 +124,10 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter int rollingBlue = 0; int xMin = mutableBlockPos.getX() - this.smoothingRadiusInBlocks; - int xMax = mutableBlockPos.getX() + this.smoothingRadiusInBlocks; + int xMax = mutableBlockPos.getX() + this.smoothingRadiusInBlocks + 1; // +1 to account for the center block int zMin = mutableBlockPos.getZ() - this.smoothingRadiusInBlocks; - int zMax = mutableBlockPos.getZ() + this.smoothingRadiusInBlocks; + int zMax = mutableBlockPos.getZ() + this.smoothingRadiusInBlocks + 1; int levelMinY = this.clientLevelWrapper.getMinHeight(); @@ -141,7 +141,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter // this can return the same position/datapoint for larger LODs duplicating work, // however for small smoothing ranges that isn't a big deal and for large LODs // we ignore smoothing anyway - long dataPoint = this.fullDataSource.getDataPointAtBlockPos(mutableBlockPos.getX(), mutableBlockPos.getY(), mutableBlockPos.getZ()); + long dataPoint = this.fullDataSource.getDataPointAtBlockPos(mutableBlockPos.getX(), mutableBlockPos.getY(), mutableBlockPos.getZ(), levelMinY); if (dataPoint == FullDataPointUtil.EMPTY_DATA_POINT) { continue; diff --git a/coreSubProjects b/coreSubProjects index 7e46adf46..227d0d09b 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 7e46adf46938642c9f6f9cf7dd741246a2e32e55 +Subproject commit 227d0d09ba34ef486c41c3dca3f0751077a3e781 From 2c71c2bf767a6fbba4cd4fa85c95c02221b079fb Mon Sep 17 00:00:00 2001 From: James Seibel Date: Fri, 28 Nov 2025 16:31:23 -0600 Subject: [PATCH 22/33] maybe fix concurrency error during world gen shutdown --- coreSubProjects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreSubProjects b/coreSubProjects index 227d0d09b..4e96728c2 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 227d0d09ba34ef486c41c3dca3f0751077a3e781 +Subproject commit 4e96728c2516dfc2c67f9f5d394a40d0fc3c2a05 From 30da01f5808912b570746336371838d5f681a5e8 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 29 Nov 2025 09:59:38 -0600 Subject: [PATCH 23/33] TEST --- .../BatchGenerationEnvironment.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 28568d7e7..881650971 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -504,7 +504,13 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm ChunkPos pos = iterator.next(); DhChunkPos dhPos = new DhChunkPos(pos.x, pos.z); ChunkWrapper wrappedChunk = chunkWrappersByDhPos.get(dhPos); - genEvent.resultConsumer.accept(wrappedChunk); + + // only pass along chunks that have been generated up to BIOMES + // this is to prevent issues with generating existing + if (wrappedChunk.getStatus().isOrAfter(ChunkStatus.BIOMES)) + { + genEvent.resultConsumer.accept(wrappedChunk); + } } } catch (CompletionException | UncheckedInterruptedException e) @@ -630,17 +636,17 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // make sure the height maps are all properly generated // if this isn't done everything else afterward may fail - Heightmap.primeHeightmaps(centerChunk.getChunk(), ChunkStatus.FEATURES.heightmapsAfter()); + //Heightmap.primeHeightmaps(centerChunk.getChunk(), ChunkStatus.FEATURES.heightmapsAfter()); centerChunk.recalculateDhHeightMapsIfNeeded(); // pre-generated chunks should have lighting but new ones won't - if (!centerChunk.isDhBlockLightingCorrect()) - { - DhLightingEngine.INSTANCE.bakeChunkBlockLighting(centerChunk, iChunkWrapperList, maxSkyLight); - } -// centerChunk.setIsDhBlockLightCorrect(true); + //if (!centerChunk.isDhBlockLightingCorrect()) + //{ + // DhLightingEngine.INSTANCE.bakeChunkBlockLighting(centerChunk, iChunkWrapperList, maxSkyLight); + //} + centerChunk.setIsDhBlockLightCorrect(true); - this.dhServerLevel.updateBeaconBeamsForChunk(centerChunk, iChunkWrapperList); + //this.dhServerLevel.updateBeaconBeamsForChunk(centerChunk, iChunkWrapperList); } } } From c250a7408e149127775325af72c84db1f0851b04 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 2 Dec 2025 07:07:31 -0600 Subject: [PATCH 24/33] enable long file paths on windows for the DB --- coreSubProjects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreSubProjects b/coreSubProjects index 4e96728c2..4e9559f23 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 4e96728c2516dfc2c67f9f5d394a40d0fc3c2a05 +Subproject commit 4e9559f23043f8f3568362374025ff7c2c77c4df From 47e97630b406fc573a3a1b9594740e0c6d064bec Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 4 Dec 2025 07:52:54 -0600 Subject: [PATCH 25/33] Improve pre-existing chunk handling --- .../common/wrappers/chunk/ChunkWrapper.java | 107 ++++++++-------- .../BatchGenerationEnvironment.java | 86 ++++++++----- .../worldGeneration/GlobalWorldGenParams.java | 20 +-- .../worldGeneration/ThreadWorldGenParams.java | 6 +- .../ChunkCompoundTagParser.java | 116 +++++------------- .../chunkFileHandling/ChunkFileReader.java | 84 ++++++------- .../InternalServerGenerator.java | 7 +- .../step/StepStructureStart.java | 4 +- coreSubProjects | 2 +- 9 files changed, 197 insertions(+), 235 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java index e04273faf..d0e9c9a9e 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java @@ -18,10 +18,10 @@ */ package com.seibel.distanthorizons.common.wrappers.chunk; +import com.google.gson.internal.NonNullElementWrapperList; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; import com.seibel.distanthorizons.common.wrappers.misc.MutableBlockPosWrapper; -import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; import com.seibel.distanthorizons.core.pos.DhChunkPos; @@ -98,9 +98,9 @@ public class ChunkWrapper implements IChunkWrapper private int maxNonEmptyHeight = Integer.MAX_VALUE; /** will be null if we are using MC heightmaps */ - private final int[][] solidHeightMap; + private int[][] solidHeightMap = null; /** will be null if we are using MC heightmaps */ - private final int[][] lightBlockingHeightMap; + private int[][] lightBlockingHeightMap = null; @@ -109,23 +109,18 @@ public class ChunkWrapper implements IChunkWrapper //=============// public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel) + { + this(chunk, wrappedLevel, true); + } + public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel, boolean recreateHeightmaps) { this.chunk = chunk; this.wrappedLevel = wrappedLevel; this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z); - // use DH heightmaps if requested - if (Config.Common.LodBuilding.recalculateChunkHeightmaps.get()) + if (recreateHeightmaps) { - this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH]; - this.lightBlockingHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH]; - - this.recalculateDhHeightMapsIfNeeded(); - } - else - { - this.solidHeightMap = null; - this.lightBlockingHeightMap = null; + this.createDhHeightMaps(); } } @@ -248,56 +243,66 @@ public class ChunkWrapper implements IChunkWrapper } private int getChunkSectionMinHeight(int index) { return (index * 16) + this.getInclusiveMinBuildHeight(); } - /** Will only run if the config says the MC heightmaps shouldn't be trusted. */ - public void recalculateDhHeightMapsIfNeeded() + public void createDhHeightMaps() { + // only continue if we haven't already generated the DH heightmaps + if (this.solidHeightMap != null) + { + return; + } + + // re-calculate the min/max heights for consistency (during world gen these may be wrong) this.minNonEmptyHeight = Integer.MIN_VALUE; this.maxNonEmptyHeight = Integer.MAX_VALUE; - // recalculate heightmaps if needed - if (this.solidHeightMap != null) + this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH]; + this.lightBlockingHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH]; + + for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++) { - for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++) + for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++) { - for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++) + int minInclusiveBuildHeight = this.getMinNonEmptyHeight(); + // if no blocks are found the height map will be at the bottom of the world + int solidHeight = minInclusiveBuildHeight; + int lightBlockingHeight = minInclusiveBuildHeight; + + + int y = this.getMaxNonEmptyHeight(); //this.getExclusiveMaxBuildHeight(); + IBlockStateWrapper block = this.getBlockState(x, y, z); + while (// go down until we reach the minimum build height + y > minInclusiveBuildHeight + // keep going until we find both height map values + && + ( + solidHeight == minInclusiveBuildHeight + || lightBlockingHeight == minInclusiveBuildHeight + ) + ) { - int minInclusiveBuildHeight = this.getMinNonEmptyHeight(); - // if no blocks are found the height map will be at the bottom of the world - int solidHeight = minInclusiveBuildHeight; - int lightBlockingHeight = minInclusiveBuildHeight; - - - int y = this.getMaxNonEmptyHeight(); //this.getExclusiveMaxBuildHeight(); - IBlockStateWrapper block = this.getBlockState(x, y, z); - while (// go down until we reach the minimum build height - y > minInclusiveBuildHeight - // keep going until we find both height map values - && (solidHeight == minInclusiveBuildHeight || lightBlockingHeight == minInclusiveBuildHeight)) + // is this block solid? + if (solidHeight == minInclusiveBuildHeight + && block.isSolid()) { - // is this block solid? - if (solidHeight == minInclusiveBuildHeight - && block.isSolid()) - { - solidHeight = y; - } - - // is this block light blocking? - if (lightBlockingHeight == minInclusiveBuildHeight - && block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT) - { - lightBlockingHeight = y; - } - - // get the next block down - y--; - block = this.getBlockState(x, y, z); + solidHeight = y; } - this.solidHeightMap[x][z] = solidHeight; - this.lightBlockingHeightMap[x][z] = lightBlockingHeight; + // is this block light blocking? + if (lightBlockingHeight == minInclusiveBuildHeight + && block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT) + { + lightBlockingHeight = y; + } + + // get the next block down + y--; + block = this.getBlockState(x, y, z); } + + this.solidHeightMap[x][z] = solidHeight; + this.lightBlockingHeightMap[x][z] = lightBlockingHeight; } } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 881650971..06265cf61 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -34,6 +34,7 @@ import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; import com.seibel.distanthorizons.core.util.ExceptionUtil; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; @@ -61,7 +62,6 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.chunk.*; import net.minecraft.world.level.levelgen.DebugLevelSource; import net.minecraft.world.level.levelgen.FlatLevelSource; -import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; #if MC_VER <= MC_1_17_1 @@ -309,13 +309,12 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm int refPosX = genEvent.minPos.getX() - borderSize; int refPosZ = genEvent.minPos.getZ() - borderSize; - LightGetterAdaptor lightGetterAdaptor = new LightGetterAdaptor(this.globalParams.level); + LightGetterAdaptor lightGetterAdaptor = new LightGetterAdaptor(this.globalParams.mcServerLevel); DummyLightEngine dummyLightEngine = new DummyLightEngine(lightGetterAdaptor); // reused data between each offset Map chunkSkyLightingByDhPos = Collections.synchronizedMap(new HashMap<>()); Map chunkBlockLightingByDhPos = Collections.synchronizedMap(new HashMap<>()); - Map generatedChunkByDhPos = Collections.synchronizedMap(new HashMap<>()); Map chunkWrappersByDhPos = Collections.synchronizedMap(new HashMap<>()); @@ -324,7 +323,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // read existing chunks from file // //================================// - HashMap> readFutureByDhChunkPos = new HashMap<>(); + HashMap> readFutureByDhChunkPos = new HashMap<>(); Iterator existingChunkPosIterator = ChunkPosGenStream.getIterator( genEvent.minPos.getX(), genEvent.minPos.getZ(), @@ -336,18 +335,18 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm ChunkPos chunkPos = existingChunkPosIterator.next(); DhChunkPos dhChunkPos = new DhChunkPos(chunkPos.x, chunkPos.z); - CompletableFuture getExistingChunkFuture + CompletableFuture getExistingChunkFuture // running async allows file IO to run in parallel when C2ME is present - = this.chunkFileReader.createEmptyOrPreExistingChunkAsync( + = this.chunkFileReader.createEmptyOrPreExistingChunkWrapperAsync( chunkPos.x, chunkPos.z, - chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, generatedChunkByDhPos); + chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, chunkWrappersByDhPos); readFutureByDhChunkPos.put(dhChunkPos, getExistingChunkFuture); } // normally DH will handle each of these futures serially // but if C2ME is present these will be completed in parallel - for (CompletableFuture readChunkFuture : readFutureByDhChunkPos.values()) + for (CompletableFuture readChunkFuture : readFutureByDhChunkPos.values()) { readChunkFuture.join(); } @@ -371,8 +370,8 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // create empty chunks outside the generation radius if (!readFutureByDhChunkPos.containsKey(dhChunkPos)) { - ChunkAccess chunk = ChunkFileReader.CreateEmptyChunk(this.globalParams.level, chunkPos); - generatedChunkByDhPos.put(dhChunkPos, chunk); + ChunkWrapper chunkWrapper = this.chunkFileReader.CreateProtoChunkWrapper(this.globalParams.mcServerLevel, chunkPos); + chunkWrappersByDhPos.put(dhChunkPos, chunkWrapper); } } @@ -407,7 +406,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // get/create the list of chunks we're going to generate IEmptyChunkRetrievalFunc fallbackChunkGetterFunc = (chunkPosX, chunkPosZ) -> Objects.requireNonNull( - generatedChunkByDhPos.get(new DhChunkPos(chunkPosX, chunkPosZ)), + chunkWrappersByDhPos.get(new DhChunkPos(chunkPosX, chunkPosZ)).getChunk(), () -> String.format("Requested chunk [%d, %d] unavailable during world generation", chunkPosX, chunkPosZ)); ArrayGridList regionChunks = new ArrayGridList<>( @@ -424,7 +423,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm DhLitWorldGenRegion region = new DhLitWorldGenRegion( centerX, centerZ, centerChunk, - this.globalParams.level, dummyLightEngine, regionChunks, + this.globalParams.mcServerLevel, dummyLightEngine, regionChunks, ChunkStatus.STRUCTURE_STARTS, radius, // this method shouldn't be necessary since we're passing in a pre-populated // list of chunks, but just in case @@ -436,8 +435,8 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm //=============================// - // create chunk wrappers // - // and process existing chunks // + // process existing chunks // + // //=============================// ArrayGridList chunkWrapperList = new ArrayGridList<>(regionChunks.gridSize); @@ -454,17 +453,32 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm } else if (chunk != null) { - // wrap the chunk + // ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper()); chunkWrapperList.set(relX, relZ, chunkWrapper); // try setting the wrapper's lighting if (chunkBlockLightingByDhPos.containsKey(chunkWrapper.getChunkPos())) { - chunkWrapper.setBlockLightStorage(chunkBlockLightingByDhPos.get(chunkWrapper.getChunkPos())); - chunkWrapper.setSkyLightStorage(chunkSkyLightingByDhPos.get(chunkWrapper.getChunkPos())); - chunkWrapper.setIsDhBlockLightCorrect(true); - chunkWrapper.setIsDhSkyLightCorrect(true); + // block + ChunkLightStorage blockLightStorage = chunkBlockLightingByDhPos.get(chunkWrapper.getChunkPos()); + // if the light storage is empty then we should try generating the lighting + // ourselves, the light data is probably missing + if (blockLightStorage != null + && !blockLightStorage.isEmpty()) + { + chunkWrapper.setBlockLightStorage(blockLightStorage); + chunkWrapper.setIsDhBlockLightCorrect(true); + } + + // sky + ChunkLightStorage skyLightStorage = chunkSkyLightingByDhPos.get(chunkWrapper.getChunkPos()); + if (skyLightStorage != null + && !skyLightStorage.isEmpty()) + { + chunkWrapper.setSkyLightStorage(skyLightStorage); + chunkWrapper.setIsDhSkyLightCorrect(true); + } } chunkWrappersByDhPos.put(chunkPos, chunkWrapper); @@ -553,6 +567,16 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm } }); + + // if we're only working with pre-existing chunks, + // biomes need to be initialized but no other steps should be done + if (genEvent.generatorMode == EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY) + { + this.stepBiomes.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.BIOMES)); + return; + } + + EDhApiWorldGenerationStep step = genEvent.targetGenerationStep; if (step == EDhApiWorldGenerationStep.EMPTY) { @@ -626,27 +650,25 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm // light each chunk in the list for (int i = 0; i < iChunkWrapperList.size(); i++) { - ChunkWrapper centerChunk = (ChunkWrapper) iChunkWrapperList.get(i); - if (centerChunk == null) + ChunkWrapper centerChunkWrapper = (ChunkWrapper) iChunkWrapperList.get(i); + if (centerChunkWrapper == null) { continue; } throwIfThreadInterrupted(); - // make sure the height maps are all properly generated - // if this isn't done everything else afterward may fail - //Heightmap.primeHeightmaps(centerChunk.getChunk(), ChunkStatus.FEATURES.heightmapsAfter()); - centerChunk.recalculateDhHeightMapsIfNeeded(); - // pre-generated chunks should have lighting but new ones won't - //if (!centerChunk.isDhBlockLightingCorrect()) - //{ - // DhLightingEngine.INSTANCE.bakeChunkBlockLighting(centerChunk, iChunkWrapperList, maxSkyLight); - //} - centerChunk.setIsDhBlockLightCorrect(true); + if (!centerChunkWrapper.isDhBlockLightingCorrect()) + { + DhLightingEngine.INSTANCE.bakeChunkBlockLighting(centerChunkWrapper, iChunkWrapperList, maxSkyLight); + } - //this.dhServerLevel.updateBeaconBeamsForChunk(centerChunk, iChunkWrapperList); + List activeBeamList = centerChunkWrapper.getAllActiveBeacons(iChunkWrapperList); + if (!activeBeamList.isEmpty()) + { + this.dhServerLevel.updateBeaconBeamsForChunkPos(centerChunkWrapper.getChunkPos(), activeBeamList); + } } } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java index e1b112ec2..241e1d375 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java @@ -67,8 +67,8 @@ import net.minecraft.world.level.levelgen.RandomState; public final class GlobalWorldGenParams { public final ChunkGenerator generator; - public final IDhServerLevel lodLevel; - public final ServerLevel level; + public final IDhServerLevel dhServerLevel; + public final ServerLevel mcServerLevel; public final Registry biomes; public final RegistryAccess registry; public final long worldSeed; @@ -98,12 +98,12 @@ public final class GlobalWorldGenParams // constructor // //=============// - public GlobalWorldGenParams(IDhServerLevel lodLevel) + public GlobalWorldGenParams(IDhServerLevel dhServerLevel) { - this.lodLevel = lodLevel; + this.dhServerLevel = dhServerLevel; - this.level = ((ServerLevelWrapper) lodLevel.getServerLevelWrapper()).getWrappedMcObject(); - MinecraftServer server = this.level.getServer(); + this.mcServerLevel = ((ServerLevelWrapper) dhServerLevel.getServerLevelWrapper()).getWrappedMcObject(); + MinecraftServer server = this.mcServerLevel.getServer(); WorldData worldData = server.getWorldData(); this.registry = server.registryAccess(); @@ -122,16 +122,16 @@ public final class GlobalWorldGenParams #endif #if MC_VER >= MC_1_18_2 - this.biomeManager = new BiomeManager(this.level, BiomeManager.obfuscateSeed(this.worldSeed)); - this.chunkScanner = this.level.getChunkSource().chunkScanner(); + this.biomeManager = new BiomeManager(this.mcServerLevel, BiomeManager.obfuscateSeed(this.worldSeed)); + this.chunkScanner = this.mcServerLevel.getChunkSource().chunkScanner(); #endif this.structures = server.getStructureManager(); - this.generator = this.level.getChunkSource().getGenerator(); + this.generator = this.mcServerLevel.getChunkSource().getGenerator(); this.dataFixer = server.getFixerUpper(); #if MC_VER >= MC_1_19_2 - this.randomState = this.level.getChunkSource().randomState(); + this.randomState = this.mcServerLevel.getChunkSource().randomState(); #endif } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java index 5c6b20a71..d2b50b795 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java @@ -56,7 +56,7 @@ public final class ThreadWorldGenParams ThreadWorldGenParams threadParam = LOCAL_PARAM_REF.get(); if (threadParam != null && threadParam.isValid - && threadParam.level == globalParams.level) + && threadParam.level == globalParams.mcServerLevel) { return threadParam; } @@ -70,7 +70,7 @@ public final class ThreadWorldGenParams { previousGlobalWorldGenParams = param; - this.level = param.level; + this.level = param.mcServerLevel; #if MC_VER < MC_1_18_2 this.structFeatManager = new WorldGenStructFeatManager(param.worldGenSettings, this.level); @@ -78,7 +78,7 @@ public final class ThreadWorldGenParams this.structCheck = this.createStructureCheck(param); #else this.structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures, - param.level.dimension(), param.generator, param.randomState, this.level, param.generator.getBiomeSource(), param.worldSeed, + param.mcServerLevel.dimension(), param.generator, param.randomState, this.level, param.generator.getBiomeSource(), param.worldSeed, param.dataFixer); #endif } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java index 826992cce..6c197356d 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java @@ -20,11 +20,10 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling; import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.Dynamic; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.level.IDhServerLevel; import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.util.LodUtil; @@ -36,6 +35,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; import net.minecraft.core.Registry; #if MC_VER >= MC_1_19_4 import net.minecraft.core.registries.Registries; @@ -64,7 +64,6 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.levelgen.Heightmap; #if MC_VER >= MC_1_18_2 -import net.minecraft.world.level.levelgen.blending.BlendingData; #if MC_VER < MC_1_19_2 import net.minecraft.world.level.levelgen.feature.StructureFeature; #endif @@ -86,7 +85,6 @@ import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkType; #elif MC_VER >= MC_1_21_1 import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.chunk.status.ChunkType; #endif import net.minecraft.world.level.material.Fluid; @@ -111,7 +109,9 @@ public class ChunkCompoundTagParser // read chunk // //============// - public static LevelChunk createFromTag(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData) + public static ChunkWrapper createFromTag( + WorldGenLevel mcWorldGenLevel, IDhServerLevel dhServerLevel, + ChunkPos chunkPos, CompoundTag chunkData) { #if MC_VER < MC_1_18_2 CompoundTag tagLevel = chunkData.getCompound("Level"); @@ -158,57 +158,27 @@ public class ChunkCompoundTagParser - //==========================// - // ignore incomplete chunks // - //==========================// - - #if MC_VER < MC_1_20_6 - ChunkStatus.ChunkType chunkType; - #else - ChunkType chunkType; - #endif - chunkType = readChunkType(tagLevel); - - #if MC_VER < MC_1_18_2 - if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK) - { - return null; - } - #elif MC_VER < MC_1_20_6 - if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK) - { - return null; - } - #else - if (chunkType == ChunkType.PROTOCHUNK) - { - return null; - } - #endif - - - //===========// // get ticks // //===========// #if MC_VER < MC_1_18_2 ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer( - level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), #if MC_VER >= MC_1_17_1 level, #endif - chunkPos, level.getLevel().getChunkSource().getGenerator().getBiomeSource(), + mcWorldGenLevel.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), #if MC_VER >= MC_1_17_1 mcWorldGenLevel, #endif + chunkPos, mcWorldGenLevel.getLevel().getChunkSource().getGenerator().getBiomeSource(), tagLevel.contains("Biomes", 11) ? tagLevel.getIntArray("Biomes") : null); String BLOCK_TICKS_TAG_PRE18 = "TileTicks"; TickList blockTicks = tagLevel.contains(BLOCK_TICKS_TAG_PRE18, 9) ? ChunkTickList.create(tagLevel.getList(BLOCK_TICKS_TAG_PRE18, 10), Registry.BLOCK::getKey, Registry.BLOCK::get) : new ProtoTickList(block -> (block == null || block.defaultBlockState().isAir()), chunkPos, - tagLevel.getList("ToBeTicked", 9) #if MC_VER >= MC_1_17_1 , level #endif ); + tagLevel.getList("ToBeTicked", 9) #if MC_VER >= MC_1_17_1 , mcWorldGenLevel #endif ); String FLUID_TICKS_TAG_PRE18 = "LiquidTicks"; TickList fluidTicks = tagLevel.contains(FLUID_TICKS_TAG_PRE18, 9) ? ChunkTickList.create(tagLevel.getList(FLUID_TICKS_TAG_PRE18, 10), Registry.FLUID::getKey, Registry.FLUID::get) : new ProtoTickList(fluid -> (fluid == null || fluid == Fluids.EMPTY), chunkPos, - tagLevel.getList("LiquidsToBeTicked", 9) #if MC_VER >= MC_1_17_1 , level #endif ); + tagLevel.getList("LiquidsToBeTicked", 9) #if MC_VER >= MC_1_17_1 , mcWorldGenLevel #endif ); #else // ticks shouldn't be needed so ignore them for MC versions after 1.18.2 LevelChunkTicks blockTicks = new LevelChunkTicks<>(); @@ -221,7 +191,10 @@ public class ChunkCompoundTagParser // get misc properties // //=====================// - LevelChunkSection[] levelChunkSections = readSections(level, chunkPos, tagLevel); + int sectionYCount = #if MC_VER < MC_1_17_1 16; #else mcWorldGenLevel.getSectionsCount(); #endif + LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYCount]; + boolean hasBlocks = readAndPopulateSections(mcWorldGenLevel, chunkPos, tagLevel, chunkSections); + long inhabitedTime = CompoundTagUtil.getLong(tagLevel, "InhabitedTime"); boolean isLightOn = CompoundTagUtil.getBoolean(tagLevel, "isLightOn"); @@ -232,48 +205,20 @@ public class ChunkCompoundTagParser //============// #if MC_VER < MC_1_18_2 - LevelChunk chunk = new LevelChunk((Level) level.getLevel(), chunkPos, chunkBiomeContainer, UpgradeData.EMPTY, blockTicks, - fluidTicks, inhabitedTime, levelChunkSections, null); + LevelChunk chunk = new LevelChunk((Level) mcWorldGenLevel.getLevel(), chunkPos, chunkBiomeContainer, UpgradeData.EMPTY, blockTicks, + fluidTicks, inhabitedTime, chunkSections, null); #else - LevelChunk chunk = new LevelChunk((Level) level, chunkPos, UpgradeData.EMPTY, blockTicks, - fluidTicks, inhabitedTime, levelChunkSections, null, null); + LevelChunk chunk = new LevelChunk((Level) mcWorldGenLevel, chunkPos, UpgradeData.EMPTY, blockTicks, + fluidTicks, inhabitedTime, chunkSections, null, null); #endif // Set some states after object creation chunk.setLightCorrect(isLightOn); - readHeightmaps(chunk, chunkData); + boolean hasHeightmapData = readHeightmaps(chunk, chunkData); - return chunk; - } - - - - //==========================// - // chunk type // - // (incomplete chunk check) // - //==========================// - - private static - #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType - #elif MC_VER < MC_1_21_1 ChunkType - #else ChunkType #endif - readChunkType(CompoundTag tagLevel) - { - String statusString = CompoundTagUtil.getString(tagLevel,"Status"); - if (statusString != null) - { - ChunkStatus chunkStatus = ChunkStatus.byName(statusString); - if (chunkStatus != null) - { - return chunkStatus.getChunkType(); - } - } - - #if MC_VER <= MC_1_20_4 - return ChunkStatus.ChunkType.PROTOCHUNK; - #else - return ChunkType.PROTOCHUNK; - #endif + // chunk wrapper so we can pass along extra data more easily + ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, dhServerLevel.getServerLevelWrapper(), !hasHeightmapData); + return chunkWrapper; } @@ -284,10 +229,11 @@ public class ChunkCompoundTagParser //=================// /** handles both blocks and biomes */ - private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData) + private static boolean readAndPopulateSections( + LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData, + LevelChunkSection[] chunkSections) { - int sectionYIndex = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif - LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYIndex]; + int sectionYCount = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif ListTag tagSections = CompoundTagUtil.getListTag(chunkData, "Sections", 10); // try lower-case "sections" if capital "Sections" is missing @@ -298,6 +244,7 @@ public class ChunkCompoundTagParser } + boolean blocksFound = false; if (tagSections != null) { for (int j = 0; j < tagSections.size(); ++j) @@ -364,6 +311,8 @@ public class ChunkCompoundTagParser .promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string)) .getOrThrow((message) -> logErrorAndReturnException(message)); #endif + + blocksFound = true; } else { @@ -416,7 +365,7 @@ public class ChunkCompoundTagParser biomeRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); #else biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, biomeTag) - .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) + .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYCount, (String) string)) .getOrThrow((message) -> logErrorAndReturnException(message)); #endif } @@ -450,7 +399,7 @@ public class ChunkCompoundTagParser } } - return chunkSections; + return blocksFound; } private static Codec> getBlockStateCodec(LevelAccessor level) @@ -511,12 +460,12 @@ public class ChunkCompoundTagParser // heightmaps // //============// - private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData) + private static boolean readHeightmaps(LevelChunk chunk, CompoundTag chunkData) { CompoundTag tagHeightmaps = CompoundTagUtil.getCompoundTag(chunkData, "Heightmaps"); if (tagHeightmaps == null) { - return; + return false; } @@ -542,6 +491,7 @@ public class ChunkCompoundTagParser } Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter()); + return true; } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java index aaede6f57..2753f81f1 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java @@ -15,7 +15,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.storage.IOWorker; @@ -117,64 +116,57 @@ public class ChunkFileReader implements AutoCloseable * If the given chunk pos already exists in the world, that chunk will be returned, * otherwise this will return an empty chunk. */ - public CompletableFuture createEmptyOrPreExistingChunkAsync( + public CompletableFuture createEmptyOrPreExistingChunkWrapperAsync( int chunkX, int chunkZ, Map chunkSkyLightingByDhPos, Map chunkBlockLightingByDhPos, - Map generatedChunkByDhPos) + Map generatedChunkWrapperByDhPos) { ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); DhChunkPos dhChunkPos = new DhChunkPos(chunkX, chunkZ); - if (generatedChunkByDhPos.containsKey(dhChunkPos)) + if (generatedChunkWrapperByDhPos.containsKey(dhChunkPos)) { - return CompletableFuture.completedFuture(generatedChunkByDhPos.get(dhChunkPos)); + return CompletableFuture.completedFuture(generatedChunkWrapperByDhPos.get(dhChunkPos)); } return this.getChunkNbtDataAsync(chunkPos) .thenApply((CompoundTag chunkData) -> { - ChunkAccess newChunk = this.loadOrMakeChunk(chunkPos, chunkData); + ChunkWrapper newChunkWrapper = this.loadOrMakeChunkWrapper(chunkPos, chunkData); - if (Config.Common.LodBuilding.pullLightingForPregeneratedChunks.get()) + // attempt to get chunk lighting + ChunkCompoundTagParser.CombinedChunkLightStorage combinedLights = ChunkCompoundTagParser.readLight(newChunkWrapper.getChunk(), chunkData); + if (combinedLights != null) { - // attempt to get chunk lighting - ChunkCompoundTagParser.CombinedChunkLightStorage combinedLights = ChunkCompoundTagParser.readLight(newChunk, chunkData); - if (combinedLights != null) - { - chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage); - chunkBlockLightingByDhPos.put(dhChunkPos, combinedLights.blockLightStorage); - } + // may be empty, empty checks are handled later + chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage); + chunkBlockLightingByDhPos.put(dhChunkPos, combinedLights.blockLightStorage); } - return newChunk; + return newChunkWrapper; }) // separate handle so we can cleanly handle missing chunks and/or thrown errors - .handle((newChunk, throwable) -> + .handle((ChunkWrapper newChunkWrapper, Throwable throwable) -> { - if (newChunk != null) + if (newChunkWrapper != null) { - return newChunk; + return newChunkWrapper; } else { - return CreateEmptyChunk(this.params.level, chunkPos); + return this.CreateProtoChunkWrapper(this.params.mcServerLevel, chunkPos); } }) - .thenApply((newChunk) -> + .thenApply((ChunkWrapper newChunkWrapper) -> { - generatedChunkByDhPos.put(dhChunkPos, newChunk); - return newChunk; + generatedChunkWrapperByDhPos.put(dhChunkPos, newChunkWrapper); + return newChunkWrapper; }); } private CompletableFuture getChunkNbtDataAsync(ChunkPos chunkPos) { - ServerLevel level = this.params.level; - - //if (true) - // return CompletableFuture.completedFuture(null); - - // TODO disabling drastically reduces GC overhead (2Gb/s -> 1GB/s) + ServerLevel level = this.params.mcServerLevel; try { @@ -190,7 +182,7 @@ public class ChunkFileReader implements AutoCloseable { try { - RegionFileStorage storage = this.params.level.getChunkSource().chunkMap.worker.storage; + RegionFileStorage storage = this.params.mcServerLevel.getChunkSource().chunkMap.worker.storage; RegionFileStorageExternalCache cache = this.getOrCreateRegionFileCache(storage); return CompletableFuture.completedFuture(cache.read(chunkPos)); } @@ -264,35 +256,24 @@ public class ChunkFileReader implements AutoCloseable return CompletableFuture.completedFuture(null); } } - private ChunkAccess loadOrMakeChunk(ChunkPos chunkPos, CompoundTag chunkTagData) + private ChunkWrapper loadOrMakeChunkWrapper(ChunkPos chunkPos, CompoundTag chunkTagData) { - ServerLevel level = this.params.level; + ServerLevel mcServerLevel = this.params.mcServerLevel; if (chunkTagData == null) { - return CreateEmptyChunk(level, chunkPos); + return this.CreateProtoChunkWrapper(mcServerLevel, chunkPos); } else { try { - @Nullable - ChunkAccess chunk = ChunkCompoundTagParser.createFromTag(level, chunkPos, chunkTagData); - if (chunk != null) + ChunkWrapper chunkWrapper = ChunkCompoundTagParser.createFromTag(mcServerLevel, this.params.dhServerLevel, chunkPos, chunkTagData); + if (chunkWrapper == null) { - if (Config.Common.LodBuilding.assumePreExistingChunksAreFinished.get()) - { - // Sometimes the chunk status is wrong - // (this might be an issue with some versions of chunky) - // which can cause issues with some world gen steps re-running and locking up - ChunkWrapper.trySetStatus(chunk, ChunkStatus.FULL); - } + chunkWrapper = this.CreateProtoChunkWrapper(mcServerLevel, chunkPos); } - else - { - chunk = CreateEmptyChunk(level, chunkPos); - } - return chunk; + return chunkWrapper; } catch (Exception e) { @@ -303,12 +284,17 @@ public class ChunkFileReader implements AutoCloseable "Error: [" + e.getMessage() + "]." , e); - return CreateEmptyChunk(level, chunkPos); + return this.CreateProtoChunkWrapper(mcServerLevel, chunkPos); } } } - public static ProtoChunk CreateEmptyChunk(ServerLevel level, ChunkPos chunkPos) + public ChunkWrapper CreateProtoChunkWrapper(ServerLevel level, ChunkPos chunkPos) + { + ProtoChunk chunk = CreateProtoChunk(level, chunkPos); + return new ChunkWrapper(chunk, this.params.dhServerLevel.getLevelWrapper()); + } + public static ProtoChunk CreateProtoChunk(ServerLevel level, ChunkPos chunkPos) { #if MC_VER <= MC_1_16_5 return new ProtoChunk(chunkPos, UpgradeData.EMPTY); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java index bfa3805a8..d0cf3f5e8 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java @@ -172,7 +172,6 @@ public class InternalServerGenerator for (int i = 0; i < chunkWrappers.size(); i++) { ChunkWrapper chunkWrapper = (ChunkWrapper)chunkWrappers.get(i); - chunkWrapper.recalculateDhHeightMapsIfNeeded(); // pre-generated chunks should have lighting but new ones won't if (!chunkWrapper.isDhBlockLightingCorrect()) @@ -191,7 +190,7 @@ public class InternalServerGenerator while (chunkPosIterator.hasNext()) { ChunkPos chunkPos = chunkPosIterator.next(); - this.releaseChunkFromServer(this.params.level, chunkPos); + this.releaseChunkFromServer(this.params.mcServerLevel, chunkPos); } } } @@ -233,7 +232,7 @@ public class InternalServerGenerator { return CompletableFuture.supplyAsync(() -> { - ServerLevel level = this.params.level; + ServerLevel level = this.params.mcServerLevel; // ignore chunk update events for this position SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.addPosToIgnore(new DhChunkPos(chunkPos.x, chunkPos.z)); @@ -265,7 +264,7 @@ public class InternalServerGenerator .thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.getError()))); // can throw if the server is shutting down #endif - }, this.params.level.getChunkSource().chunkMap.mainThreadExecutor) + }, this.params.mcServerLevel.getChunkSource().chunkMap.mainThreadExecutor) .thenCompose(Function.identity()); } /** diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java index 70c2d1431..a22da9ab2 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java @@ -106,9 +106,9 @@ public final class StepStructureStart extends AbstractWorldGenStep tParams.structFeatManager, chunk, this.environment.globalParams.structures); #else this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry, - this.environment.globalParams.level.getChunkSource().getGeneratorState(), + this.environment.globalParams.mcServerLevel.getChunkSource().getGeneratorState(), tParams.structFeatManager, chunk, this.environment.globalParams.structures, - this.environment.globalParams.level.dimension()); + this.environment.globalParams.mcServerLevel.dimension()); #endif #if MC_VER >= MC_1_18_2 diff --git a/coreSubProjects b/coreSubProjects index 4e9559f23..385bd326c 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 4e9559f23043f8f3568362374025ff7c2c77c4df +Subproject commit 385bd326cf2488bcef7be82194e55743a141e3cf From ea92a8f9227eb937a42f79ef20e153342d4e9ab6 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 6 Dec 2025 09:18:55 -0600 Subject: [PATCH 26/33] revert internal server to FEATURES to improve speed --- .../internalServer/InternalServerGenerator.java | 6 +++--- coreSubProjects | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java index d0cf3f5e8..684e5bc99 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java @@ -254,13 +254,13 @@ public class InternalServerGenerator } #if MC_VER <= MC_1_20_4 - return chunkHolder.getOrScheduleFuture(ChunkStatus.FULL, level.getChunkSource().chunkMap) + return chunkHolder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) .thenApply(result -> result.left().orElseThrow(() -> new RuntimeException(result.right().get().toString()))); // can throw if the server is shutting down #elif MC_VER <= MC_1_20_6 - return chunkHolder.getOrScheduleFuture(ChunkStatus.FULL, level.getChunkSource().chunkMap) + return chunkHolder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) .thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.toString()))); // can throw if the server is shutting down #else - return chunkHolder.scheduleChunkGenerationTask(ChunkStatus.FULL, level.getChunkSource().chunkMap) + return chunkHolder.scheduleChunkGenerationTask(ChunkStatus.FEATURES, level.getChunkSource().chunkMap) .thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.getError()))); // can throw if the server is shutting down #endif diff --git a/coreSubProjects b/coreSubProjects index 385bd326c..5ca754d2a 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 385bd326cf2488bcef7be82194e55743a141e3cf +Subproject commit 5ca754d2ac1e65c4b800194a9fd1350232d5ab2c From d2327ae8367e7bf1622a8f82fd185564937edc86 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 6 Dec 2025 09:35:39 -0600 Subject: [PATCH 27/33] log incomplete world gen warnings --- .../worldGeneration/BatchGenerationEnvironment.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 06265cf61..00b1d1cde 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -120,6 +120,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm public final StepFeatures stepFeatures = new StepFeatures(this); public boolean unsafeThreadingRecorded = false; + public boolean generatedChunkWithoutBiomeWarningLogged = false; public int unknownExceptionCount = 0; public long lastExceptionTriggerTime = 0; @@ -525,6 +526,15 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm { genEvent.resultConsumer.accept(wrappedChunk); } + else + { + // this shouldn't happen, but if it does log it + if (!this.generatedChunkWithoutBiomeWarningLogged) + { + this.generatedChunkWithoutBiomeWarningLogged = true; + LOGGER.warn("Chunk [" + dhPos + "] wasn't generated up to BIOMES, world gen may appear empty."); + } + } } } catch (CompletionException | UncheckedInterruptedException e) From 7888de82002fc5443ff0fd2bc7f83af7fda980fe Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 6 Dec 2025 09:44:32 -0600 Subject: [PATCH 28/33] Move world gen files into different namespaces --- .../worldGeneration/BatchGenerationEnvironment.java | 2 +- .../common/wrappers/worldGeneration/GenerationEvent.java | 1 + .../{internalServer => }/InternalServerGenerator.java | 6 ++---- .../worldGeneration/chunkFileHandling/ChunkFileReader.java | 5 +---- .../worldGeneration/{ => params}/GlobalWorldGenParams.java | 4 +--- .../worldGeneration/{ => params}/ThreadWorldGenParams.java | 2 +- .../wrappers/worldGeneration/step/AbstractWorldGenStep.java | 2 +- .../common/wrappers/worldGeneration/step/StepBiomes.java | 2 +- .../common/wrappers/worldGeneration/step/StepFeatures.java | 2 +- .../common/wrappers/worldGeneration/step/StepNoise.java | 2 +- .../worldGeneration/step/StepStructureReference.java | 2 +- .../wrappers/worldGeneration/step/StepStructureStart.java | 2 +- .../common/wrappers/worldGeneration/step/StepSurface.java | 2 +- 13 files changed, 14 insertions(+), 20 deletions(-) rename common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/{internalServer => }/InternalServerGenerator.java (98%) rename common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/{ => params}/GlobalWorldGenParams.java (96%) rename common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/{ => params}/ThreadWorldGenParams.java (99%) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 00b1d1cde..6ece223cc 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -26,8 +26,8 @@ import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGenerat import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling.ChunkFileReader; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.internalServer.InternalServerGenerator; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.*; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.GlobalWorldGenParams; import com.seibel.distanthorizons.core.generation.DhLightingEngine; import com.seibel.distanthorizons.core.level.IDhServerLevel; import com.seibel.distanthorizons.core.config.Config; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java index 351f22c52..603318235 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GenerationEvent.java @@ -25,6 +25,7 @@ import java.util.function.Consumer; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams; import com.seibel.distanthorizons.core.util.ExceptionUtil; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhChunkPos; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/InternalServerGenerator.java similarity index 98% rename from common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java rename to common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/InternalServerGenerator.java index 684e5bc99..eb7fa0b25 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/internalServer/InternalServerGenerator.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/InternalServerGenerator.java @@ -1,10 +1,8 @@ -package com.seibel.distanthorizons.common.wrappers.worldGeneration.internalServer; +package com.seibel.distanthorizons.common.wrappers.worldGeneration; import com.seibel.distanthorizons.api.DhApi; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ChunkPosGenStream; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.GenerationEvent; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.GlobalWorldGenParams; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.GlobalWorldGenParams; import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.config.Config; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java index 2753f81f1..ee344339a 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java @@ -1,7 +1,7 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.GlobalWorldGenParams; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.GlobalWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.RegionFileStorageExternalCache; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; @@ -20,8 +20,6 @@ import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.chunk.storage.RegionFileStorage; -import org.jetbrains.annotations.Nullable; - import java.io.IOException; import java.nio.channels.ClosedByInterruptException; import java.nio.channels.ClosedChannelException; @@ -45,7 +43,6 @@ import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.core.registries.Registries; import net.minecraft.world.level.chunk.status.ChunkStatus; #else -import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.PalettedContainerFactory; #endif diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/params/GlobalWorldGenParams.java similarity index 96% rename from common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java rename to common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/params/GlobalWorldGenParams.java index 241e1d375..2f5b729d0 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/GlobalWorldGenParams.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/params/GlobalWorldGenParams.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.distanthorizons.common.wrappers.worldGeneration; +package com.seibel.distanthorizons.common.wrappers.worldGeneration.params; import com.mojang.datafixers.DataFixer; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; @@ -55,8 +55,6 @@ import net.minecraft.core.registries.Registries; import net.minecraft.world.level.levelgen.WorldGenSettings; #else import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; -import net.minecraft.world.level.levelgen.RandomState; #endif /** diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/params/ThreadWorldGenParams.java similarity index 99% rename from common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java rename to common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/params/ThreadWorldGenParams.java index d2b50b795..82905556f 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/ThreadWorldGenParams.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/params/ThreadWorldGenParams.java @@ -18,7 +18,7 @@ */ -package com.seibel.distanthorizons.common.wrappers.worldGeneration; +package com.seibel.distanthorizons.common.wrappers.worldGeneration.params; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.WorldGenStructFeatManager; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/AbstractWorldGenStep.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/AbstractWorldGenStep.java index dad094c37..4cf169062 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/AbstractWorldGenStep.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/AbstractWorldGenStep.java @@ -1,7 +1,7 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.step; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; import net.minecraft.world.level.chunk.ChunkAccess; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java index 5d04bc004..a4fa04f80 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepBiomes.java @@ -23,7 +23,7 @@ import java.util.ArrayList; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java index 20407770e..24542b106 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepFeatures.java @@ -21,7 +21,7 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.step; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java index 04cd3d356..f6b7625cd 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepNoise.java @@ -23,7 +23,7 @@ import java.util.ArrayList; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java index 714019300..4a0bf6ddd 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java @@ -23,7 +23,7 @@ import java.util.ArrayList; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java index a22da9ab2..271fe1c05 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java @@ -24,7 +24,7 @@ import java.util.concurrent.locks.ReentrantLock; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java index 6e9a2d606..92c5bd1da 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepSurface.java @@ -23,7 +23,7 @@ import java.util.ArrayList; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; -import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadWorldGenParams; +import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; From 9ecbb9cc9f966f28401a709dc2bc4682d105079f Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 6 Dec 2025 10:05:32 -0600 Subject: [PATCH 29/33] Fix old version compiling --- .../common/wrappers/chunk/ChunkWrapper.java | 1 - .../chunkFileHandling/ChunkFileReader.java | 9 ++++++++- .../worldGeneration/params/ThreadWorldGenParams.java | 2 +- .../worldGeneration/step/StepStructureStart.java | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java index d0e9c9a9e..72e8cee5c 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java @@ -18,7 +18,6 @@ */ package com.seibel.distanthorizons.common.wrappers.chunk; -import com.google.gson.internal.NonNullElementWrapperList; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; import com.seibel.distanthorizons.common.wrappers.misc.MutableBlockPosWrapper; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java index ee344339a..d1dc68445 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java @@ -38,10 +38,17 @@ import net.minecraft.core.registries.Registries; import net.minecraft.world.level.chunk.ChunkStatus; #elif MC_VER <= MC_1_20_6 import net.minecraft.core.registries.Registries; +#elif MC_VER <= MC_1_21_3 +import net.minecraft.core.registries.Registries; import net.minecraft.world.level.chunk.ChunkStatus; -#elif MC_VER <= MC_1_21_9 +#elif MC_VER <= MC_1_21_3 import net.minecraft.core.registries.Registries; import net.minecraft.world.level.chunk.status.ChunkStatus; +#elif MC_VER <= MC_1_21_8 +import net.minecraft.core.registries.Registries; +import net.minecraft.world.level.chunk.status.ChunkStatus; +#elif MC_VER <= MC_1_21_9 +import net.minecraft.world.level.chunk.PalettedContainerFactory; #else import net.minecraft.world.level.chunk.PalettedContainerFactory; #endif diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/params/ThreadWorldGenParams.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/params/ThreadWorldGenParams.java index 82905556f..00944a550 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/params/ThreadWorldGenParams.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/params/ThreadWorldGenParams.java @@ -112,7 +112,7 @@ public final class ThreadWorldGenParams private StructureCheck createStructureCheck(GlobalWorldGenParams param) { return new StructureCheck(param.chunkScanner, param.registry, param.structures, - param.level.dimension(), param.generator, this.level, param.generator.getBiomeSource(), param.worldSeed, + param.mcServerLevel.dimension(), param.generator, this.level, param.generator.getBiomeSource(), param.worldSeed, param.dataFixer); } #else diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java index 271fe1c05..340bbf683 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java @@ -102,7 +102,7 @@ public final class StepStructureStart extends AbstractWorldGenStep this.environment.globalParams.worldSeed); #elif MC_VER <= MC_1_21_3 this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry, - this.environment.globalParams.level.getChunkSource().getGeneratorState(), + this.environment.globalParams.mcServerLevel.getChunkSource().getGeneratorState(), tParams.structFeatManager, chunk, this.environment.globalParams.structures); #else this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry, From b3f607e13292544263af142a2b7b00555fad8806 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 6 Dec 2025 11:07:41 -0600 Subject: [PATCH 30/33] clean up version property files --- neoforge/build.gradle | 1 - versionProperties/1.16.5.properties | 1 - versionProperties/1.17.1.properties | 1 - versionProperties/1.18.2.properties | 1 - versionProperties/1.19.2.properties | 1 - versionProperties/1.19.4.properties | 1 - versionProperties/1.20.1.properties | 1 - versionProperties/1.20.2.properties | 1 - versionProperties/1.20.4.properties | 9 ++++----- versionProperties/1.20.6.properties | 13 ++++--------- versionProperties/1.21.1.properties | 11 +++-------- versionProperties/1.21.10.properties | 9 ++------- versionProperties/1.21.3.properties | 11 +++-------- versionProperties/1.21.4.properties | 11 +++-------- versionProperties/1.21.5.properties | 10 +++------- versionProperties/1.21.6.properties | 11 +++-------- versionProperties/1.21.8.properties | 11 +++-------- versionProperties/1.21.9.properties | 9 ++------- 18 files changed, 30 insertions(+), 83 deletions(-) diff --git a/neoforge/build.gradle b/neoforge/build.gradle index 89b5b2f6d..bcfa14bda 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -65,7 +65,6 @@ dependencies { // Neoforge neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}" - addMod("curse.maven:TerraFirmaCraft-302973:4616004", rootProject.enable_terrafirmacraft) } diff --git a/versionProperties/1.16.5.properties b/versionProperties/1.16.5.properties index 01d2bac2b..1c1751740 100644 --- a/versionProperties/1.16.5.properties +++ b/versionProperties/1.16.5.properties @@ -48,7 +48,6 @@ forge_version=36.2.39 neoforge_version_range=[*,) # Forge mod versions - starlight_version_forge= terraforged_version=4044290 # Forge mod run diff --git a/versionProperties/1.17.1.properties b/versionProperties/1.17.1.properties index ff748417c..e289396c6 100644 --- a/versionProperties/1.17.1.properties +++ b/versionProperties/1.17.1.properties @@ -47,7 +47,6 @@ forge_version=37.1.1 neoforge_version_range=[*,) # Forge mod versions - starlight_version_forge=3457784 terraforged_version= # Forge mod run diff --git a/versionProperties/1.18.2.properties b/versionProperties/1.18.2.properties index a3d752b49..0690b97bb 100644 --- a/versionProperties/1.18.2.properties +++ b/versionProperties/1.18.2.properties @@ -56,7 +56,6 @@ forge_version=40.2.10 neoforge_version_range=[*,) # Forge mod versions - starlight_version_forge= terraforged_version= # Forge mod run diff --git a/versionProperties/1.19.2.properties b/versionProperties/1.19.2.properties index 36daf1491..e3d228d3a 100644 --- a/versionProperties/1.19.2.properties +++ b/versionProperties/1.19.2.properties @@ -47,7 +47,6 @@ forge_version=43.3.2 neoforge_version_range=[*,) # Forge mod versions - starlight_version_forge= terraforged_version= # Forge mod run diff --git a/versionProperties/1.19.4.properties b/versionProperties/1.19.4.properties index 64a2048a5..ddddb1129 100644 --- a/versionProperties/1.19.4.properties +++ b/versionProperties/1.19.4.properties @@ -46,7 +46,6 @@ forge_version=45.2.4 neoforge_version_range=[*,) # Forge mod versions - starlight_version_forge= terraforged_version= # Forge mod run diff --git a/versionProperties/1.20.1.properties b/versionProperties/1.20.1.properties index 5c0d75b60..ae501f639 100644 --- a/versionProperties/1.20.1.properties +++ b/versionProperties/1.20.1.properties @@ -46,7 +46,6 @@ forge_version=47.2.1 neoforge_version_range=[*,) # Forge mod versions - starlight_version_forge= terraforged_version= # Forge mod run diff --git a/versionProperties/1.20.2.properties b/versionProperties/1.20.2.properties index b72f17a3b..625a901ba 100644 --- a/versionProperties/1.20.2.properties +++ b/versionProperties/1.20.2.properties @@ -46,7 +46,6 @@ forge_version=48.0.13 neoforge_version_range=[*,) # Forge mod versions - starlight_version_forge= terraforged_version= # Forge mod run diff --git a/versionProperties/1.20.4.properties b/versionProperties/1.20.4.properties index 47152d13f..f996087a3 100644 --- a/versionProperties/1.20.4.properties +++ b/versionProperties/1.20.4.properties @@ -41,16 +41,15 @@ fabric_api_version=0.91.2+1.20.4 enable_immersive_portals=0 enable_canvas=0 -# (Neo)Forge loader +# Forge loader forge_version=49.1.13 -neoforge_version=20.4.246 +neoforge_version= neoforge_version_range=[*,) - # (Neo)Forge mod versions - starlight_version_forge= + # Forge mod versions terraforged_version= - # (Neo)Forge mod run + # Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client diff --git a/versionProperties/1.20.6.properties b/versionProperties/1.20.6.properties index cda4dca1a..57ae30653 100644 --- a/versionProperties/1.20.6.properties +++ b/versionProperties/1.20.6.properties @@ -41,19 +41,14 @@ fabric_api_version=0.97.8+1.20.6 enable_immersive_portals=0 enable_canvas=0 -# (Neo)Forge loader -forge_version=50.0.19 +# NeoForge loader +forge_version= neoforge_version=20.6.136 neoforge_version_range=[*,) - # (Neo)Forge mod versions - starlight_version_forge= - terraforged_version= - + # NeoForge mod versions + # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client - enable_starlight_forge=0 - enable_terraforged=0 - enable_terrafirmacraft=0 diff --git a/versionProperties/1.21.1.properties b/versionProperties/1.21.1.properties index b68287f2c..b726cef95 100644 --- a/versionProperties/1.21.1.properties +++ b/versionProperties/1.21.1.properties @@ -41,19 +41,14 @@ fabric_api_version=0.115.0+1.21.1 enable_immersive_portals=0 enable_canvas=0 -# (Neo)Forge loader +# NeoForge loader forge_version= neoforge_version=21.1.192 neoforge_version_range=[*,) - # (Neo)Forge mod versions - starlight_version_forge= - terraforged_version= - + # NeoForge mod versions + # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client - enable_starlight_forge=0 - enable_terraforged=0 - enable_terrafirmacraft=0 diff --git a/versionProperties/1.21.10.properties b/versionProperties/1.21.10.properties index 209285e56..999770a7e 100644 --- a/versionProperties/1.21.10.properties +++ b/versionProperties/1.21.10.properties @@ -39,19 +39,14 @@ fabric_api_version=0.138.3+1.21.10 enable_immersive_portals=0 enable_canvas=0 -# (Neo)Forge loader +# NeoForge loader forge_version= neoforge_version=21.10.55-beta neoforge_version_range=[21.10.6-beta,) - # (Neo)Forge mod versions - starlight_version_forge= - terraforged_version= + # NeoForge mod versions # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client - enable_starlight_forge=0 - enable_terraforged=0 - enable_terrafirmacraft=0 diff --git a/versionProperties/1.21.3.properties b/versionProperties/1.21.3.properties index a719956f5..dbc622648 100644 --- a/versionProperties/1.21.3.properties +++ b/versionProperties/1.21.3.properties @@ -41,19 +41,14 @@ fabric_api_version=0.110.0+1.21.3 enable_immersive_portals=0 enable_canvas=0 -# (Neo)Forge loader +# NeoForge loader forge_version= neoforge_version=21.3.86 neoforge_version_range=[*,) - # (Neo)Forge mod versions - starlight_version_forge= - terraforged_version= - + # NeoForge mod versions + # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client - enable_starlight_forge=0 - enable_terraforged=0 - enable_terrafirmacraft=0 diff --git a/versionProperties/1.21.4.properties b/versionProperties/1.21.4.properties index b221459dc..fa4e5573f 100644 --- a/versionProperties/1.21.4.properties +++ b/versionProperties/1.21.4.properties @@ -40,20 +40,15 @@ fabric_api_version=0.110.5+1.21.4 enable_immersive_portals=0 enable_canvas=0 -# (Neo)Forge loader +# NeoForge loader forge_version= neoforge_version=21.4.147 # version range may not be necessary, but having compiled DH for an older version caused issues with shaders neoforge_version_range=[21.4.147,) - # (Neo)Forge mod versions - starlight_version_forge= - terraforged_version= - + # NeoForge mod versions + # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client - enable_starlight_forge=0 - enable_terraforged=0 - enable_terrafirmacraft=0 diff --git a/versionProperties/1.21.5.properties b/versionProperties/1.21.5.properties index 289fbe64e..c492b12f0 100644 --- a/versionProperties/1.21.5.properties +++ b/versionProperties/1.21.5.properties @@ -40,19 +40,15 @@ fabric_api_version=0.119.5+1.21.5 enable_immersive_portals=0 enable_canvas=0 -# (Neo)Forge loader +# NeoForge loader forge_version= neoforge_version=21.5.87 neoforge_version_range=[*,) - # (Neo)Forge mod versions - starlight_version_forge= - terraforged_version= + # NeoForge mod versions + # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client - enable_starlight_forge=0 - enable_terraforged=0 - enable_terrafirmacraft=0 diff --git a/versionProperties/1.21.6.properties b/versionProperties/1.21.6.properties index 647df0aa1..be99ed899 100644 --- a/versionProperties/1.21.6.properties +++ b/versionProperties/1.21.6.properties @@ -39,20 +39,15 @@ fabric_api_version=0.127.0+1.21.6 enable_immersive_portals=0 enable_canvas=0 -# (Neo)Forge loader +# NeoForge loader forge_version= neoforge_version=21.6.20-beta # around 6.19 neo changed how their render API works, failing to meet this causes the game to crash neoforge_version_range=[21.6.19-beta,) - - # (Neo)Forge mod versions - starlight_version_forge= - terraforged_version= + # NeoForge mod versions + # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client - enable_starlight_forge=0 - enable_terraforged=0 - enable_terrafirmacraft=0 diff --git a/versionProperties/1.21.8.properties b/versionProperties/1.21.8.properties index c00be8478..7699fa59d 100644 --- a/versionProperties/1.21.8.properties +++ b/versionProperties/1.21.8.properties @@ -39,20 +39,15 @@ fabric_api_version=0.133.4+1.21.8 enable_immersive_portals=0 enable_canvas=0 -# (Neo)Forge loader +# NeoForge loader forge_version= neoforge_version=21.8.2-beta # around 6.19 neo changed how their render API works, failing to meet this causes the game to crash neoforge_version_range=[*,) - # (Neo)Forge mod versions - starlight_version_forge= - terraforged_version= + # NeoForge mod versions - # (Neo)Forge mod run + # NeoForge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client - enable_starlight_forge=0 - enable_terraforged=0 - enable_terrafirmacraft=0 diff --git a/versionProperties/1.21.9.properties b/versionProperties/1.21.9.properties index 3d5437bde..471f8207b 100644 --- a/versionProperties/1.21.9.properties +++ b/versionProperties/1.21.9.properties @@ -39,21 +39,16 @@ fabric_api_version=0.134.0+1.21.9 enable_immersive_portals=0 enable_canvas=0 -# (Neo)Forge loader +# NeoForge loader forge_version= neoforge_version=21.9.15-beta # sometime before 21.9.15-beta Neoforge changed how their rendering API events handle levels # so we can't support both versions at once neoforge_version_range=[21.9.15-beta,) - # (Neo)Forge mod versions - starlight_version_forge= - terraforged_version= + # NeoForge mod versions # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client - enable_starlight_forge=0 - enable_terraforged=0 - enable_terrafirmacraft=0 From ff41e070fd029c82db22bbdd00a5ef646dc72e49 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 6 Dec 2025 11:59:39 -0600 Subject: [PATCH 31/33] Fix some iris issues on Neoforge --- .../wrappers/modAccessor/IrisAccessor.java | 16 ++--- neoforge/build.gradle | 4 ++ .../neoforge/NeoforgeMain.java | 7 ++ .../wrappers/modAccessor/IrisAccessor.java | 67 +++++++++++++++++++ versionProperties/1.20.6.properties | 4 +- versionProperties/1.21.1.properties | 7 +- versionProperties/1.21.10.properties | 6 +- versionProperties/1.21.3.properties | 2 + versionProperties/1.21.4.properties | 2 + versionProperties/1.21.5.properties | 3 +- versionProperties/1.21.6.properties | 2 + versionProperties/1.21.8.properties | 11 +-- versionProperties/1.21.9.properties | 7 +- 13 files changed, 114 insertions(+), 24 deletions(-) create mode 100644 neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/IrisAccessor.java diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/IrisAccessor.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/IrisAccessor.java index 84f666cd5..40790483d 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/IrisAccessor.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/wrappers/modAccessor/IrisAccessor.java @@ -34,22 +34,14 @@ import net.irisshaders.iris.api.v0.IrisApi; public class IrisAccessor implements IIrisAccessor { @Override - public String getModName() - { - return Iris.MODID; - } + public String getModName() { return Iris.MODID; } @Override - public boolean isShaderPackInUse() - { - return IrisApi.getInstance().isShaderPackInUse(); - } + public boolean isShaderPackInUse() { return IrisApi.getInstance().isShaderPackInUse(); } @Override - public boolean isRenderingShadowPass() - { - return IrisApi.getInstance().isRenderingShadowPass(); - } + public boolean isRenderingShadowPass() { return IrisApi.getInstance().isRenderingShadowPass(); } + } #endif diff --git a/neoforge/build.gradle b/neoforge/build.gradle index bcfa14bda..20c8f3f27 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -65,6 +65,10 @@ dependencies { // Neoforge neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}" + + // Iris + addMod("maven.modrinth:iris:${rootProject.neo_iris_version}", rootProject.neo_enable_iris) + } diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java index 8559b24d5..0fd84bd81 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java @@ -31,10 +31,12 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRen import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor; +import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor; import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.C2meAccessor; +import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.IrisAccessor; import com.seibel.distanthorizons.neoforge.wrappers.NeoforgeMinecraftRenderWrapper; import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.ModChecker; import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.OptifineAccessor; @@ -148,6 +150,11 @@ public class NeoforgeMain extends AbstractModInitializer this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new); this.tryCreateModCompatAccessor("c2me", IC2meAccessor.class, C2meAccessor::new); + #if MC_VER >= MC_1_20_6 + // 1.20.6 is the lowest version Iris supports Neoforge + this.tryCreateModCompatAccessor("iris", IIrisAccessor.class, IrisAccessor::new); + #endif + #if MC_VER < MC_1_20_6 ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, () -> new ConfigScreenHandler.ConfigScreenFactory((client, parent) -> GetConfigScreen.getScreen(parent))); diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/IrisAccessor.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/IrisAccessor.java new file mode 100644 index 000000000..26e9148a6 --- /dev/null +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/wrappers/modAccessor/IrisAccessor.java @@ -0,0 +1,67 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.neoforge.wrappers.modAccessor; + +// 1.20.6 is the lowest version Iris supports Neoforge +#if MC_VER >= MC_1_20_6 + +import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor; + +#if MC_VER != MC_1_21_9 +import net.irisshaders.iris.Iris; +import net.irisshaders.iris.api.v0.IrisApi; +#endif + +public class IrisAccessor implements IIrisAccessor +{ + @Override + public String getModName() + { + #if MC_VER == MC_1_21_9 + return "iris"; // Iris doesn't support this MC version + #else + return Iris.MODID; + #endif + } + + @Override + public boolean isShaderPackInUse() + { + #if MC_VER == MC_1_21_9 + return true; // Iris doesn't support this MC version + #else + return IrisApi.getInstance().isShaderPackInUse(); + #endif + } + + @Override + public boolean isRenderingShadowPass() + { + #if MC_VER == MC_1_21_9 + return false; // Iris doesn't support this MC version + #else + return IrisApi.getInstance().isRenderingShadowPass(); + #endif + } + +} + +#endif + diff --git a/versionProperties/1.20.6.properties b/versionProperties/1.20.6.properties index 57ae30653..33b8a9c40 100644 --- a/versionProperties/1.20.6.properties +++ b/versionProperties/1.20.6.properties @@ -45,10 +45,12 @@ fabric_api_version=0.97.8+1.20.6 forge_version= neoforge_version=20.6.136 neoforge_version_range=[*,) - + # NeoForge mod versions + neo_iris_version=1.8.12+1.21.1-neoforge # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client + neo_enable_iris=1 diff --git a/versionProperties/1.21.1.properties b/versionProperties/1.21.1.properties index b726cef95..5d54e32c4 100644 --- a/versionProperties/1.21.1.properties +++ b/versionProperties/1.21.1.properties @@ -43,12 +43,15 @@ fabric_api_version=0.115.0+1.21.1 # NeoForge loader forge_version= -neoforge_version=21.1.192 +neoforge_version=21.1.216 neoforge_version_range=[*,) # NeoForge mod versions - + neo_iris_version=1.8.12+1.21.1-neoforge + # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client + neo_enable_iris=1 + diff --git a/versionProperties/1.21.10.properties b/versionProperties/1.21.10.properties index 999770a7e..dc30ac02b 100644 --- a/versionProperties/1.21.10.properties +++ b/versionProperties/1.21.10.properties @@ -41,12 +41,14 @@ fabric_api_version=0.138.3+1.21.10 # NeoForge loader forge_version= -neoforge_version=21.10.55-beta +neoforge_version=21.10.56-beta neoforge_version_range=[21.10.6-beta,) # NeoForge mod versions - + neo_iris_version=1.9.6+1.21.10-neoforge + # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client + neo_enable_iris=1 diff --git a/versionProperties/1.21.3.properties b/versionProperties/1.21.3.properties index dbc622648..5dec76fc8 100644 --- a/versionProperties/1.21.3.properties +++ b/versionProperties/1.21.3.properties @@ -47,8 +47,10 @@ neoforge_version=21.3.86 neoforge_version_range=[*,) # NeoForge mod versions + neo_iris_version=1.8.1+1.21.3-neoforge # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client + neo_enable_iris=1 diff --git a/versionProperties/1.21.4.properties b/versionProperties/1.21.4.properties index fa4e5573f..deaa58a70 100644 --- a/versionProperties/1.21.4.properties +++ b/versionProperties/1.21.4.properties @@ -47,8 +47,10 @@ neoforge_version=21.4.147 neoforge_version_range=[21.4.147,) # NeoForge mod versions + neo_iris_version=1.8.8+1.21.4-neoforge # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client + neo_enable_iris=1 \ No newline at end of file diff --git a/versionProperties/1.21.5.properties b/versionProperties/1.21.5.properties index c492b12f0..365920e6a 100644 --- a/versionProperties/1.21.5.properties +++ b/versionProperties/1.21.5.properties @@ -45,10 +45,11 @@ forge_version= neoforge_version=21.5.87 neoforge_version_range=[*,) - # NeoForge mod versions + neo_iris_version=1.8.11+1.21.5-neoforge # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client + neo_enable_iris=1 \ No newline at end of file diff --git a/versionProperties/1.21.6.properties b/versionProperties/1.21.6.properties index be99ed899..ebbd0fc9c 100644 --- a/versionProperties/1.21.6.properties +++ b/versionProperties/1.21.6.properties @@ -46,8 +46,10 @@ neoforge_version=21.6.20-beta neoforge_version_range=[21.6.19-beta,) # NeoForge mod versions + neo_iris_version=1.9.6+1.21.8-neoforge # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client + neo_enable_iris=1 diff --git a/versionProperties/1.21.8.properties b/versionProperties/1.21.8.properties index 7699fa59d..714227dea 100644 --- a/versionProperties/1.21.8.properties +++ b/versionProperties/1.21.8.properties @@ -41,13 +41,16 @@ fabric_api_version=0.133.4+1.21.8 # NeoForge loader forge_version= -neoforge_version=21.8.2-beta +neoforge_version=21.8.52 # around 6.19 neo changed how their render API works, failing to meet this causes the game to crash neoforge_version_range=[*,) - - # NeoForge mod versions - # NeoForge mod run + # NeoForge mod versions + neo_iris_version=1.9.6+1.21.8-neoforge + + # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client + neo_enable_iris=1 + diff --git a/versionProperties/1.21.9.properties b/versionProperties/1.21.9.properties index 471f8207b..6f9f0ca76 100644 --- a/versionProperties/1.21.9.properties +++ b/versionProperties/1.21.9.properties @@ -45,10 +45,13 @@ neoforge_version=21.9.15-beta # sometime before 21.9.15-beta Neoforge changed how their rendering API events handle levels # so we can't support both versions at once neoforge_version_range=[21.9.15-beta,) - - # NeoForge mod versions + # NeoForge mod versions + # Iris doesn't exist for this MC version + neo_iris_version= + # (Neo)Forge mod run # 0 = Don't enable and don't run # 1 = Can be referenced in code but doesn't run # 2 = Can be referenced in code and runs in client + neo_enable_iris=0 From 533c6a7f937562885732966ef5bda4f1847e5d0e Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 6 Dec 2025 12:04:35 -0600 Subject: [PATCH 32/33] Fix compiling MC 1.21.5 --- .../worldGeneration/chunkFileHandling/ChunkFileReader.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java index d1dc68445..3ea80ceec 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java @@ -40,9 +40,6 @@ import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.core.registries.Registries; #elif MC_VER <= MC_1_21_3 import net.minecraft.core.registries.Registries; -import net.minecraft.world.level.chunk.ChunkStatus; -#elif MC_VER <= MC_1_21_3 -import net.minecraft.core.registries.Registries; import net.minecraft.world.level.chunk.status.ChunkStatus; #elif MC_VER <= MC_1_21_8 import net.minecraft.core.registries.Registries; From e5ea86bf8f962c9603534171e8bea5e7a99d3bfe Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 6 Dec 2025 12:14:03 -0600 Subject: [PATCH 33/33] Fix handling bad heightmaps --- .../common/wrappers/chunk/ChunkWrapper.java | 7 --- .../BatchGenerationEnvironment.java | 4 ++ .../ChunkCompoundTagParser.java | 53 +++++++++++++++++-- .../chunkFileHandling/ChunkFileReader.java | 2 +- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java index 72e8cee5c..0e4eca66b 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/chunk/ChunkWrapper.java @@ -244,13 +244,6 @@ public class ChunkWrapper implements IChunkWrapper public void createDhHeightMaps() { - // only continue if we haven't already generated the DH heightmaps - if (this.solidHeightMap != null) - { - return; - } - - // re-calculate the min/max heights for consistency (during world gen these may be wrong) this.minNonEmptyHeight = Integer.MIN_VALUE; this.maxNonEmptyHeight = Integer.MAX_VALUE; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 6ece223cc..e58be1b81 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -668,6 +668,10 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm throwIfThreadInterrupted(); + // not always necessary, but sometimes MC heightmap is wrong + // and can cause LODs to generate incorrectly + centerChunkWrapper.createDhHeightMaps(); + // pre-generated chunks should have lighting but new ones won't if (!centerChunkWrapper.isDhBlockLightingCorrect()) { diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java index 6c197356d..9ad4cabb3 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkCompoundTagParser.java @@ -194,6 +194,11 @@ public class ChunkCompoundTagParser int sectionYCount = #if MC_VER < MC_1_17_1 16; #else mcWorldGenLevel.getSectionsCount(); #endif LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYCount]; boolean hasBlocks = readAndPopulateSections(mcWorldGenLevel, chunkPos, tagLevel, chunkSections); + if (!hasBlocks) + { + return null; + } + long inhabitedTime = CompoundTagUtil.getLong(tagLevel, "InhabitedTime"); boolean isLightOn = CompoundTagUtil.getBoolean(tagLevel, "isLightOn"); @@ -218,7 +223,49 @@ public class ChunkCompoundTagParser // chunk wrapper so we can pass along extra data more easily ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, dhServerLevel.getServerLevelWrapper(), !hasHeightmapData); - return chunkWrapper; + + + + //===========================// + // check if chunk has blocks // + //===========================// + + // in some MC versions all the NBT data will be there + // but the chunk will be totally empty, + // usually this means the chunk was only partially generated. + // If that happens we should try to generate the chunk from scratch + // otherwise we can end up with large empty holes in the world. + + // walking through the heightmap (recreated by DH if missing) + // is a fast way to check if there are any blocks in the chunk + boolean chunkHasBlocks = false; + int serverMinHeight = dhServerLevel.getServerLevelWrapper().getMinHeight(); + for (int x = 0; x < 16 && !chunkHasBlocks; x++) + { + for (int z = 0; z < 16 && !chunkHasBlocks; z++) + { + int heightMap = Math.max( + // max between both heightmaps just in case there's a discrepancy + chunkWrapper.getLightBlockingHeightMapValue(x, z), + chunkWrapper.getSolidHeightMapValue(x, z) + ); + if (heightMap != serverMinHeight) + { + chunkHasBlocks = true; + } + } + } + + + if (chunkHasBlocks) + { + return chunkWrapper; + } + else + { + // no blocks detected, this chunk should be generated from scratch + return null; + } } @@ -247,9 +294,9 @@ public class ChunkCompoundTagParser boolean blocksFound = false; if (tagSections != null) { - for (int j = 0; j < tagSections.size(); ++j) + for (int i = 0; i < tagSections.size(); ++i) { - CompoundTag tagSection = CompoundTagUtil.getCompoundTag(tagSections, j); + CompoundTag tagSection = CompoundTagUtil.getCompoundTag(tagSections, i); if (tagSection == null) { continue; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java index 3ea80ceec..cc51b392d 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/chunkFileHandling/ChunkFileReader.java @@ -293,7 +293,7 @@ public class ChunkFileReader implements AutoCloseable public ChunkWrapper CreateProtoChunkWrapper(ServerLevel level, ChunkPos chunkPos) { ProtoChunk chunk = CreateProtoChunk(level, chunkPos); - return new ChunkWrapper(chunk, this.params.dhServerLevel.getLevelWrapper()); + return new ChunkWrapper(chunk, this.params.dhServerLevel.getLevelWrapper(), false); } public static ProtoChunk CreateProtoChunk(ServerLevel level, ChunkPos chunkPos) {