diff --git a/core/src/main/java/com/seibel/distanthorizons/core/logging/f3/F3Screen.java b/core/src/main/java/com/seibel/distanthorizons/core/logging/f3/F3Screen.java index 7c49c6efe..14c1923b7 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/logging/f3/F3Screen.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/logging/f3/F3Screen.java @@ -36,7 +36,6 @@ import com.seibel.distanthorizons.core.world.AbstractDhWorld; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.util.StringUtil; -import org.apache.logging.log4j.LogManager; import com.seibel.distanthorizons.core.logging.DhLogger; import java.text.NumberFormat; @@ -219,7 +218,11 @@ public class F3Screen // active threads int activeThreadCount = pool.getRunningTaskCount(); int threadCount = pool.getPoolSize(); - message += ", Active: "+activeThreadCount+"/"+threadCount; + + boolean threadPoolActive = pool.canRun(); + String poolActiveString = threadPoolActive ? "Active" : "Paused"; + + message += ", "+poolActiveString+": "+activeThreadCount+"/"+threadCount; // thread runtime String runTimeAvgStr; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/LodUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/LodUtil.java index 1cce4a623..a4047ad45 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/LodUtil.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/LodUtil.java @@ -85,17 +85,10 @@ public class LodUtil /** the opacity value returned by {@link IBlockStateWrapper#getOpacity()} if a block is fully opaque */ public static final int BLOCK_FULLY_OPAQUE = 16; - /** - * List of every block that can be used in a beacon's base.
- * Should be all lowercase - */ - public static final List BEACON_BASE_BLOCK_NAME_LIST = Arrays.asList( - "iron_block", - "gold_block", - "diamond_block", - "emerald_block", - "netherite_block" - ); + public static final double WALKING_SPEED_IN_BLOCKS_PER_SEC = 4.1; + public static final double SPRINTING_SPEED_IN_BLOCKS_PER_SEC = 7.1; + public static final double ROCKET_ELYTRA_SPEED_IN_BLOCKS_PER_SEC = 30.0; + public static final double MAX_SPECTATOR_SPEED_IN_BLOCKS_PER_SEC = 100.0; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java index f03496cb1..84c536a5a 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java @@ -37,16 +37,18 @@ public class RenderUtil private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); - /** all speeds are measured in blocks per second */ + /** + * all speeds are measured in blocks per second + * + * @see LodUtil#WALKING_SPEED_IN_BLOCKS_PER_SEC + * @see LodUtil#SPRINTING_SPEED_IN_BLOCKS_PER_SEC + * @see LodUtil#ROCKET_ELYTRA_SPEED_IN_BLOCKS_PER_SEC + * @see LodUtil#MAX_SPECTATOR_SPEED_IN_BLOCKS_PER_SEC + */ private static class DynamicOverdraw { - /** - * A walking player moves around 4.1 blocks/sec - * A sprint jumping player around 7.1 blocks/sec - */ - public static final float MIN_SPEED = 10.0f; - /** a max speed spectator player can move just shy of 100 blocks/sec */ - public static final float MAX_SPEED = 100.0f; + public static final float MIN_SPEED = 10.0f; // a little faster than sprinting (7) + public static final float MAX_SPEED = (float)LodUtil.MAX_SPECTATOR_SPEED_IN_BLOCKS_PER_SEC; public static final float MIN_OVERDRAW_RATIO = 0.2f; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/threading/PriorityTaskPicker.java b/core/src/main/java/com/seibel/distanthorizons/core/util/threading/PriorityTaskPicker.java index 0b1b42619..bb60dd9ec 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/threading/PriorityTaskPicker.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/threading/PriorityTaskPicker.java @@ -6,6 +6,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.util.objects.RollingAverage; import com.seibel.distanthorizons.core.logging.DhLogger; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.*; @@ -39,10 +40,12 @@ public class PriorityTaskPicker //==========// // executor // //==========// + ///region - public Executor createExecutor(String name) + public Executor createExecutor(String name) { return this.createExecutor(name, null); } + public Executor createExecutor(String name, @Nullable PriorityTaskPicker.IExecutorCanRunFunc canRunFunc) { - Executor executor = new Executor(this, name); + Executor executor = new Executor(this, name, canRunFunc); this.executors.add(executor); return executor; } @@ -73,6 +76,13 @@ public class PriorityTaskPicker while (iterator.hasNext()) { Executor executor = iterator.next(); + + // skip executors that are paused + if (!executor.canRun()) + { + continue; + } + int queuedTaskCount = 0; TrackedRunnable task; @@ -142,11 +152,14 @@ public class PriorityTaskPicker } } + ///endregion + //================// // helper classes // //================// + ///region /** * Each executor handles a specific type of work that DH needs done. @@ -167,6 +180,9 @@ public class PriorityTaskPicker /** used for performance logging */ private final RollingAverage runTimeInMsRollingAverage = new RollingAverage(200); + @Nullable + private final PriorityTaskPicker.IExecutorCanRunFunc canRunFunc; + /** holds the threads this {@link Executor} can run */ private RateLimitedThreadPoolExecutor threadPoolExecutor; @@ -175,11 +191,13 @@ public class PriorityTaskPicker //=============// // constructor // //=============// + ///region - public Executor(PriorityTaskPicker parentTaskPicker, String name) + public Executor(PriorityTaskPicker parentTaskPicker, String name, @Nullable PriorityTaskPicker.IExecutorCanRunFunc canRunFunc) { this.parentTaskPicker = parentTaskPicker; this.name = name; + this.canRunFunc = canRunFunc; this.threadPoolExecutor = this.createThreadPool(); @@ -195,11 +213,14 @@ public class PriorityTaskPicker ); } + ///endregion + //=================// // config handling // //=================// + ///region @Override public void onConfigValueSet() @@ -215,11 +236,14 @@ public class PriorityTaskPicker } } + ///endregion + //=====================// // task queue handling // //=====================// + ///region @Override public void execute(@NotNull Runnable command) @@ -258,11 +282,25 @@ public class PriorityTaskPicker public void clearQueue() { this.taskQueue.clear(); } + public boolean canRun() + { + if (this.canRunFunc == null) + { + return true; + } + + return this.canRunFunc.canRun(); + } + + + //endregion + //==========// // shutdown // //==========// + ///region @Override public void shutdown() { this.threadPoolExecutor.shutdown(); } @@ -279,6 +317,8 @@ public class PriorityTaskPicker public boolean awaitTermination(long timeout, @NotNull TimeUnit unit) throws InterruptedException { return this.threadPoolExecutor.awaitTermination(timeout, unit); } + ///endregion + } /** used so we can {@link PriorityTaskPicker.Executor#remove(Runnable)} using the original {@link Runnable} */ @@ -334,6 +374,18 @@ public class PriorityTaskPicker } + /** + * Provides a way to dynamically enable/disable + * certain {@link PriorityTaskPicker.Executor}'s. + */ + @FunctionalInterface + public interface IExecutorCanRunFunc + { + boolean canRun(); + } + + ///endregion + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/threading/ThreadPoolUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/threading/ThreadPoolUtil.java index c0d31fa8e..d39a081ad 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/threading/ThreadPoolUtil.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/threading/ThreadPoolUtil.java @@ -19,6 +19,8 @@ package com.seibel.distanthorizons.core.util.threading; +import com.seibel.distanthorizons.core.api.internal.ClientApi; +import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.ThreadUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -94,6 +96,7 @@ public class ThreadPoolUtil //=================// // setup / cleanup // //=================// + ///region public static void setupThreadPools() { @@ -112,8 +115,9 @@ public class ThreadPoolUtil fileHandlerThreadPool = taskPicker.createExecutor("IO"); renderSectionLoadThreadPool = taskPicker.createExecutor("Render Loader"); chunkToLodBuilderThreadPool = taskPicker.createExecutor("LOD Builder"); - updatePropagatorThreadPool = taskPicker.createExecutor("Update Propagator"); - worldGenThreadPool = taskPicker.createExecutor("World Gen"); + updatePropagatorThreadPool = taskPicker.createExecutor("Update Propagator", ThreadPoolUtil::onlyRunThreadIfCameraMovingSlowly); + worldGenThreadPool = taskPicker.createExecutor("World Gen", ThreadPoolUtil::onlyRunThreadIfCameraMovingSlowly); + @@ -144,4 +148,42 @@ public class ThreadPoolUtil fullDataMigrationThreadPool.shutdown(); } + ///endregion + + + + //================// + // helper methods // + //================// + ///region + + /** + * Some thread pools are very heavy (IE world gen) + * making LOD load times slower. Pausing those + * threads when the player is moving can provide a better experience.

+ * + * all speeds are measured in blocks per second + * + * @see LodUtil#WALKING_SPEED_IN_BLOCKS_PER_SEC + * @see LodUtil#SPRINTING_SPEED_IN_BLOCKS_PER_SEC + * @see LodUtil#ROCKET_ELYTRA_SPEED_IN_BLOCKS_PER_SEC + * @see LodUtil#MAX_SPECTATOR_SPEED_IN_BLOCKS_PER_SEC + */ + public static boolean onlyRunThreadIfCameraMovingSlowly() + { + double cameraSpeed = ClientApi.INSTANCE.cameraSpeedRollingAverage.getAverage(); + double maxAllowedSpeed = (LodUtil.ROCKET_ELYTRA_SPEED_IN_BLOCKS_PER_SEC - 10.0); + if (cameraSpeed > maxAllowedSpeed) + { + // pause this thread pool if the user is moving too fast + return false; + } + + return true; + } + + ///endregion + + + }