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
+
+
+
}