diff --git a/src/main/java/com/seibel/lod/core/api/EventApi.java b/src/main/java/com/seibel/lod/core/api/EventApi.java index eaffb8a96..8f2f6cdd9 100644 --- a/src/main/java/com/seibel/lod/core/api/EventApi.java +++ b/src/main/java/com/seibel/lod/core/api/EventApi.java @@ -133,41 +133,27 @@ public class EventApi // Note: using isCurrentlyOnSinglePlayerServer as often API call unload event AFTER setting MC to not be in a singlePlayerServer if (isCurrentlyOnSinglePlayerServer && world.getWorldType() == WorldType.ClientWorld) return; - // the player just unloaded a world/dimension - checkIfDisconnectedFromServer(); - } - private void checkIfDisconnectedFromServer() - { - { - // the player just left the server - - // TODO should "resetMod()" be called here? -James - - // if this isn't done unfinished tasks may be left in the queue - // preventing new LodChunks form being generated - ApiShared.isShuttingDown = true; - - // TODO Check why world gen is sometimes stuck and timeout - LodWorldGenerator.INSTANCE.restartExecutorService(); - - LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.set(0); - ApiShared.lodWorld.deselectWorld(); // This force a save - - // prevent issues related to the buffer builder - // breaking or retaining previous data when changing worlds. - ClientApi.renderer.destroyBuffers(); - ClientApi.renderer.requestCleanup(); - GLProxy.ensureAllGLJobCompleted(); - recalculateWidths = true; - // TODO: Check if after the refactoring, is this still needed - ClientApi.renderer = new LodRenderer(ApiShared.lodBufferBuilderFactory); - ClientApi.INSTANCE.rendererDisabledBecauseOfExceptions = false; - - // make sure the nulled objects are freed. - // (this prevents an out of memory error when - // changing worlds) - System.gc(); - } + // TODO should "resetMod()" be called here? -James + + // if this isn't done unfinished tasks may be left in the queue + // preventing new LodChunks form being generated + ApiShared.isShuttingDown = true; + + // TODO Better report on when world gen is stuck and timeout + LodWorldGenerator.INSTANCE.restartExecutorService(); + + ApiShared.lodWorld.deselectWorld(); // This force a save and shutdown lodDim properly + + // prevent issues related to the buffer builder + // breaking or retaining previous data when changing worlds. + ClientApi.renderer.destroyBuffers(); + ClientApi.renderer.requestCleanup(); + GLProxy.ensureAllGLJobCompleted(); + recalculateWidths = true; + + // TODO: Check if after the refactoring, is this still needed + ClientApi.renderer = new LodRenderer(ApiShared.lodBufferBuilderFactory); + ClientApi.INSTANCE.rendererDisabledBecauseOfExceptions = false; } public void blockChangeEvent(IChunkWrapper chunk, IDimensionTypeWrapper dimType) diff --git a/src/main/java/com/seibel/lod/core/builders/worldGeneration/LodWorldGenerator.java b/src/main/java/com/seibel/lod/core/builders/worldGeneration/LodWorldGenerator.java index 27fa45daa..6eef1501a 100644 --- a/src/main/java/com/seibel/lod/core/builders/worldGeneration/LodWorldGenerator.java +++ b/src/main/java/com/seibel/lod/core/builders/worldGeneration/LodWorldGenerator.java @@ -75,7 +75,7 @@ public class LodWorldGenerator * to limit how many chunks are queued at once. To prevent chunks from being * generated for a long time in an area the player is no longer in. */ - public final AtomicInteger numberOfChunksWaitingToGenerate = new AtomicInteger(0); + public AtomicInteger numberOfChunksWaitingToGenerate = new AtomicInteger(0); public final Set positionsWaitingToBeGenerated = new HashSet<>(); @@ -385,6 +385,8 @@ public class LodWorldGenerator new ThreadFactoryBuilder().setNameFormat("Gen-Worker-Thread-%d").build()); } } + // Doing this instead of setting it to 0 because even if shutdown fail, it won't cause the int to underflow below 0 afterwards + numberOfChunksWaitingToGenerate = new AtomicInteger(0); } } diff --git a/src/main/java/com/seibel/lod/core/enums/config/VerticalQuality.java b/src/main/java/com/seibel/lod/core/enums/config/VerticalQuality.java index c1ac97148..d809c1848 100644 --- a/src/main/java/com/seibel/lod/core/enums/config/VerticalQuality.java +++ b/src/main/java/com/seibel/lod/core/enums/config/VerticalQuality.java @@ -34,12 +34,12 @@ public enum VerticalQuality ), MEDIUM( - new int[] { 8, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1 }, + new int[] { 8, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1 }, 8 ), HIGH( - new int[] { 16, 8, 4, 2, 1, 1, 1, 1, 1, 1, 1 }, + new int[] { 16, 8, 4, 2, 2, 2, 2, 1, 1, 1, 1 }, 16 ); diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java index a1b3d0416..e45dfcd9a 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java @@ -24,6 +24,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import com.seibel.lod.core.api.ClientApi; import com.seibel.lod.core.enums.config.DistanceGenerationMode; @@ -780,4 +781,16 @@ public class LodDimension } return stringBuilder.toString(); } + + public void shutdown() { + cutAndExpandThread.shutdown(); + try { + boolean worked = cutAndExpandThread.awaitTermination(5, TimeUnit.SECONDS); + if (!worked) + ClientApi.LOGGER.error("Cut And Expend threads timed out! May cause crash on game exit due to cleanup failure."); + } catch (InterruptedException e) { + ClientApi.LOGGER.error("Cut And Expend threads shutdown is interrupted! May cause crash on game exit due to cleanup failure: ", e); + } + + } } diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodWorld.java b/src/main/java/com/seibel/lod/core/objects/lod/LodWorld.java index 0d7f2e3a9..00dc4e00d 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodWorld.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodWorld.java @@ -149,6 +149,19 @@ public class LodWorld } //FIXME: This should block until file is saved. } + /** + * Requests all dimensions to shutdown + */ + public void shutdownAllDimensions() + { + if (lodDimensions == null) + return; + + // TODO: Add parallel shutdowns. + for (IDimensionTypeWrapper key : lodDimensions.keySet()) { + lodDimensions.get(key).shutdown(); + } + } public boolean getIsWorldNotLoaded()