Potentially fix lag when moving across chunk borders
This commit is contained in:
@@ -22,6 +22,7 @@ package com.seibel.distanthorizons.core.api.internal;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelUnloadEvent;
|
||||
import com.seibel.distanthorizons.core.generation.DhLightingEngine;
|
||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
@@ -37,6 +38,7 @@ import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* This holds the methods that should be called by the host mod loader (Fabric,
|
||||
@@ -48,6 +50,14 @@ public class ServerApi
|
||||
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
private static final ThreadPoolExecutor LIGHT_POPULATOR_THREAD_POOL = ThreadUtil.makeRateLimitedThreadPool(
|
||||
// thread count doesn't need to be very high since the player can only move so fast, 1 should be plenty
|
||||
(Runtime.getRuntime().availableProcessors() <= 12) ? 1 : 2,
|
||||
"Server Light Populator",
|
||||
// only run the thread 50% of the time to prevent lagging the server thread
|
||||
0.5,
|
||||
ThreadUtil.MINIMUM_RELATIVE_PRIORITY);
|
||||
|
||||
private int lastWorldGenTickDelta = 0;
|
||||
|
||||
|
||||
@@ -56,9 +66,9 @@ public class ServerApi
|
||||
|
||||
|
||||
|
||||
// =============//
|
||||
// tick events //
|
||||
// =============//
|
||||
//=============//
|
||||
// tick events //
|
||||
//=============//
|
||||
|
||||
public void serverTickEvent()
|
||||
{
|
||||
@@ -152,40 +162,48 @@ public class ServerApi
|
||||
public void serverChunkSaveEvent(IChunkWrapper chunk, ILevelWrapper level)
|
||||
{
|
||||
AbstractDhWorld dhWorld = SharedApi.getAbstractDhWorld();
|
||||
if (dhWorld != null)
|
||||
if (dhWorld == null)
|
||||
{
|
||||
IDhLevel dhLevel = SharedApi.getAbstractDhWorld().getLevel(level);
|
||||
if (dhLevel != null)
|
||||
return;
|
||||
}
|
||||
|
||||
IDhLevel dhLevel = SharedApi.getAbstractDhWorld().getLevel(level);
|
||||
if (dhLevel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// lighting the chunk needs to be done outside the event thread to prevent lagging the server thread
|
||||
LIGHT_POPULATOR_THREAD_POOL.execute(() ->
|
||||
{
|
||||
// Save or populate the chunk wrapper's lighting
|
||||
// this is done so we don't have to worry about MC unloading the lighting data for this chunk
|
||||
if (chunk.isLightCorrect())
|
||||
{
|
||||
|
||||
// Save or populate the chunk wrapper's lighting
|
||||
// this is done so we don't have to worry about MC unloading the lighting data for this chunk
|
||||
if (chunk.isLightCorrect())
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
chunk.bakeDhLightingUsingMcLightingEngine();
|
||||
chunk.setUseDhLighting(true);
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
LOGGER.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// generate the chunk's lighting, ignoring neighbors.
|
||||
// not a perfect solution, but should prevent chunks from having completely broken lighting
|
||||
List<IChunkWrapper> nearbyChunkList = new LinkedList<>();
|
||||
nearbyChunkList.add(chunk);
|
||||
DhLightingEngine.INSTANCE.lightChunks(chunk, nearbyChunkList, level.hasSkyLight() ? 15 : 0);
|
||||
// If MC's lighting engine isn't thread safe this may cause the server thread to lag
|
||||
chunk.bakeDhLightingUsingMcLightingEngine();
|
||||
chunk.setUseDhLighting(true);
|
||||
}
|
||||
|
||||
|
||||
dhLevel.updateChunkAsync(chunk);
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
LOGGER.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// generate the chunk's lighting, ignoring neighbors.
|
||||
// not a perfect solution, but should prevent chunks from having completely broken lighting
|
||||
List<IChunkWrapper> nearbyChunkList = new LinkedList<>();
|
||||
nearbyChunkList.add(chunk);
|
||||
DhLightingEngine.INSTANCE.lightChunks(chunk, nearbyChunkList, level.hasSkyLight() ? 15 : 0);
|
||||
chunk.setUseDhLighting(true);
|
||||
}
|
||||
|
||||
dhLevel.updateChunkAsync(chunk);
|
||||
});
|
||||
}
|
||||
|
||||
public void serverPlayerJoinEvent(IServerPlayerWrapper player)
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.quadTree.QuadNode;
|
||||
import com.seibel.distanthorizons.core.util.objects.quadTree.QuadTree;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.util.MathUtil;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.concurrent.*;
|
||||
|
||||
public class ThreadUtil
|
||||
{
|
||||
public static int MINIMUM_RELATIVE_PRIORITY = -5;
|
||||
public static int MINIMUM_RELATIVE_PRIORITY = -4;
|
||||
public static int DEFAULT_RELATIVE_PRIORITY = 0;
|
||||
|
||||
// TODO currently only used for RateLimitedThreadPools could this be used for all thread pools?
|
||||
@@ -20,7 +20,7 @@ public class ThreadUtil
|
||||
|
||||
// create rate limited thread pool //
|
||||
|
||||
public static RateLimitedThreadPoolExecutor makeRateLimitedThreadPool(int poolSize, String name, ConfigEntry<Double> runTimeRatioConfigEntry) { return makeRateLimitedThreadPool(poolSize, name, 0, runTimeRatioConfigEntry); }
|
||||
public static RateLimitedThreadPoolExecutor makeRateLimitedThreadPool(int poolSize, String name, ConfigEntry<Double> runTimeRatioConfigEntry) { return makeRateLimitedThreadPool(poolSize, name, DEFAULT_RELATIVE_PRIORITY, runTimeRatioConfigEntry); }
|
||||
public static RateLimitedThreadPoolExecutor makeRateLimitedThreadPool(int poolSize, String name, int relativePriority, ConfigEntry<Double> runTimeRatioConfigEntry)
|
||||
{
|
||||
// remove the old listener if one exists
|
||||
@@ -31,7 +31,7 @@ public class ThreadUtil
|
||||
THREAD_CHANGE_LISTENERS_BY_THREAD_NAME.remove(name);
|
||||
}
|
||||
|
||||
RateLimitedThreadPoolExecutor executor = new RateLimitedThreadPoolExecutor(poolSize, runTimeRatioConfigEntry.get(), new DhThreadFactory("DH-" + name, Thread.NORM_PRIORITY + relativePriority));
|
||||
RateLimitedThreadPoolExecutor executor = makeRateLimitedThreadPool(poolSize, name, runTimeRatioConfigEntry.get(), relativePriority);
|
||||
|
||||
ConfigChangeListener<Double> changeListener = new ConfigChangeListener<>(runTimeRatioConfigEntry, (newRunTimeRatio) -> { executor.runTimeRatio = newRunTimeRatio; });
|
||||
THREAD_CHANGE_LISTENERS_BY_THREAD_NAME.put(name, changeListener);
|
||||
@@ -39,6 +39,12 @@ public class ThreadUtil
|
||||
return executor;
|
||||
}
|
||||
|
||||
/** should only be used if there isn't a config controlling the run time ratio of this thread pool */
|
||||
public static RateLimitedThreadPoolExecutor makeRateLimitedThreadPool(int poolSize, String name, Double runTimeRatio, int relativePriority)
|
||||
{
|
||||
return new RateLimitedThreadPoolExecutor(poolSize, runTimeRatio, new DhThreadFactory("DH-" + name, Thread.NORM_PRIORITY + relativePriority));
|
||||
}
|
||||
|
||||
|
||||
// create thread pool //
|
||||
|
||||
@@ -54,16 +60,16 @@ public class ThreadUtil
|
||||
}
|
||||
|
||||
public static ThreadPoolExecutor makeThreadPool(int poolSize, Class<?> clazz, int relativePriority) { return makeThreadPool(poolSize, clazz.getSimpleName(), relativePriority); }
|
||||
public static ThreadPoolExecutor makeThreadPool(int poolSize, String name) { return makeThreadPool(poolSize, name, 0); }
|
||||
public static ThreadPoolExecutor makeThreadPool(int poolSize, Class<?> clazz) { return makeThreadPool(poolSize, clazz.getSimpleName(), 0); }
|
||||
public static ThreadPoolExecutor makeThreadPool(int poolSize, String name) { return makeThreadPool(poolSize, name, DEFAULT_RELATIVE_PRIORITY); }
|
||||
public static ThreadPoolExecutor makeThreadPool(int poolSize, Class<?> clazz) { return makeThreadPool(poolSize, clazz.getSimpleName(), DEFAULT_RELATIVE_PRIORITY); }
|
||||
|
||||
|
||||
// create single thread pool //
|
||||
|
||||
public static ThreadPoolExecutor makeSingleThreadPool(String name, int relativePriority) { return makeThreadPool(1, name, relativePriority); }
|
||||
public static ThreadPoolExecutor makeSingleThreadPool(Class<?> clazz, int relativePriority) { return makeThreadPool(1, clazz.getSimpleName(), relativePriority); }
|
||||
public static ThreadPoolExecutor makeSingleThreadPool(String name) { return makeThreadPool(1, name, 0); }
|
||||
public static ThreadPoolExecutor makeSingleThreadPool(Class<?> clazz) { return makeThreadPool(1, clazz.getSimpleName(), 0); }
|
||||
public static ThreadPoolExecutor makeSingleThreadPool(String name) { return makeThreadPool(1, name, DEFAULT_RELATIVE_PRIORITY); }
|
||||
public static ThreadPoolExecutor makeSingleThreadPool(Class<?> clazz) { return makeThreadPool(1, clazz.getSimpleName(), DEFAULT_RELATIVE_PRIORITY); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ public class DhThreadFactory implements ThreadFactory
|
||||
{
|
||||
if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY)
|
||||
{
|
||||
throw new IllegalArgumentException("Thread priority should be [" + Thread.MIN_PRIORITY + "-" + Thread.MAX_PRIORITY + "]!");
|
||||
throw new IllegalArgumentException("Thread priority [" + priority + "] out of bounds. Priority should be between [" + Thread.MIN_PRIORITY + "-" + Thread.MAX_PRIORITY + "]!");
|
||||
}
|
||||
|
||||
this.threadName = newThreadName + " Thread";
|
||||
|
||||
@@ -23,7 +23,6 @@ public class DhClientServerWorld extends AbstractDhWorld implements IDhClientWor
|
||||
private final HashSet<DhClientServerLevel> dhLevels;
|
||||
public final LocalSaveStructure saveStructure;
|
||||
|
||||
// TODO why does this executor have 2 threads?
|
||||
public ExecutorService dhTickerThread = ThreadUtil.makeSingleThreadPool("DH Client Server World Ticker Thread", 2);
|
||||
public EventLoop eventLoop = new EventLoop(this.dhTickerThread, this::_clientTick); //TODO: Rate-limit the loop
|
||||
|
||||
|
||||
Reference in New Issue
Block a user