Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a4bfef7a6 | |||
| 7be65a2258 | |||
| 1a540cf2bc | |||
| 20fc2efb46 | |||
| d8beba2498 | |||
| 9f0cb5a394 | |||
| df63401d11 | |||
| db95951ade | |||
| 1e020f93a6 | |||
| 7aee6dfb44 | |||
| 546a51a295 | |||
| ec7e791e9f | |||
| d60dec3d82 | |||
| 89a80103f0 | |||
| 8e14a7223c | |||
| 7cf1e901f5 | |||
| ba923fa829 |
@@ -32,9 +32,7 @@ public final class ModInfo
|
||||
|
||||
/** Incremented every time any packets are added, changed or removed, with a few exceptions. */
|
||||
public static final int PROTOCOL_VERSION = 13;
|
||||
|
||||
/** The full plugin channel name (RESOURCE_NAMESPACE:WRAPPER_PACKET_PATH) must be 20 characters or fewer for compatibility with <1.13. */
|
||||
public static final String WRAPPER_PACKET_PATH = "msg";
|
||||
public static final String WRAPPER_PACKET_PATH = "message";
|
||||
|
||||
/** The internal mod name */
|
||||
public static final String NAME = "DistantHorizons";
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.seibel.distanthorizons.api.enums.config.EDhApiMcRenderingFadeMode;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
|
||||
import com.seibel.distanthorizons.core.api.internal.rendering.DhRenderState;
|
||||
import com.seibel.distanthorizons.core.enums.EMinecraftColor;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
|
||||
@@ -33,6 +33,8 @@ import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
|
||||
import com.seibel.distanthorizons.core.render.renderer.*;
|
||||
import com.seibel.distanthorizons.core.util.TimerUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.Pair;
|
||||
import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker;
|
||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
@@ -58,6 +60,8 @@ import org.lwjgl.glfw.GLFW;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* This holds the methods that should be called
|
||||
@@ -153,10 +157,10 @@ public class ClientApi
|
||||
|
||||
if (Config.Common.Logging.Warning.showReplayWarningOnStartup.get())
|
||||
{
|
||||
MC_CLIENT.sendChatMessage(EMinecraftColor.ORANGE + "Distant Horizons: Replay detected." + EMinecraftColor.CLEAR_FORMATTING);
|
||||
MC_CLIENT.sendChatMessage(MinecraftTextFormat.ORANGE + "Distant Horizons: Replay detected." + MinecraftTextFormat.CLEAR_FORMATTING);
|
||||
MC_CLIENT.sendChatMessage("DH may behave strangely or have missing functionality.");
|
||||
MC_CLIENT.sendChatMessage("In order to use pre-generated LODs, put your DH database(s) in:");
|
||||
MC_CLIENT.sendChatMessage(EMinecraftColor.GRAY +".Minecraft" + File.separator + ClientOnlySaveStructure.SERVER_DATA_FOLDER_NAME + File.separator + ClientOnlySaveStructure.REPLAY_SERVER_FOLDER_NAME + File.separator + "DIMENSION_NAME"+EMinecraftColor.CLEAR_FORMATTING);
|
||||
MC_CLIENT.sendChatMessage(MinecraftTextFormat.GRAY +".Minecraft" + File.separator + ClientOnlySaveStructure.SERVER_DATA_FOLDER_NAME + File.separator + ClientOnlySaveStructure.REPLAY_SERVER_FOLDER_NAME + File.separator + "DIMENSION_NAME"+ MinecraftTextFormat.CLEAR_FORMATTING);
|
||||
MC_CLIENT.sendChatMessage("This can be disabled in DH's config under Advanced -> Logging.");
|
||||
MC_CLIENT.sendChatMessage("");
|
||||
}
|
||||
@@ -329,10 +333,27 @@ public class ClientApi
|
||||
*/
|
||||
public void pluginMessageReceived(@NotNull AbstractNetworkMessage message)
|
||||
{
|
||||
NetworkSession networkSession = this.pluginChannelApi.networkSession;
|
||||
if (networkSession != null)
|
||||
@Nullable ThreadPoolExecutor executor = ThreadPoolUtil.networkClientHandlerExecutor();
|
||||
if (executor == null)
|
||||
{
|
||||
networkSession.tryHandleMessage(message);
|
||||
LOGGER.warn("warn");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
executor.execute(() ->
|
||||
{
|
||||
NetworkSession networkSession = this.pluginChannelApi.networkSession;
|
||||
if (networkSession != null)
|
||||
{
|
||||
networkSession.tryHandleMessage(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (RejectedExecutionException e)
|
||||
{
|
||||
LOGGER.warn("Plugin message executor rejected");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,10 +529,10 @@ public class ClientApi
|
||||
this.rendererDisabledBecauseOfExceptions = true;
|
||||
LOGGER.error("Unexpected Renderer error in render pass [" + renderPass + "]. Error: " + e.getMessage(), e);
|
||||
|
||||
MC_CLIENT.sendChatMessage(EMinecraftColor.DARK_RED + "" + EMinecraftColor.BOLD + "ERROR: Distant Horizons renderer has encountered an exception!" + EMinecraftColor.CLEAR_FORMATTING);
|
||||
MC_CLIENT.sendChatMessage(EMinecraftColor.DARK_RED + "Renderer disabled to try preventing GL state corruption." + EMinecraftColor.CLEAR_FORMATTING);
|
||||
MC_CLIENT.sendChatMessage(EMinecraftColor.DARK_RED + "Toggle DH rendering via the config UI to re-activate DH rendering." + EMinecraftColor.CLEAR_FORMATTING);
|
||||
MC_CLIENT.sendChatMessage(EMinecraftColor.DARK_RED + "Error: " + EMinecraftColor.CLEAR_FORMATTING + e);
|
||||
MC_CLIENT.sendChatMessage(MinecraftTextFormat.DARK_RED + "" + MinecraftTextFormat.BOLD + "ERROR: Distant Horizons renderer has encountered an exception!" + MinecraftTextFormat.CLEAR_FORMATTING);
|
||||
MC_CLIENT.sendChatMessage(MinecraftTextFormat.DARK_RED + "Renderer disabled to try preventing GL state corruption." + MinecraftTextFormat.CLEAR_FORMATTING);
|
||||
MC_CLIENT.sendChatMessage(MinecraftTextFormat.DARK_RED + "Toggle DH rendering via the config UI to re-activate DH rendering." + MinecraftTextFormat.CLEAR_FORMATTING);
|
||||
MC_CLIENT.sendChatMessage(MinecraftTextFormat.DARK_RED + "Error: " + MinecraftTextFormat.CLEAR_FORMATTING + e);
|
||||
}
|
||||
|
||||
|
||||
@@ -656,7 +677,7 @@ public class ClientApi
|
||||
|
||||
// remind the user that this is a development build
|
||||
String message =
|
||||
EMinecraftColor.DARK_GREEN + "Distant Horizons: nightly/unstable build, version: [" + ModInfo.VERSION+"]." +EMinecraftColor.CLEAR_FORMATTING + "\n" +
|
||||
MinecraftTextFormat.DARK_GREEN + "Distant Horizons: nightly/unstable build, version: [" + ModInfo.VERSION+"]." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"Issues may occur with this version.\n" +
|
||||
"Here be dragons!\n";
|
||||
MC_CLIENT.sendChatMessage(message);
|
||||
@@ -680,7 +701,7 @@ public class ClientApi
|
||||
{
|
||||
String message =
|
||||
// orange text
|
||||
EMinecraftColor.ORANGE + "Distant Horizons: Low memory detected." + EMinecraftColor.CLEAR_FORMATTING + "\n" +
|
||||
MinecraftTextFormat.ORANGE + "Distant Horizons: Low memory detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"Stuttering or low FPS may occur. \n" +
|
||||
"Please increase Minecraft's available memory to 4 GB or more. \n" +
|
||||
"This warning can be disabled in DH's config under Advanced -> Logging. \n";
|
||||
@@ -702,12 +723,12 @@ public class ClientApi
|
||||
this.lastStaticWarningMessageSentMsTime = System.currentTimeMillis();
|
||||
|
||||
String message =
|
||||
EMinecraftColor.YELLOW + "Distant Horizons: High vanilla render distance detected." + EMinecraftColor.CLEAR_FORMATTING + "\n" +
|
||||
MinecraftTextFormat.YELLOW + "Distant Horizons: High vanilla render distance detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"Using a high vanilla render distance uses a lot of CPU power \n" +
|
||||
"and doesn't improve graphics much after about 12.\n" +
|
||||
"Lowing your vanilla render distance will give you better FPS\n" +
|
||||
"Lowering your vanilla render distance will give you better FPS\n" +
|
||||
"and reduce stuttering at a similar visual quality.\n" +
|
||||
EMinecraftColor.GRAY + "A vanilla render distance of 8 is recommended." + EMinecraftColor.CLEAR_FORMATTING + "\n" +
|
||||
MinecraftTextFormat.GRAY + "A vanilla render distance of 8 is recommended." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"This message can be disabled in DH's config under Advanced -> Logging.\n";
|
||||
MC_CLIENT.sendChatMessage(message);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,13 +1,11 @@
|
||||
package com.seibel.distanthorizons.core.api.internal.chunkUpdating;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.enums.EMinecraftColor;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.multiplayer.client.SyncOnLoadRequestQueue;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.world.EWorldEnvironment;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
@@ -120,7 +118,7 @@ public class ChunkUpdateQueueManager
|
||||
{
|
||||
lastOverloadedLogMessageMsTime = System.currentTimeMillis();
|
||||
|
||||
String message = EMinecraftColor.ORANGE + "Distant Horizons overloaded, too many chunks queued for LOD processing. " + EMinecraftColor.CLEAR_FORMATTING +
|
||||
String message = MinecraftTextFormat.ORANGE + "Distant Horizons overloaded, too many chunks queued for LOD processing. " + MinecraftTextFormat.CLEAR_FORMATTING +
|
||||
"\nThis may result in holes in your LODs. " +
|
||||
"\nFix: move through the world slower, decrease your vanilla render distance, slow down your world pre-generator (IE Chunky), or increase the Distant Horizons' CPU thread counts. " +
|
||||
"\nMax queue count [" + SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.maxSize + "] ([" + SharedApi.MAX_UPDATING_CHUNK_COUNT_PER_THREAD_AND_PLAYER + "] per thread+players).";
|
||||
|
||||
@@ -101,6 +101,7 @@ public class Config
|
||||
.build();
|
||||
|
||||
public static ConfigUiLinkedEntry quickEnableWorldGenerator = new ConfigUiLinkedEntry(Common.WorldGenerator.enableDistantGeneration);
|
||||
public static ConfigUiLinkedEntry quickEnableServerGeneration = new ConfigUiLinkedEntry(Server.enableServerGeneration);
|
||||
|
||||
public static ConfigUiLinkedEntry quickShowWorldGenProgress = new ConfigUiLinkedEntry(Common.WorldGenerator.showGenerationProgress);
|
||||
|
||||
@@ -457,6 +458,15 @@ public class Config
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> expandDistantBeacons = new ConfigEntry.Builder<Boolean>()
|
||||
.set(true)
|
||||
.comment(""
|
||||
+ "If true LOD beacon beams will be rendered wider at extreme distances, \n"
|
||||
+ "making them easier to see. \n"
|
||||
+ "If false all LOD beacon beams will only ever be 1 block wide. \n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> enableCloudRendering = new ConfigEntry.Builder<Boolean>()
|
||||
.set(true)
|
||||
.comment(""
|
||||
@@ -1725,6 +1735,15 @@ public class Config
|
||||
|
||||
|
||||
// Generation
|
||||
public static ConfigEntry<Boolean> enableServerGeneration = new ConfigEntry.Builder<Boolean>()
|
||||
.set(true)
|
||||
.comment(""
|
||||
+ "When enabled, Distant Horizons will attempt to download missing LODs from the server.\n"
|
||||
+ "\n"
|
||||
+ "Note: the server must have Distant Generation enabled for it to work."
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Integer> generationRequestRateLimit = new ConfigEntry.Builder<Integer>()
|
||||
.setChatCommandName("generation.requestRateLimit")
|
||||
.setMinDefaultMax(1, 20, 100)
|
||||
|
||||
+10
-13
@@ -295,24 +295,21 @@ public class LodBufferContainer implements AutoCloseable
|
||||
{
|
||||
this.buffersUploaded = false;
|
||||
|
||||
GLProxy.queueRunningOnRenderThread(() ->
|
||||
for (GLVertexBuffer buffer : this.vbos)
|
||||
{
|
||||
for (GLVertexBuffer buffer : this.vbos)
|
||||
if (buffer != null)
|
||||
{
|
||||
if (buffer != null)
|
||||
{
|
||||
buffer.destroyAsync();
|
||||
}
|
||||
buffer.destroyAsync();
|
||||
}
|
||||
|
||||
for (GLVertexBuffer buffer : this.vbosTransparent)
|
||||
}
|
||||
|
||||
for (GLVertexBuffer buffer : this.vbosTransparent)
|
||||
{
|
||||
if (buffer != null)
|
||||
{
|
||||
if (buffer != null)
|
||||
{
|
||||
buffer.destroyAsync();
|
||||
}
|
||||
buffer.destroyAsync();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.seibel.distanthorizons.core.enums;
|
||||
|
||||
/**
|
||||
* might be deprecated in the future? in that case we'll probably want a wrapper
|
||||
* function to handle colors for new MC versions
|
||||
* <br><br>
|
||||
* source: https://minecraft.wiki/w/Formatting_codes
|
||||
*/
|
||||
public enum EMinecraftColor // TODO EMinecraftTextFormat
|
||||
{
|
||||
BLACK("\u00A70"),
|
||||
DARK_BLUE("\u00A71"),
|
||||
DARK_GREEN("\u00A72"),
|
||||
DARK_AQUA("\u00A73"),
|
||||
DARK_RED("\u00A74"),
|
||||
DARK_PURPLE("\u00A75"),
|
||||
ORANGE("\u00A76"),
|
||||
GRAY("\u00A77"),
|
||||
DARK_GRAY("\u00A78"),
|
||||
BLUE("\u00A79"),
|
||||
GREEN("\u00A7a"),
|
||||
AQUA("\u00A7b"),
|
||||
RED("\u00A7c"),
|
||||
LIGHT_PURPLE("\u00A7d"),
|
||||
YELLOW("\u00A7e"),
|
||||
WHITE("\u00A7f"),
|
||||
|
||||
OBFUSCATED("\u00A7k"),
|
||||
BOLD("\u00A7l"),
|
||||
STRIKETHROUGH("\u00A7m"),
|
||||
UNDERLINE("\u00A7n"),
|
||||
ITALIC("\u00A7o"),
|
||||
CLEAR_FORMATTING("\u00A7r");
|
||||
|
||||
public final String colorCode;
|
||||
|
||||
EMinecraftColor(String colorCode)
|
||||
{
|
||||
this.colorCode = colorCode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() { return this.colorCode; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.seibel.distanthorizons.core.enums;
|
||||
|
||||
/**
|
||||
* might be deprecated in the future? in that case we'll probably want a wrapper
|
||||
* function to handle colors for new MC versions
|
||||
* <br><br>
|
||||
* source: https://minecraft.wiki/w/Formatting_codes
|
||||
*/
|
||||
public class MinecraftTextFormat
|
||||
{
|
||||
public static final String BLACK = "\u00A70";
|
||||
public static final String DARK_BLUE = "\u00A71";
|
||||
public static final String DARK_GREEN = "\u00A72";
|
||||
public static final String DARK_AQUA = "\u00A73";
|
||||
public static final String DARK_RED = "\u00A74";
|
||||
public static final String DARK_PURPLE = "\u00A75";
|
||||
public static final String ORANGE = "\u00A76";
|
||||
public static final String GRAY = "\u00A77";
|
||||
public static final String DARK_GRAY = "\u00A78";
|
||||
public static final String BLUE = "\u00A79";
|
||||
public static final String GREEN = "\u00A7a";
|
||||
public static final String AQUA = "\u00A7b";
|
||||
public static final String RED = "\u00A7c";
|
||||
public static final String LIGHT_PURPLE = "\u00A7d";
|
||||
public static final String YELLOW = "\u00A7e";
|
||||
public static final String WHITE = "\u00A7f";
|
||||
|
||||
public static final String OBFUSCATED = "\u00A7k";
|
||||
public static final String BOLD = "\u00A7l";
|
||||
public static final String STRIKETHROUGH = "\u00A7m";
|
||||
public static final String UNDERLINE = "\u00A7n";
|
||||
public static final String ITALIC = "\u00A7o";
|
||||
public static final String CLEAR_FORMATTING = "\u00A7r";
|
||||
|
||||
}
|
||||
@@ -104,7 +104,7 @@ public class JarUtils
|
||||
*/
|
||||
public static InputStream accessFile(String resource)
|
||||
{
|
||||
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
final ClassLoader loader = JarUtils.class.getClassLoader();
|
||||
// this is the path within the jar file
|
||||
InputStream input = loader.getResourceAsStream(resource);
|
||||
if (input == null)
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.listeners.IConfigListener;
|
||||
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.enums.EMinecraftColor;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
@@ -303,32 +303,32 @@ public class DhLogger implements IConfigListener
|
||||
String prefix = "[" + ModInfo.READABLE_NAME + "] ";
|
||||
if (logLevel == Level.ERROR)
|
||||
{
|
||||
prefix += EMinecraftColor.DARK_RED;
|
||||
prefix += MinecraftTextFormat.DARK_RED;
|
||||
}
|
||||
else if (logLevel == Level.WARN)
|
||||
{
|
||||
prefix += EMinecraftColor.ORANGE;
|
||||
prefix += MinecraftTextFormat.ORANGE;
|
||||
}
|
||||
else if (logLevel == Level.INFO)
|
||||
{
|
||||
prefix += EMinecraftColor.AQUA;
|
||||
prefix += MinecraftTextFormat.AQUA;
|
||||
}
|
||||
else if (logLevel == Level.DEBUG)
|
||||
{
|
||||
prefix += EMinecraftColor.GREEN;
|
||||
prefix += MinecraftTextFormat.GREEN;
|
||||
}
|
||||
else if (logLevel == Level.TRACE)
|
||||
{
|
||||
prefix += EMinecraftColor.DARK_GRAY;
|
||||
prefix += MinecraftTextFormat.DARK_GRAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix += EMinecraftColor.WHITE;
|
||||
prefix += MinecraftTextFormat.WHITE;
|
||||
}
|
||||
|
||||
prefix += EMinecraftColor.BOLD + "" + EMinecraftColor.WHITE;
|
||||
prefix += MinecraftTextFormat.BOLD + "" + MinecraftTextFormat.WHITE;
|
||||
prefix += logLevel.name();
|
||||
prefix += EMinecraftColor.CLEAR_FORMATTING + " ";
|
||||
prefix += MinecraftTextFormat.CLEAR_FORMATTING + " ";
|
||||
|
||||
mc_client.sendChatMessage(prefix + message);
|
||||
}
|
||||
|
||||
+10
-2
@@ -24,6 +24,7 @@ import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable;
|
||||
import com.seibel.distanthorizons.core.sql.dto.FullDataSourceV2DTO;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.ratelimiting.SupplierBasedRateLimiter;
|
||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||
import com.seibel.distanthorizons.core.world.DhApiWorldProxy;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
|
||||
@@ -217,11 +218,18 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende
|
||||
FullDataSourceResponseMessage.class
|
||||
);
|
||||
requestTask.networkDataSourceFuture = dataSourceNetworkFuture;
|
||||
dataSourceNetworkFuture.handle((FullDataSourceResponseMessage response, Throwable throwable) ->
|
||||
|
||||
Executor networkCompressionExecutor = ThreadPoolUtil.getNetworkCompressionExecutor();
|
||||
if (networkCompressionExecutor == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dataSourceNetworkFuture.handleAsync((FullDataSourceResponseMessage response, Throwable throwable) ->
|
||||
{
|
||||
this.handleNetResponse(requestTask, response, throwable);
|
||||
return null;
|
||||
});
|
||||
}, networkCompressionExecutor);
|
||||
}
|
||||
private void handleNetResponse(NetRequestTask requestTask, FullDataSourceResponseMessage response, Throwable throwable)
|
||||
{
|
||||
|
||||
+11
@@ -1,8 +1,10 @@
|
||||
package com.seibel.distanthorizons.core.multiplayer.client;
|
||||
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.multiplayer.config.SessionConfig;
|
||||
@@ -95,6 +97,15 @@ public class ClientNetworkState implements Closeable
|
||||
|| Math.abs(event.protocolVersion - ModInfo.PROTOCOL_VERSION) < this.closestProtocolVersion)
|
||||
{
|
||||
this.closestProtocolVersion = event.protocolVersion;
|
||||
|
||||
if (ModInfo.PROTOCOL_VERSION < event.protocolVersion)
|
||||
{
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(MinecraftTextFormat.ORANGE + "Distant Horizons: Your mod is outdated. Update to receive LODs on this server.");
|
||||
}
|
||||
else
|
||||
{
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(MinecraftTextFormat.ORANGE + "Distant Horizons: The server's mod is outdated. Ask the server's owner to update.");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+52
-17
@@ -11,6 +11,7 @@ import java.io.Closeable;
|
||||
import java.util.*;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SessionConfig implements INetworkObject
|
||||
@@ -31,7 +32,23 @@ public class SessionConfig implements INetworkObject
|
||||
{
|
||||
// Note: config values are transmitted in the insertion order
|
||||
|
||||
registerConfigEntry(Config.Common.WorldGenerator.enableDistantGeneration, Boolean::logicalAnd);
|
||||
registerConfigEntry(Config.Common.WorldGenerator.enableDistantGeneration.getChatCommandName(), new Entry(
|
||||
Config.Server.enableServerGeneration::get,
|
||||
runnable -> new Closeable()
|
||||
{
|
||||
private final ConfigChangeListener<Boolean> distantGenerationChanges = new ConfigChangeListener<>(Config.Common.WorldGenerator.enableDistantGeneration, ignored -> runnable.run());
|
||||
private final ConfigChangeListener<Boolean> serverGenerationChanges = new ConfigChangeListener<>(Config.Server.enableServerGeneration, ignored -> runnable.run());
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
this.serverGenerationChanges.close();
|
||||
this.distantGenerationChanges.close();
|
||||
}
|
||||
},
|
||||
(Boolean client, Boolean server) -> client && Config.Common.WorldGenerator.enableDistantGeneration.get()
|
||||
));
|
||||
|
||||
registerConfigEntry(Config.Server.maxGenerationRequestDistance, Math::min);
|
||||
registerConfigEntry(Config.Common.WorldGenerator.generationCenterChunkX, (x, y) -> y);
|
||||
registerConfigEntry(Config.Common.WorldGenerator.generationCenterChunkZ, (x, y) -> y);
|
||||
@@ -90,14 +107,24 @@ public class SessionConfig implements INetworkObject
|
||||
|
||||
private static <T> void registerConfigEntry(ConfigEntry<T> configEntry, BinaryOperator<T> valueConstrainer)
|
||||
{
|
||||
CONFIG_ENTRIES.compute(Objects.requireNonNull(configEntry.getChatCommandName()), (key, existingEntry) -> {
|
||||
if (existingEntry != null)
|
||||
{
|
||||
throw new IllegalArgumentException("Attempted to register config entry with duplicate chatCommandName: " + key);
|
||||
}
|
||||
|
||||
return new Entry(configEntry, valueConstrainer);
|
||||
});
|
||||
registerConfigEntry(
|
||||
Objects.requireNonNull(configEntry.getChatCommandName()),
|
||||
new Entry(
|
||||
configEntry::get,
|
||||
runnable -> new ConfigChangeListener<>(configEntry, ignored -> runnable.run()),
|
||||
valueConstrainer
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static void registerConfigEntry(String key, Entry entry)
|
||||
{
|
||||
if (CONFIG_ENTRIES.containsKey(key))
|
||||
{
|
||||
throw new IllegalArgumentException("Attempted to register config entry with duplicate key: " + key);
|
||||
}
|
||||
|
||||
CONFIG_ENTRIES.put(key, entry);
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +142,7 @@ public class SessionConfig implements INetworkObject
|
||||
T value = (T) this.values.get(name);
|
||||
if (value == null)
|
||||
{
|
||||
value = (T) entry.supplier.get();
|
||||
value = (T) entry.valueSupplier.get();
|
||||
}
|
||||
|
||||
return (this.constrainingConfig != null
|
||||
@@ -210,13 +237,15 @@ public class SessionConfig implements INetworkObject
|
||||
|
||||
private static class Entry
|
||||
{
|
||||
public final ConfigEntry<Object> supplier;
|
||||
public final Supplier<Object> valueSupplier;
|
||||
public final Function<Runnable, Closeable> changeListenerFactory;
|
||||
public final BinaryOperator<Object> valueConstrainer;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Entry(ConfigEntry<T> supplier, BinaryOperator<T> valueConstrainer)
|
||||
private <T> Entry(Supplier<Object> valueSupplier, Function<Runnable, Closeable> changeListenerFactory, BinaryOperator<T> valueConstrainer)
|
||||
{
|
||||
this.supplier = (ConfigEntry<Object>) supplier;
|
||||
this.valueSupplier = valueSupplier;
|
||||
this.changeListenerFactory = changeListenerFactory;
|
||||
this.valueConstrainer = (BinaryOperator<Object>) valueConstrainer;
|
||||
}
|
||||
|
||||
@@ -225,23 +254,29 @@ public class SessionConfig implements INetworkObject
|
||||
/** fires if any config value was changed */
|
||||
public static class AnyChangeListener implements Closeable
|
||||
{
|
||||
private final ArrayList<ConfigChangeListener<?>> changeListeners;
|
||||
private final ArrayList<Closeable> changeListeners;
|
||||
|
||||
public AnyChangeListener(Runnable runnable)
|
||||
{
|
||||
this.changeListeners = new ArrayList<>(CONFIG_ENTRIES.size());
|
||||
for (Entry entry : CONFIG_ENTRIES.values())
|
||||
{
|
||||
this.changeListeners.add(new ConfigChangeListener<>(entry.supplier, ignored -> runnable.run()));
|
||||
this.changeListeners.add(entry.changeListenerFactory.apply(runnable));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
for (ConfigChangeListener<?> changeListener : this.changeListeners)
|
||||
for (Closeable changeListener : this.changeListeners)
|
||||
{
|
||||
changeListener.close();
|
||||
try
|
||||
{
|
||||
changeListener.close();
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
this.changeListeners.clear();
|
||||
}
|
||||
|
||||
+1
@@ -45,6 +45,7 @@ public class FullDataPayloadReceiver implements AutoCloseable
|
||||
return null;
|
||||
}
|
||||
|
||||
message.buffer.readerIndex(0);
|
||||
composite.addComponent(message.buffer);
|
||||
composite.writerIndex(composite.writerIndex() + message.buffer.writerIndex());
|
||||
LOGGER.debug("Updated full data buffer [" + message.bufferId + "]: [" + composite + "].");
|
||||
|
||||
+2
-3
@@ -2,7 +2,7 @@ package com.seibel.distanthorizons.core.pooling;
|
||||
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.enums.EMinecraftColor;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||
@@ -13,7 +13,6 @@ import com.seibel.distanthorizons.coreapi.util.StringUtil;
|
||||
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -179,7 +178,7 @@ public class PhantomArrayListPool
|
||||
{
|
||||
lowMemoryWarningLogged = true;
|
||||
|
||||
String message = EMinecraftColor.ORANGE + "Distant Horizons: Insufficient memory detected." + EMinecraftColor.CLEAR_FORMATTING + "\n" +
|
||||
String message = MinecraftTextFormat.ORANGE + "Distant Horizons: Insufficient memory detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"This may cause stuttering or crashing. \n" +
|
||||
"Potential causes: \n" +
|
||||
"1. your allocated memory isn't high enough \n" +
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.V2.FullDataSourceProviderV2;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.DataSourceRetrievalResult;
|
||||
import com.seibel.distanthorizons.core.generation.tasks.ERetrievalResultState;
|
||||
import com.seibel.distanthorizons.core.level.DhClientServerLevel;
|
||||
import com.seibel.distanthorizons.core.level.IDhClientLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
@@ -78,6 +79,11 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
*/
|
||||
private final ConcurrentLinkedQueue<Long> sectionsToReload = new ConcurrentLinkedQueue<>();
|
||||
private final IDhClientLevel level;
|
||||
/**
|
||||
* Note: this doesn't lock all operations as some other threads/operations
|
||||
* that may traverse the tree while it's being modified.
|
||||
* IE {@link RenderBufferHandler} will walk through the tree each frame.
|
||||
*/
|
||||
private final ReentrantLock treeLock = new ReentrantLock();
|
||||
|
||||
private ArrayList<LodRenderSection> debugRenderSections = new ArrayList<>();
|
||||
@@ -139,6 +145,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
this.beaconRenderHandler = (genericObjectRenderer != null) ? new BeaconRenderHandler(genericObjectRenderer) : null;
|
||||
|
||||
Config.Common.WorldGenerator.enableDistantGeneration.addListener(this);
|
||||
Config.Server.enableServerGeneration.addListener(this);
|
||||
|
||||
}
|
||||
|
||||
@@ -166,7 +173,8 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
|
||||
|
||||
|
||||
// don't traverse the tree if it is being modified
|
||||
// don't tick the tree if a modification is still going
|
||||
// TODO is this lock necessary for anything beyond this tick method?
|
||||
if (this.treeLock.tryLock())
|
||||
{
|
||||
// this shouldn't be updated while the tree is being iterated through
|
||||
@@ -508,28 +516,23 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
// the section only needs to be updated if a buffer is currently present
|
||||
LodRenderSection renderSection = this.tryGetValue(pos);
|
||||
if (renderSection != null)
|
||||
{
|
||||
// the section only needs to be updated if a buffer is currently present
|
||||
LodRenderSection renderSection = this.getValue(pos);
|
||||
if (renderSection != null)
|
||||
if (renderSection.canRender())
|
||||
{
|
||||
if (renderSection.canRender())
|
||||
if (renderSection.gpuUploadInProgress()
|
||||
|| !renderSection.uploadRenderDataToGpuAsync())
|
||||
{
|
||||
if (renderSection.gpuUploadInProgress()
|
||||
|| !renderSection.uploadRenderDataToGpuAsync())
|
||||
{
|
||||
// if a section is already loading or failed to start upload
|
||||
// we need to wait to trigger it again
|
||||
// if we don't trigger it again the LOD will be out of date
|
||||
// and may be invisible/missing
|
||||
positionsToRequeue.add(pos);
|
||||
}
|
||||
// if a section is already loading or failed to start upload
|
||||
// we need to wait to trigger it again
|
||||
// if we don't trigger it again the LOD will be out of date
|
||||
// and may be invisible/missing
|
||||
positionsToRequeue.add(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
{ /* the section is now out of bounds, it doesn't need to be reloaded */ }
|
||||
}
|
||||
this.sectionsToReload.addAll(positionsToRequeue);
|
||||
}
|
||||
@@ -661,7 +664,9 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
@Override
|
||||
public void onConfigValueSet()
|
||||
{
|
||||
boolean generatorEnabled = Config.Common.WorldGenerator.enableDistantGeneration.get();
|
||||
boolean generatorEnabled = this.level instanceof DhClientServerLevel
|
||||
? Config.Common.WorldGenerator.enableDistantGeneration.get()
|
||||
: Config.Server.enableServerGeneration.get();
|
||||
if (generatorEnabled)
|
||||
{
|
||||
// world gen tasks will need to be re-queued
|
||||
@@ -919,6 +924,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
|
||||
|
||||
DebugRenderer.unregister(this, Config.Client.Advanced.Debugging.DebugWireframe.showQuadTreeRenderStatus);
|
||||
Config.Common.WorldGenerator.enableDistantGeneration.removeListener(this);
|
||||
Config.Server.enableServerGeneration.removeListener(this);
|
||||
|
||||
|
||||
ThreadPoolExecutor mainCleanupExecutor = ThreadPoolUtil.getCleanupExecutor();
|
||||
|
||||
@@ -77,7 +77,7 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
* contains the list of beacons currently being rendered in this section
|
||||
* if this list is modified the {@link LodRenderSection#beaconRenderHandler} should be updated to match.
|
||||
*/
|
||||
private final List<BeaconBeamDTO> activeBeaconList = new ArrayList<>();
|
||||
private final ArrayList<BeaconBeamDTO> activeBeaconList = new ArrayList<>();
|
||||
@Nullable
|
||||
public final BeaconRenderHandler beaconRenderHandler;
|
||||
@Nullable
|
||||
@@ -446,20 +446,15 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
|
||||
|
||||
// stop rendering current beacons
|
||||
for (BeaconBeamDTO beam : this.activeBeaconList)
|
||||
{
|
||||
this.beaconRenderHandler.stopRenderingBeaconAtPos(beam.blockPos);
|
||||
}
|
||||
this.beaconRenderHandler.stopRenderingBeacons(this.activeBeaconList);
|
||||
|
||||
// swap old and new active beacon list
|
||||
this.activeBeaconList.clear();
|
||||
this.activeBeaconList.addAll(activeBeacons);
|
||||
|
||||
// start rendering new beacon list
|
||||
for (BeaconBeamDTO beam : this.activeBeaconList)
|
||||
{
|
||||
this.beaconRenderHandler.startRenderingBeacon(beam);
|
||||
}
|
||||
byte absoluteDetailLevel = (byte)(DhSectionPos.getDetailLevel(this.pos) - DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL);
|
||||
this.beaconRenderHandler.startRenderingBeacons(this.activeBeaconList, absoluteDetailLevel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,10 +469,7 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
|
||||
synchronized (this.activeBeaconList)
|
||||
{
|
||||
for (BeaconBeamDTO beam : this.activeBeaconList)
|
||||
{
|
||||
this.beaconRenderHandler.stopRenderingBeaconAtPos(beam.blockPos);
|
||||
}
|
||||
this.beaconRenderHandler.stopRenderingBeacons(this.activeBeaconList);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,10 +484,8 @@ public class LodRenderSection implements IDebugRenderable, AutoCloseable
|
||||
|
||||
synchronized (this.activeBeaconList)
|
||||
{
|
||||
for (BeaconBeamDTO beam : this.activeBeaconList)
|
||||
{
|
||||
this.beaconRenderHandler.startRenderingBeacon(beam);
|
||||
}
|
||||
byte absoluteDetailLevel = (byte)(DhSectionPos.getDetailLevel(this.pos) - DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL);
|
||||
this.beaconRenderHandler.startRenderingBeacons(this.activeBeaconList, absoluteDetailLevel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -434,7 +434,7 @@ public class LodRenderer
|
||||
|
||||
// resize the textures if needed
|
||||
if (MC_RENDER.getTargetFramebufferViewportWidth() != this.textureWidth
|
||||
|| MC_RENDER.getTargetFramebufferViewportHeight() != this.textureHeight)
|
||||
|| MC_RENDER.getTargetFramebufferViewportHeight() != this.textureHeight)
|
||||
{
|
||||
// just resizing the textures doesn't work when Optifine is present,
|
||||
// so recreate the textures with the new size instead
|
||||
@@ -536,7 +536,7 @@ public class LodRenderer
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings( "deprecation" )
|
||||
@SuppressWarnings( "deprecation" ) // done to ignore DhApiColorDepthTextureCreatedEvent
|
||||
private void createAndBindTextures()
|
||||
{
|
||||
int oldWidth = this.textureWidth;
|
||||
|
||||
+99
-12
@@ -28,6 +28,7 @@ import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShad
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
@@ -39,8 +40,7 @@ import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@@ -54,6 +54,8 @@ public class BeaconRenderHandler
|
||||
/** how often should we check if a beacon should be culled? */
|
||||
private static final int MAX_CULLING_FREQUENCY_IN_MS = 1_000;
|
||||
|
||||
private static final Comparator<BeaconBeamDTO> NEGATIVE_BLOCKPOS_COMPARATOR = new NegativeInfiniteBlockPosComparator();
|
||||
|
||||
|
||||
|
||||
private final ReentrantLock updateLock = new ReentrantLock();
|
||||
@@ -89,20 +91,74 @@ public class BeaconRenderHandler
|
||||
// render handling //
|
||||
//=================//
|
||||
|
||||
public void startRenderingBeacon(BeaconBeamDTO beacon)
|
||||
public void startRenderingBeacons(ArrayList<BeaconBeamDTO> beaconList, byte detailLevel)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.updateLock.lock();
|
||||
|
||||
if (this.beaconBlockPosSet.add(beacon.blockPos))
|
||||
|
||||
// how wide should each beacon be?
|
||||
int beaconBlockWidth = 1;
|
||||
if (Config.Client.Advanced.Graphics.GenericRendering.expandDistantBeacons.get())
|
||||
{
|
||||
beaconBlockWidth = DhSectionPos.getBlockWidth(detailLevel);
|
||||
}
|
||||
|
||||
|
||||
ArrayList<BeaconBeamDTO> sortedBeaconList = new ArrayList<>(beaconList);
|
||||
|
||||
// merge distant beams if requested
|
||||
if (Config.Client.Advanced.Graphics.GenericRendering.expandDistantBeacons.get())
|
||||
{
|
||||
// sort beacons from neg inf -> pos inf
|
||||
// so we can consistently merge adjacent beacons
|
||||
sortedBeaconList.sort(NEGATIVE_BLOCKPOS_COMPARATOR);
|
||||
|
||||
// go through each beacon...
|
||||
for (int outerIndex = 0; outerIndex < sortedBeaconList.size(); outerIndex++)
|
||||
{
|
||||
BeaconBeamDTO outerBeacon = sortedBeaconList.get(outerIndex);
|
||||
DhBlockPos outerBlockPos = outerBeacon.blockPos;
|
||||
|
||||
// ...and remove any beacons that are within the block width to prevent overlaps
|
||||
for (int mergeIndex = outerIndex + 1; mergeIndex < sortedBeaconList.size(); mergeIndex++)
|
||||
{
|
||||
BeaconBeamDTO beaconToMerge = sortedBeaconList.get(mergeIndex);
|
||||
DhBlockPos mergeBlockPos = beaconToMerge.blockPos;
|
||||
|
||||
int xDiff = mergeBlockPos.getX() - outerBlockPos.getX();
|
||||
int zDiff = mergeBlockPos.getZ() - outerBlockPos.getZ();
|
||||
|
||||
// merge (remove) this beacon if
|
||||
// it's close to the outer beacon
|
||||
if (xDiff < beaconBlockWidth
|
||||
&& zDiff < beaconBlockWidth)
|
||||
{
|
||||
sortedBeaconList.remove(mergeIndex);
|
||||
mergeIndex--; // minus 1 so we don't go past the end of the array when incrementing in the for loop up top
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add each beacon to the renderer
|
||||
for (int i = 0; i < sortedBeaconList.size(); i++)
|
||||
{
|
||||
BeaconBeamDTO beacon = sortedBeaconList.get(i);
|
||||
if (!this.beaconBlockPosSet.add(beacon.blockPos))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
int maxBeaconBeamHeight = Config.Client.Advanced.Graphics.GenericRendering.beaconRenderHeight.get();
|
||||
DhApiRenderableBox beaconBox = new DhApiRenderableBox(
|
||||
new DhApiVec3d(beacon.blockPos.getX(), beacon.blockPos.getY() + 1, beacon.blockPos.getZ()),
|
||||
new DhApiVec3d(beacon.blockPos.getX() + 1, maxBeaconBeamHeight, beacon.blockPos.getZ() + 1),
|
||||
beacon.color,
|
||||
EDhApiBlockMaterial.ILLUMINATED
|
||||
new DhApiVec3d(beacon.blockPos.getX(), beacon.blockPos.getY() + 1, beacon.blockPos.getZ()),
|
||||
new DhApiVec3d(beacon.blockPos.getX() + beaconBlockWidth, maxBeaconBeamHeight, beacon.blockPos.getZ() + beaconBlockWidth),
|
||||
beacon.color,
|
||||
EDhApiBlockMaterial.ILLUMINATED
|
||||
);
|
||||
|
||||
this.beaconBoxGroup.add(beaconBox);
|
||||
@@ -116,19 +172,26 @@ public class BeaconRenderHandler
|
||||
}
|
||||
}
|
||||
|
||||
public void stopRenderingBeaconAtPos(DhBlockPos beaconPos)
|
||||
public void stopRenderingBeacons(ArrayList<BeaconBeamDTO> beaconList)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.updateLock.lock();
|
||||
|
||||
if (this.beaconBlockPosSet.remove(beaconPos))
|
||||
for (int i = 0; i < beaconList.size(); i++)
|
||||
{
|
||||
BeaconBeamDTO beacon = beaconList.get(i);
|
||||
DhBlockPos beaconPos = beacon.blockPos;
|
||||
if (!this.beaconBlockPosSet.remove(beaconPos))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Predicate<DhApiRenderableBox> removePredicate = (DhApiRenderableBox box) ->
|
||||
{
|
||||
return box.minPos.x == beaconPos.getX()
|
||||
&& box.minPos.y == beaconPos.getY() + 1 // plus 1 because the beam starts above the beacon
|
||||
&& box.minPos.z == beaconPos.getZ();
|
||||
&& box.minPos.y == beaconPos.getY() + 1 // plus 1 because the beam starts above the beacon
|
||||
&& box.minPos.z == beaconPos.getZ();
|
||||
};
|
||||
this.beaconBoxGroup.removeIf(removePredicate);
|
||||
this.fullBeaconBoxList.removeIf(removePredicate);
|
||||
@@ -255,4 +318,28 @@ public class BeaconRenderHandler
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
private static class NegativeInfiniteBlockPosComparator implements Comparator<BeaconBeamDTO>
|
||||
{
|
||||
@Override
|
||||
public int compare(BeaconBeamDTO beacon1, BeaconBeamDTO beacon2)
|
||||
{
|
||||
DhBlockPos blockPos1 = beacon1.blockPos;
|
||||
DhBlockPos blockPos2 = beacon2.blockPos;
|
||||
|
||||
// sort by X, then by Z
|
||||
if (blockPos1.getX() != blockPos2.getX())
|
||||
{
|
||||
return Integer.compare(blockPos1.getX(), blockPos2.getX());
|
||||
}
|
||||
return Integer.compare(blockPos1.getZ(), blockPos2.getZ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -493,7 +493,7 @@ public class CloudRenderHandler
|
||||
|
||||
private static boolean[][] getCloudsFromTexture() throws FileNotFoundException, IOException
|
||||
{
|
||||
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
final ClassLoader loader = CloudRenderHandler.class.getClassLoader();
|
||||
|
||||
boolean[][] whitePixels = null;
|
||||
try(InputStream imageInputStream = loader.getResourceAsStream(CLOUD_RESOURCE_TEXTURE_PATH))
|
||||
|
||||
@@ -173,7 +173,7 @@ public class DatabaseUpdater
|
||||
/** @throws NullPointerException if any of the script files failed to be read. */
|
||||
private static ArrayList<SqlScript> getAutoUpdateScripts() throws NullPointerException, IOException
|
||||
{
|
||||
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
final ClassLoader loader = DatabaseUpdater.class.getClassLoader();
|
||||
|
||||
|
||||
// get the script list
|
||||
|
||||
@@ -76,6 +76,9 @@ public class BeaconBeamDTO implements IBaseDTO<DhBlockPos>, INetworkObject
|
||||
public void close()
|
||||
{ /* no closing needed */ }
|
||||
|
||||
@Override
|
||||
public String toString() { return this.blockPos + " " + this.color; }
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+36
-50
@@ -31,12 +31,10 @@ import com.seibel.distanthorizons.coreapi.util.MathUtil;
|
||||
import com.seibel.distanthorizons.core.util.gridList.MovableGridRingList;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue;
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.LongConsumer;
|
||||
|
||||
/**
|
||||
@@ -98,9 +96,27 @@ public class QuadTree<T>
|
||||
// getters and setters //
|
||||
//=====================//
|
||||
|
||||
/** @return the value at the given section position. Null will be returned if the value is missing or the position is out of bounds. */
|
||||
@Nullable
|
||||
public final T tryGetValue(long pos)
|
||||
{
|
||||
QuadNode<T> node = this.tryGetNode(pos);
|
||||
if (node != null)
|
||||
{
|
||||
return node.value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return the node at the given section position, null if out of bounds */
|
||||
@Nullable
|
||||
public final QuadNode<T> tryGetNode(long pos) { return this.getOrSetNode(pos, false, null, false); }
|
||||
|
||||
|
||||
/** @return the node at the given section position */
|
||||
@Nullable
|
||||
public final QuadNode<T> getNode(long pos) throws IndexOutOfBoundsException { return this.getOrSetNode(pos, false, null, true); }
|
||||
|
||||
/** @return the value at the given section position */
|
||||
@Nullable
|
||||
public final T getValue(long pos) throws IndexOutOfBoundsException
|
||||
@@ -122,16 +138,24 @@ public class QuadTree<T>
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
/** @param runBoundaryChecks should only ever be set to true internally for removing out of bound nodes */
|
||||
/** @param throwIfOutOfBounds if false returns null */
|
||||
@Nullable
|
||||
protected final QuadNode<T> getOrSetNode(long pos, boolean setNewValue, T newValue, boolean runBoundaryChecks) throws IndexOutOfBoundsException
|
||||
protected final QuadNode<T> getOrSetNode(long pos, boolean setNewValue, T newValue, boolean throwIfOutOfBounds) throws IndexOutOfBoundsException
|
||||
{
|
||||
if (runBoundaryChecks && !this.isSectionPosInBounds(pos))
|
||||
if (!this.isSectionPosInBounds(pos))
|
||||
{
|
||||
int radius = this.diameterInBlocks() / 2;
|
||||
DhBlockPos2D minPos = this.getCenterBlockPos().add(new DhBlockPos2D(-radius, -radius));
|
||||
DhBlockPos2D maxPos = this.getCenterBlockPos().add(new DhBlockPos2D(radius, radius));
|
||||
throw new IndexOutOfBoundsException("QuadTree GetOrSet failed. Position out of bounds, min pos: " + minPos + ", max pos: " + maxPos + ", min detail level: " + this.treeLeafDetailLevel + ", max detail level: " + this.treeRootDetailLevel + ". Given Position: [" + DhSectionPos.toString(pos) + "] = block pos: " + DhSectionPos.convertToDetailLevel(pos, LodUtil.BLOCK_DETAIL_LEVEL));
|
||||
// how should out-of-bounds positions be handled?
|
||||
if (throwIfOutOfBounds)
|
||||
{
|
||||
int radius = this.diameterInBlocks() / 2;
|
||||
DhBlockPos2D minBlockPos = this.getCenterBlockPos().add(new DhBlockPos2D(-radius, -radius));
|
||||
DhBlockPos2D maxBlockPos = this.getCenterBlockPos().add(new DhBlockPos2D(radius, radius));
|
||||
throw new IndexOutOfBoundsException("QuadTree GetOrSet failed. Position out of bounds, min block pos: [" + minBlockPos + "], max block pos: [" + maxBlockPos + "], leaf detail level: [" + this.treeLeafDetailLevel + "], root detail level: [" + this.treeRootDetailLevel + "]. Requested section pos: [" + DhSectionPos.toString(pos) + "].");
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -278,46 +302,6 @@ public class QuadTree<T>
|
||||
removedItemConsumer.accept(quadNode.value);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// // remove out of bound nodes and clean up empty nodes
|
||||
// // Note: this will iterate over a lot of unnecessary nodes, hopefully speed won't be an issue
|
||||
// Iterator<DhSectionPos> rootNodePosIterator = this.rootNodePosIterator();
|
||||
// while (rootNodePosIterator.hasNext())
|
||||
// {
|
||||
// // get the root node (regular nodeIterators won't return them if they are out of bounds)
|
||||
// DhSectionPos rootPos = rootNodePosIterator.next();
|
||||
// QuadNode<T> rootNode = this.getOrSetNode(rootPos, false, null, false);
|
||||
// if (rootNode == null)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// // remove any child nodes that are out of bounds
|
||||
// Iterator<QuadNode<T>> nodeIterator = this.nodeIterator();
|
||||
// while (nodeIterator.hasNext())
|
||||
// {
|
||||
// QuadNode<T> node = nodeIterator.next();
|
||||
// if(!this.isSectionPosInBounds(node.sectionPos))
|
||||
// {
|
||||
// // node is out of bounds
|
||||
//
|
||||
// // FIXME(?) this appears to potentially return large nodes that are partially or entirely in bounds
|
||||
//
|
||||
// if (node.getNonNullChildCount() == 0)
|
||||
// {
|
||||
// // no child nodes, can be safely removed
|
||||
// nodeIterator.remove();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // node can't be removed, but its value can be set to null
|
||||
// node.value = null;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
public final DhBlockPos2D getCenterBlockPos() { return this.centerBlockPos; }
|
||||
@@ -544,7 +528,9 @@ public class QuadTree<T>
|
||||
&& this.rootNodeIterator.hasNext())
|
||||
{
|
||||
long sectionPos = this.rootNodeIterator.nextLong();
|
||||
QuadNode<T> rootNode = QuadTree.this.getNode(sectionPos);
|
||||
|
||||
// try-get to prevent concurrency errors if the tree is being moved while we walk through it
|
||||
QuadNode<T> rootNode = QuadTree.this.tryGetNode(sectionPos);
|
||||
if (rootNode != null)
|
||||
{
|
||||
nodeIterator = this.onlyReturnLeaves ? rootNode.getLeafNodeIterator() : rootNode.getNodeIterator(this.stopIteratingFunc);
|
||||
|
||||
+5
-6
@@ -30,7 +30,7 @@ import java.util.function.Consumer;
|
||||
public class QuadTreeNodeIterator<T> implements Iterator<QuadNode<T>>
|
||||
{
|
||||
/** lowest numerical value, inclusive */
|
||||
private final byte highestDetailLevel;
|
||||
private final byte leafDetailLevel;
|
||||
|
||||
|
||||
private final Queue<QuadNode<T>> validNodesForDetailLevel = new ArrayDeque<>();
|
||||
@@ -48,8 +48,7 @@ public class QuadTreeNodeIterator<T> implements Iterator<QuadNode<T>>
|
||||
{
|
||||
this.onlyReturnLeafValues = onlyReturnLeafValues;
|
||||
this.stopIteratingFunc = stopIteratingFunc;
|
||||
// TODO the naming conversion for these are flipped in a lot of places
|
||||
this.highestDetailLevel = rootNode.parentTreeLeafDetailLevel;
|
||||
this.leafDetailLevel = rootNode.parentTreeLeafDetailLevel;
|
||||
this.iteratorDetailLevel = DhSectionPos.getDetailLevel(rootNode.sectionPos);
|
||||
|
||||
|
||||
@@ -110,9 +109,9 @@ public class QuadTreeNodeIterator<T> implements Iterator<QuadNode<T>>
|
||||
@Override
|
||||
public QuadNode<T> next()
|
||||
{
|
||||
if (this.iteratorDetailLevel < this.highestDetailLevel)
|
||||
if (this.iteratorDetailLevel < this.leafDetailLevel)
|
||||
{
|
||||
throw new NoSuchElementException("Highest detail level reached [" + this.highestDetailLevel + "].");
|
||||
throw new NoSuchElementException("Leaf detail level reached [" + this.leafDetailLevel + "].");
|
||||
}
|
||||
if (this.iteratorNodeQueue.size() == 0)
|
||||
{
|
||||
@@ -133,7 +132,7 @@ public class QuadTreeNodeIterator<T> implements Iterator<QuadNode<T>>
|
||||
|
||||
this.iteratorDetailLevel--;
|
||||
// only continue if we can go down farther
|
||||
if (this.iteratorDetailLevel >= this.highestDetailLevel)
|
||||
if (this.iteratorDetailLevel >= this.leafDetailLevel)
|
||||
{
|
||||
Queue<QuadNode<T>> parentNodes = new LinkedList<>(this.validNodesForDetailLevel);
|
||||
this.validNodesForDetailLevel.clear();
|
||||
|
||||
+7
-1
@@ -69,10 +69,14 @@ public class ThreadPoolUtil
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor getBeaconCullingExecutor() { return beaconCullingThreadPool; }
|
||||
|
||||
// The main distinction between these thread pools is that one for compression has multiple threads and client handler is single-threaded
|
||||
private static PriorityTaskPicker.Executor networkCompressionThreadPool;
|
||||
@Nullable
|
||||
public static PriorityTaskPicker.Executor getNetworkCompressionExecutor() { return networkCompressionThreadPool; }
|
||||
|
||||
private static ThreadPoolExecutor networkClientHandlerThreadPool;
|
||||
@Nullable
|
||||
public static ThreadPoolExecutor networkClientHandlerExecutor() { return networkClientHandlerThreadPool; }
|
||||
|
||||
|
||||
public static final String FULL_DATA_MIGRATION_THREAD_NAME = "Full Data Migration";
|
||||
@@ -103,7 +107,8 @@ public class ThreadPoolUtil
|
||||
}
|
||||
taskPicker = new PriorityTaskPicker();
|
||||
|
||||
networkCompressionThreadPool = taskPicker.createExecutor("Network");
|
||||
networkCompressionThreadPool = taskPicker.createExecutor("Network Compression");
|
||||
networkClientHandlerThreadPool = ThreadUtil.makeSingleThreadPool("Network Client Handler");
|
||||
fileHandlerThreadPool = taskPicker.createExecutor("IO");
|
||||
renderSectionLoadThreadPool = taskPicker.createExecutor("Render Loader");
|
||||
chunkToLodBuilderThreadPool = taskPicker.createExecutor("LOD Builder");
|
||||
@@ -133,6 +138,7 @@ public class ThreadPoolUtil
|
||||
public static void shutdownThreadPools()
|
||||
{
|
||||
// standalone threads
|
||||
networkClientHandlerThreadPool.shutdownNow();
|
||||
taskPicker.shutdownNow();
|
||||
beaconCullingThreadPool.shutdown();
|
||||
fullDataMigrationThreadPool.shutdown();
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
package com.seibel.distanthorizons.core.world;
|
||||
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.enums.EMinecraftColor;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.level.DhClientServerLevel;
|
||||
import com.seibel.distanthorizons.core.util.TimerUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
@@ -83,7 +83,7 @@ public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLev
|
||||
LOGGER.fatal("Failed to load client-server level, error: ["+e.getMessage()+"].", e);
|
||||
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(// red text
|
||||
EMinecraftColor.RED + "Distant Horizons: ClientServer level loading failed." + EMinecraftColor.CLEAR_FORMATTING + "\n" +
|
||||
MinecraftTextFormat.RED + "Distant Horizons: ClientServer level loading failed." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"Unable to load level ["+levelWrapper.getDhIdentifier()+"], LODs may not appear. See log for more information.");
|
||||
|
||||
return null;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
package com.seibel.distanthorizons.core.world;
|
||||
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.enums.EMinecraftColor;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
|
||||
import com.seibel.distanthorizons.core.level.DhClientLevel;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
@@ -96,7 +96,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
LOGGER.fatal("Failed to load client level, error: ["+e.getMessage()+"].", e);
|
||||
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(
|
||||
EMinecraftColor.RED + "Distant Horizons: Client level loading failed." + EMinecraftColor.CLEAR_FORMATTING + "\n" +
|
||||
MinecraftTextFormat.RED + "Distant Horizons: Client level loading failed." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"Unable to load level ["+clientLevelWrapper.getDhIdentifier()+"], LODs may not appear. See log for more information.");
|
||||
|
||||
return null;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
package com.seibel.distanthorizons.core.world;
|
||||
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.enums.EMinecraftColor;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.level.DhServerLevel;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
@@ -64,7 +64,7 @@ public class DhServerWorld extends AbstractDhServerWorld<DhServerLevel>
|
||||
LOGGER.fatal("Failed to load server level, error: ["+e.getMessage()+"].", e);
|
||||
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(
|
||||
EMinecraftColor.RED + "Distant Horizons: Server level loading failed." + EMinecraftColor.CLEAR_FORMATTING + "\n" +
|
||||
MinecraftTextFormat.RED + "Distant Horizons: Server level loading failed." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
"Unable to load level ["+serverLevelWrapper.getDhIdentifier()+"], LODs may not appear. See log for more information.");
|
||||
|
||||
return null;
|
||||
|
||||
@@ -227,6 +227,10 @@
|
||||
"Beacon render height",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.beaconRenderHeight.@tooltip":
|
||||
"Sets the maximum height at which beacons will render. \nThis will only affect new beacons coming into LOD render distance. \nBeacons currently visible in LOD chunks will not be affected.",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.expandDistantBeacons":
|
||||
"Expand Distant Beacons",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.expandDistantBeacons.@tooltip":
|
||||
"If true LOD beacon beams will be rendered wider at extreme distances, \nmaking them easier to see. \nIf false all LOD beacon beams will only ever be 1 block wide.",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.enableBeaconRendering.@tooltip":
|
||||
"If true LOD beacon beams will be rendered.",
|
||||
"distanthorizons.config.client.advanced.graphics.genericRendering.enableCloudRendering":
|
||||
@@ -759,6 +763,11 @@
|
||||
"distanthorizons.config.server.levelKeyPrefix.@tooltip":
|
||||
"Prefix of the level keys sent to the clients.\nIf the mod is running behind a proxy, each backend should use a unique value.\nIf this value is empty, level key will be based on the server's seed hash.",
|
||||
|
||||
"distanthorizons.config.server.enableServerGeneration":
|
||||
"Enable Server Generation",
|
||||
"distanthorizons.config.server.enableServerGeneration.@tooltip":
|
||||
"When enabled, Distant Horizons will attempt to download missing LODs from the server.\n\nNote: the server must have Distant Generation enabled for it to work.",
|
||||
|
||||
"distanthorizons.config.server.generationRequestRateLimit":
|
||||
"Rate Limit for Generation Requests",
|
||||
"distanthorizons.config.server.generationRequestRateLimit.@tooltip":
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 103 KiB |
Reference in New Issue
Block a user