From c41fd1ab5b16f926ca96eb3b5cd7c74dbfc55f15 Mon Sep 17 00:00:00 2001 From: tom lee Date: Sat, 12 Feb 2022 16:28:37 +0800 Subject: [PATCH] Backport changes from 1.16 --- .../config/LodConfigWrapperSingleton.java | 16 +--- .../minecraft/MinecraftRenderWrapper.java | 32 ++++++-- .../BatchGenerationEnvironment.java | 79 ++++++++++++++----- .../worldGeneration/GenerationEvent.java | 2 +- .../worldGeneration/step/StepNoise.java | 7 +- 5 files changed, 85 insertions(+), 51 deletions(-) diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/config/LodConfigWrapperSingleton.java b/common/src/main/java/com/seibel/lod/common/wrappers/config/LodConfigWrapperSingleton.java index ac40b5de9..707a5b156 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/config/LodConfigWrapperSingleton.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/config/LodConfigWrapperSingleton.java @@ -332,20 +332,6 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton ConfigGui.editSingleOption.saveOption("client.worldGenerator.distanceGenerationMode"); } - /* - @Override - public boolean getAllowUnstableFeatureGeneration() - { - return Config.Client.WorldGenerator.allowUnstableFeatureGeneration; - } - @Override - public void setAllowUnstableFeatureGeneration(boolean newAllowUnstableFeatureGeneration) - { - ConfigGui.editSingleOption.getEntry("client.worldGenerator.allowUnstableFeatureGeneration").value = newAllowUnstableFeatureGeneration; - ConfigGui.editSingleOption.saveOption("client.worldGenerator.allowUnstableFeatureGeneration"); - }*/ - - @Override public BlocksToAvoid getBlocksToAvoid() { @@ -360,7 +346,7 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton @Override public boolean getEnableDistantGeneration() { - return Config.Client.WorldGenerator.enableDistantGeneration; + return (boolean) ConfigGui.editSingleOption.getEntry("client.worldGenerator.enableDistantGeneration").value; } @Override public void setEnableDistantGeneration(boolean newEnableDistantGeneration) diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/minecraft/MinecraftRenderWrapper.java b/common/src/main/java/com/seibel/lod/common/wrappers/minecraft/MinecraftRenderWrapper.java index 860e3d590..d29dc02fd 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/minecraft/MinecraftRenderWrapper.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/minecraft/MinecraftRenderWrapper.java @@ -7,6 +7,7 @@ import java.util.stream.Collectors; import com.mojang.blaze3d.platform.NativeImage; import com.mojang.blaze3d.systems.RenderSystem; import com.seibel.lod.common.wrappers.misc.LightMapWrapper; +import com.seibel.lod.core.api.ClientApi; import com.seibel.lod.core.api.ModAccessorApi; import com.seibel.lod.core.util.LodUtil; @@ -147,7 +148,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper * is going to render this frame.

*

*/ - + public boolean usingBackupGetVanillaRenderedChunks = false; @Override public HashSet getVanillaRenderedChunks() { @@ -164,14 +165,29 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper pos = getMaximumRenderedChunks(); return pos; } + if (!usingBackupGetVanillaRenderedChunks) { + try { + LevelRenderer levelRenderer = MC.levelRenderer; + ObjectArrayList chunks = levelRenderer.renderChunks; + return (chunks.stream().map((chunk) -> { + AABB chunkBoundingBox = chunk.chunk.bb; + return FACTORY.createChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16), + Math.floorDiv((int) chunkBoundingBox.minZ, 16)); + }).collect(Collectors.toCollection(HashSet::new))); + } catch (LinkageError e) { + try { + MinecraftWrapper.INSTANCE.sendChatMessage( + "\u00A7e\u00A7l\u00A7uWRANING: Distant Horizons: getVanillaRenderedChunks method failed." + + " Using Backup Method."); + MinecraftWrapper.INSTANCE.sendChatMessage( + "\u00A7eOverdraw prevention will be worse than normal."); + } catch (Exception e2) {} + ClientApi.LOGGER.error("getVanillaRenderedChunks Error: {}", e); + usingBackupGetVanillaRenderedChunks = true; + } + } + return getMaximumRenderedChunks(); - LevelRenderer levelRenderer = MC.levelRenderer; - ObjectArrayList chunks = levelRenderer.renderChunks; - return (chunks.stream().map((chunk) -> { - AABB chunkBoundingBox = chunk.chunk.bb; - return FACTORY.createChunkPos(Math.floorDiv((int) chunkBoundingBox.minX, 16), - Math.floorDiv((int) chunkBoundingBox.minZ, 16)); - }).collect(Collectors.toCollection(HashSet::new))); } @Override diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 498a454af..5c4002f1d 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -29,6 +29,7 @@ import com.seibel.lod.core.util.GridList; import com.seibel.lod.core.util.LodThreadFactory; import com.seibel.lod.core.util.SingletonHandler; import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; +import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper; import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper; import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvionmentWrapper; @@ -36,6 +37,7 @@ import java.io.IOException; import java.time.Duration; import java.util.Iterator; import java.util.LinkedList; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -57,10 +59,14 @@ import com.seibel.lod.common.wrappers.worldGeneration.step.StepSurface; 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.ChunkGenerator; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.levelgen.DebugLevelSource; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.lighting.LevelLightEngine; @@ -203,7 +209,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv } } - public static final int TIMEOUT_SECONDS = 30; + public static final int TIMEOUT_SECONDS = 60; //=================Generation Step=================== @@ -216,13 +222,30 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv public final StepSurface stepSurface = new StepSurface(this); public final StepFeatures stepFeatures = new StepFeatures(this); public final StepLight stepLight = new StepLight(this); + public boolean unsafeThreadingRecorded = false; + //public boolean safeMode = false; private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class); - + private static final IMinecraftWrapper MC = SingletonHandler.get(IMinecraftWrapper.class); + 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; + public static final LodThreadFactory threadFactory = new LodThreadFactory("Gen-Worker-Thread", Thread.MIN_PRIORITY); public ExecutorService executors = Executors.newFixedThreadPool( CONFIG.client().advanced().threading().getNumberOfWorldGenerationThreads(), threadFactory); + public T joinSync(CompletableFuture f) { + if (!unsafeThreadingRecorded && !f.isDone()) { + MC.sendChatMessage("\u00A74\u00A7l\u00A7uERROR: Distant Horizons: Unsafe Threading in Chunk Generator Detected!"); + MC.sendChatMessage("\u00A7eTo increase stability, it is recommended to set world generation threads count to 1."); + ClientApi.LOGGER.error("Unsafe Threading in Chunk Generator: ", new RuntimeException("Concurrent future")); + unsafeThreadingRecorded = true; + } + return f.join(); + } + public void resizeThreadPool(int newThreadCount) { executors = Executors.newFixedThreadPool(newThreadCount, @@ -247,6 +270,11 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv public void updateAllFutures() { + if (unknownExceptionCount > 0) { + if (System.nanoTime() - lastExceptionTriggerTime >= EXCEPTION_TIMER_RESET_TIME) { + unknownExceptionCount = 0; + } + } // Update all current out standing jobs Iterator iter = events.iterator(); while (iter.hasNext()) @@ -260,12 +288,10 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv } catch (Throwable e) { - e.printStackTrace(); - while (e.getCause() != null) - { - e = e.getCause(); - e.printStackTrace(); - } + ClientApi.LOGGER.error("Batching World Generator: Event {} gotten an exception", event); + ClientApi.LOGGER.error("Exception: ", e); + unknownExceptionCount++; + lastExceptionTriggerTime = System.nanoTime(); } finally { @@ -287,22 +313,31 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv } } } + if (unknownExceptionCount > EXCEPTION_COUNTER_TRIGGER) { + try { + MC.sendChatMessage("\u00A74\u00A7l\u00A7uERROR: Distant Horizons: Too many exceptions in Batching World Generator! Disabling the generator."); + } catch (Exception e) {} + ClientApi.LOGGER.error("Too many exceptions in Batching World Generator! Now disabling."); + unknownExceptionCount = 0; + CONFIG.client().worldGenerator().setEnableDistantGeneration(false); + } } public BatchGenerationEnvironment(IWorldWrapper serverlevel, LodBuilder lodBuilder, LodDimension lodDim) { super(serverlevel, lodBuilder, lodDim); ClientApi.LOGGER.info("================WORLD_GEN_STEP_INITING============="); + ChunkGenerator generator = ((WorldWrapper) serverlevel).getServerWorld().getChunkSource().getGenerator(); + if (!(generator instanceof NoiseBasedChunkGenerator || + generator instanceof DebugLevelSource || + generator instanceof FlatLevelSource)) { + MC.sendChatMessage("\u00A74\u00A7l\u00A7uWARNING: Distant Horizons: Unknown Chunk Generator Detected! Distant Generation May Fail!"); + MC.sendChatMessage("\u00A7eIf it does crash, set Distant Generation to OFF or Generation Mode to None."); + ClientApi.LOGGER.warn("Unknown Chunk Generator detected: {}", generator.getClass()); + } params = new GlobalParameters((ServerLevel) ((WorldWrapper) serverlevel).getWorld(), lodBuilder, lodDim); } - - public void startLoadingAllRegionsFromFile(LodDimension lodDim) - { - ServerLevel level = params.level; - level.getChunkSource(); - - } - + @SuppressWarnings("resource") public static ChunkAccess loadOrMakeChunk(ChunkPos chunkPos, ServerLevel level, LevelLightEngine lightEngine) { @@ -311,7 +346,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv { chunkData = level.getChunkSource().chunkMap.readChunk(chunkPos); } - catch (IOException e) + catch (Exception e) { ClientApi.LOGGER.error("DistantHorizons: Couldn't load chunk {}", chunkPos, e); } @@ -321,13 +356,16 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv } else { - return ChunkLoader.read(level, lightEngine, chunkPos, chunkData); + try { + return ChunkLoader.read(level, lightEngine, chunkPos, chunkData); + } catch (Exception e) { + ClientApi.LOGGER.error("DistantHorizons: Couldn't load chunk {}", chunkPos, e); + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level); + } } } - - public void generateLodFromList(GenerationEvent e) { if (ENABLE_EVENT_LOGGING) @@ -361,7 +399,6 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv catch (RuntimeException e2) { // Continue... - e2.printStackTrace(); } if (target == null) target = new ProtoChunk(chunkPos, UpgradeData.EMPTY, params.level); diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/GenerationEvent.java b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/GenerationEvent.java index c65c8726a..4dfd85305 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/GenerationEvent.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/GenerationEvent.java @@ -78,7 +78,7 @@ public final class GenerationEvent } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); + throw new RuntimeException(e.getCause()==null? e : e.getCause()); } } diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/step/StepNoise.java b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/step/StepNoise.java index 96f1bcc48..314828360 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/step/StepNoise.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/step/StepNoise.java @@ -3,7 +3,6 @@ package com.seibel.lod.common.wrappers.worldGeneration.step; import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.concurrent.CompletableFuture; import com.google.common.collect.Sets; import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment; @@ -34,10 +33,6 @@ public final class StepNoise { environment = batchGenerationEnvironment; } - private static T joinSync(CompletableFuture f) { - if (!f.isDone()) throw new RuntimeException("The future is concurrent!"); - return f.join(); - } public final ChunkStatus STATUS = ChunkStatus.NOISE; private ChunkAccess NoiseBased$fillFromNoise(NoiseBasedChunkGenerator generator, StructureFeatureManager structureFeatureManager, ChunkAccess chunkAccess) { @@ -85,7 +80,7 @@ public final class StepNoise { chunk = NoiseBased$fillFromNoise((NoiseBasedChunkGenerator)environment.params.generator, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk); } else { - chunk = joinSync(environment.params.generator.fillFromNoise(Runnable::run, + chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk)); } }