Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6feb7f1b42 | |||
| 016fc66293 | |||
| 6d3e30d425 | |||
| 5be5c5a5bc | |||
| ed5aeb8951 | |||
| 7f0ddadf26 |
@@ -38,7 +38,7 @@ public final class ModInfo
|
|||||||
public static final String NAME = "DistantHorizons";
|
public static final String NAME = "DistantHorizons";
|
||||||
/** Human-readable version of NAME */
|
/** Human-readable version of NAME */
|
||||||
public static final String READABLE_NAME = "Distant Horizons";
|
public static final String READABLE_NAME = "Distant Horizons";
|
||||||
public static final String VERSION = "2.4.0-b";
|
public static final String VERSION = "2.4.1-b";
|
||||||
/** Returns true if the current build is an unstable developer build, false otherwise. */
|
/** Returns true if the current build is an unstable developer build, false otherwise. */
|
||||||
public static final boolean IS_DEV_BUILD = VERSION.toLowerCase().contains("dev");
|
public static final boolean IS_DEV_BUILD = VERSION.toLowerCase().contains("dev");
|
||||||
|
|
||||||
|
|||||||
@@ -25,23 +25,16 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
|||||||
import com.seibel.distanthorizons.core.render.renderer.generic.GenericRenderObjectFactory;
|
import com.seibel.distanthorizons.core.render.renderer.generic.GenericRenderObjectFactory;
|
||||||
import com.seibel.distanthorizons.core.sql.DatabaseUpdater;
|
import com.seibel.distanthorizons.core.sql.DatabaseUpdater;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
|
||||||
import com.seibel.distanthorizons.core.world.DhApiWorldProxy;
|
import com.seibel.distanthorizons.core.world.DhApiWorldProxy;
|
||||||
import com.seibel.distanthorizons.core.api.external.methods.config.DhApiConfig;
|
import com.seibel.distanthorizons.core.api.external.methods.config.DhApiConfig;
|
||||||
import com.seibel.distanthorizons.core.api.external.methods.data.DhApiTerrainDataRepo;
|
import com.seibel.distanthorizons.core.api.external.methods.data.DhApiTerrainDataRepo;
|
||||||
import com.seibel.distanthorizons.api.DhApi;
|
import com.seibel.distanthorizons.api.DhApi;
|
||||||
import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
|
import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
|
||||||
import net.jpountz.lz4.LZ4FrameOutputStream;
|
import net.jpountz.lz4.LZ4FrameOutputStream;
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
import org.sqlite.SQLiteJDBCLoader;
|
import org.sqlite.SQLiteJDBCLoader;
|
||||||
import org.sqlite.util.OSInfo;
|
|
||||||
import org.tukaani.xz.XZOutputStream;
|
import org.tukaani.xz.XZOutputStream;
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
/** Handles first time Core setup. */
|
/** Handles first time Core setup. */
|
||||||
public class Initializer
|
public class Initializer
|
||||||
{
|
{
|
||||||
@@ -57,6 +50,7 @@ public class Initializer
|
|||||||
// will throw an error (not an exception)
|
// will throw an error (not an exception)
|
||||||
Class<?> lz4Compressor = LZ4FrameOutputStream.class;
|
Class<?> lz4Compressor = LZ4FrameOutputStream.class;
|
||||||
Class<?> zstdCompressor = ZstdOutputStream.class;
|
Class<?> zstdCompressor = ZstdOutputStream.class;
|
||||||
|
Runnable zstdBlockDecompress = () -> { com.github.luben.zstd.Zstd.decompress(new byte [0]); };
|
||||||
Class<?> lzmaCompressor = XZOutputStream.class;
|
Class<?> lzmaCompressor = XZOutputStream.class;
|
||||||
//Class<?> networking = ByteBuf.class;
|
//Class<?> networking = ByteBuf.class;
|
||||||
Class<?> config = com.electronwill.nightconfig.core.Config.class;
|
Class<?> config = com.electronwill.nightconfig.core.Config.class;
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.lang.management.GarbageCollectorMXBean;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
@@ -93,6 +95,7 @@ public class ClientApi
|
|||||||
private boolean isDevBuildMessagePrinted = false;
|
private boolean isDevBuildMessagePrinted = false;
|
||||||
private boolean lowMemoryWarningPrinted = false;
|
private boolean lowMemoryWarningPrinted = false;
|
||||||
private boolean highVanillaRenderDistanceWarningPrinted = false;
|
private boolean highVanillaRenderDistanceWarningPrinted = false;
|
||||||
|
private boolean g1GarbageCollectorWarningPrinted = false;
|
||||||
|
|
||||||
private long lastStaticWarningMessageSentMsTime = 0L;
|
private long lastStaticWarningMessageSentMsTime = 0L;
|
||||||
|
|
||||||
@@ -318,35 +321,6 @@ public class ClientApi
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============//
|
|
||||||
// clint tick //
|
|
||||||
//============//
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void clientTickEvent()
|
|
||||||
{
|
|
||||||
IProfilerWrapper profiler = MC_CLIENT.getProfiler();
|
|
||||||
profiler.push("DH-ClientTick");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IDhClientWorld clientWorld = SharedApi.tryGetDhClientWorld();
|
|
||||||
if (clientWorld != null)
|
|
||||||
{
|
|
||||||
clientWorld.clientTick();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
// handle errors here to prevent blowing up a mixin or API up stream
|
|
||||||
LOGGER.error("Unexpected error in ClientApi.clientTickEvent(), error: "+e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
profiler.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============//
|
//============//
|
||||||
// networking //
|
// networking //
|
||||||
//============//
|
//============//
|
||||||
@@ -674,7 +648,8 @@ public class ClientApi
|
|||||||
{
|
{
|
||||||
// dev build
|
// dev build
|
||||||
if (ModInfo.IS_DEV_BUILD
|
if (ModInfo.IS_DEV_BUILD
|
||||||
&& !this.isDevBuildMessagePrinted && MC_CLIENT.playerExists())
|
&& !this.isDevBuildMessagePrinted
|
||||||
|
&& MC_CLIENT.playerExists())
|
||||||
{
|
{
|
||||||
this.isDevBuildMessagePrinted = true;
|
this.isDevBuildMessagePrinted = true;
|
||||||
this.lastStaticWarningMessageSentMsTime = System.currentTimeMillis();
|
this.lastStaticWarningMessageSentMsTime = System.currentTimeMillis();
|
||||||
@@ -720,10 +695,11 @@ public class ClientApi
|
|||||||
if (!this.highVanillaRenderDistanceWarningPrinted
|
if (!this.highVanillaRenderDistanceWarningPrinted
|
||||||
&& Config.Common.Logging.Warning.showHighVanillaRenderDistanceWarning.get())
|
&& Config.Common.Logging.Warning.showHighVanillaRenderDistanceWarning.get())
|
||||||
{
|
{
|
||||||
|
this.highVanillaRenderDistanceWarningPrinted = true;
|
||||||
|
|
||||||
// DH generally doesn't need a vanilla render distance above 12
|
// DH generally doesn't need a vanilla render distance above 12
|
||||||
if (MC_RENDER.getRenderDistance() > 12)
|
if (MC_RENDER.getRenderDistance() > 12)
|
||||||
{
|
{
|
||||||
this.highVanillaRenderDistanceWarningPrinted = true;
|
|
||||||
this.lastStaticWarningMessageSentMsTime = System.currentTimeMillis();
|
this.lastStaticWarningMessageSentMsTime = System.currentTimeMillis();
|
||||||
|
|
||||||
String message =
|
String message =
|
||||||
@@ -739,6 +715,48 @@ public class ClientApi
|
|||||||
MC_CLIENT.sendChatMessage(message);
|
MC_CLIENT.sendChatMessage(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// print a warning if G1GC is being used
|
||||||
|
// (this garbage collector is known to cause stuttering)
|
||||||
|
if (this.staticStartupMessageSentRecently()) return;
|
||||||
|
if (!this.g1GarbageCollectorWarningPrinted
|
||||||
|
&& Config.Common.Logging.Warning.showGarbageCollectorWarning.get())
|
||||||
|
{
|
||||||
|
this.g1GarbageCollectorWarningPrinted = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
boolean g1GcInUse = false;
|
||||||
|
|
||||||
|
List<GarbageCollectorMXBean> gcMxBeans = ManagementFactory.getGarbageCollectorMXBeans();
|
||||||
|
for (GarbageCollectorMXBean gcMxBean : gcMxBeans)
|
||||||
|
{
|
||||||
|
// "G1 Young Generation" // "G1 Concurrent GC" // "G1 Old Generation"
|
||||||
|
if (gcMxBean.getName().toLowerCase().contains("g1 "))
|
||||||
|
{
|
||||||
|
g1GcInUse = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g1GcInUse)
|
||||||
|
{
|
||||||
|
ClientApi.INSTANCE.showChatMessageNextFrame(
|
||||||
|
// yellow text
|
||||||
|
"\u00A7e" + "Distant Horizons: G1 Garbage collector detected." + "\u00A7r \n" +
|
||||||
|
"This garbage collector can cause FPS stuttering. \n" +
|
||||||
|
"It's recommended to use a concurrent garbage collector \n" +
|
||||||
|
"like ZGC (Java 21+) for a smoother experience. \n" +
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception re)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Unable to determine garbage collector type. If stuttering occurs please try a concurrent garbage collector like ZGC.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
/** done to prevent sending a bunch of startup messages all at once, causing some to be missed. */
|
/** done to prevent sending a bunch of startup messages all at once, causing some to be missed. */
|
||||||
private boolean staticStartupMessageSentRecently()
|
private boolean staticStartupMessageSentRecently()
|
||||||
|
|||||||
@@ -1629,6 +1629,15 @@ public class Config
|
|||||||
+ "")
|
+ "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
public static ConfigEntry<Boolean> showGarbageCollectorWarning = new ConfigEntry.Builder<Boolean>()
|
||||||
|
.set(true)
|
||||||
|
.comment(""
|
||||||
|
+ "If enabled, a chat message will be displayed if the garbage \n"
|
||||||
|
+ "collector Java is currently using is known \n"
|
||||||
|
+ "to cause stutters and/or issues. \n"
|
||||||
|
+ "")
|
||||||
|
.build();
|
||||||
|
|
||||||
public static ConfigEntry<Boolean> showReplayWarningOnStartup = new ConfigEntry.Builder<Boolean>()
|
public static ConfigEntry<Boolean> showReplayWarningOnStartup = new ConfigEntry.Builder<Boolean>()
|
||||||
.set(true)
|
.set(true)
|
||||||
.comment(""
|
.comment(""
|
||||||
|
|||||||
+11
-8
@@ -96,16 +96,19 @@ public class DhFadeRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.fadeTexture = GL32.glGenTextures();
|
this.fadeTexture = GL32.glGenTextures();
|
||||||
GLMC.glBindTexture(this.fadeTexture);
|
{
|
||||||
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RGBA16, width, height, 0, GL32.GL_RGBA, GL32.GL_UNSIGNED_SHORT_4_4_4_4, (ByteBuffer) null);
|
GLMC.glBindTexture(this.fadeTexture);
|
||||||
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
|
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RGBA16, width, height, 0, GL32.GL_RGBA, GL32.GL_UNSIGNED_SHORT_4_4_4_4, (ByteBuffer) null);
|
||||||
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
|
||||||
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
|
||||||
// disable mip-mapping since DH is just going to draw straight to the screen
|
|
||||||
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
|
// disable mip-mapping since DH is just going to draw straight to the screen
|
||||||
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
|
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
|
||||||
|
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.fadeTexture, 0);
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.fadeTexture, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+11
-9
@@ -88,15 +88,17 @@ public class FogRenderer
|
|||||||
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fogFramebuffer);
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fogFramebuffer);
|
||||||
|
|
||||||
this.fogTexture = GLMC.glGenTextures();
|
this.fogTexture = GLMC.glGenTextures();
|
||||||
GLMC.glBindTexture(this.fogTexture);
|
{
|
||||||
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RGBA16, width, height, 0, GL32.GL_RGBA, GL32.GL_UNSIGNED_SHORT_4_4_4_4, (ByteBuffer) null);
|
GLMC.glBindTexture(this.fogTexture);
|
||||||
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
|
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RGBA16, width, height, 0, GL32.GL_RGBA, GL32.GL_UNSIGNED_SHORT_4_4_4_4, (ByteBuffer) null);
|
||||||
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
|
||||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.fogTexture, 0);
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.fogTexture, 0);
|
||||||
// disable mip-mapping since DH is just going to draw straight to the screen
|
|
||||||
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
|
// disable mip-mapping since DH is just going to draw straight to the screen
|
||||||
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
|
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
|
||||||
|
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+10
-8
@@ -88,14 +88,16 @@ public class SSAORenderer
|
|||||||
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.ssaoFramebuffer);
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.ssaoFramebuffer);
|
||||||
|
|
||||||
this.ssaoTexture = GLMC.glGenTextures();
|
this.ssaoTexture = GLMC.glGenTextures();
|
||||||
GLMC.glBindTexture(this.ssaoTexture);
|
{
|
||||||
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_R16F, width, height, 0, GL32.GL_RED, GL32.GL_HALF_FLOAT, (ByteBuffer) null);
|
GLMC.glBindTexture(this.ssaoTexture);
|
||||||
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
|
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_R16F, width, height, 0, GL32.GL_RED, GL32.GL_HALF_FLOAT, (ByteBuffer) null);
|
||||||
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
|
||||||
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
|
||||||
// disable mip-mapping since DH is just going to draw straight to the screen
|
|
||||||
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
|
// disable mip-mapping since DH is just going to draw straight to the screen
|
||||||
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
|
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
|
||||||
|
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.ssaoTexture, 0);
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.ssaoTexture, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod
|
|
||||||
* licensed under the GNU LGPL v3 License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 James Seibel
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.seibel.distanthorizons.core.util.objects;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.CompletionException;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
public class EventLoop implements AutoCloseable
|
|
||||||
{
|
|
||||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
|
||||||
|
|
||||||
private final boolean PAUSE_ON_ERROR = ModInfo.IS_DEV_BUILD;
|
|
||||||
private final ExecutorService executorService;
|
|
||||||
|
|
||||||
private final Runnable runnable;
|
|
||||||
/** the future related to the given runnable */
|
|
||||||
private CompletableFuture<Void> runnableFuture;
|
|
||||||
|
|
||||||
private boolean isRunning = true;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public EventLoop(ExecutorService executorService, Runnable runnable)
|
|
||||||
{
|
|
||||||
this.executorService = executorService;
|
|
||||||
this.runnable = runnable;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void tick()
|
|
||||||
{
|
|
||||||
if (runnableFuture != null && runnableFuture.isDone())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
runnableFuture.join();
|
|
||||||
}
|
|
||||||
catch (CompletionException ce)
|
|
||||||
{
|
|
||||||
LOGGER.error("Uncaught exception in event loop", ce.getCause());
|
|
||||||
if (PAUSE_ON_ERROR)
|
|
||||||
{
|
|
||||||
isRunning = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
LOGGER.error("Exception in event loop", e);
|
|
||||||
if (PAUSE_ON_ERROR)
|
|
||||||
{
|
|
||||||
isRunning = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
runnableFuture = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runnableFuture == null && isRunning)
|
|
||||||
{
|
|
||||||
runnableFuture = CompletableFuture.runAsync(runnable, executorService);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
{
|
|
||||||
if (runnableFuture != null)
|
|
||||||
{
|
|
||||||
runnableFuture.cancel(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
runnableFuture = null;
|
|
||||||
executorService.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRunning() { return runnableFuture != null && !runnableFuture.isDone(); }
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -21,27 +21,21 @@ package com.seibel.distanthorizons.core.world;
|
|||||||
|
|
||||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
import com.seibel.distanthorizons.core.level.DhClientServerLevel;
|
import com.seibel.distanthorizons.core.level.DhClientServerLevel;
|
||||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
import com.seibel.distanthorizons.core.util.TimerUtil;
|
||||||
import com.seibel.distanthorizons.core.util.objects.EventLoop;
|
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLevel> implements IDhClientWorld
|
public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLevel> implements IDhClientWorld
|
||||||
{
|
{
|
||||||
private final Set<DhClientServerLevel> dhLevels = Collections.synchronizedSet(new HashSet<>());
|
private final Set<DhClientServerLevel> dhLevels = Collections.synchronizedSet(new HashSet<>());
|
||||||
|
|
||||||
public ExecutorService dhTickerThread = ThreadUtil.makeSingleThreadPool("Client Server World Ticker", 2);
|
private final Timer clientTickTimer = TimerUtil.CreateTimer("ClientTickTimer");
|
||||||
public EventLoop eventLoop = new EventLoop(this.dhTickerThread, this::_clientTick); //TODO: Rate-limit the loop
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -53,6 +47,15 @@ public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLev
|
|||||||
{
|
{
|
||||||
super(EWorldEnvironment.CLIENT_SERVER);
|
super(EWorldEnvironment.CLIENT_SERVER);
|
||||||
LOGGER.info("Started DhWorld of type " + this.environment);
|
LOGGER.info("Started DhWorld of type " + this.environment);
|
||||||
|
|
||||||
|
this.clientTickTimer.scheduleAtFixedRate(new TimerTask()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
DhClientServerWorld.this.dhLevels.forEach(DhClientServerLevel::clientTick);
|
||||||
|
}
|
||||||
|
}, 0, IDhClientWorld.TICK_RATE_IN_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -136,19 +139,6 @@ public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLev
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _clientTick()
|
|
||||||
{
|
|
||||||
//LOGGER.info("Client world tick with {} levels", levels.size());
|
|
||||||
this.dhLevels.forEach(DhClientServerLevel::clientTick);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clientTick()
|
|
||||||
{
|
|
||||||
//LOGGER.info("Client world tick");
|
|
||||||
this.eventLoop.tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
//================//
|
||||||
@@ -194,8 +184,8 @@ public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLev
|
|||||||
|
|
||||||
|
|
||||||
this.dhLevelByLevelWrapper.clear();
|
this.dhLevelByLevelWrapper.clear();
|
||||||
this.eventLoop.close();
|
this.clientTickTimer.cancel();
|
||||||
LOGGER.info("Closed DhWorld of type " + this.environment);
|
LOGGER.info("Closed DhWorld of type [" + this.environment + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,17 +24,17 @@ import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
|
|||||||
import com.seibel.distanthorizons.core.level.DhClientLevel;
|
import com.seibel.distanthorizons.core.level.DhClientLevel;
|
||||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||||
import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
|
import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
|
||||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
import com.seibel.distanthorizons.core.util.TimerUtil;
|
||||||
import com.seibel.distanthorizons.core.util.objects.EventLoop;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||||
{
|
{
|
||||||
@@ -42,8 +42,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
|||||||
public final ClientOnlySaveStructure saveStructure;
|
public final ClientOnlySaveStructure saveStructure;
|
||||||
public final ClientNetworkState networkState = new ClientNetworkState();
|
public final ClientNetworkState networkState = new ClientNetworkState();
|
||||||
|
|
||||||
public final ExecutorService dhTickerThread = ThreadUtil.makeSingleThreadPool("Client World Ticker");
|
private final Timer clientTickTimer = TimerUtil.CreateTimer("ClientTickTimer");
|
||||||
public final EventLoop eventLoop = new EventLoop(this.dhTickerThread, this::_clientTick);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -59,6 +58,15 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
|||||||
this.levels = new ConcurrentHashMap<>();
|
this.levels = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
LOGGER.info("Started DhWorld of type " + this.environment);
|
LOGGER.info("Started DhWorld of type " + this.environment);
|
||||||
|
|
||||||
|
this.clientTickTimer.scheduleAtFixedRate(new TimerTask()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
DhClientWorld.this.levels.values().forEach(DhClientLevel::clientTick);
|
||||||
|
}
|
||||||
|
}, 0, IDhClientWorld.TICK_RATE_IN_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -127,11 +135,6 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _clientTick() { this.levels.values().forEach(DhClientLevel::clientTick); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clientTick() { this.eventLoop.tick(); }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addDebugMenuStringsToList(List<String> messageList)
|
public void addDebugMenuStringsToList(List<String> messageList)
|
||||||
{
|
{
|
||||||
@@ -143,7 +146,6 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
|||||||
public void close()
|
public void close()
|
||||||
{
|
{
|
||||||
this.networkState.close();
|
this.networkState.close();
|
||||||
this.dhTickerThread.shutdownNow();
|
|
||||||
|
|
||||||
ArrayList<CompletableFuture<Void>> closeFutures = new ArrayList<>();
|
ArrayList<CompletableFuture<Void>> closeFutures = new ArrayList<>();
|
||||||
for (DhClientLevel dhClientLevel : this.levels.values())
|
for (DhClientLevel dhClientLevel : this.levels.values())
|
||||||
@@ -175,7 +177,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.levels.clear();
|
this.levels.clear();
|
||||||
this.eventLoop.close();
|
this.clientTickTimer.cancel();
|
||||||
LOGGER.info("Closed DhWorld of type [" + this.environment + "].");
|
LOGGER.info("Closed DhWorld of type [" + this.environment + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
|||||||
|
|
||||||
public interface IDhClientWorld extends IDhWorld
|
public interface IDhClientWorld extends IDhWorld
|
||||||
{
|
{
|
||||||
void clientTick();
|
/** how long in between client ticks in milliseconds */
|
||||||
|
long TICK_RATE_IN_MS = 100L;
|
||||||
|
|
||||||
default IDhClientLevel getOrLoadClientLevel(ILevelWrapper levelWrapper) { return (IDhClientLevel) this.getOrLoadLevel(levelWrapper); }
|
default IDhClientLevel getOrLoadClientLevel(ILevelWrapper levelWrapper) { return (IDhClientLevel) this.getOrLoadLevel(levelWrapper); }
|
||||||
default IDhClientLevel getClientLevel(ILevelWrapper levelWrapper) { return (IDhClientLevel) this.getLevel(levelWrapper); }
|
default IDhClientLevel getClientLevel(ILevelWrapper levelWrapper) { return (IDhClientLevel) this.getLevel(levelWrapper); }
|
||||||
|
|||||||
@@ -725,6 +725,8 @@
|
|||||||
"If DH detects that pooled objects are being garbage collected this will send a chat warning.",
|
"If DH detects that pooled objects are being garbage collected this will send a chat warning.",
|
||||||
"distanthorizons.config.common.logging.warning.showHighVanillaRenderDistanceWarning":
|
"distanthorizons.config.common.logging.warning.showHighVanillaRenderDistanceWarning":
|
||||||
"Show High Vanilla Render Distance Warning",
|
"Show High Vanilla Render Distance Warning",
|
||||||
|
"distanthorizons.config.common.logging.warning.showGarbageCollectorWarning":
|
||||||
|
"Show Garbage Collector Warning",
|
||||||
"distanthorizons.config.common.logging.warning.showReplayWarningOnStartup":
|
"distanthorizons.config.common.logging.warning.showReplayWarningOnStartup":
|
||||||
"Show Replay Warning",
|
"Show Replay Warning",
|
||||||
"distanthorizons.config.common.logging.warning.showUpdateQueueOverloadedChatWarning":
|
"distanthorizons.config.common.logging.warning.showUpdateQueueOverloadedChatWarning":
|
||||||
|
|||||||
Reference in New Issue
Block a user