Compare commits
136 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f11f9bc9c | |||
| 9972363846 | |||
| 4f171234c4 | |||
| 2716059840 | |||
| a60887e9a7 | |||
| 1b6c5a451a | |||
| 4e91911e58 | |||
| bfae194919 | |||
| e562b2fdca | |||
| 47fa6d7d8b | |||
| 053d1333ca | |||
| 961c4190ad | |||
| 2f2ac0859c | |||
| b59781b064 | |||
| 39cc5bb8aa | |||
| abdbc73865 | |||
| 596f9f834a | |||
| 8f2aaf4ef4 | |||
| 2320740a4a | |||
| 4f0dc07995 | |||
| 336a9a94c8 | |||
| 1158496d9d | |||
| 84479ed48c | |||
| 0c71ca96c6 | |||
| 43dff26063 | |||
| 3cba883ba2 | |||
| 2d2e7524ae | |||
| e8ff7abaea | |||
| 008ad52bbc | |||
| d0b44a1ffc | |||
| 4ffe430686 | |||
| 19ca97c6c1 | |||
| 3334394bfd | |||
| 180e7cd814 | |||
| 84cf4505f2 | |||
| 1d74eea3ef | |||
| 6ee2e6be25 | |||
| b5c47d67cb | |||
| ead59d0817 | |||
| 1c9229c8f1 | |||
| 968a14c6a5 | |||
| 5608db9c56 | |||
| 81b6a25805 | |||
| 276d90b3e6 | |||
| 851c7439d5 | |||
| c902357a8f | |||
| 63170078f5 | |||
| d0dd1f125b | |||
| 32950d793e | |||
| 54e9bad907 | |||
| bb4ac770bd | |||
| 16afada6e9 | |||
| 7d0785a5fa | |||
| 6a67df462b | |||
| 0c45c76ff8 | |||
| bcb442e38d | |||
| 977ae471ea | |||
| b1701ab0d0 | |||
| c048d5cb56 | |||
| 2702f742d6 | |||
| 7add025c8a | |||
| 9dc220feb2 | |||
| 79955252c9 | |||
| bf13cc48a3 | |||
| cf454c80d7 | |||
| e6404cd882 | |||
| 52e64dc403 | |||
| 7c858afc5d | |||
| a44a5d7465 | |||
| f2d373b779 | |||
| 5138af0b78 | |||
| 37e99cd0a5 | |||
| 6cb8cd2bd9 | |||
| c5ae7da96c | |||
| 59b886c5e3 | |||
| 01e78f249f | |||
| e1c3da59db | |||
| cdfb46b041 | |||
| f944fe4409 | |||
| c2e45f3d65 | |||
| a9c4f3ea46 | |||
| 204d48517b | |||
| 759ec3676c | |||
| 8d2b5fa3ce | |||
| 2851b2c2db | |||
| e5ea86bf8f | |||
| 533c6a7f93 | |||
| ff41e070fd | |||
| b3f607e132 | |||
| 9ecbb9cc9f | |||
| 7888de8200 | |||
| d2327ae836 | |||
| ea92a8f922 | |||
| 47e97630b4 | |||
| c518345bcd | |||
| c250a7408e | |||
| 30da01f580 | |||
| 2c71c2bf76 | |||
| 13a4505d7d | |||
| 7f0eeb9f15 | |||
| d7eabcf3a6 | |||
| 7047d0afdf | |||
| f318b52280 | |||
| f50613e20c | |||
| af3a993042 | |||
| ace1aab42e | |||
| 350d72b6ec | |||
| 986a6cdc19 | |||
| 2aa8d9f489 | |||
| 5652a9328c | |||
| b7253b6549 | |||
| e026cf104c | |||
| ab4a9cbb55 | |||
| a709ab6071 | |||
| 3c11a2dc33 | |||
| ce2aa6602a | |||
| 738aff8ec6 | |||
| 91da0bf252 | |||
| af8dea9d9f | |||
| 384933d351 | |||
| a5344d50c2 | |||
| 2b4c5b91a4 | |||
| 3090544b85 | |||
| 75e1bbbe17 | |||
| 31b604b5c8 | |||
| 70ba93abec | |||
| f628a7f21e | |||
| 254f51ea5e | |||
| d44152dc46 | |||
| 0ef979ee6c | |||
| cf643372b6 | |||
| dc1a117f6b | |||
| 2545c7e76d | |||
| 8d9b5f66fa | |||
| aec28854a3 | |||
| 63acd94fd4 |
+1
-1
@@ -11,7 +11,7 @@ insert_final_newline = false
|
||||
max_line_length = 1000
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = false
|
||||
ij_continuation_indent_size = 8
|
||||
ij_continuation_indent_size = 4
|
||||
ij_formatter_off_tag = @formatter:off
|
||||
ij_formatter_on_tag = @formatter:on
|
||||
ij_formatter_tags_enabled = true
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ build:
|
||||
parallel:
|
||||
matrix:
|
||||
- MC_VER: [
|
||||
"1.21.10", "1.21.9", "1.21.8", "1.21.6", "1.21.5", "1.21.4", "1.21.3", "1.21.1",
|
||||
"1.21.11", "1.21.10", "1.21.9", "1.21.8", "1.21.6", "1.21.5", "1.21.4", "1.21.3", "1.21.1",
|
||||
"1.20.6", "1.20.4", "1.20.2", "1.20.1",
|
||||
"1.19.4", "1.19.2",
|
||||
"1.18.2",
|
||||
|
||||
@@ -1,3 +1,37 @@
|
||||
Before creating an issue, please select the appropriate template from the dropdown above.
|
||||
## Check off each item in this list before submitting:
|
||||
|
||||
<!--
|
||||
To mark a section as complete either put an "x" in between the square brackets, example: "[x]"
|
||||
Or click the checkbox once the issue has been created.
|
||||
-->
|
||||
|
||||
1. [ ] Check the FAQ to see if your issue has already been reported and has a solution:
|
||||
[Problems-and-solutions](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/2-problems-and-solutions/Problems-and-Solutions)
|
||||
|
||||
2. [ ] Make sure you are not using any mods on the incompatible list:
|
||||
[Mod support FAQ](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/4-mod-support/Mod-Support)
|
||||
|
||||
3. [ ] Check the existing issues to verify that your bug hasn't already been submitted:
|
||||
[Issues](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues)
|
||||
|
||||
4. [ ] Upload Minecraft's crash report and/or log. \
|
||||
Minecraft crash reports are located in: `.minecraft/crash-reports` \
|
||||
Minecraft logs are located in: `.minecraft/logs`
|
||||
|
||||
5. [ ] Upload your Distant Horizons Config. \
|
||||
The config is found in: `.minecraft/configs/DistantHorizons.toml`
|
||||
|
||||
6. [ ] Fill out the information below:
|
||||
|
||||
* **minecraft version**:
|
||||
|
||||
* **Distant Horizons version**:
|
||||
|
||||
* **Mod loader**:
|
||||
|
||||
* **Installed mods (list the smallest number of mods that you can use to re-create the bug)**:
|
||||
|
||||
* **Describe the bug**:
|
||||
|
||||
* **Steps to reproduce the bug**:
|
||||
|
||||
The template will walk you through submitting a bug, feature, or improvement request.
|
||||
|
||||
+40
-9
@@ -5,6 +5,9 @@ import org.apache.tools.zip.ZipEntry
|
||||
import javax.annotation.Nonnull
|
||||
import org.apache.tools.zip.ZipOutputStream
|
||||
|
||||
import java.util.function.Function
|
||||
import java.util.function.Predicate
|
||||
|
||||
|
||||
plugins {
|
||||
id "java"
|
||||
@@ -19,7 +22,7 @@ plugins {
|
||||
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
|
||||
|
||||
// Architectury is used here only as a replacement for forge's own loom
|
||||
id "dev.architectury.loom" version "1.11-SNAPSHOT" apply false
|
||||
id "dev.architectury.loom" version "1.13-SNAPSHOT" apply false
|
||||
}
|
||||
|
||||
|
||||
@@ -73,12 +76,23 @@ writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
|
||||
rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm")
|
||||
|
||||
class NativeTransformer implements Transformer {
|
||||
private Predicate<String> fileMatcher
|
||||
private Function<String, String> filePathMapper
|
||||
|
||||
private final HashMap<String, String> replacements = new HashMap()
|
||||
private final HashMap<String, byte[]> rewrittenFiles = new HashMap()
|
||||
private var nativeRelocator
|
||||
|
||||
public File rootDir
|
||||
|
||||
void matchFiles(Predicate<String> matcher) {
|
||||
fileMatcher = matcher
|
||||
}
|
||||
|
||||
void mapPaths(Function<String, String> mapper) {
|
||||
filePathMapper = mapper
|
||||
}
|
||||
|
||||
void relocateNative(String target, String replacement) {
|
||||
if (replacement.length() > target.length()) {
|
||||
throw new GradleException("Length of value \"${replacement}\" exceeds the length of \"${target}\": ${replacement.length()} > ${target.length()}")
|
||||
@@ -89,9 +103,7 @@ class NativeTransformer implements Transformer {
|
||||
|
||||
@Override
|
||||
boolean canTransformResource(@Nonnull FileTreeElement element) {
|
||||
return replacements.keySet().stream().anyMatch {
|
||||
element.name.startsWith(it as String)
|
||||
}
|
||||
return fileMatcher.test(element.name)
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,11 +115,9 @@ class NativeTransformer implements Transformer {
|
||||
}
|
||||
|
||||
try {
|
||||
Map.Entry<String, String> pathReplacement = replacements.entrySet().stream().filter {
|
||||
context.path.startsWith(it.key as String)
|
||||
}.findFirst().orElseThrow()
|
||||
|
||||
String path = context.path.replace(pathReplacement.key as String, pathReplacement.value as String)
|
||||
String path = filePathMapper != null
|
||||
? filePathMapper.apply(context.path)
|
||||
: context.path
|
||||
content = nativeRelocator.processBinary(path, content, replacements)
|
||||
|
||||
rewrittenFiles.put(path, content)
|
||||
@@ -351,10 +361,31 @@ subprojects { p ->
|
||||
|
||||
transform(NativeTransformer) {
|
||||
rootDir = project.rootDir
|
||||
|
||||
matchFiles { it.startsWith("org/sqlite") }
|
||||
mapPaths { it.replace("org/sqlite", "dh_sqlite") }
|
||||
|
||||
relocateNative "org/sqlite", "dh_sqlite"
|
||||
relocateNative "org_sqlite", "dh_1sqlite"
|
||||
}
|
||||
|
||||
// ZStd
|
||||
// librariesLocation isn't used because it's too long for replacing paths in native libraries
|
||||
// Allowing strings larger than the original string would require shifting the entire binary's contents
|
||||
relocate "com.github.luben", "dhcomgithubluben"
|
||||
relocate "libzstd-jni", "libzstd-jni_dh"
|
||||
relocate "zstd-jni", "zstd-jni_dh"
|
||||
|
||||
transform(NativeTransformer) {
|
||||
rootDir = project.rootDir
|
||||
|
||||
matchFiles { it.contains("libzstd-jni") && !it.contains("aix/ppc64") }
|
||||
mapPaths { it.replace("libzstd-jni", "libzstd-jni_dh") }
|
||||
|
||||
relocateNative "com/github/luben", "dhcomgithubluben"
|
||||
relocateNative "com_github_luben", "dhcomgithubluben"
|
||||
}
|
||||
|
||||
|
||||
// JOML
|
||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||
|
||||
+11
-10
@@ -14,6 +14,7 @@ import com.seibel.distanthorizons.core.config.ConfigHandler;
|
||||
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.jar.ModJarInfo;
|
||||
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
@@ -26,7 +27,6 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -115,8 +115,8 @@ public abstract class AbstractModInitializer
|
||||
this.initializeModCompat();
|
||||
|
||||
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized, adding event subscribers...");
|
||||
|
||||
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer = new CommandInitializer(dispatcher); });
|
||||
this.commandInitializer = new CommandInitializer();
|
||||
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer.initCommands(dispatcher); });
|
||||
|
||||
this.subscribeServerStartingEvent(server ->
|
||||
{
|
||||
@@ -124,7 +124,7 @@ public abstract class AbstractModInitializer
|
||||
|
||||
this.initConfig();
|
||||
this.postInit();
|
||||
this.commandInitializer.initCommands();
|
||||
this.commandInitializer.onServerReady();
|
||||
|
||||
this.checkForUpdates();
|
||||
|
||||
@@ -166,6 +166,10 @@ public abstract class AbstractModInitializer
|
||||
//noinspection unchecked
|
||||
ModAccessorInjector.INSTANCE.bind((Class<? extends IModAccessor>) accessorClass, accessorConstructor.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.debug("Skipping mod compatibility accessor for: ["+modId+"]");
|
||||
}
|
||||
}
|
||||
|
||||
private void initConfig()
|
||||
@@ -236,8 +240,7 @@ public abstract class AbstractModInitializer
|
||||
if (showChatWarnings)
|
||||
{
|
||||
String message =
|
||||
// orange text
|
||||
"\u00A76" + "Distant Horizons: Alex's Cave detected." + "\u00A7r\n" +
|
||||
MinecraftTextFormat.ORANGE + "Distant Horizons: Alex's Cave detected." + MinecraftTextFormat.CLEAR_FORMATTING +
|
||||
"You may have to change Alex's config for DH to render. ";
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||
}
|
||||
@@ -259,8 +262,7 @@ public abstract class AbstractModInitializer
|
||||
if (showChatWarnings)
|
||||
{
|
||||
String message =
|
||||
// orange text
|
||||
"\u00A76" + "Distant Horizons: WWOO detected." + "\u00A7r\n" +
|
||||
MinecraftTextFormat.ORANGE + "Distant Horizons: WWOO detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
wwooWarning;
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||
}
|
||||
@@ -290,8 +292,7 @@ public abstract class AbstractModInitializer
|
||||
if (showChatWarnings)
|
||||
{
|
||||
String message =
|
||||
// orange text
|
||||
"\u00A76" + "Distant Horizons: Chunky detected." + "\u00A7r\n" +
|
||||
MinecraftTextFormat.ORANGE + "Distant Horizons: Chunky detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
chunkyWarning;
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||
}
|
||||
|
||||
+10
-3
@@ -13,9 +13,14 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapp
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
#else
|
||||
import net.minecraft.resources.Identifier;
|
||||
#endif
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -25,10 +30,12 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
|
||||
.fileLevelConfig(Config.Common.Logging.logNetworkEventToFile)
|
||||
.build();
|
||||
|
||||
#if MC_VER >= MC_1_21_1
|
||||
#if MC_VER <= MC_1_20_6
|
||||
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
||||
#else
|
||||
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
||||
public static final Identifier WRAPPER_PACKET_RESOURCE = Identifier.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
||||
#endif
|
||||
|
||||
// "Forge byte" is an unused packet ID. We have our own system which works with all mod loaders,
|
||||
|
||||
+49
-14
@@ -3,36 +3,71 @@ package com.seibel.distanthorizons.common.commands;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_CODEC_CRASH_MESSAGE;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
/**
|
||||
* Initializes commands of the mod.
|
||||
*/
|
||||
#if MC_VER <= MC_1_21_10
|
||||
#else
|
||||
import net.minecraft.server.permissions.PermissionCheck;
|
||||
import net.minecraft.server.permissions.Permissions;
|
||||
#endif
|
||||
|
||||
public class CommandInitializer
|
||||
{
|
||||
private final CommandDispatcher<CommandSourceStack> commandDispatcher;
|
||||
private boolean serverReady = false;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
private static final int REQUIRED_PERMISSION_LEVEL = 4;
|
||||
#else
|
||||
private static final PermissionCheck COMMAND_PERMISSION_CHECK = new PermissionCheck.Require(Permissions.COMMANDS_OWNER);
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new instance of this class.
|
||||
*
|
||||
* @param commandDispatcher The dispatcher to use for registering commands.
|
||||
* A received command dispatcher, which is held until the server is ready to initialize the commands.
|
||||
*/
|
||||
public CommandInitializer(CommandDispatcher<CommandSourceStack> commandDispatcher)
|
||||
@Nullable
|
||||
private CommandDispatcher<CommandSourceStack> commandDispatcher;
|
||||
|
||||
/**
|
||||
* Notify the command initializer that the game is ready to accept commands.
|
||||
* If {@link CommandInitializer#initCommands(CommandDispatcher)} has been fired before it was ready, it will also initialize the commands.
|
||||
*/
|
||||
public void onServerReady()
|
||||
{
|
||||
this.commandDispatcher = commandDispatcher;
|
||||
this.serverReady = true;
|
||||
if (this.commandDispatcher != null)
|
||||
{
|
||||
this.initCommands(this.commandDispatcher);
|
||||
this.commandDispatcher = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initializes all available commands.
|
||||
* If the game is not ready yet, it stores the dispatcher to initialize the commands later.
|
||||
*
|
||||
* @param commandDispatcher The command dispatcher to register commands to.
|
||||
*/
|
||||
public void initCommands()
|
||||
public void initCommands(CommandDispatcher<CommandSourceStack> commandDispatcher)
|
||||
{
|
||||
if (!this.serverReady)
|
||||
{
|
||||
this.commandDispatcher = commandDispatcher;
|
||||
return;
|
||||
}
|
||||
|
||||
LiteralArgumentBuilder<CommandSourceStack> builder = literal("dh")
|
||||
.requires(source -> source.hasPermission(4));
|
||||
.requires((source) ->
|
||||
{
|
||||
#if MC_VER <= MC_1_21_10
|
||||
return source.hasPermission(REQUIRED_PERMISSION_LEVEL);
|
||||
#else
|
||||
return COMMAND_PERMISSION_CHECK.check(source.permissions());
|
||||
#endif
|
||||
});
|
||||
|
||||
builder.then(new ConfigCommand().buildCommand());
|
||||
builder.then(new DebugCommand().buildCommand());
|
||||
@@ -43,7 +78,7 @@ public class CommandInitializer
|
||||
builder.then(new CrashCommand().buildCommand());
|
||||
}
|
||||
|
||||
this.commandDispatcher.register(builder);
|
||||
commandDispatcher.register(builder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@ public class DependencySetup
|
||||
SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IKeyedClientLevelManager.class, KeyedClientLevelManager.INSTANCE);
|
||||
DependencySetupDoneCheck.isDone = true;
|
||||
}
|
||||
|
||||
public static void createServerBindings()
|
||||
|
||||
@@ -83,6 +83,8 @@ public class VersionConstants implements IVersionConstants
|
||||
return "1.21.9";
|
||||
#elif MC_VER == MC_1_21_10
|
||||
return "1.21.10";
|
||||
#elif MC_VER == MC_1_21_11
|
||||
return "1.21.11";
|
||||
#else
|
||||
ERROR MC version constant missing
|
||||
#endif
|
||||
|
||||
@@ -38,7 +38,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrappe
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
#if MC_VER > MC_1_17_1
|
||||
import net.minecraft.core.Holder;
|
||||
@@ -67,7 +67,7 @@ public class WrapperFactory implements IWrapperFactory
|
||||
//==============//
|
||||
|
||||
@Override
|
||||
public AbstractBatchGenerationEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel)
|
||||
public IBatchGeneratorEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel)
|
||||
{
|
||||
if (targetLevel instanceof IDhServerLevel)
|
||||
{
|
||||
|
||||
+5
-3
@@ -124,11 +124,12 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
|
||||
int rollingBlue = 0;
|
||||
|
||||
int xMin = mutableBlockPos.getX() - this.smoothingRadiusInBlocks;
|
||||
int xMax = mutableBlockPos.getX() + this.smoothingRadiusInBlocks;
|
||||
int xMax = mutableBlockPos.getX() + this.smoothingRadiusInBlocks + 1; // +1 to account for the center block
|
||||
|
||||
int zMin = mutableBlockPos.getZ() - this.smoothingRadiusInBlocks;
|
||||
int zMax = mutableBlockPos.getZ() + this.smoothingRadiusInBlocks;
|
||||
int zMax = mutableBlockPos.getZ() + this.smoothingRadiusInBlocks + 1;
|
||||
|
||||
int levelMinY = this.clientLevelWrapper.getMinHeight();
|
||||
|
||||
for (int x = xMin; x < xMax; x++)
|
||||
{
|
||||
@@ -140,12 +141,13 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
|
||||
// this can return the same position/datapoint for larger LODs duplicating work,
|
||||
// however for small smoothing ranges that isn't a big deal and for large LODs
|
||||
// we ignore smoothing anyway
|
||||
long dataPoint = this.fullDataSource.getDataPointAtBlockPos(mutableBlockPos);
|
||||
long dataPoint = this.fullDataSource.getDataPointAtBlockPos(mutableBlockPos.getX(), mutableBlockPos.getY(), mutableBlockPos.getZ(), levelMinY);
|
||||
if (dataPoint == FullDataPointUtil.EMPTY_DATA_POINT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// get the color for this nearby position
|
||||
int id = FullDataPointUtil.getId(dataPoint);
|
||||
BiomeWrapper biomeWrapper = (BiomeWrapper) this.fullDataSource.mapping.getBiomeWrapper(id);
|
||||
|
||||
+18
-3
@@ -29,7 +29,6 @@ import java.util.concurrent.ConcurrentMap;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
@@ -46,7 +45,12 @@ import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
#endif
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
#else
|
||||
import net.minecraft.resources.Identifier;
|
||||
#endif
|
||||
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
@@ -217,7 +221,12 @@ public class BiomeWrapper implements IBiomeWrapper
|
||||
Level level = (Level)levelWrapper.getWrappedMcObject();
|
||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||
|
||||
#if MC_VER < MC_1_21_11
|
||||
ResourceLocation resourceLocation;
|
||||
#else
|
||||
Identifier resourceLocation;
|
||||
#endif
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome);
|
||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||
@@ -324,13 +333,19 @@ public class BiomeWrapper implements IBiomeWrapper
|
||||
throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "].");
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_21_11
|
||||
ResourceLocation resourceLocation;
|
||||
#else
|
||||
Identifier resourceLocation;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
#if MC_VER < MC_1_21_1
|
||||
#if MC_VER <= MC_1_20_6
|
||||
resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
||||
#else
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
||||
#else
|
||||
resourceLocation = Identifier.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
||||
#endif
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
+69
-11
@@ -28,7 +28,6 @@ import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.level.block.BeaconBeamBlock;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
@@ -42,6 +41,7 @@ import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -50,12 +50,14 @@ import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.EmptyBlockGetter;
|
||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.world.level.EmptyBlockGetter;
|
||||
#else
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
@@ -63,6 +65,12 @@ import net.minecraft.world.level.EmptyBlockGetter;
|
||||
import net.minecraft.core.Holder;
|
||||
#endif
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
#else
|
||||
import net.minecraft.resources.Identifier;
|
||||
#endif
|
||||
|
||||
public class BlockStateWrapper implements IBlockStateWrapper
|
||||
{
|
||||
/** example "minecraft:water" */
|
||||
@@ -83,11 +91,24 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
||||
public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt";
|
||||
public static final String WATER_RESOURCE_LOCATION_STRING = "minecraft:water";
|
||||
|
||||
/** Used to handle older MC versions that don't have an simple way of getting the block's tags */
|
||||
public static final List<String> OLD_BEACON_BASE_BLOCK_NAME_LIST = Arrays.asList(
|
||||
"iron_block",
|
||||
"gold_block",
|
||||
"diamond_block",
|
||||
"emerald_block",
|
||||
"netherite_block"
|
||||
);
|
||||
|
||||
public static HashSet<IBlockStateWrapper> rendererIgnoredBlocks = null;
|
||||
public static HashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null;
|
||||
|
||||
/** keep track of broken blocks so we don't log every time */
|
||||
#if MC_VER <= MC_1_21_10
|
||||
private static final HashSet<ResourceLocation> BROKEN_RESOURCE_LOCATIONS = new HashSet<>();
|
||||
#else
|
||||
private static final HashSet<Identifier> BROKEN_RESOURCE_LOCATIONS = new HashSet<>();
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -167,11 +188,14 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
||||
String lowercaseSerial = this.serialString.toLowerCase();
|
||||
|
||||
|
||||
// beacon blocks
|
||||
|
||||
// beacon base blocks
|
||||
#if MC_VER <= MC_1_18_2
|
||||
// Older MC versions are harder to get block tags, so just use a static list to determine beacon blocks
|
||||
boolean isBeaconBaseBlock = false;
|
||||
for (int i = 0; i < LodUtil.BEACON_BASE_BLOCK_NAME_LIST.size(); i++)
|
||||
for (int i = 0; i < OLD_BEACON_BASE_BLOCK_NAME_LIST.size(); i++)
|
||||
{
|
||||
String baseBlockName = LodUtil.BEACON_BASE_BLOCK_NAME_LIST.get(i);
|
||||
String baseBlockName = OLD_BEACON_BASE_BLOCK_NAME_LIST.get(i);
|
||||
if (lowercaseSerial.contains(baseBlockName))
|
||||
{
|
||||
isBeaconBaseBlock = true;
|
||||
@@ -179,8 +203,23 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
||||
}
|
||||
}
|
||||
this.isBeaconBaseBlock = isBeaconBaseBlock;
|
||||
#else
|
||||
if (blockState != null)
|
||||
{
|
||||
// check if this block has any tags
|
||||
Stream<TagKey<Block>> tags = blockState.getTags();
|
||||
this.isBeaconBaseBlock = tags.anyMatch((TagKey<Block> tag) -> tag.location().getPath().toLowerCase().contains("beacon_base_blocks"));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.isBeaconBaseBlock = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// beacon block
|
||||
this.isBeaconBlock = lowercaseSerial.contains("minecraft:beacon");
|
||||
|
||||
|
||||
// beacon tint color
|
||||
Color beaconTintColor = null;
|
||||
if (this.blockState != null
|
||||
@@ -216,6 +255,12 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
||||
// bedrock is a special case fully opaque block that does allow beacons through
|
||||
allowsBeaconBeamPassage = true;
|
||||
}
|
||||
else if (lowercaseSerial.contains("minecraft:tinted_glass"))
|
||||
{
|
||||
// tinted glass is a special case where it isn't fully opaque,
|
||||
// but should block beacons
|
||||
allowsBeaconBeamPassage = false;
|
||||
}
|
||||
else if (propagatesSkyLightDown || !canOcclude)
|
||||
{
|
||||
// stairs, cake, fences, etc.
|
||||
@@ -274,7 +319,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
||||
|
||||
HashSet<String> baseIgnoredBlock = new HashSet<>();
|
||||
baseIgnoredBlock.add(AIR_STRING);
|
||||
rendererIgnoredBlocks = getBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper);
|
||||
rendererIgnoredBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper);
|
||||
return rendererIgnoredBlocks;
|
||||
}
|
||||
/**
|
||||
@@ -291,7 +336,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
||||
|
||||
HashSet<String> baseIgnoredBlock = new HashSet<>();
|
||||
baseIgnoredBlock.add(AIR_STRING);
|
||||
rendererIgnoredCaveBlocks = getBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper);
|
||||
rendererIgnoredCaveBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper);
|
||||
return rendererIgnoredCaveBlocks;
|
||||
}
|
||||
|
||||
@@ -302,7 +347,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
||||
|
||||
// lod builder helpers //
|
||||
|
||||
private static HashSet<IBlockStateWrapper> getBlockWrappers(ConfigEntry<String> config, HashSet<String> baseResourceLocations, ILevelWrapper levelWrapper)
|
||||
private static HashSet<IBlockStateWrapper> getAllBlockWrappers(ConfigEntry<String> config, HashSet<String> baseResourceLocations, ILevelWrapper levelWrapper)
|
||||
{
|
||||
// get the base blocks
|
||||
HashSet<String> blockStringList = new HashSet<>();
|
||||
@@ -318,9 +363,9 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
||||
blockStringList.addAll(Arrays.asList(ignoreBlockCsv.split(",")));
|
||||
}
|
||||
|
||||
return getBlockWrappers(blockStringList, levelWrapper);
|
||||
return getAllBlockWrappers(blockStringList, levelWrapper);
|
||||
}
|
||||
private static HashSet<IBlockStateWrapper> getBlockWrappers(HashSet<String> blockResourceLocationSet, ILevelWrapper levelWrapper)
|
||||
private static HashSet<IBlockStateWrapper> getAllBlockWrappers(HashSet<String> blockResourceLocationSet, ILevelWrapper levelWrapper)
|
||||
{
|
||||
// deserialize each of the given resource locations
|
||||
HashSet<IBlockStateWrapper> blockStateWrappers = new HashSet<>();
|
||||
@@ -555,7 +600,12 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_21_11
|
||||
ResourceLocation resourceLocation;
|
||||
#else
|
||||
Identifier resourceLocation;
|
||||
#endif
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
resourceLocation = Registry.BLOCK.getKey(this.blockState.getBlock());
|
||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||
@@ -587,7 +637,8 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
||||
// we need the final string for the concurrent hash map later
|
||||
final String finalResourceStateString = resourceStateString;
|
||||
|
||||
if (finalResourceStateString.equals(AIR_STRING) || finalResourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case
|
||||
if (finalResourceStateString.equals(AIR_STRING)
|
||||
|| finalResourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case
|
||||
{
|
||||
return AIR;
|
||||
}
|
||||
@@ -621,13 +672,20 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
||||
throw new IOException("Unable to parse Resource Location out of string: [" + resourceStateString + "].");
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_21_11
|
||||
ResourceLocation resourceLocation;
|
||||
#else
|
||||
Identifier resourceLocation;
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
#if MC_VER < MC_1_21_1
|
||||
resourceLocation = new ResourceLocation(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
||||
#else
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
||||
#else
|
||||
resourceLocation = Identifier.fromNamespaceAndPath(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
||||
#endif
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
+44
-14
@@ -30,10 +30,7 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.FlowerBlock;
|
||||
import net.minecraft.world.level.block.LeavesBlock;
|
||||
import net.minecraft.world.level.block.RotatedPillarBlock;
|
||||
import net.minecraft.world.level.block.*;
|
||||
#if MC_VER >= MC_1_19_2
|
||||
import net.minecraft.util.RandomSource;
|
||||
#else
|
||||
@@ -41,6 +38,7 @@ import java.util.Random;
|
||||
#endif
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import net.minecraft.world.level.block.state.properties.SlabType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -64,6 +62,8 @@ public class ClientBlockStateColorCache
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final Minecraft MC = Minecraft.getInstance();
|
||||
|
||||
private static final HashSet<BlockState> BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>();
|
||||
private static final HashSet<BlockState> BROKEN_BLOCK_STATES = new HashSet<>();
|
||||
|
||||
@@ -79,7 +79,16 @@ public class ClientBlockStateColorCache
|
||||
|
||||
|
||||
/** This is the order each direction on a block is processed when attempting to get the texture/color */
|
||||
private static final Direction[] COLOR_RESOLUTION_DIRECTION_ORDER = { Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN };
|
||||
private static final @Nullable Direction[] COLOR_RESOLUTION_DIRECTION_ORDER =
|
||||
{
|
||||
Direction.UP,
|
||||
null, // null represents "unculled" faces, IE the top of farmland
|
||||
Direction.NORTH,
|
||||
Direction.EAST,
|
||||
Direction.WEST,
|
||||
Direction.SOUTH,
|
||||
Direction.DOWN
|
||||
};
|
||||
|
||||
private static final int FLOWER_COLOR_SCALE = 5;
|
||||
|
||||
@@ -281,14 +290,23 @@ public class ClientBlockStateColorCache
|
||||
@Nullable
|
||||
private List<BakedQuad> getQuadsForDirection(@Nullable Direction direction)
|
||||
{
|
||||
List<BakedQuad> quads = null;
|
||||
BlockState effectiveBlockState = this.blockState;
|
||||
|
||||
// if this block is a slab, use it's double variant so we can get the top face,
|
||||
// otherwise the color will use the side, which isn't as accurate
|
||||
if (this.blockState.getBlock() instanceof SlabBlock)
|
||||
{
|
||||
effectiveBlockState = this.blockState.setValue( SlabBlock.TYPE, SlabType.DOUBLE );
|
||||
}
|
||||
|
||||
List<BakedQuad> quads;
|
||||
|
||||
#if MC_VER < MC_1_21_5
|
||||
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
||||
getBlockModel(this.blockState).getQuads(this.blockState, direction, RANDOM);
|
||||
quads = MC.getModelManager().getBlockModelShaper().
|
||||
getBlockModel(effectiveBlockState).getQuads(effectiveBlockState, direction, RANDOM);
|
||||
#else
|
||||
List<BlockModelPart> blockModelPartList = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
||||
getBlockModel(this.blockState).collectParts(RANDOM);
|
||||
List<BlockModelPart> blockModelPartList = MC.getModelManager().getBlockModelShaper().
|
||||
getBlockModel(effectiveBlockState).collectParts(RANDOM);
|
||||
|
||||
quads = new ArrayList<>();
|
||||
if (blockModelPartList != null)
|
||||
@@ -558,10 +576,22 @@ public class ClientBlockStateColorCache
|
||||
|
||||
static EColorMode getColorMode(Block block)
|
||||
{
|
||||
if (block instanceof LeavesBlock) return Leaves;
|
||||
if (block instanceof FlowerBlock) return Flower;
|
||||
if (block.toString().contains("glass")) return Glass;
|
||||
if (block.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel;
|
||||
if (block instanceof LeavesBlock)
|
||||
{
|
||||
return Leaves;
|
||||
}
|
||||
if (block instanceof FlowerBlock)
|
||||
{
|
||||
return Flower;
|
||||
}
|
||||
if (block.toString().contains("glass"))
|
||||
{
|
||||
return Glass;
|
||||
}
|
||||
if (block.toString().equals("Block{chiselsandbits:chiseled}"))
|
||||
{
|
||||
return Chisel;
|
||||
}
|
||||
return Default;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -51,10 +51,10 @@ public class TintGetterOverride extends AbstractDhTintGetter
|
||||
|
||||
public TintGetterOverride() { }
|
||||
|
||||
public void update(LevelReader parent, BiomeWrapper biomeWrapper, BlockStateWrapper blockStateWrapper, FullDataSourceV2 fullDataSource, IClientLevelWrapper clientLevelWrapper)
|
||||
public void update(BiomeWrapper biomeWrapper, BlockStateWrapper blockStateWrapper, FullDataSourceV2 fullDataSource, IClientLevelWrapper clientLevelWrapper)
|
||||
{
|
||||
super.update(biomeWrapper, blockStateWrapper, fullDataSource, clientLevelWrapper);
|
||||
this.parent = parent;
|
||||
this.parent = (LevelReader)this.clientLevelWrapper.getWrappedMcObject();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+62
-68
@@ -18,10 +18,10 @@
|
||||
*/
|
||||
package com.seibel.distanthorizons.common.wrappers.chunk;
|
||||
|
||||
import com.seibel.distanthorizons.api.DhApi;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.misc.MutableBlockPosWrapper;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
@@ -81,6 +81,8 @@ public class ChunkWrapper implements IChunkWrapper
|
||||
private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos());
|
||||
private static final ThreadLocal<MutableBlockPosWrapper> MUTABLE_BLOCK_POS_WRAPPER_REF = ThreadLocal.withInitial(() -> new MutableBlockPosWrapper());
|
||||
|
||||
private static boolean heightmapThreadWarningLogged = false;
|
||||
|
||||
|
||||
private final ChunkAccess chunk;
|
||||
private final DhChunkPos chunkPos;
|
||||
@@ -98,9 +100,9 @@ public class ChunkWrapper implements IChunkWrapper
|
||||
private int maxNonEmptyHeight = Integer.MAX_VALUE;
|
||||
|
||||
/** will be null if we are using MC heightmaps */
|
||||
private final int[][] solidHeightMap;
|
||||
private int[][] solidHeightMap = null;
|
||||
/** will be null if we are using MC heightmaps */
|
||||
private final int[][] lightBlockingHeightMap;
|
||||
private int[][] lightBlockingHeightMap = null;
|
||||
|
||||
|
||||
|
||||
@@ -108,27 +110,21 @@ public class ChunkWrapper implements IChunkWrapper
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
/**
|
||||
* Note: this constructor should be very
|
||||
* fast since it will be called frequently on the MC
|
||||
* server thread and a slow method will cause server lag.
|
||||
*/
|
||||
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel)
|
||||
{
|
||||
this.chunk = chunk;
|
||||
this.wrappedLevel = wrappedLevel;
|
||||
this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
|
||||
|
||||
// use DH heightmaps if requested
|
||||
if (Config.Common.LodBuilding.recalculateChunkHeightmaps.get())
|
||||
{
|
||||
this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||
this.lightBlockingHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||
|
||||
this.recalculateDhHeightMapsIfNeeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.solidHeightMap = null;
|
||||
this.lightBlockingHeightMap = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkWrapper copy() { return new ChunkWrapper(this.chunk, this.wrappedLevel); }
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
@@ -248,56 +244,63 @@ public class ChunkWrapper implements IChunkWrapper
|
||||
}
|
||||
private int getChunkSectionMinHeight(int index) { return (index * 16) + this.getInclusiveMinBuildHeight(); }
|
||||
|
||||
/** Will only run if the config says the MC heightmaps shouldn't be trusted. */
|
||||
public void recalculateDhHeightMapsIfNeeded()
|
||||
@Override
|
||||
public void createDhHeightMaps()
|
||||
{
|
||||
// re-calculate the min/max heights for consistency (during world gen these may be wrong)
|
||||
this.minNonEmptyHeight = Integer.MIN_VALUE;
|
||||
this.maxNonEmptyHeight = Integer.MAX_VALUE;
|
||||
|
||||
|
||||
// recalculate heightmaps if needed
|
||||
if (this.solidHeightMap != null)
|
||||
if (heightmapThreadWarningLogged
|
||||
&& !DhApi.isDhThread())
|
||||
{
|
||||
for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++)
|
||||
LOGGER.warn("ChunkWrapper Height maps created on non-DH thread ["+Thread.currentThread().getName()+"]. This may cause stuttering.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||
this.lightBlockingHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||
|
||||
for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++)
|
||||
{
|
||||
for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++)
|
||||
{
|
||||
for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++)
|
||||
int minInclusiveBuildHeight = this.getMinNonEmptyHeight();
|
||||
// if no blocks are found the height map will be at the bottom of the world
|
||||
int solidHeight = minInclusiveBuildHeight;
|
||||
int lightBlockingHeight = minInclusiveBuildHeight;
|
||||
|
||||
|
||||
int y = this.getMaxNonEmptyHeight(); //this.getExclusiveMaxBuildHeight();
|
||||
IBlockStateWrapper block = this.getBlockState(x, y, z);
|
||||
while (// go down until we reach the minimum build height
|
||||
y > minInclusiveBuildHeight
|
||||
// keep going until we find both height map values
|
||||
&&
|
||||
(
|
||||
solidHeight == minInclusiveBuildHeight
|
||||
|| lightBlockingHeight == minInclusiveBuildHeight
|
||||
)
|
||||
)
|
||||
{
|
||||
int minInclusiveBuildHeight = this.getMinNonEmptyHeight();
|
||||
// if no blocks are found the height map will be at the bottom of the world
|
||||
int solidHeight = minInclusiveBuildHeight;
|
||||
int lightBlockingHeight = minInclusiveBuildHeight;
|
||||
|
||||
|
||||
int y = this.getMaxNonEmptyHeight(); //this.getExclusiveMaxBuildHeight();
|
||||
IBlockStateWrapper block = this.getBlockState(x, y, z);
|
||||
while (// go down until we reach the minimum build height
|
||||
y > minInclusiveBuildHeight
|
||||
// keep going until we find both height map values
|
||||
&& (solidHeight == minInclusiveBuildHeight || lightBlockingHeight == minInclusiveBuildHeight))
|
||||
// is this block solid?
|
||||
if (solidHeight == minInclusiveBuildHeight
|
||||
&& block.isSolid())
|
||||
{
|
||||
// is this block solid?
|
||||
if (solidHeight == minInclusiveBuildHeight
|
||||
&& block.isSolid())
|
||||
{
|
||||
solidHeight = y;
|
||||
}
|
||||
|
||||
// is this block light blocking?
|
||||
if (lightBlockingHeight == minInclusiveBuildHeight
|
||||
&& block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT)
|
||||
{
|
||||
lightBlockingHeight = y;
|
||||
}
|
||||
|
||||
// get the next block down
|
||||
y--;
|
||||
block = this.getBlockState(x, y, z);
|
||||
solidHeight = y;
|
||||
}
|
||||
|
||||
this.solidHeightMap[x][z] = solidHeight;
|
||||
this.lightBlockingHeightMap[x][z] = lightBlockingHeight;
|
||||
// is this block light blocking?
|
||||
if (lightBlockingHeight == minInclusiveBuildHeight
|
||||
&& block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT)
|
||||
{
|
||||
lightBlockingHeight = y;
|
||||
}
|
||||
|
||||
// get the next block down
|
||||
y--;
|
||||
block = this.getBlockState(x, y, z);
|
||||
}
|
||||
|
||||
this.solidHeightMap[x][z] = solidHeight;
|
||||
this.lightBlockingHeightMap[x][z] = lightBlockingHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -617,15 +620,6 @@ public class ChunkWrapper implements IChunkWrapper
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// other methods //
|
||||
//===============//
|
||||
|
||||
@Override
|
||||
public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; }
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
|
||||
+68
-35
@@ -13,6 +13,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui;
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.config.ConfigGuiInfo;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.ConfigHandler;
|
||||
import com.seibel.distanthorizons.core.config.types.*;
|
||||
@@ -26,6 +27,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.AnnotationUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -37,7 +39,6 @@ import net.minecraft.client.gui.components.EditBox;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -54,6 +55,15 @@ import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
||||
#endif
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
#else
|
||||
import net.minecraft.resources.Identifier;
|
||||
#endif
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import com.mojang.blaze3d.platform.InputConstants;
|
||||
|
||||
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
|
||||
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.Translatable;
|
||||
|
||||
@@ -79,6 +89,8 @@ public class ClassicConfigGUI
|
||||
|
||||
public static final ConfigCoreInterface CONFIG_CORE_INTERFACE = new ConfigCoreInterface();
|
||||
|
||||
private static final MinecraftClientWrapper MC_CLIENT = MinecraftClientWrapper.INSTANCE;
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
@@ -170,34 +182,36 @@ public class ClassicConfigGUI
|
||||
&& !ModInfo.IS_DEV_BUILD)
|
||||
{
|
||||
this.addBtn(new TexturedButtonWidget(
|
||||
// Where the button is on the screen
|
||||
this.width - 28, this.height - 28,
|
||||
// Width and height of the button
|
||||
20, 20,
|
||||
// texture UV Offset
|
||||
0, 0,
|
||||
// Some texture stuff
|
||||
0,
|
||||
#if MC_VER < MC_1_21_1
|
||||
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#else
|
||||
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#endif
|
||||
20, 20,
|
||||
// Create the button and tell it where to go
|
||||
(buttonWidget) -> {
|
||||
ChangelogScreen changelogScreen = new ChangelogScreen(this);
|
||||
if (changelogScreen.usable)
|
||||
{
|
||||
Objects.requireNonNull(this.minecraft).setScreen(changelogScreen);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("Changelog was not able to open");
|
||||
}
|
||||
},
|
||||
// Add a title to the button
|
||||
Translatable(ModInfo.ID + ".updater.title")
|
||||
// Where the button is on the screen
|
||||
this.width - 28, this.height - 28,
|
||||
// Width and height of the button
|
||||
20, 20,
|
||||
// texture UV Offset
|
||||
0, 0,
|
||||
// Some texture stuff
|
||||
0,
|
||||
#if MC_VER < MC_1_21_1
|
||||
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#else
|
||||
Identifier.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#endif
|
||||
20, 20,
|
||||
// Create the button and tell it where to go
|
||||
(buttonWidget) -> {
|
||||
ChangelogScreen changelogScreen = new ChangelogScreen(this);
|
||||
if (changelogScreen.usable)
|
||||
{
|
||||
Objects.requireNonNull(this.minecraft).setScreen(changelogScreen);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("Changelog was not able to open");
|
||||
}
|
||||
},
|
||||
// Add a title to the button
|
||||
Translatable(ModInfo.ID + ".updater.title")
|
||||
));
|
||||
}
|
||||
|
||||
@@ -409,16 +423,24 @@ public class ClassicConfigGUI
|
||||
|
||||
Function<Object, Component> getEnumTranslatableFunc = (value) -> Translatable(TRANSLATION_PREFIX + "enum." + enumClass.getSimpleName() + "." + enumConfigEntry.get().toString());
|
||||
configGuiInfo.buttonOptionMap =
|
||||
new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(
|
||||
new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(
|
||||
(button) ->
|
||||
{
|
||||
// get the currently selected enum and enum index
|
||||
int startingIndex = enumList.indexOf(enumConfigEntry.get());
|
||||
Enum<?> enumValue = enumList.get(startingIndex);
|
||||
|
||||
// search for the next enum that is selectable
|
||||
int index = startingIndex + 1;
|
||||
boolean shiftPressed =
|
||||
InputConstants.isKeyDown(MC_CLIENT.getGlfwWindowId(), GLFW.GLFW_KEY_LEFT_SHIFT)
|
||||
|| InputConstants.isKeyDown(MC_CLIENT.getGlfwWindowId(), GLFW.GLFW_KEY_RIGHT_SHIFT);
|
||||
|
||||
|
||||
|
||||
// move forward or backwards depending on if the shift key is pressed
|
||||
int index = shiftPressed ? startingIndex-1 : startingIndex+1;
|
||||
index = (index >= enumList.size()) ? 0 : index;
|
||||
|
||||
// walk through the enums to find the next selectable one
|
||||
while (index != startingIndex)
|
||||
{
|
||||
enumValue = enumList.get(index);
|
||||
@@ -429,13 +451,24 @@ public class ClassicConfigGUI
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
index = (index >= enumList.size()) ? 0 : index;
|
||||
// move forward or backwards depending on if the shift key is pressed
|
||||
index = shiftPressed ? index-1 : index+1;
|
||||
|
||||
// wrap around to the other side of the array when necessary
|
||||
if (index >= enumList.size())
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
else if (index < 0)
|
||||
{
|
||||
index = enumList.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (index == startingIndex)
|
||||
{
|
||||
// none of the enums should be selectable, this is a programmer error
|
||||
// one of the enums should be selectable, this is a programmer error
|
||||
enumValue = enumList.get(startingIndex);
|
||||
LOGGER.warn("Enum [" + enumValue.getClass() + "] doesn't contain any values that should be selectable via the UI, sticking to the currently selected value [" + enumValue + "].");
|
||||
}
|
||||
|
||||
+10
-1
@@ -14,9 +14,13 @@ import java.util.List;
|
||||
|
||||
import net.minecraft.client.gui.components.debug.DebugScreenDisplayer;
|
||||
import net.minecraft.client.gui.components.debug.DebugScreenEntries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_21_9
|
||||
@@ -31,7 +35,12 @@ public class DhDebugScreenEntry implements net.minecraft.client.gui.components.d
|
||||
// This method is private, so its access will need to be widened
|
||||
DebugScreenEntries.register(
|
||||
// The id, this will be displayed on the options screen
|
||||
#if MC_VER <= MC_1_21_10
|
||||
ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, "distant_horizons"),
|
||||
#else
|
||||
"distant_horizons",
|
||||
#endif
|
||||
|
||||
// The screen entry
|
||||
new DhDebugScreenEntry()
|
||||
);
|
||||
|
||||
+13
-1
@@ -95,10 +95,22 @@ public class MinecraftScreen
|
||||
super.render(matrices, mouseX, mouseY, delta); // Render the vanilla stuff (currently only used for the background and tint)
|
||||
}
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
@Override
|
||||
public void resize(Minecraft mc, int width, int height)
|
||||
#else
|
||||
@Override
|
||||
public void resize(int width, int height)
|
||||
#endif
|
||||
{
|
||||
super.resize(mc, width, height); // Resize Minecraft's screen
|
||||
// Resize Minecraft's screen
|
||||
#if MC_VER <= MC_1_21_10
|
||||
super.resize(mc, width, height);
|
||||
#else
|
||||
super.resize(width, height);
|
||||
#endif
|
||||
|
||||
|
||||
Window mcWindow = this.minecraft.getWindow();
|
||||
this.screen.width = mcWindow.getWidth();
|
||||
this.screen.height = mcWindow.getHeight();
|
||||
|
||||
+32
-4
@@ -20,7 +20,6 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.gui;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
@@ -42,10 +41,19 @@ import net.minecraft.client.gui.GuiGraphics;
|
||||
#elif MC_VER < MC_1_21_6
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
#else
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.RenderPipelines;
|
||||
#else
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.renderer.RenderPipelines;
|
||||
#endif
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
#else
|
||||
import net.minecraft.resources.Identifier;
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -67,18 +75,33 @@ public class TexturedButtonWidget extends Button
|
||||
private final int v;
|
||||
private final int hoveredVOffset;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
private final ResourceLocation textureResourceLocation;
|
||||
#else
|
||||
private final Identifier textureResourceLocation;
|
||||
#endif
|
||||
|
||||
private final int textureWidth;
|
||||
private final int textureHeight;
|
||||
#endif
|
||||
|
||||
|
||||
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text)
|
||||
public TexturedButtonWidget(
|
||||
int x, int y, int width, int height, int u, int v, int hoveredVOffset,
|
||||
#if MC_VER <= MC_1_21_10 ResourceLocation textureResourceLocation,
|
||||
#else Identifier textureResourceLocation,
|
||||
#endif
|
||||
int textureWidth, int textureHeight, OnPress pressAction, Component text)
|
||||
{
|
||||
this(x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, pressAction, text, true);
|
||||
}
|
||||
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text, boolean renderBackground)
|
||||
public TexturedButtonWidget(
|
||||
int x, int y, int width, int height, int u, int v, int hoveredVOffset,
|
||||
#if MC_VER <= MC_1_21_10 ResourceLocation textureResourceLocation,
|
||||
#else Identifier textureResourceLocation,
|
||||
#endif
|
||||
int textureWidth, int textureHeight, OnPress pressAction, Component text,
|
||||
boolean renderBackground)
|
||||
{
|
||||
#if MC_VER < MC_1_20_2
|
||||
super(x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, pressAction, text);
|
||||
@@ -169,8 +192,13 @@ public class TexturedButtonWidget extends Button
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if MC_VER < MC_1_21_11
|
||||
@Override
|
||||
public void renderWidget(GuiGraphics matrices, int mouseX, int mouseY, float delta)
|
||||
#else
|
||||
@Override
|
||||
protected void renderContents(GuiGraphics matrices, int mouseX, int mouseY, float delta)
|
||||
#endif
|
||||
{
|
||||
if (this.renderBackground)
|
||||
{
|
||||
|
||||
+33
-22
@@ -9,14 +9,21 @@ import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
|
||||
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
|
||||
#if MC_VER >= MC_1_20_1
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
#else
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
#endif
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
#else
|
||||
import net.minecraft.resources.Identifier;
|
||||
#endif
|
||||
|
||||
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
|
||||
|
||||
@@ -88,10 +95,12 @@ public class UpdateModScreen extends DhScreen
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
0,
|
||||
#if MC_VER < MC_1_21_1
|
||||
#if MC_VER <= MC_1_20_6
|
||||
new ResourceLocation(ModInfo.ID, "logo.png"),
|
||||
#else
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "logo.png"),
|
||||
#else
|
||||
Identifier.fromNamespaceAndPath(ModInfo.ID, "logo.png"),
|
||||
#endif
|
||||
195, 65,
|
||||
// Create the button and tell it where to go
|
||||
@@ -111,24 +120,26 @@ public class UpdateModScreen extends DhScreen
|
||||
if (!ModInfo.IS_DEV_BUILD)
|
||||
{
|
||||
this.addBtn(new TexturedButtonWidget(
|
||||
// Where the button is on the screen
|
||||
this.width / 2 - 97, this.height / 2 + 8,
|
||||
// Width and height of the button
|
||||
20, 20,
|
||||
// Offset
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
0,
|
||||
#if MC_VER < MC_1_21_1
|
||||
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#else
|
||||
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#endif
|
||||
20, 20,
|
||||
// Create the button and tell it where to go
|
||||
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(new ChangelogScreen(this, this.newVersionID)), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
|
||||
// Add a title to the button
|
||||
Translatable(ModInfo.ID + ".updater.title")
|
||||
// Where the button is on the screen
|
||||
this.width / 2 - 97, this.height / 2 + 8,
|
||||
// Width and height of the button
|
||||
20, 20,
|
||||
// Offset
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
0,
|
||||
#if MC_VER < MC_1_21_1
|
||||
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#else
|
||||
Identifier.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#endif
|
||||
20, 20,
|
||||
// Create the button and tell it where to go
|
||||
(buttonWidget) -> Objects.requireNonNull(this.minecraft).setScreen(new ChangelogScreen(this, this.newVersionID)),
|
||||
// Add a title to the button
|
||||
Translatable(ModInfo.ID + ".updater.title")
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
+130
-174
@@ -20,18 +20,9 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.minecraft;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiLodShading;
|
||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||
import com.mojang.blaze3d.platform.Window;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
|
||||
import com.seibel.distanthorizons.core.render.glObject.GLProxy;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
@@ -40,25 +31,25 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
|
||||
import net.minecraft.CrashReport;
|
||||
import net.minecraft.client.CloudStatus;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.multiplayer.ServerData;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
#endif
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
#else
|
||||
@@ -78,82 +69,13 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
||||
public static final MinecraftClientWrapper INSTANCE = new MinecraftClientWrapper();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The lightmap for the current:
|
||||
* Time, dimension, brightness setting, etc.
|
||||
*/
|
||||
private NativeImage lightMap = null;
|
||||
|
||||
private ProfilerWrapper profilerWrapper;
|
||||
|
||||
|
||||
private MinecraftClientWrapper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
/**
|
||||
* This should be called at the beginning of every frame to
|
||||
* clear any Minecraft data that becomes out of date after a frame. <br> <br>
|
||||
* <p>
|
||||
* LightMaps and other time sensitive objects fall in this category. <br> <br>
|
||||
* <p>
|
||||
* This doesn't affect OpenGL objects in any way.
|
||||
*/
|
||||
@Override
|
||||
public void clearFrameObjectCache() { this.lightMap = null; }
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// method wrappers //
|
||||
//=================//
|
||||
|
||||
@Override
|
||||
public float getShade(EDhDirection lodDirection)
|
||||
{
|
||||
EDhApiLodShading lodShading = Config.Client.Advanced.Graphics.Quality.lodShading.get();
|
||||
switch (lodShading)
|
||||
{
|
||||
default:
|
||||
case AUTO:
|
||||
if (MINECRAFT.level != null)
|
||||
{
|
||||
Direction mcDir = McObjectConverter.Convert(lodDirection);
|
||||
return MINECRAFT.level.getShade(mcDir, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
case ENABLED:
|
||||
switch (lodDirection)
|
||||
{
|
||||
case DOWN:
|
||||
return 0.5F;
|
||||
default:
|
||||
case UP:
|
||||
return 1.0F;
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
return 0.8F;
|
||||
case WEST:
|
||||
case EAST:
|
||||
return 0.6F;
|
||||
}
|
||||
|
||||
case DISABLED:
|
||||
return 1.0F;
|
||||
}
|
||||
}
|
||||
//======================//
|
||||
// multiplayer handling //
|
||||
//======================//
|
||||
|
||||
@Override
|
||||
public boolean hasSinglePlayerServer() { return MINECRAFT.hasSingleplayerServer(); }
|
||||
@@ -183,7 +105,6 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
||||
return (server != null) ? server.name : "NULL";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentServerIp()
|
||||
{
|
||||
@@ -197,7 +118,6 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
||||
return (server != null) ? server.ip : "NA";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentServerVersion()
|
||||
{
|
||||
@@ -205,21 +125,17 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
||||
return (server != null) ? server.version.getString() : "UNKOWN";
|
||||
}
|
||||
|
||||
//=============//
|
||||
// Simple gets //
|
||||
//=============//
|
||||
|
||||
|
||||
//=================//
|
||||
// player handling //
|
||||
//=================//
|
||||
|
||||
public LocalPlayer getPlayer() { return MINECRAFT.player; }
|
||||
|
||||
@Override
|
||||
public boolean playerExists() { return MINECRAFT.player != null; }
|
||||
|
||||
@Override
|
||||
public UUID getPlayerUUID() { return this.getPlayer().getUUID(); }
|
||||
|
||||
@Override
|
||||
public String getUsername() { return MINECRAFT.getUser().getName(); }
|
||||
|
||||
@Override
|
||||
public DhBlockPos getPlayerBlockPos()
|
||||
{
|
||||
@@ -250,6 +166,12 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
||||
return new DhChunkPos(playerPos.x, playerPos.z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// level handling //
|
||||
//================//
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IClientLevelWrapper getWrappedClientLevel() { return this.getWrappedClientLevel(false); }
|
||||
@@ -267,6 +189,98 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
||||
return ClientLevelWrapper.getWrapper(level, bypassLevelKeyManager);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// messaging //
|
||||
//===========//
|
||||
|
||||
@Override
|
||||
public void sendChatMessage(String string)
|
||||
{
|
||||
LocalPlayer player = this.getPlayer();
|
||||
if (player == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
player.sendMessage(new TextComponent(string), getPlayer().getUUID());
|
||||
#elif MC_VER < MC_1_21_9
|
||||
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false);
|
||||
#else
|
||||
|
||||
GLProxy.queueRunningOnRenderThread(() ->
|
||||
{
|
||||
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendOverlayMessage(String string)
|
||||
{
|
||||
LocalPlayer player = this.getPlayer();
|
||||
if (player == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
player.displayClientMessage(new TextComponent(string), /*isOverlay*/true);
|
||||
#else
|
||||
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/true);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================//
|
||||
// vanilla option overrides //
|
||||
//==========================//
|
||||
|
||||
public void disableVanillaClouds()
|
||||
{
|
||||
#if MC_VER <= MC_1_18_2
|
||||
MINECRAFT.options.renderClouds = CloudStatus.OFF;
|
||||
#else
|
||||
MINECRAFT.options.cloudStatus().set(CloudStatus.OFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void disableVanillaChunkFadeIn()
|
||||
{
|
||||
#if MC_VER <= MC_1_21_10
|
||||
// chunk fade in was added MC 1.21.11
|
||||
#else
|
||||
MINECRAFT.options.chunkSectionFadeInTime().set(0.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//======//
|
||||
// misc //
|
||||
//======//
|
||||
|
||||
/**
|
||||
* no override and not included in {@link IMinecraftClientWrapper}
|
||||
* since this would only be used in common/client, not core.
|
||||
*/
|
||||
public
|
||||
#if MC_VER < MC_1_21_9 long
|
||||
#else Window
|
||||
#endif
|
||||
getGlfwWindowId()
|
||||
{
|
||||
#if MC_VER < MC_1_21_9
|
||||
long glfwWindowId = MINECRAFT.getWindow().getWindow();
|
||||
return glfwWindowId;
|
||||
#else
|
||||
return MINECRAFT.getWindow();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public IProfilerWrapper getProfiler()
|
||||
{
|
||||
@@ -289,99 +303,39 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
||||
return this.profilerWrapper;
|
||||
}
|
||||
|
||||
/** Returns all worlds available to the server */
|
||||
@Override
|
||||
public ArrayList<ILevelWrapper> getAllServerWorlds()
|
||||
{
|
||||
ArrayList<ILevelWrapper> worlds = new ArrayList<ILevelWrapper>();
|
||||
|
||||
Iterable<ServerLevel> serverWorlds = MINECRAFT.getSingleplayerServer().getAllLevels();
|
||||
for (ServerLevel world : serverWorlds)
|
||||
{
|
||||
worlds.add(ServerLevelWrapper.getWrapper(world));
|
||||
}
|
||||
|
||||
return worlds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void sendChatMessage(String string)
|
||||
{
|
||||
LocalPlayer player = this.getPlayer();
|
||||
if (player == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GLProxy.hasInstance())
|
||||
{
|
||||
// rendering setup hasn't finished
|
||||
return;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
player.sendMessage(new TextComponent(string), getPlayer().getUUID());
|
||||
#elif MC_VER < MC_1_21_9
|
||||
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false);
|
||||
#else
|
||||
|
||||
GLProxy.getInstance().queueRunningOnRenderThread(() ->
|
||||
{
|
||||
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendOverlayMessage(String string)
|
||||
{
|
||||
LocalPlayer player = this.getPlayer();
|
||||
if (player == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
player.displayClientMessage(new TextComponent(string), /*isOverlay*/true);
|
||||
#else
|
||||
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/true);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Crashes Minecraft, displaying the given errorMessage <br> <br>
|
||||
* In the following format: <br>
|
||||
*
|
||||
* The game crashed whilst <strong>errorMessage</strong> <br>
|
||||
* Error: <strong>ExceptionClass: exceptionErrorMessage</strong> <br>
|
||||
* Exit Code: -1 <br>
|
||||
*/
|
||||
@Override
|
||||
public void crashMinecraft(String errorMessage, Throwable exception)
|
||||
{
|
||||
LOGGER.error(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft...", exception);
|
||||
LOGGER.fatal(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft...", exception);
|
||||
CrashReport report = new CrashReport(errorMessage, exception);
|
||||
#if MC_VER < MC_1_20_4
|
||||
Minecraft.crash(report);
|
||||
#else
|
||||
Minecraft.getInstance().delayCrash(report);
|
||||
MINECRAFT.delayCrash(report);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// mod support //
|
||||
//=============//
|
||||
|
||||
@Override
|
||||
public Object getOptionsObject() { return MINECRAFT.options; }
|
||||
|
||||
|
||||
|
||||
//========//
|
||||
// shared //
|
||||
//========//
|
||||
|
||||
@Override
|
||||
public boolean isDedicatedServer() { return false; }
|
||||
|
||||
@Override
|
||||
public File getInstallationDirectory() { return MINECRAFT.gameDirectory; }
|
||||
|
||||
@Override
|
||||
public void executeOnRenderThread(Runnable runnable) { MINECRAFT.execute(runnable); }
|
||||
|
||||
@Override
|
||||
public int getPlayerCount()
|
||||
{
|
||||
@@ -396,4 +350,6 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+104
-54
@@ -25,9 +25,13 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.mojang.blaze3d.pipeline.RenderTarget;
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiLodShading;
|
||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||
|
||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
|
||||
@@ -52,12 +56,12 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWra
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
@@ -79,6 +83,11 @@ import com.mojang.blaze3d.opengl.GlTexture;
|
||||
#else
|
||||
#endif
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
#else
|
||||
import net.minecraft.world.attribute.EnvironmentAttributes;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A singleton that contains everything
|
||||
* related to rendering in Minecraft.
|
||||
@@ -90,8 +99,6 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
private static final Minecraft MC = Minecraft.getInstance();
|
||||
|
||||
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
|
||||
|
||||
/**
|
||||
* In the case of immersive portals multiple levels may be active at once, causing conflicting lightmaps. <br>
|
||||
* Requiring the use of multiple {@link LightMapWrapper}.
|
||||
@@ -121,12 +128,20 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
@Override
|
||||
public Vec3f getLookAtVector()
|
||||
{
|
||||
#if MC_VER <= MC_1_21_10
|
||||
Camera camera = MC.gameRenderer.getMainCamera();
|
||||
return new Vec3f(camera.getLookVector().x(), camera.getLookVector().y(), camera.getLookVector().z());
|
||||
#else
|
||||
Camera camera = MC.gameRenderer.getMainCamera();
|
||||
return new Vec3f(camera.forwardVector().x(), camera.forwardVector().y(), camera.forwardVector().z());
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Unless you really need to know if the player is blind,
|
||||
* use {@link MinecraftRenderWrapper#isFogStateSpecial()} or {@link IMinecraftRenderWrapper#isFogStateSpecial()} instead
|
||||
*/
|
||||
@Override
|
||||
/** Unless you really need to know if the player is blind, use {@link MinecraftRenderWrapper#isFogStateSpecial()}/{@link IMinecraftRenderWrapper#isFogStateSpecial()} instead */
|
||||
public boolean playerHasBlindingEffect()
|
||||
{
|
||||
if (MC.player == null)
|
||||
@@ -151,7 +166,11 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
public Vec3d getCameraExactPosition()
|
||||
{
|
||||
Camera camera = MC.gameRenderer.getMainCamera();
|
||||
#if MC_VER <= MC_1_21_10
|
||||
Vec3 projectedView = camera.getPosition();
|
||||
#else
|
||||
Vec3 projectedView = camera.position();
|
||||
#endif
|
||||
|
||||
return new Vec3d(projectedView.x, projectedView.y, projectedView.z);
|
||||
}
|
||||
@@ -185,8 +204,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
Math.max(0f, Math.min(colorValues.z, 1f)), // b
|
||||
Math.max(0f, Math.min(colorValues.w, 1f)) // a
|
||||
);
|
||||
#else
|
||||
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
if (mcFogRenderer == null)
|
||||
{
|
||||
mcFogRenderer = new FogRenderer();
|
||||
@@ -210,9 +228,33 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
Math.max(0f, Math.min(colorValues.z, 1f)), // b
|
||||
Math.max(0f, Math.min(colorValues.w, 1f)) // a
|
||||
);
|
||||
#else
|
||||
|
||||
if (mcFogRenderer == null)
|
||||
{
|
||||
mcFogRenderer = new FogRenderer();
|
||||
}
|
||||
|
||||
if (MC.level == null)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
Vector4f colorValues = mcFogRenderer.setupFog(
|
||||
MC.gameRenderer.getMainCamera(),
|
||||
MC.options.getEffectiveRenderDistance(),
|
||||
MC.deltaTracker,
|
||||
MC.gameRenderer.getDarkenWorldAmount(MC.deltaTracker.getGameTimeDeltaPartialTick(true)),
|
||||
MC.level);
|
||||
return new Color(
|
||||
Math.max(0f, Math.min(colorValues.x, 1f)), // r
|
||||
Math.max(0f, Math.min(colorValues.y, 1f)), // g
|
||||
Math.max(0f, Math.min(colorValues.z, 1f)), // b
|
||||
Math.max(0f, Math.min(colorValues.w, 1f)) // a
|
||||
);
|
||||
#endif
|
||||
}
|
||||
// getSpecialFogColor() is the same as getFogColor()
|
||||
|
||||
@Override
|
||||
public Color getSkyColor()
|
||||
@@ -224,8 +266,10 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
frameTime = MC.getFrameTime();
|
||||
#elif MC_VER < MC_1_21_3
|
||||
frameTime = MC.getTimer().getRealtimeDeltaTicks();
|
||||
#else
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
frameTime = MC.deltaTracker.getGameTimeDeltaTicks();
|
||||
#else
|
||||
frameTime = 0f; // unused
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_17_1
|
||||
@@ -234,9 +278,12 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
#elif MC_VER < MC_1_21_3
|
||||
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);
|
||||
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
int argbColorInt = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);
|
||||
return ColorUtil.toColorObjARGB(argbColorInt);
|
||||
#else
|
||||
int argbColorInt = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);;
|
||||
return ColorUtil.toColorObjARGB(argbColorInt); // TODO MC changed color formats
|
||||
int argbColor = MC.level.environmentAttributes().getValue(EnvironmentAttributes.SKY_COLOR, BlockPos.ZERO);
|
||||
return new Color(ColorUtil.getRed(argbColor), ColorUtil.getGreen(argbColor), ColorUtil.getBlue(argbColor), 255 /* ignore alpha since DH clouds don't render correctly with transparency */);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -246,10 +293,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getFov(float partialTicks)
|
||||
{
|
||||
return MC.gameRenderer.getFov(MC.gameRenderer.getMainCamera(), partialTicks, true);
|
||||
}
|
||||
public double getFov(float partialTicks) { return MC.gameRenderer.getFov(MC.gameRenderer.getMainCamera(), partialTicks, true); }
|
||||
|
||||
/** Measured in chunks */
|
||||
@Override
|
||||
@@ -263,41 +307,6 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScreenWidth()
|
||||
{
|
||||
// alternate ways of getting the window's resolution,
|
||||
// using one of these methods may fix the optifine render resolution bug
|
||||
// TODO: test these once we can run with Optifine again
|
||||
// int[] heightArray = new int[1];
|
||||
// int[] widthArray = new int[1];
|
||||
//
|
||||
// long window = GLProxy.getInstance().minecraftGlContext;
|
||||
// GLFW.glfwGetWindowSize(window, widthArray, heightArray); // option 1
|
||||
// GLFW.glfwGetFramebufferSize(window, widthArray, heightArray); // option 2
|
||||
|
||||
|
||||
|
||||
int width = MC.getWindow().getWidth();
|
||||
if (OPTIFINE_ACCESSOR != null)
|
||||
{
|
||||
// TODO remove comment after testing:
|
||||
// this should fix the issue where different optifine render resolutions screw up the LOD rendering
|
||||
width *= OPTIFINE_ACCESSOR.getRenderResolutionMultiplier();
|
||||
}
|
||||
return width;
|
||||
}
|
||||
@Override
|
||||
public int getScreenHeight()
|
||||
{
|
||||
int height = MC.getWindow().getHeight();
|
||||
if (OPTIFINE_ACCESSOR != null)
|
||||
{
|
||||
height *= OPTIFINE_ACCESSOR.getRenderResolutionMultiplier();
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
protected RenderTarget getRenderTarget() { return MC.getMainRenderTarget(); }
|
||||
|
||||
@Override
|
||||
@@ -353,7 +362,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
if (glTexture == null)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return glTexture.glId();
|
||||
@@ -367,7 +376,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
this.depthTextureCastFailLogged = true;
|
||||
LOGGER.error("Unable to cast render Target depth texture to GlTexture. MC or a rendering mod may have changed the object type.", e);
|
||||
}
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -383,7 +392,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
if (glTexture == null)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return glTexture.glId();
|
||||
@@ -396,7 +405,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
this.colorTextureCastFailLogged = true;
|
||||
LOGGER.error("Unable to cast render Target color texture to GlTexture. MC or a rendering mod may have changed the object type.", e);
|
||||
}
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -466,4 +475,45 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
wrapper.setLightmapId(tetxureId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getShade(EDhDirection lodDirection)
|
||||
{
|
||||
EDhApiLodShading lodShading = Config.Client.Advanced.Graphics.Quality.lodShading.get();
|
||||
switch (lodShading)
|
||||
{
|
||||
default:
|
||||
case AUTO:
|
||||
if (MC.level != null)
|
||||
{
|
||||
Direction mcDir = McObjectConverter.Convert(lodDirection);
|
||||
return MC.level.getShade(mcDir, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
case ENABLED:
|
||||
switch (lodDirection)
|
||||
{
|
||||
case DOWN:
|
||||
return 0.5F;
|
||||
default:
|
||||
case UP:
|
||||
return 1.0F;
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
return 0.8F;
|
||||
case WEST:
|
||||
case EAST:
|
||||
return 0.6F;
|
||||
}
|
||||
|
||||
case DISABLED:
|
||||
return 1.0F;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+12
-2
@@ -2,17 +2,20 @@ package com.seibel.distanthorizons.common.wrappers.minecraft;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
//@Environment(EnvType.SERVER)
|
||||
public class MinecraftServerWrapper implements IMinecraftSharedWrapper
|
||||
{
|
||||
public static final MinecraftServerWrapper INSTANCE = new MinecraftServerWrapper();
|
||||
|
||||
/** set during server startup */
|
||||
@Nullable
|
||||
public DedicatedServer dedicatedServer = null;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
@@ -33,7 +36,7 @@ public class MinecraftServerWrapper implements IMinecraftSharedWrapper
|
||||
{
|
||||
if (this.dedicatedServer == null)
|
||||
{
|
||||
throw new IllegalStateException("Trying to get Installation Direction before Dedicated server completed initialization!");
|
||||
throw new IllegalStateException("Trying to get Installation Direction before dedicated server completed initialization!");
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_21_1
|
||||
@@ -46,7 +49,14 @@ public class MinecraftServerWrapper implements IMinecraftSharedWrapper
|
||||
@Override
|
||||
public int getPlayerCount()
|
||||
{
|
||||
if (this.dedicatedServer == null)
|
||||
{
|
||||
throw new IllegalStateException("Trying to get player count before dedicated server completed initialization!");
|
||||
}
|
||||
|
||||
return this.dedicatedServer.getPlayerCount();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+87
-25
@@ -21,6 +21,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWra
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
@@ -50,6 +51,12 @@ import net.minecraft.world.phys.Vec3;
|
||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||
#endif
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
#else
|
||||
import net.minecraft.world.attribute.EnvironmentAttributes;
|
||||
#endif
|
||||
|
||||
|
||||
public class ClientLevelWrapper implements IClientLevelWrapper
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
@@ -70,6 +77,8 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
||||
private final Function<BlockState, ClientBlockStateColorCache> createCachedBlockColorCacheFunc = (blockState) -> new ClientBlockStateColorCache(blockState, this);
|
||||
|
||||
|
||||
private boolean cloudColorFailLogged = false;
|
||||
|
||||
private BlockStateWrapper dirtBlockWrapper;
|
||||
private IDhLevel dhLevel;
|
||||
|
||||
@@ -92,7 +101,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
||||
* IE rendering.
|
||||
*/
|
||||
@Nullable
|
||||
public static IClientLevelWrapper getWrapperIfDifferent(@Nullable IClientLevelWrapper levelWrapper, @NotNull ClientLevel level)
|
||||
public static IClientLevelWrapper getWrapperIfDifferent(@Nullable IClientLevelWrapper levelWrapper, @NotNull ClientLevel level) // TODO handle null level
|
||||
{
|
||||
if (KEYED_CLIENT_LEVEL_MANAGER.isEnabled() && KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel() != levelWrapper)
|
||||
{
|
||||
@@ -237,11 +246,24 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
||||
public void clearBlockColorCache() { this.blockColorCacheByBlockState.clear(); }
|
||||
|
||||
@Override
|
||||
public IDimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); }
|
||||
|
||||
public IDimensionTypeWrapper getDimensionType()
|
||||
{
|
||||
#if MC_VER <= MC_1_21_10
|
||||
return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType());
|
||||
#else
|
||||
return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType(), this.getDimensionName());
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDimensionName() { return this.level.dimension().location().toString(); }
|
||||
public String getDimensionName()
|
||||
{
|
||||
#if MC_VER <= MC_1_21_10
|
||||
return this.level.dimension().location().toString();
|
||||
#else
|
||||
return this.level.dimension().identifier().toString();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getHashedSeed() { return this.level.getBiomeManager().biomeZoomSeed; }
|
||||
@@ -275,23 +297,6 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkWrapper tryGetChunk(DhChunkPos pos)
|
||||
{
|
||||
if (!this.level.hasChunk(pos.getX(), pos.getZ()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.EMPTY, false);
|
||||
if (chunk == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ChunkWrapper(chunk, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientLevel getWrappedMcObject() { return this.level; }
|
||||
|
||||
@@ -340,11 +345,68 @@ public class ClientLevelWrapper implements IClientLevelWrapper
|
||||
public Color getCloudColor(float tickDelta)
|
||||
{
|
||||
#if MC_VER < MC_1_21_3
|
||||
Vec3 colorVec3 = this.level.getCloudColor(tickDelta);
|
||||
return new Color((float)colorVec3.x, (float)colorVec3.y, (float)colorVec3.z);
|
||||
Vec3 colorVec3 = null;
|
||||
try
|
||||
{
|
||||
colorVec3 = this.level.getCloudColor(tickDelta);
|
||||
return new Color((float)colorVec3.x, (float)colorVec3.y, (float)colorVec3.z);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// extra logging is due to some mods returning weird values, this way we can track down the issue better
|
||||
if (!this.cloudColorFailLogged)
|
||||
{
|
||||
this.cloudColorFailLogged = true;
|
||||
|
||||
String colorString = "NULL";
|
||||
if (colorVec3 != null)
|
||||
{
|
||||
colorString = "r["+(float)colorVec3.x+"] g["+(float)colorVec3.y+"] b["+(float)colorVec3.z+"]";
|
||||
}
|
||||
LOGGER.warn("Failed to get cloud color for ["+this.getDhIdentifier()+"]. vec3 ["+colorString+"], error: ["+e.getMessage()+"].", e);
|
||||
}
|
||||
|
||||
// default to white if there's an issue
|
||||
return Color.WHITE;
|
||||
}
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
int argbColor = 0;
|
||||
try
|
||||
{
|
||||
argbColor = this.level.getCloudColor(tickDelta);
|
||||
return ColorUtil.toColorObjARGB(argbColor);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// extra logging is due to some mods returning weird values, this way we can track down the issue better
|
||||
if (!this.cloudColorFailLogged)
|
||||
{
|
||||
this.cloudColorFailLogged = true;
|
||||
LOGGER.warn("Failed to get cloud color for ["+this.getDhIdentifier()+"]. Int ["+argbColor+"], col ["+ColorUtil.toString(argbColor)+"], error: ["+e.getMessage()+"].", e);
|
||||
}
|
||||
|
||||
// default to white if there's an issue
|
||||
return Color.WHITE;
|
||||
}
|
||||
#else
|
||||
int argbColor = this.level.getCloudColor(tickDelta);
|
||||
return ColorUtil.toColorObjARGB(argbColor);
|
||||
int argbColor = 0;
|
||||
try
|
||||
{
|
||||
argbColor = this.level.environmentAttributes().getValue(EnvironmentAttributes.CLOUD_COLOR, BlockPos.ZERO);
|
||||
return new Color(ColorUtil.getRed(argbColor), ColorUtil.getGreen(argbColor), ColorUtil.getBlue(argbColor), 255 /* ignore alpha since DH clouds don't render correctly with transparency */);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// extra logging is due to some mods returning weird values, this way we can track down the issue better
|
||||
if (!this.cloudColorFailLogged)
|
||||
{
|
||||
this.cloudColorFailLogged = true;
|
||||
LOGGER.warn("Failed to get cloud color for ["+this.getDhIdentifier()+"]. Int ["+argbColor+"], col ["+ColorUtil.toString(argbColor)+"], error: ["+e.getMessage()+"].", e);
|
||||
}
|
||||
|
||||
// default to white if there's an issue
|
||||
return Color.WHITE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+44
-19
@@ -26,25 +26,45 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWra
|
||||
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
*/
|
||||
public class DimensionTypeWrapper implements IDimensionTypeWrapper
|
||||
{
|
||||
private static final ConcurrentMap<String, DimensionTypeWrapper> DIMENSION_WRAPPER_BY_NAME = new ConcurrentHashMap<>();
|
||||
private final DimensionType dimensionType;
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// Constructor //
|
||||
//=============//
|
||||
|
||||
public DimensionTypeWrapper(DimensionType dimensionType) { this.dimensionType = dimensionType; }
|
||||
|
||||
public static DimensionTypeWrapper getDimensionTypeWrapper(DimensionType dimensionType)
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public DimensionTypeWrapper(DimensionType dimensionType)
|
||||
#else
|
||||
public DimensionTypeWrapper(DimensionType dimensionType, String name)
|
||||
#endif
|
||||
{
|
||||
String dimName = getName(dimensionType);
|
||||
this.dimensionType = dimensionType;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
this.name = determineName(dimensionType);
|
||||
#else
|
||||
this.name = name;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public static DimensionTypeWrapper getDimensionTypeWrapper(DimensionType dimensionType)
|
||||
#else
|
||||
public static DimensionTypeWrapper getDimensionTypeWrapper(DimensionType dimensionType, String name)
|
||||
#endif
|
||||
{
|
||||
#if MC_VER <= MC_1_21_10
|
||||
String dimName = determineName(dimensionType);
|
||||
#else
|
||||
String dimName = name;
|
||||
#endif
|
||||
|
||||
// check if the dimension has already been wrapped
|
||||
if (DIMENSION_WRAPPER_BY_NAME.containsKey(dimName)
|
||||
@@ -55,10 +75,26 @@ public class DimensionTypeWrapper implements IDimensionTypeWrapper
|
||||
|
||||
|
||||
// create the missing wrapper
|
||||
#if MC_VER <= MC_1_21_10
|
||||
DimensionTypeWrapper dimensionTypeWrapper = new DimensionTypeWrapper(dimensionType);
|
||||
#else
|
||||
DimensionTypeWrapper dimensionTypeWrapper = new DimensionTypeWrapper(dimensionType, dimName);
|
||||
#endif
|
||||
|
||||
DIMENSION_WRAPPER_BY_NAME.put(dimName, dimensionTypeWrapper);
|
||||
return dimensionTypeWrapper;
|
||||
}
|
||||
private static String determineName(DimensionType dimensionType)
|
||||
{
|
||||
#if MC_VER <= MC_1_16_5
|
||||
// effectsLocation() is marked as client only, so using the backing field directly
|
||||
return dimensionType.effectsLocation.getPath();
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
return dimensionType.effectsLocation().getPath();
|
||||
#else
|
||||
throw new UnsupportedOperationException("As of MC 1.21.11 the dimension type no longer stores it's name and must be determined from the level.");
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void clearMap() { DIMENSION_WRAPPER_BY_NAME.clear(); }
|
||||
|
||||
@@ -69,16 +105,7 @@ public class DimensionTypeWrapper implements IDimensionTypeWrapper
|
||||
//=================//
|
||||
|
||||
@Override
|
||||
public String getName() { return getName(this.dimensionType); }
|
||||
public static String getName(DimensionType dimensionType)
|
||||
{
|
||||
#if MC_VER <= MC_1_16_5
|
||||
// effectsLocation() is marked as client only, so using the backing field directly
|
||||
return dimensionType.effectsLocation.getPath();
|
||||
#else
|
||||
return dimensionType.effectsLocation().getPath();
|
||||
#endif
|
||||
}
|
||||
public String getName() { return this.name; }
|
||||
|
||||
@Override
|
||||
public boolean hasCeiling() { return this.dimensionType.hasCeiling(); }
|
||||
@@ -89,7 +116,6 @@ public class DimensionTypeWrapper implements IDimensionTypeWrapper
|
||||
@Override
|
||||
public Object getWrappedMcObject() { return this.dimensionType; }
|
||||
|
||||
// there's definitely a better way of doing this, but it should work well enough for now
|
||||
@Override
|
||||
public boolean isTheEnd() { return this.getName().equalsIgnoreCase("the_end"); }
|
||||
|
||||
@@ -98,7 +124,6 @@ public class DimensionTypeWrapper implements IDimensionTypeWrapper
|
||||
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
|
||||
+16
-19
@@ -172,10 +172,24 @@ public class ServerLevelWrapper implements IServerLevelWrapper
|
||||
|
||||
|
||||
@Override
|
||||
public DimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); }
|
||||
public DimensionTypeWrapper getDimensionType()
|
||||
{
|
||||
#if MC_VER <= MC_1_21_10
|
||||
return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType());
|
||||
#else
|
||||
return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType(), this.getDimensionName());
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDimensionName() { return this.level.dimension().location().toString(); }
|
||||
public String getDimensionName()
|
||||
{
|
||||
#if MC_VER <= MC_1_21_10
|
||||
return this.level.dimension().location().toString();
|
||||
#else
|
||||
return this.level.dimension().identifier().toString();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getHashedSeed() { return this.level.getBiomeManager().biomeZoomSeed; }
|
||||
@@ -209,23 +223,6 @@ public class ServerLevelWrapper implements IServerLevelWrapper
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkWrapper tryGetChunk(DhChunkPos pos)
|
||||
{
|
||||
if (!this.level.hasChunk(pos.getX(), pos.getZ()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.FULL, false);
|
||||
if (chunk == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ChunkWrapper(chunk, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerLevel getWrappedMcObject() { return this.level; }
|
||||
|
||||
|
||||
+369
-886
File diff suppressed because it is too large
Load Diff
+92
@@ -0,0 +1,92 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class ChunkPosGenStream
|
||||
{
|
||||
|
||||
public static Iterator<ChunkPos> getIterator(int genMinX, int genMinZ, int width, int extraRadius)
|
||||
{ return getStream(genMinX, genMinZ, width, extraRadius).iterator(); }
|
||||
/** @param extraRadius in both the positive and negative directions */
|
||||
public static Stream<ChunkPos> getStream(int genMinX, int genMinZ, int width, int extraRadius)
|
||||
{ return StreamSupport.stream(new InclusiveChunkPosIterator(genMinX, genMinZ, width, extraRadius), false); }
|
||||
|
||||
private static class InclusiveChunkPosIterator extends Spliterators.AbstractSpliterator<ChunkPos>
|
||||
{
|
||||
private final int minX;
|
||||
private final int minZ;
|
||||
|
||||
private final int maxX;
|
||||
private final int maxZ;
|
||||
|
||||
|
||||
/** current X pos */
|
||||
int x;
|
||||
/** current Z pos */
|
||||
private int z;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
protected InclusiveChunkPosIterator(int genMinX, int genMinZ, int width, int extraRadius)
|
||||
{
|
||||
super(getCount(width, extraRadius), Spliterator.SIZED);
|
||||
|
||||
this.minX = genMinX - extraRadius;
|
||||
this.minZ = genMinZ - extraRadius;
|
||||
|
||||
this.maxX = genMinX + (width - 1) + extraRadius;
|
||||
this.maxZ = genMinZ + (width - 1) + extraRadius;
|
||||
|
||||
// X starts at 1 minus the minX so we can immediately re-add 1 in the tryAdvance() loop
|
||||
this.x = this.minX - 1;
|
||||
this.z = this.minZ;
|
||||
}
|
||||
private static int getCount(int width, int extraRadius)
|
||||
{
|
||||
int widthPlusExtra = width + (extraRadius * 2);
|
||||
return widthPlusExtra * widthPlusExtra;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// iterator method //
|
||||
//=================//
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(Consumer<? super ChunkPos> consumer)
|
||||
{
|
||||
if (this.x == this.maxX && this.z == this.maxZ)
|
||||
{
|
||||
// the last returned position was the final valid position
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.x == this.maxX)
|
||||
{
|
||||
// we reached the max X position, loop back around in the next Z row
|
||||
this.x = this.minX;
|
||||
this.z++;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.x++;
|
||||
}
|
||||
|
||||
consumer.accept(new ChunkPos(this.x, this.z));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+71
-88
@@ -19,17 +19,16 @@
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
||||
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||
import com.seibel.distanthorizons.core.util.ExceptionUtil;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.util.objects.EventTimer;
|
||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
@@ -37,96 +36,101 @@ import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
public final class GenerationEvent
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();;
|
||||
private static int generationFutureDebugIDs = 0;
|
||||
|
||||
private static final AtomicInteger DEBUG_ID_REF = new AtomicInteger(0);
|
||||
|
||||
|
||||
/** can be used for troubleshooting */
|
||||
public final int id;
|
||||
public final ThreadedParameters threadedParam;
|
||||
|
||||
public final ThreadWorldGenParams threadedParam;
|
||||
public final DhChunkPos minPos;
|
||||
/** the number of chunks wide this event is */
|
||||
public final int size;
|
||||
public final int widthInChunks;
|
||||
public final EDhApiWorldGenerationStep targetGenerationStep;
|
||||
public final EDhApiDistantGeneratorMode generatorMode;
|
||||
public EventTimer timer = null;
|
||||
public long inQueueTime;
|
||||
public long timeoutTime = -1;
|
||||
public CompletableFuture<Void> future = null;
|
||||
public final CompletableFuture<Void> future;
|
||||
public final Consumer<IChunkWrapper> resultConsumer;
|
||||
|
||||
|
||||
|
||||
public GenerationEvent(
|
||||
DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup,
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
private GenerationEvent(
|
||||
DhChunkPos minPos, int widthInChunks, BatchGenerationEnvironment generationGroup,
|
||||
EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetGenerationStep, Consumer<IChunkWrapper> resultConsumer)
|
||||
{
|
||||
this.inQueueTime = System.nanoTime();
|
||||
this.id = generationFutureDebugIDs++;
|
||||
this.id = DEBUG_ID_REF.getAndIncrement();
|
||||
|
||||
this.minPos = minPos;
|
||||
this.size = size;
|
||||
this.generatorMode = generatorMode;
|
||||
this.widthInChunks = widthInChunks;
|
||||
this.targetGenerationStep = targetGenerationStep;
|
||||
this.threadedParam = ThreadedParameters.getOrMake(generationGroup.params);
|
||||
this.generatorMode = generatorMode;
|
||||
this.threadedParam = ThreadWorldGenParams.getOrMake(generationGroup.globalParams);
|
||||
this.future = new CompletableFuture<>();
|
||||
this.resultConsumer = resultConsumer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static GenerationEvent startEvent(
|
||||
DhChunkPos minPos, int size, BatchGenerationEnvironment genEnvironment,
|
||||
//=======//
|
||||
// start //
|
||||
//=======//
|
||||
|
||||
public static GenerationEvent start(
|
||||
DhChunkPos minPos, int widthInChunks, BatchGenerationEnvironment genEnvironment,
|
||||
EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep target, Consumer<IChunkWrapper> resultConsumer,
|
||||
ExecutorService worldGeneratorThreadPool)
|
||||
{
|
||||
GenerationEvent generationEvent = new GenerationEvent(minPos, size, genEnvironment, generatorMode, target, resultConsumer);
|
||||
generationEvent.future = CompletableFuture.supplyAsync(() ->
|
||||
GenerationEvent genEvent = new GenerationEvent(minPos, widthInChunks, genEnvironment, generatorMode, target, resultConsumer);
|
||||
|
||||
try
|
||||
{
|
||||
long runStartTime = System.nanoTime();
|
||||
generationEvent.timeoutTime = runStartTime;
|
||||
generationEvent.inQueueTime = runStartTime - generationEvent.inQueueTime;
|
||||
generationEvent.timer = new EventTimer("setup");
|
||||
|
||||
BatchGenerationEnvironment.isDistantGeneratorThread.set(true);
|
||||
|
||||
try
|
||||
worldGeneratorThreadPool.execute(() ->
|
||||
{
|
||||
genEnvironment.generateLodFromListAsync(generationEvent, (runnable) ->
|
||||
try
|
||||
{
|
||||
worldGeneratorThreadPool.execute(() ->
|
||||
{
|
||||
boolean alreadyMarked = BatchGenerationEnvironment.isCurrentThreadDistantGeneratorThread();
|
||||
if (!alreadyMarked)
|
||||
{
|
||||
BatchGenerationEnvironment.isDistantGeneratorThread.set(true);
|
||||
}
|
||||
BatchGenerationEnvironment.isDhWorldGenThreadRef.set(true);
|
||||
|
||||
|
||||
if (genEvent.generatorMode == EDhApiDistantGeneratorMode.INTERNAL_SERVER)
|
||||
{
|
||||
genEnvironment.internalServerGenerator.generateChunksViaInternalServer(genEvent);
|
||||
genEvent.future.complete(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
runnable.run();
|
||||
genEnvironment.generateEvent(genEvent);
|
||||
}
|
||||
catch (Throwable throwable)
|
||||
{
|
||||
handleWorldGenThrowable(generationEvent, throwable);
|
||||
handleWorldGenThrowable(genEvent, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!alreadyMarked)
|
||||
{
|
||||
BatchGenerationEnvironment.isDistantGeneratorThread.set(false);
|
||||
}
|
||||
genEvent.future.complete(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
catch (Throwable initialThrowable)
|
||||
{
|
||||
handleWorldGenThrowable(generationEvent, initialThrowable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BatchGenerationEnvironment.isDistantGeneratorThread.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable initialThrowable)
|
||||
{
|
||||
handleWorldGenThrowable(genEvent, initialThrowable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BatchGenerationEnvironment.isDhWorldGenThreadRef.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (RejectedExecutionException e)
|
||||
{
|
||||
genEvent.future.completeExceptionally(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}, worldGeneratorThreadPool);
|
||||
return generationEvent;
|
||||
return genEvent;
|
||||
}
|
||||
/** There's probably a better way to handle this, but it'll work for now */
|
||||
private static void handleWorldGenThrowable(GenerationEvent generationEvent, Throwable initialThrowable)
|
||||
@@ -137,9 +141,8 @@ public final class GenerationEvent
|
||||
throwable = throwable.getCause();
|
||||
}
|
||||
|
||||
if (throwable instanceof InterruptedException
|
||||
|| throwable instanceof UncheckedInterruptedException
|
||||
|| throwable instanceof RejectedExecutionException)
|
||||
boolean isShutdownException = ExceptionUtil.isShutdownException(throwable);
|
||||
if (isShutdownException)
|
||||
{
|
||||
// these exceptions can be ignored, generally they just mean
|
||||
// the thread is busy so it'll need to try again later.
|
||||
@@ -154,35 +157,15 @@ public final class GenerationEvent
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isComplete() { return this.future.isDone(); }
|
||||
|
||||
public boolean hasTimeout(int duration, TimeUnit unit)
|
||||
{
|
||||
if (this.timeoutTime == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long currentTime = System.nanoTime();
|
||||
long delta = currentTime - this.timeoutTime;
|
||||
return (delta > TimeUnit.NANOSECONDS.convert(duration, unit));
|
||||
}
|
||||
|
||||
public boolean terminate()
|
||||
{
|
||||
LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN=======================");
|
||||
ThreadPoolUtil.WORLD_GEN_THREAD_FACTORY.dumpAllThreadStacks();
|
||||
this.future.cancel(true);
|
||||
return this.future.isCancelled();
|
||||
}
|
||||
|
||||
public void refreshTimeout()
|
||||
{
|
||||
this.timeoutTime = System.nanoTime();
|
||||
UncheckedInterruptedException.throwIfInterrupted();
|
||||
}
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
|
||||
@Override
|
||||
public String toString() { return this.id + ":" + this.size + "@" + this.minPos + "(" + this.targetGenerationStep + ")"; }
|
||||
public String toString() { return this.id + ":" + this.widthInChunks + "@" + this.minPos + "(" + this.targetGenerationStep + ")"; }
|
||||
|
||||
|
||||
|
||||
}
|
||||
+311
@@ -0,0 +1,311 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||
|
||||
import com.seibel.distanthorizons.api.DhApi;
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.GlobalWorldGenParams;
|
||||
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.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.generation.DhLightingEngine;
|
||||
import com.seibel.distanthorizons.core.level.IDhServerLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.util.ExceptionUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.TimerUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
|
||||
#if MC_VER <= MC_1_20_4
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
#else
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
#endif
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class InternalServerGenerator
|
||||
{
|
||||
public static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||
.name("LOD World Gen - Internal Server")
|
||||
.fileLevelConfig(Config.Common.Logging.logWorldGenEventToFile)
|
||||
.build();
|
||||
|
||||
public static final DhLogger CHUNK_LOAD_LOGGER = new DhLoggerBuilder()
|
||||
.name("LOD Chunk Loading")
|
||||
.fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile)
|
||||
.build();
|
||||
|
||||
private static final IC2meAccessor C2ME_ACCESSOR = ModAccessorInjector.INSTANCE.get(IC2meAccessor.class);
|
||||
|
||||
/**
|
||||
* Used to revert the ignore logic in {@link SharedApi} so
|
||||
* that a given chunk pos can be handled again.
|
||||
* A timer is used so we don't have to inject into MC's code and it works sell enough
|
||||
* most of the time.
|
||||
* If a chunk does get through due the timeout not being long enough that isn't the end of the world.
|
||||
*/
|
||||
private static final int MS_TO_IGNORE_CHUNK_AFTER_COMPLETION = 5_000;
|
||||
|
||||
#if MC_VER < MC_1_21_5
|
||||
private static final TicketType<ChunkPos> DH_SERVER_GEN_TICKET = TicketType.create("dh_server_gen_ticket", Comparator.comparingLong(ChunkPos::toLong));
|
||||
#elif MC_VER < MC_1_21_9
|
||||
private static final TicketType DH_SERVER_GEN_TICKET = new TicketType(/* timeout, 0 = disabled*/0L, /* persist */ false, TicketType.TicketUse.LOADING);
|
||||
#else
|
||||
private static final TicketType DH_SERVER_GEN_TICKET = new TicketType(/* timeout, 0 = disabled*/0L, /* flags */TicketType.FLAG_LOADING);
|
||||
#endif
|
||||
|
||||
private static boolean c2meMissingWarningLogged = false;
|
||||
|
||||
|
||||
private final GlobalWorldGenParams params;
|
||||
private final IDhServerLevel dhServerLevel;
|
||||
private final Timer chunkSaveIgnoreTimer = TimerUtil.CreateTimer("ChunkSaveIgnoreTimer");
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public InternalServerGenerator(GlobalWorldGenParams params, IDhServerLevel dhServerLevel)
|
||||
{
|
||||
this.params = params;
|
||||
this.dhServerLevel = dhServerLevel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//============//
|
||||
// generation //
|
||||
//============//
|
||||
|
||||
public void generateChunksViaInternalServer(GenerationEvent genEvent)
|
||||
{
|
||||
this.runValidation();
|
||||
|
||||
try
|
||||
{
|
||||
//=====================//
|
||||
// create gen requests //
|
||||
//=====================//
|
||||
|
||||
ArrayList<CompletableFuture<ChunkAccess>> getChunkFutureList = new ArrayList<>();
|
||||
{
|
||||
Iterator<ChunkPos> chunkPosIterator = ChunkPosGenStream.getIterator(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0);
|
||||
while (chunkPosIterator.hasNext())
|
||||
{
|
||||
ChunkPos chunkPos = chunkPosIterator.next();
|
||||
|
||||
CompletableFuture<ChunkAccess> requestChunkFuture =
|
||||
this.requestChunkFromServerAsync(chunkPos)
|
||||
// log errors if necessary
|
||||
.whenCompleteAsync(
|
||||
(chunk, throwable) ->
|
||||
{
|
||||
// unwrap the CompletionException if necessary
|
||||
Throwable actualThrowable = throwable;
|
||||
while (actualThrowable instanceof CompletionException)
|
||||
{
|
||||
actualThrowable = actualThrowable.getCause();
|
||||
}
|
||||
|
||||
if (actualThrowable != null)
|
||||
{
|
||||
// ignore expected shutdown exceptions
|
||||
boolean isShutdownException =
|
||||
ExceptionUtil.isShutdownException(actualThrowable)
|
||||
|| actualThrowable.getMessage().contains("Unloaded chunk");
|
||||
if (!isShutdownException)
|
||||
{
|
||||
CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load chunk [" + chunkPos + "] from server, error: [" + actualThrowable.getMessage() + "].", actualThrowable);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
getChunkFutureList.add(requestChunkFuture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============================//
|
||||
// wait for generation requests //
|
||||
//==============================//
|
||||
|
||||
// Join-ing each thread will prevent DH from working on anything else
|
||||
// but will also prevent over-queuing world gen tasks.
|
||||
// If C2ME is present the CPU will still be well utilized.
|
||||
|
||||
ArrayList<IChunkWrapper> chunkWrappers = new ArrayList<>();
|
||||
for (int i = 0; i < getChunkFutureList.size(); i++)
|
||||
{
|
||||
CompletableFuture<ChunkAccess> getChunkFuture = getChunkFutureList.get(i);
|
||||
ChunkAccess chunk = getChunkFuture.join();
|
||||
if (chunk != null)
|
||||
{
|
||||
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper());
|
||||
chunkWrapper.createDhHeightMaps();
|
||||
chunkWrappers.add(chunkWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================//
|
||||
// process generated chunks //
|
||||
//==========================//
|
||||
|
||||
int maxSkyLight = this.dhServerLevel.getServerLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT;
|
||||
for (int i = 0; i < chunkWrappers.size(); i++)
|
||||
{
|
||||
ChunkWrapper chunkWrapper = (ChunkWrapper)chunkWrappers.get(i);
|
||||
|
||||
// pre-generated chunks should have lighting but new ones won't
|
||||
if (!chunkWrapper.isDhBlockLightingCorrect())
|
||||
{
|
||||
DhLightingEngine.INSTANCE.bakeChunkBlockLighting(chunkWrapper, chunkWrappers, maxSkyLight);
|
||||
}
|
||||
|
||||
this.dhServerLevel.updateBeaconBeamsForChunk(chunkWrapper, chunkWrappers);
|
||||
genEvent.resultConsumer.accept(chunkWrapper);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// release all chunks from the server to prevent out of memory issues
|
||||
Iterator<ChunkPos> chunkPosIterator = ChunkPosGenStream.getIterator(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0);
|
||||
while (chunkPosIterator.hasNext())
|
||||
{
|
||||
ChunkPos chunkPos = chunkPosIterator.next();
|
||||
this.releaseChunkFromServer(this.params.mcServerLevel, chunkPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void runValidation()
|
||||
{
|
||||
// DH thread check
|
||||
if (!DhApi.isDhThread()
|
||||
&& ModInfo.IS_DEV_BUILD)
|
||||
{
|
||||
throw new IllegalStateException("Internal server generation should be called from one of DH's world gen thread. Current thread: ["+Thread.currentThread().getName()+"]");
|
||||
}
|
||||
|
||||
|
||||
// C2ME present?
|
||||
if (C2ME_ACCESSOR == null
|
||||
&& !c2meMissingWarningLogged)
|
||||
{
|
||||
c2meMissingWarningLogged = true;
|
||||
|
||||
String c2meWarning = "C2ME missing, \n" +
|
||||
"low CPU usage and slow world gen speeds expected. \n" +
|
||||
"DH is set to use MC's internal server for world gen \n" +
|
||||
"this mode is less efficient unless a mod like C2ME is present."
|
||||
;
|
||||
|
||||
if (Config.Common.Logging.Warning.showSlowWorldGenSettingWarnings.get())
|
||||
{
|
||||
String message =
|
||||
MinecraftTextFormat.ORANGE + "Distant Horizons: slow world gen." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||
c2meWarning;
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||
}
|
||||
|
||||
LOGGER.warn(c2meWarning);
|
||||
}
|
||||
}
|
||||
private CompletableFuture<ChunkAccess> requestChunkFromServerAsync(ChunkPos chunkPos)
|
||||
{
|
||||
return CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
ServerLevel level = this.params.mcServerLevel;
|
||||
|
||||
// ignore chunk update events for this position
|
||||
SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.addPosToIgnore(new DhChunkPos(chunkPos.x, chunkPos.z));
|
||||
|
||||
#if MC_VER < MC_1_21_5
|
||||
int chunkLevel = 33; // 33 is equivalent to FULL Chunk
|
||||
level.getChunkSource().distanceManager.addTicket(DH_SERVER_GEN_TICKET, chunkPos, chunkLevel, chunkPos);
|
||||
#else
|
||||
level.getChunkSource().addTicketWithRadius(DH_SERVER_GEN_TICKET, chunkPos, 0);
|
||||
#endif
|
||||
|
||||
// probably not the most optimal to run updates here, but fast enough
|
||||
level.getChunkSource().distanceManager.runAllUpdates(level.getChunkSource().chunkMap);
|
||||
|
||||
ChunkHolder chunkHolder = level.getChunkSource().chunkMap.getUpdatingChunkIfPresent(chunkPos.toLong());
|
||||
if (chunkHolder == null)
|
||||
{
|
||||
throw new IllegalStateException("No chunk chunkHolder for pos ["+chunkPos+"] after ticket has been added.");
|
||||
}
|
||||
|
||||
#if MC_VER <= MC_1_20_4
|
||||
return chunkHolder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap)
|
||||
.thenApply(result -> result.left().orElseThrow(() -> new RuntimeException(result.right().get().toString()))); // can throw if the server is shutting down
|
||||
#elif MC_VER <= MC_1_20_6
|
||||
return chunkHolder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap)
|
||||
.thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.toString()))); // can throw if the server is shutting down
|
||||
#else
|
||||
return chunkHolder.scheduleChunkGenerationTask(ChunkStatus.FEATURES, level.getChunkSource().chunkMap)
|
||||
.thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.getError()))); // can throw if the server is shutting down
|
||||
#endif
|
||||
|
||||
}, this.params.mcServerLevel.getChunkSource().chunkMap.mainThreadExecutor)
|
||||
.thenCompose(Function.identity());
|
||||
}
|
||||
/**
|
||||
* mitigates out of memory issues in the vanilla chunk system. <br>
|
||||
* See: https://github.com/pop4959/Chunky/pull/383
|
||||
*/
|
||||
private void releaseChunkFromServer(ServerLevel level, ChunkPos chunkPos)
|
||||
{
|
||||
level.getChunkSource().chunkMap.mainThreadExecutor.execute(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
int chunkLevel = 33; // 33 is equivalent to FULL Chunk
|
||||
level.getChunkSource().distanceManager.removeTicket(DH_SERVER_GEN_TICKET, chunkPos, chunkLevel, chunkPos);
|
||||
#else
|
||||
level.getChunkSource().removeTicketWithRadius(DH_SERVER_GEN_TICKET, chunkPos, 0);
|
||||
#endif
|
||||
|
||||
level.getChunkSource().chunkMap.tick(() -> false);
|
||||
|
||||
#if MC_VER > MC_1_16_5
|
||||
level.entityManager.tick();
|
||||
#endif
|
||||
|
||||
|
||||
// give MC a few seconds to save the chunk before
|
||||
// we can process update events there again
|
||||
this.chunkSaveIgnoreTimer.schedule(new TimerTask()
|
||||
{
|
||||
@Override
|
||||
public void run() { SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.removePosToIgnore(new DhChunkPos(chunkPos.x, chunkPos.z)); }
|
||||
}, MS_TO_IGNORE_CHUNK_AFTER_COMPLETION);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warn("Failed to release chunk back to internal server. Error: ["+e.getMessage()+"]", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
-109
@@ -1,109 +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.common.wrappers.worldGeneration;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment.PerfCalculator;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.WorldGenStructFeatManager;
|
||||
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.structure.StructureCheck;
|
||||
#endif
|
||||
|
||||
public final class ThreadedParameters
|
||||
{
|
||||
private static final ThreadLocal<ThreadedParameters> LOCAL_PARAM = new ThreadLocal<>();
|
||||
|
||||
final ServerLevel level;
|
||||
public WorldGenStructFeatManager structFeat = null;
|
||||
#if MC_VER >= MC_1_18_2
|
||||
public StructureCheck structCheck;
|
||||
#endif
|
||||
boolean isValid = true;
|
||||
public final PerfCalculator perf = new PerfCalculator();
|
||||
|
||||
private static GlobalParameters previousGlobalParameters = null;
|
||||
|
||||
|
||||
|
||||
public static ThreadedParameters getOrMake(GlobalParameters param)
|
||||
{
|
||||
ThreadedParameters tParam = LOCAL_PARAM.get();
|
||||
if (tParam != null && tParam.isValid && tParam.level == param.level)
|
||||
{
|
||||
return tParam;
|
||||
}
|
||||
|
||||
tParam = new ThreadedParameters(param);
|
||||
LOCAL_PARAM.set(tParam);
|
||||
return tParam;
|
||||
}
|
||||
|
||||
private ThreadedParameters(GlobalParameters param)
|
||||
{
|
||||
previousGlobalParameters = param;
|
||||
|
||||
this.level = param.level;
|
||||
#if MC_VER < MC_1_18_2
|
||||
this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, level);
|
||||
#elif MC_VER < MC_1_19_2
|
||||
this.structCheck = this.createStructureCheck(param);
|
||||
#else
|
||||
this.structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
||||
param.level.dimension(), param.generator, param.randomState, level, param.generator.getBiomeSource(), param.worldSeed,
|
||||
param.fixerUpper);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void markAsInvalid() { isValid = false; }
|
||||
|
||||
public void makeStructFeat(WorldGenLevel genLevel, GlobalParameters param)
|
||||
{
|
||||
#if MC_VER < MC_1_19_4
|
||||
structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel #if MC_VER >= MC_1_18_2 , structCheck #endif );
|
||||
#else
|
||||
structFeat = new WorldGenStructFeatManager(param.worldOptions, genLevel, structCheck);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if MC_VER >= MC_1_18_2 && MC_VER < MC_1_19_2
|
||||
public void recreateStructureCheck()
|
||||
{
|
||||
if (previousGlobalParameters != null)
|
||||
{
|
||||
this.structCheck = createStructureCheck(previousGlobalParameters);
|
||||
}
|
||||
}
|
||||
private StructureCheck createStructureCheck(GlobalParameters param)
|
||||
{
|
||||
return new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
||||
param.level.dimension(), param.generator, this.level, param.generator.getBiomeSource(), param.worldSeed,
|
||||
param.fixerUpper);
|
||||
}
|
||||
#else
|
||||
public void recreateStructureCheck() { /* do nothing */ }
|
||||
#endif
|
||||
|
||||
}
|
||||
+745
@@ -0,0 +1,745 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU GPL 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 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.level.IDhServerLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import net.minecraft.core.Registry;
|
||||
#if MC_VER >= MC_1_19_4
|
||||
import net.minecraft.core.registries.Registries;
|
||||
#endif
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.world.level.*;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.Biomes;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.*;
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
|
||||
#else
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_21_9
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
#else
|
||||
#endif
|
||||
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
#if MC_VER >= MC_1_18_2
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
||||
#endif
|
||||
import net.minecraft.world.ticks.LevelChunkTicks;
|
||||
#endif
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.core.Holder;
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
#endif
|
||||
|
||||
#if MC_VER == MC_1_20_6
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.status.ChunkType;
|
||||
#elif MC_VER >= MC_1_21_1
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
#endif
|
||||
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
|
||||
|
||||
public class ChunkCompoundTagParser
|
||||
{
|
||||
public static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||
.name("LOD Chunk Reader")
|
||||
.fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile)
|
||||
.build();
|
||||
|
||||
private static final AtomicBoolean ZERO_CHUNK_POS_ERROR_LOGGED_REF = new AtomicBoolean(false);
|
||||
private static final ConcurrentHashMap<String, Object> LOGGED_ERROR_MESSAGE_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private static boolean lightingSectionErrorLogged = false;
|
||||
|
||||
|
||||
|
||||
|
||||
//============//
|
||||
// read chunk //
|
||||
//============//
|
||||
|
||||
public static ChunkWrapper createFromTag(
|
||||
WorldGenLevel mcWorldGenLevel, IDhServerLevel dhServerLevel,
|
||||
ChunkPos chunkPos, CompoundTag chunkData)
|
||||
{
|
||||
#if MC_VER < MC_1_18_2
|
||||
CompoundTag tagLevel = chunkData.getCompound("Level");
|
||||
#else
|
||||
CompoundTag tagLevel = chunkData;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//=======================//
|
||||
// validate the chunkPos //
|
||||
//=======================//
|
||||
|
||||
int chunkX = CompoundTagUtil.getInt(tagLevel,"xPos");
|
||||
int chunkZ = CompoundTagUtil.getInt(tagLevel, "zPos");
|
||||
ChunkPos actualChunkPos = new ChunkPos(chunkX, chunkZ);
|
||||
|
||||
// confirm chunk pos is correct
|
||||
if (!Objects.equals(chunkPos, actualChunkPos))
|
||||
{
|
||||
if (chunkX == 0 && chunkZ == 0)
|
||||
{
|
||||
if (!ZERO_CHUNK_POS_ERROR_LOGGED_REF.getAndSet(true))
|
||||
{
|
||||
// explicit chunkPos toString is necessary otherwise the JDK 17 compiler breaks
|
||||
LOGGER.warn("Chunk file at ["+chunkPos.toString()+"] doesn't have a chunk pos. \n" +
|
||||
"This might happen if the world was created using an external program. \n" +
|
||||
"DH will attempt to parse the chunk anyway and won't log this message again.\n" +
|
||||
"If issues arise please try optimizing your world to fix this issue. \n" +
|
||||
"World optimization can be done from the singleplayer world selection screen." +
|
||||
" ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.error("Chunk file at ["+chunkPos.toString()+"] is in the wrong location. \n" +
|
||||
"Please try optimizing your world to fix this issue. \n" +
|
||||
"World optimization can be done from the singleplayer world selection screen. \n" +
|
||||
"(Expected pos: ["+chunkPos.toString()+"], actual ["+actualChunkPos.toString()+"])" +
|
||||
" ");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// get ticks //
|
||||
//===========//
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer(
|
||||
mcWorldGenLevel.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), #if MC_VER >= MC_1_17_1 mcWorldGenLevel, #endif
|
||||
chunkPos, mcWorldGenLevel.getLevel().getChunkSource().getGenerator().getBiomeSource(),
|
||||
tagLevel.contains("Biomes", 11) ? tagLevel.getIntArray("Biomes") : null);
|
||||
|
||||
String BLOCK_TICKS_TAG_PRE18 = "TileTicks";
|
||||
TickList<Block> blockTicks = tagLevel.contains(BLOCK_TICKS_TAG_PRE18, 9)
|
||||
? ChunkTickList.create(tagLevel.getList(BLOCK_TICKS_TAG_PRE18, 10), Registry.BLOCK::getKey, Registry.BLOCK::get)
|
||||
: new ProtoTickList<Block>(block -> (block == null || block.defaultBlockState().isAir()), chunkPos,
|
||||
tagLevel.getList("ToBeTicked", 9) #if MC_VER >= MC_1_17_1 , mcWorldGenLevel #endif );
|
||||
|
||||
String FLUID_TICKS_TAG_PRE18 = "LiquidTicks";
|
||||
TickList<Fluid> fluidTicks = tagLevel.contains(FLUID_TICKS_TAG_PRE18, 9)
|
||||
? ChunkTickList.create(tagLevel.getList(FLUID_TICKS_TAG_PRE18, 10), Registry.FLUID::getKey, Registry.FLUID::get)
|
||||
: new ProtoTickList<Fluid>(fluid -> (fluid == null || fluid == Fluids.EMPTY), chunkPos,
|
||||
tagLevel.getList("LiquidsToBeTicked", 9) #if MC_VER >= MC_1_17_1 , mcWorldGenLevel #endif );
|
||||
#else
|
||||
// ticks shouldn't be needed so ignore them for MC versions after 1.18.2
|
||||
LevelChunkTicks<Block> blockTicks = new LevelChunkTicks<>();
|
||||
LevelChunkTicks<Fluid> fluidTicks = new LevelChunkTicks<>();
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//=====================//
|
||||
// get misc properties //
|
||||
//=====================//
|
||||
|
||||
int sectionYCount = #if MC_VER < MC_1_17_1 16; #else mcWorldGenLevel.getSectionsCount(); #endif
|
||||
LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYCount];
|
||||
boolean hasBlocks = readAndPopulateSections(mcWorldGenLevel, chunkPos, tagLevel, chunkSections);
|
||||
if (!hasBlocks)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
long inhabitedTime = CompoundTagUtil.getLong(tagLevel, "InhabitedTime");
|
||||
boolean isLightOn = CompoundTagUtil.getBoolean(tagLevel, "isLightOn");
|
||||
|
||||
|
||||
|
||||
//============//
|
||||
// make chunk //
|
||||
//============//
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
LevelChunk chunk = new LevelChunk((Level) mcWorldGenLevel.getLevel(), chunkPos, chunkBiomeContainer, UpgradeData.EMPTY, blockTicks,
|
||||
fluidTicks, inhabitedTime, chunkSections, null);
|
||||
#else
|
||||
LevelChunk chunk = new LevelChunk((Level) mcWorldGenLevel, chunkPos, UpgradeData.EMPTY, blockTicks,
|
||||
fluidTicks, inhabitedTime, chunkSections, null, null);
|
||||
#endif
|
||||
|
||||
// Set some states after object creation
|
||||
chunk.setLightCorrect(isLightOn);
|
||||
boolean hasHeightmapData = readHeightmaps(chunk, chunkData);
|
||||
|
||||
// chunk wrapper so we can pass along extra data more easily
|
||||
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, dhServerLevel.getServerLevelWrapper());
|
||||
chunkWrapper.createDhHeightMaps();
|
||||
|
||||
|
||||
|
||||
//===========================//
|
||||
// check if chunk has blocks //
|
||||
//===========================//
|
||||
|
||||
// in some MC versions all the NBT data will be there
|
||||
// but the chunk will be totally empty,
|
||||
// usually this means the chunk was only partially generated.
|
||||
// If that happens we should try to generate the chunk from scratch
|
||||
// otherwise we can end up with large empty holes in the world.
|
||||
|
||||
// walking through the heightmap (recreated by DH if missing)
|
||||
// is a fast way to check if there are any blocks in the chunk
|
||||
boolean chunkHasBlocks = false;
|
||||
int serverMinHeight = dhServerLevel.getServerLevelWrapper().getMinHeight();
|
||||
for (int x = 0; x < 16 && !chunkHasBlocks; x++)
|
||||
{
|
||||
for (int z = 0; z < 16 && !chunkHasBlocks; z++)
|
||||
{
|
||||
int heightMap = Math.max(
|
||||
// max between both heightmaps just in case there's a discrepancy
|
||||
chunkWrapper.getLightBlockingHeightMapValue(x, z),
|
||||
chunkWrapper.getSolidHeightMapValue(x, z)
|
||||
);
|
||||
if (heightMap != serverMinHeight)
|
||||
{
|
||||
chunkHasBlocks = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (chunkHasBlocks)
|
||||
{
|
||||
return chunkWrapper;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no blocks detected, this chunk should be generated from scratch
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// chunk sections //
|
||||
// (Blocks/biomes) //
|
||||
//=================//
|
||||
|
||||
/** handles both blocks and biomes */
|
||||
private static boolean readAndPopulateSections(
|
||||
LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData,
|
||||
LevelChunkSection[] chunkSections)
|
||||
{
|
||||
int sectionYCount = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif
|
||||
|
||||
ListTag tagSections = CompoundTagUtil.getListTag(chunkData, "Sections", 10);
|
||||
// try lower-case "sections" if capital "Sections" is missing
|
||||
if (tagSections == null
|
||||
|| tagSections.isEmpty())
|
||||
{
|
||||
tagSections = CompoundTagUtil.getListTag(chunkData, "sections", 10);
|
||||
}
|
||||
|
||||
|
||||
boolean blocksFound = false;
|
||||
if (tagSections != null)
|
||||
{
|
||||
for (int i = 0; i < tagSections.size(); ++i)
|
||||
{
|
||||
CompoundTag tagSection = CompoundTagUtil.getCompoundTag(tagSections, i);
|
||||
if (tagSection == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final int sectionYPos = CompoundTagUtil.getByte(tagSection, "Y");
|
||||
|
||||
|
||||
|
||||
//===================//
|
||||
// get blocks/biomes //
|
||||
//===================//
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
if (tagSection.contains("Palette", 9)
|
||||
&& tagSection.contains("BlockStates", 12))
|
||||
{
|
||||
LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4);
|
||||
levelChunkSection.getStates().read(tagSection.getList("Palette", 10), tagSection.getLongArray("BlockStates"));
|
||||
levelChunkSection.recalcBlockCounts();
|
||||
if (!levelChunkSection.isEmpty())
|
||||
{
|
||||
int sectionIndex;
|
||||
#if MC_VER < MC_1_17_1
|
||||
sectionIndex = sectionYPos;
|
||||
#else
|
||||
sectionIndex = level.getSectionIndexFromSectionY(sectionYPos);
|
||||
#endif
|
||||
|
||||
chunkSections[sectionIndex] = levelChunkSection;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int sectionId = level.getSectionIndexFromSectionY(sectionYPos);
|
||||
if (sectionId >= 0
|
||||
&& sectionId < chunkSections.length)
|
||||
{
|
||||
//========//
|
||||
// blocks //
|
||||
//========//
|
||||
|
||||
PalettedContainer<BlockState> blockStateContainer;
|
||||
|
||||
boolean containsBlockStates = CompoundTagUtil.contains(tagSection, "block_states", 10);
|
||||
if (containsBlockStates)
|
||||
{
|
||||
Codec<PalettedContainer<BlockState>> blockStateCodec = getBlockStateCodec(level);
|
||||
|
||||
#if MC_VER < MC_1_20_6
|
||||
blockStateContainer = blockStateCodec
|
||||
.parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "block_states"))
|
||||
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
|
||||
.getOrThrow(false, (message) -> logParsingWarningOnce(message));
|
||||
#else
|
||||
blockStateContainer = blockStateCodec
|
||||
.parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "block_states"))
|
||||
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
|
||||
.getOrThrow((message) -> logErrorAndReturnException(message));
|
||||
#endif
|
||||
|
||||
blocksFound = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if MC_VER < MC_1_21_9
|
||||
blockStateContainer = new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
||||
#else
|
||||
blockStateContainer = PalettedContainerFactory.create(level.registryAccess()).createForBlockStates();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//========//
|
||||
// biomes //
|
||||
//========//
|
||||
|
||||
Registry<Biome> biomeRegistry = getBiomeRegistry(level);
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
Codec<PalettedContainer<Biome>> biomeCodec;
|
||||
#else
|
||||
Codec<PalettedContainer<Holder<Biome>>> biomeCodec;
|
||||
#endif
|
||||
biomeCodec = getBiomeCodec(level, biomeRegistry);
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
PalettedContainer<Biome> biomeContainer;
|
||||
#else
|
||||
PalettedContainer<Holder<Biome>> biomeContainer;
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
biomeContainer = tagSection.contains("biomeRegistry", 10)
|
||||
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomeRegistry")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, (message) -> logWarningOnce(message))
|
||||
: new PalettedContainer<Biome>(biomeRegistry, biomeRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
#else
|
||||
{
|
||||
CompoundTag biomeTag = CompoundTagUtil.getCompoundTag(tagSection, "biomeRegistry");
|
||||
if (biomeTag == null)
|
||||
{
|
||||
biomeTag = CompoundTagUtil.getCompoundTag(tagSection, "biomes");
|
||||
}
|
||||
|
||||
if (biomeTag != null
|
||||
&& !biomeTag.isEmpty())
|
||||
{
|
||||
#if MC_VER < MC_1_20_6
|
||||
biomeContainer = new PalettedContainer<Holder<Biome>>(
|
||||
biomeRegistry.asHolderIdMap(),
|
||||
biomeRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
#else
|
||||
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, biomeTag)
|
||||
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYCount, (String) string))
|
||||
.getOrThrow((message) -> logErrorAndReturnException(message));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// no biomes found, use the default (probably plains)
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
biomeContainer = new PalettedContainer<Holder<Biome>>(
|
||||
biomeRegistry.asHolderIdMap(),
|
||||
biomeRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
#elif MC_VER < MC_1_21_9
|
||||
biomeContainer = new PalettedContainer<Holder<Biome>>(biomeRegistry.asHolderIdMap(),
|
||||
biomeRegistry.getOrThrow(Biomes.PLAINS),
|
||||
PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
#else
|
||||
biomeContainer = PalettedContainerFactory.create(level.registryAccess()).createForBiomes();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_20_1
|
||||
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
|
||||
#else
|
||||
chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return blocksFound;
|
||||
}
|
||||
|
||||
private static Codec<PalettedContainer<BlockState>> getBlockStateCodec(LevelAccessor level)
|
||||
{
|
||||
#if MC_VER < MC_1_18_2
|
||||
return null; // unused for older MC versions
|
||||
#elif MC_VER < MC_1_19_2
|
||||
return PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
||||
#elif MC_VER <= MC_1_21_8
|
||||
return PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
||||
#else
|
||||
return PalettedContainerFactory.create(level.registryAccess()).blockStatesContainerCodec();
|
||||
#endif
|
||||
}
|
||||
|
||||
private static Registry<Biome> getBiomeRegistry(LevelAccessor level)
|
||||
{
|
||||
#if MC_VER < MC_1_18_2
|
||||
// not needed
|
||||
return null;
|
||||
#elif MC_VER < MC_1_19_4
|
||||
return level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
|
||||
#elif MC_VER < MC_1_21_3
|
||||
return level.registryAccess().registryOrThrow(Registries.BIOME);
|
||||
#else
|
||||
return level.registryAccess().lookupOrThrow(Registries.BIOME);
|
||||
#endif
|
||||
}
|
||||
private static
|
||||
#if MC_VER < MC_1_19_2 Codec<PalettedContainer<Biome>>
|
||||
#else Codec<PalettedContainer<Holder<Biome>>>
|
||||
#endif
|
||||
getBiomeCodec(LevelAccessor level, Registry<Biome> biomeRegistry)
|
||||
{
|
||||
#if MC_VER < MC_1_18_2
|
||||
return null; // unused for older MC versions
|
||||
#elif MC_VER < MC_1_19_2
|
||||
return PalettedContainer.codec(
|
||||
biomeRegistry, biomeRegistry.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getOrThrow(Biomes.PLAINS));
|
||||
#elif MC_VER < MC_1_19_2
|
||||
return PalettedContainer.codec(
|
||||
biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getHolderOrThrow(Biomes.PLAINS));
|
||||
#elif MC_VER < MC_1_21_3
|
||||
return PalettedContainer.codecRW(
|
||||
biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getHolderOrThrow(Biomes.PLAINS));
|
||||
#elif MC_VER < MC_1_21_9
|
||||
return PalettedContainer.codecRW(
|
||||
biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getOrThrow(Biomes.PLAINS));
|
||||
#else
|
||||
return PalettedContainer.codecRW(
|
||||
biomeRegistry.holderByNameCodec(), PalettedContainerFactory.create(level.registryAccess()).biomeStrategy(), biomeRegistry.getOrThrow(Biomes.PLAINS));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//============//
|
||||
// heightmaps //
|
||||
//============//
|
||||
|
||||
private static boolean readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
|
||||
{
|
||||
CompoundTag tagHeightmaps = CompoundTagUtil.getCompoundTag(chunkData, "Heightmaps");
|
||||
if (tagHeightmaps == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
|
||||
{
|
||||
String heightmapKey = type.getSerializationKey();
|
||||
|
||||
#if MC_VER < MC_1_21_5
|
||||
if (tagHeightmaps.contains(heightmapKey, 12))
|
||||
{
|
||||
chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmapKey));
|
||||
}
|
||||
#else
|
||||
if (tagHeightmaps.contains(heightmapKey))
|
||||
{
|
||||
Optional<long[]> optionalHeightmap = tagHeightmaps.getLongArray(heightmapKey);
|
||||
if (optionalHeightmap.isPresent())
|
||||
{
|
||||
chunk.setHeightmap(type, optionalHeightmap.get());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// chunk lighting //
|
||||
//================//
|
||||
|
||||
/** source: https://minecraft.wiki/w/Chunk_format */
|
||||
public static CombinedChunkLightStorage readLight(ChunkAccess chunk, CompoundTag chunkData)
|
||||
{
|
||||
#if MC_VER <= MC_1_17_1
|
||||
// MC 1.16 and 1.17 doesn't have the necessary NBT info
|
||||
return null;
|
||||
#else
|
||||
|
||||
CombinedChunkLightStorage combinedStorage = new CombinedChunkLightStorage(ChunkWrapper.getInclusiveMinBuildHeight(chunk), ChunkWrapper.getExclusiveMaxBuildHeight(chunk));
|
||||
ChunkLightStorage blockLightStorage = combinedStorage.blockLightStorage;
|
||||
ChunkLightStorage skyLightStorage = combinedStorage.skyLightStorage;
|
||||
|
||||
boolean foundSkyLight = false;
|
||||
|
||||
|
||||
|
||||
//===================//
|
||||
// get NBT tags info //
|
||||
//===================//
|
||||
|
||||
Tag chunkSectionTags = chunkData.get("sections");
|
||||
if (chunkSectionTags == null)
|
||||
{
|
||||
if (!lightingSectionErrorLogged)
|
||||
{
|
||||
lightingSectionErrorLogged = true;
|
||||
LOGGER.error("No sections found for chunk at pos ["+chunk.getPos()+"] chunk data may be out of date.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else if (!(chunkSectionTags instanceof ListTag))
|
||||
{
|
||||
if (!lightingSectionErrorLogged)
|
||||
{
|
||||
lightingSectionErrorLogged = true;
|
||||
LOGGER.error("Chunk section tag list have unexpected type ["+chunkSectionTags.getClass().getName()+"], expected ["+ListTag.class.getName()+"].");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
ListTag chunkSectionListTag = (ListTag) chunkSectionTags;
|
||||
|
||||
|
||||
|
||||
//===================//
|
||||
// get lighting info //
|
||||
//===================//
|
||||
|
||||
for (int sectionIndex = 0; sectionIndex < chunkSectionListTag.size(); sectionIndex++)
|
||||
{
|
||||
Tag chunkSectionTag = chunkSectionListTag.get(sectionIndex);
|
||||
if (!(chunkSectionTag instanceof CompoundTag))
|
||||
{
|
||||
if (!lightingSectionErrorLogged)
|
||||
{
|
||||
lightingSectionErrorLogged = true;
|
||||
LOGGER.error("Chunk section tag has an unexpected type ["+chunkSectionTag.getClass().getName()+"], expected ["+CompoundTag.class.getName()+"].");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
CompoundTag chunkSectionCompoundTag = (CompoundTag) chunkSectionTag;
|
||||
|
||||
|
||||
// if null all lights = 0
|
||||
byte[] blockLightNibbleArray = CompoundTagUtil.getByteArray(chunkSectionCompoundTag, "BlockLight");
|
||||
byte[] skyLightNibbleArray = CompoundTagUtil.getByteArray(chunkSectionCompoundTag, "SkyLight");
|
||||
|
||||
if (blockLightNibbleArray != null
|
||||
&& skyLightNibbleArray != null)
|
||||
{
|
||||
// if any sky light was found then all lights above will be max brightness
|
||||
if (skyLightNibbleArray.length != 0)
|
||||
{
|
||||
foundSkyLight = true;
|
||||
}
|
||||
|
||||
for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++)
|
||||
{
|
||||
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
|
||||
{
|
||||
// chunk sections are also 16 blocks tall
|
||||
for (int relY = 0; relY < LodUtil.CHUNK_WIDTH; relY++)
|
||||
{
|
||||
int blockPosIndex = relY*16*16 + relZ*16 + relX;
|
||||
byte blockLight = (blockLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(blockLightNibbleArray, blockPosIndex);
|
||||
byte skyLight = (skyLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(skyLightNibbleArray, blockPosIndex);
|
||||
if (skyLightNibbleArray.length == 0 && foundSkyLight)
|
||||
{
|
||||
skyLight = LodUtil.MAX_MC_LIGHT;
|
||||
}
|
||||
|
||||
int y = relY + (sectionIndex * LodUtil.CHUNK_WIDTH) + ChunkWrapper.getInclusiveMinBuildHeight(chunk);
|
||||
blockLightStorage.set(relX, y, relZ, blockLight);
|
||||
skyLightStorage.set(relX, y, relZ, skyLight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return combinedStorage;
|
||||
#endif
|
||||
}
|
||||
/** source: https://minecraft.wiki/w/Chunk_format#Block_Format */
|
||||
private static byte getNibbleAtIndex(byte[] arr, int index)
|
||||
{
|
||||
if (index % 2 == 0)
|
||||
{
|
||||
return (byte)(arr[index/2] & 0x0F);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (byte)((arr[index/2]>>4) & 0x0F);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// logging //
|
||||
//=========//
|
||||
|
||||
private static void logBlockDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
|
||||
{
|
||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||
{
|
||||
LOGGER.warn("Unable to deserialize blocks for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+newMessage+"]. " +
|
||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
}
|
||||
private static void logBiomeDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
|
||||
{
|
||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||
{
|
||||
LOGGER.warn("Unable to deserialize biomes for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+newMessage+"]. " +
|
||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
}
|
||||
|
||||
private static void logParsingWarningOnce(String message) { logParsingWarningOnce(message, null); }
|
||||
private static void logParsingWarningOnce(String message, Exception e)
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||
{
|
||||
LOGGER.warn("Parsing error: ["+newMessage+"]. " +
|
||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.",
|
||||
e);
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
}
|
||||
|
||||
private static RuntimeException logErrorAndReturnException(String message)
|
||||
{
|
||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||
{
|
||||
LOGGER.warn("Parsing error: ["+newMessage+"]. " +
|
||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
|
||||
// Currently we want to ignore these errors, if returning null is a problem, we can change this later
|
||||
return null; //new RuntimeException(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
public static class CombinedChunkLightStorage
|
||||
{
|
||||
public ChunkLightStorage blockLightStorage;
|
||||
public ChunkLightStorage skyLightStorage;
|
||||
|
||||
public CombinedChunkLightStorage(int minY, int maxY)
|
||||
{
|
||||
this.blockLightStorage = ChunkLightStorage.createBlockLightStorage(minY, maxY);
|
||||
this.skyLightStorage = ChunkLightStorage.createSkyLightStorage(minY, maxY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+343
@@ -0,0 +1,343 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.GlobalWorldGenParams;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.RegionFileStorageExternalCache;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.util.ExceptionUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import net.minecraft.world.level.chunk.UpgradeData;
|
||||
import net.minecraft.world.level.chunk.storage.IOWorker;
|
||||
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.ClosedByInterruptException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
#if MC_VER <= MC_1_17_1
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
#elif MC_VER <= MC_1_19_2
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.core.Registry;
|
||||
#elif MC_VER <= MC_1_19_4
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
#elif MC_VER <= MC_1_20_6
|
||||
import net.minecraft.core.registries.Registries;
|
||||
#elif MC_VER <= MC_1_21_3
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
#elif MC_VER <= MC_1_21_8
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
#elif MC_VER <= MC_1_21_9
|
||||
import net.minecraft.world.level.chunk.PalettedContainerFactory;
|
||||
#else
|
||||
import net.minecraft.world.level.chunk.PalettedContainerFactory;
|
||||
#endif
|
||||
|
||||
public class ChunkFileReader implements AutoCloseable
|
||||
{
|
||||
|
||||
public static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||
.name("LOD World Gen")
|
||||
.fileLevelConfig(Config.Common.Logging.logWorldGenEventToFile)
|
||||
.build();
|
||||
|
||||
public static final DhLogger CHUNK_LOAD_LOGGER = new DhLoggerBuilder()
|
||||
.name("LOD Chunk Loading")
|
||||
.fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile)
|
||||
.build();
|
||||
|
||||
private static final IModChecker MOD_CHECKER = SingletonInjector.INSTANCE.get(IModChecker.class);
|
||||
|
||||
public final GlobalWorldGenParams params;
|
||||
|
||||
/**
|
||||
* will be true if C2ME is installed (since they require us to
|
||||
* pull chunks using their async method), or if there
|
||||
* was an issue with the sync pulling method.
|
||||
*/
|
||||
private boolean pullExistingChunkUsingMcAsyncMethod = false;
|
||||
|
||||
private final AtomicReference<RegionFileStorageExternalCache> regionFileStorageCacheRef = new AtomicReference<>();
|
||||
public RegionFileStorageExternalCache getOrCreateRegionFileCache(RegionFileStorage storage)
|
||||
{
|
||||
RegionFileStorageExternalCache cache = this.regionFileStorageCacheRef.get();
|
||||
if (cache == null)
|
||||
{
|
||||
cache = new RegionFileStorageExternalCache(storage);
|
||||
if (!this.regionFileStorageCacheRef.compareAndSet(null, cache))
|
||||
{
|
||||
cache = this.regionFileStorageCacheRef.get();
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public ChunkFileReader(GlobalWorldGenParams params)
|
||||
{
|
||||
this.params = params;
|
||||
|
||||
if (MOD_CHECKER.isModLoaded("c2me"))
|
||||
{
|
||||
LOGGER.info("C2ME detected: DH's pre-existing chunk accessing will use methods handled by C2ME.");
|
||||
this.pullExistingChunkUsingMcAsyncMethod = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
/**
|
||||
* If the given chunk pos already exists in the world, that chunk will be returned,
|
||||
* otherwise this will return an empty chunk.
|
||||
*/
|
||||
public CompletableFuture<ChunkWrapper> createEmptyOrPreExistingChunkWrapperAsync(
|
||||
int chunkX, int chunkZ,
|
||||
Map<DhChunkPos, ChunkLightStorage> chunkSkyLightingByDhPos,
|
||||
Map<DhChunkPos, ChunkLightStorage> chunkBlockLightingByDhPos,
|
||||
Map<DhChunkPos, ChunkWrapper> generatedChunkWrapperByDhPos)
|
||||
{
|
||||
ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
|
||||
DhChunkPos dhChunkPos = new DhChunkPos(chunkX, chunkZ);
|
||||
|
||||
if (generatedChunkWrapperByDhPos.containsKey(dhChunkPos))
|
||||
{
|
||||
return CompletableFuture.completedFuture(generatedChunkWrapperByDhPos.get(dhChunkPos));
|
||||
}
|
||||
|
||||
return this.getChunkNbtDataAsync(chunkPos)
|
||||
.thenApply((CompoundTag chunkData) ->
|
||||
{
|
||||
ChunkWrapper newChunkWrapper = this.loadOrMakeChunkWrapper(chunkPos, chunkData);
|
||||
|
||||
// attempt to get chunk lighting
|
||||
ChunkCompoundTagParser.CombinedChunkLightStorage combinedLights = ChunkCompoundTagParser.readLight(newChunkWrapper.getChunk(), chunkData);
|
||||
if (combinedLights != null)
|
||||
{
|
||||
// may be empty, empty checks are handled later
|
||||
chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage);
|
||||
chunkBlockLightingByDhPos.put(dhChunkPos, combinedLights.blockLightStorage);
|
||||
}
|
||||
|
||||
return newChunkWrapper;
|
||||
})
|
||||
// separate handle so we can cleanly handle missing chunks and/or thrown errors
|
||||
.handle((ChunkWrapper newChunkWrapper, Throwable throwable) ->
|
||||
{
|
||||
if (newChunkWrapper != null)
|
||||
{
|
||||
return newChunkWrapper;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.CreateProtoChunkWrapper(this.params.mcServerLevel, chunkPos);
|
||||
}
|
||||
})
|
||||
.thenApply((ChunkWrapper newChunkWrapper) ->
|
||||
{
|
||||
generatedChunkWrapperByDhPos.put(dhChunkPos, newChunkWrapper);
|
||||
return newChunkWrapper;
|
||||
});
|
||||
}
|
||||
private CompletableFuture<CompoundTag> getChunkNbtDataAsync(ChunkPos chunkPos)
|
||||
{
|
||||
ServerLevel level = this.params.mcServerLevel;
|
||||
|
||||
try
|
||||
{
|
||||
IOWorker ioWorker = level.getChunkSource().chunkMap.worker;
|
||||
|
||||
#if MC_VER <= MC_1_18_2
|
||||
return CompletableFuture.completedFuture(ioWorker.load(chunkPos));
|
||||
#else
|
||||
|
||||
// storage will be null if C2ME is installed
|
||||
if (!this.pullExistingChunkUsingMcAsyncMethod
|
||||
&& ioWorker.storage != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
RegionFileStorage storage = this.params.mcServerLevel.getChunkSource().chunkMap.worker.storage;
|
||||
RegionFileStorageExternalCache cache = this.getOrCreateRegionFileCache(storage);
|
||||
return CompletableFuture.completedFuture(cache.read(chunkPos));
|
||||
}
|
||||
catch (NullPointerException e)
|
||||
{
|
||||
// this shouldn't happen, if anything is null it should be
|
||||
// ioWorker.storage
|
||||
// but just in case
|
||||
LOGGER.error("Unexpected issue pulling pre-existing chunk ["+chunkPos+"], falling back to async chunk pulling. This may cause server-tick lag.", e);
|
||||
this.pullExistingChunkUsingMcAsyncMethod = true;
|
||||
|
||||
// try again now using the async method
|
||||
return this.getChunkNbtDataAsync(chunkPos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// log if we unexpectedly weren't able to run the sync chunk pulling
|
||||
if (!this.pullExistingChunkUsingMcAsyncMethod)
|
||||
{
|
||||
// this shouldn't happen, but just in case
|
||||
LOGGER.info("Unable to pull pre-existing chunk using synchronous method. Falling back to async method. this may cause server-tick lag.");
|
||||
this.pullExistingChunkUsingMcAsyncMethod = true;
|
||||
}
|
||||
|
||||
//GET_CHUNK_COUNT_REF.incrementAndGet();
|
||||
|
||||
// When running in vanilla MC on versions before 1.21.4,
|
||||
// DH would attempt to run loadAsync on this same thread via a threading mixin,
|
||||
// to prevent causing lag on the server thread.
|
||||
// However, if a mod like C2ME is installed this will run on a C2ME thread instead.
|
||||
return ioWorker.loadAsync(chunkPos)
|
||||
.thenApply(optional ->
|
||||
{
|
||||
// Debugging note:
|
||||
// If there are reports of extreme memory use when C2ME is installed, that probably means
|
||||
// this method is queuing a lot of tasks (1,000+), which causes C2ME to explode.
|
||||
|
||||
//GET_CHUNK_COUNT_REF.decrementAndGet();
|
||||
//PREF_LOGGER.info("chunk getter count ["+F3Screen.NUMBER_FORMAT.format(GET_CHUNK_COUNT_REF.get())+"]");
|
||||
return optional.orElse(null);
|
||||
})
|
||||
.exceptionally((throwable) ->
|
||||
{
|
||||
// unwrap the CompletionException if necessary
|
||||
Throwable actualThrowable = throwable;
|
||||
while (actualThrowable instanceof CompletionException completionException)
|
||||
{
|
||||
actualThrowable = completionException.getCause();
|
||||
}
|
||||
|
||||
boolean isShutdownException = ExceptionUtil.isShutdownException(actualThrowable);
|
||||
if (!isShutdownException)
|
||||
{
|
||||
CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load or make chunk ["+chunkPos+"], error: ["+actualThrowable.getMessage()+"].", actualThrowable);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (ClosedByInterruptException ignore)
|
||||
{
|
||||
// this just means the world generator is being shut down
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CHUNK_LOAD_LOGGER.warn("Couldn't load or make chunk [" + chunkPos + "]. Error: [" + e.getMessage() + "].", e);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
private ChunkWrapper loadOrMakeChunkWrapper(ChunkPos chunkPos, CompoundTag chunkTagData)
|
||||
{
|
||||
ServerLevel mcServerLevel = this.params.mcServerLevel;
|
||||
|
||||
if (chunkTagData == null)
|
||||
{
|
||||
return this.CreateProtoChunkWrapper(mcServerLevel, chunkPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ChunkWrapper chunkWrapper = ChunkCompoundTagParser.createFromTag(mcServerLevel, this.params.dhServerLevel, chunkPos, chunkTagData);
|
||||
if (chunkWrapper == null)
|
||||
{
|
||||
chunkWrapper = this.CreateProtoChunkWrapper(mcServerLevel, chunkPos);
|
||||
}
|
||||
return chunkWrapper;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CHUNK_LOAD_LOGGER.error(
|
||||
"DistantHorizons: couldn't load or make chunk at [" + chunkPos + "]." +
|
||||
"Please try optimizing your world to fix this issue. \n" +
|
||||
"World optimization can be done from the singleplayer world selection screen.\n" +
|
||||
"Error: [" + e.getMessage() + "]."
|
||||
, e);
|
||||
|
||||
return this.CreateProtoChunkWrapper(mcServerLevel, chunkPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkWrapper CreateProtoChunkWrapper(ServerLevel level, ChunkPos chunkPos)
|
||||
{
|
||||
ProtoChunk chunk = CreateProtoChunk(level, chunkPos);
|
||||
return new ChunkWrapper(chunk, this.params.dhServerLevel.getLevelWrapper());
|
||||
}
|
||||
public static ProtoChunk CreateProtoChunk(ServerLevel level, ChunkPos chunkPos)
|
||||
{
|
||||
#if MC_VER <= MC_1_16_5
|
||||
return new ProtoChunk(chunkPos, UpgradeData.EMPTY);
|
||||
#elif MC_VER <= MC_1_17_1
|
||||
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level);
|
||||
#elif MC_VER <= MC_1_19_2
|
||||
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null);
|
||||
#elif MC_VER <= MC_1_19_4
|
||||
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null);
|
||||
#elif MC_VER < MC_1_21_3
|
||||
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null);
|
||||
#elif MC_VER < MC_1_21_9
|
||||
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().lookupOrThrow(Registries.BIOME), null);
|
||||
#else
|
||||
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, PalettedContainerFactory.create(level.registryAccess()), null);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
RegionFileStorageExternalCache regionStorage = this.regionFileStorageCacheRef.get();
|
||||
if (regionStorage != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
regionStorage.close();
|
||||
}
|
||||
catch (ClosedChannelException ignore) { /* world generator is being shut down */ }
|
||||
catch (IOException e)
|
||||
{
|
||||
LOGGER.error("Failed to close region file storage cache, error: ["+e.getMessage()+"].", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* these tag helpers are usedd to simplify tag accessing between MC versions
|
||||
*/
|
||||
public class CompoundTagUtil
|
||||
{
|
||||
|
||||
/** defaults to "false" if the tag isn't present */
|
||||
public static boolean getBoolean(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getBoolean(key);
|
||||
#else
|
||||
return tag.getBoolean(key).orElse(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to "0" if the tag isn't present */
|
||||
public static byte getByte(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getByte(key);
|
||||
#else
|
||||
return tag.getByte(key).orElse((byte)0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to "0" if the tag isn't present */
|
||||
public static short getShort(ListTag tag, int index)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getShort(index);
|
||||
#else
|
||||
return tag.getShort(index).orElse((short)0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to "0" if the tag isn't present */
|
||||
public static int getInt(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getInt(key);
|
||||
#else
|
||||
return tag.getInt(key).orElse(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to "0" if the tag isn't present */
|
||||
public static long getLong(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getInt(key);
|
||||
#else
|
||||
return tag.getLong(key).orElse(0L);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
public static String getString(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getString(key);
|
||||
#else
|
||||
return tag.getString(key).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
public static byte[] getByteArray(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getByteArray(key);
|
||||
#else
|
||||
return tag.getByteArray(key).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
public static CompoundTag getCompoundTag(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getCompound(key);
|
||||
#else
|
||||
return tag.getCompound(key).orElse(null);
|
||||
#endif
|
||||
}
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
public static CompoundTag getCompoundTag(ListTag tag, int index)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getCompound(index);
|
||||
#else
|
||||
return tag.getCompound(index).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* defaults to null if the tag isn't present
|
||||
* @param elementType unused after MC 1.21.5
|
||||
*/
|
||||
@Nullable
|
||||
public static ListTag getListTag(CompoundTag tag, String key, int elementType)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getList(key, elementType);
|
||||
#else
|
||||
return tag.getList(key).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
public static ListTag getListTag(ListTag tag, int index)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getList(index);
|
||||
#else
|
||||
return tag.getList(index).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static boolean contains(CompoundTag tag, String key, int index)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.contains(key, index);
|
||||
#else
|
||||
return tag.contains(key);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
-876
@@ -1,876 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU GPL 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 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
||||
import it.unimi.dsi.fastutil.shorts.ShortList;
|
||||
import net.minecraft.core.Registry;
|
||||
#if MC_VER >= MC_1_19_4
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
#endif
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.*;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.Biomes;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.*;
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
|
||||
#else
|
||||
#endif
|
||||
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.blending.BlendingData;
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
||||
#endif
|
||||
import net.minecraft.world.ticks.LevelChunkTicks;
|
||||
#endif
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.core.Holder;
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
#endif
|
||||
|
||||
#if MC_VER == MC_1_20_6
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.status.ChunkType;
|
||||
#elif MC_VER >= MC_1_21_1
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.status.ChunkType;
|
||||
#endif
|
||||
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
public class ChunkFileReader
|
||||
{
|
||||
private static final AtomicBoolean ZERO_CHUNK_POS_ERROR_LOGGED_REF = new AtomicBoolean(false);
|
||||
|
||||
private static final DhLogger LOGGER = BatchGenerationEnvironment.CHUNK_LOAD_LOGGER;
|
||||
|
||||
|
||||
#if MC_VER >= MC_1_21_9
|
||||
// BLOCK_STATE_CODEC can no longer be statically created since
|
||||
// it needs a level reference
|
||||
#elif MC_VER >= MC_1_19_2
|
||||
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
||||
#elif MC_VER >= MC_1_18_2
|
||||
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
||||
#endif
|
||||
|
||||
private static final String TAG_UPGRADE_DATA = "UpgradeData";
|
||||
private static final String BLOCK_TICKS_TAG_18 = "block_ticks";
|
||||
private static final String FLUID_TICKS_TAG_18 = "fluid_ticks";
|
||||
private static final String BLOCK_TICKS_TAG_PRE18 = "TileTicks";
|
||||
private static final String FLUID_TICKS_TAG_PRE18 = "LiquidTicks";
|
||||
|
||||
private static boolean lightingSectionErrorLogged = false;
|
||||
|
||||
private static final ConcurrentHashMap<String, Object> LOGGED_ERROR_MESSAGE_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
|
||||
//============//
|
||||
// read chunk //
|
||||
//============//
|
||||
|
||||
public static LevelChunk read(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData)
|
||||
{
|
||||
#if MC_VER < MC_1_18_2
|
||||
CompoundTag tagLevel = chunkData.getCompound("Level");
|
||||
#else
|
||||
CompoundTag tagLevel = chunkData;
|
||||
#endif
|
||||
|
||||
int chunkX = tagGetInt(tagLevel,"xPos");
|
||||
int chunkZ = tagGetInt(tagLevel, "zPos");
|
||||
ChunkPos actualPos = new ChunkPos(chunkX, chunkZ);
|
||||
|
||||
if (!Objects.equals(chunkPos, actualPos))
|
||||
{
|
||||
if (chunkX == 0 && chunkZ == 0)
|
||||
{
|
||||
if (!ZERO_CHUNK_POS_ERROR_LOGGED_REF.getAndSet(true))
|
||||
{
|
||||
// explicit chunkPos toString is necessary otherwise the JDK 17 compiler breaks
|
||||
LOGGER.warn("Chunk file at ["+chunkPos.toString()+"] doesn't have a chunk pos. \n" +
|
||||
"This might happen if the world was created using an external program. \n" +
|
||||
"DH will attempt to parse the chunk anyway and won't log this message again.\n" +
|
||||
"If issues arise please try optimizing your world to fix this issue. \n" +
|
||||
"World optimization can be done from the singleplayer world selection screen."+
|
||||
"");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// everything is on one line to fix a JDK 17 compiler issue
|
||||
// if the issue is ever resolved, feel free to make this multi-line for readability
|
||||
LOGGER.error("Chunk file at ["+chunkPos.toString()+"] is in the wrong location. \nPlease try optimizing your world to fix this issue. \nWorld optimization can be done from the singleplayer world selection screen. \n(Expected pos: ["+chunkPos.toString()+"], actual ["+actualPos.toString()+"])");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_20_6
|
||||
ChunkStatus.ChunkType chunkType;
|
||||
#else
|
||||
ChunkType chunkType;
|
||||
#endif
|
||||
chunkType = readChunkType(tagLevel);
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK)
|
||||
return null;
|
||||
#elif MC_VER < MC_1_21_6
|
||||
|
||||
BlendingData blendingData = readBlendingData(tagLevel);
|
||||
#if MC_VER < MC_1_19_2
|
||||
if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || !blendingData.oldNoise()))
|
||||
return null;
|
||||
#else
|
||||
if (chunkType == #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType.PROTOCHUNK #else ChunkType.PROTOCHUNK #endif && blendingData == null)
|
||||
return null;
|
||||
#endif
|
||||
#else
|
||||
|
||||
// ignore blending data, there appears to be an issue with parsing it in 1.21.6
|
||||
BlendingData blendingData = null;
|
||||
|
||||
if (chunkType == ChunkType.PROTOCHUNK)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
|
||||
long inhabitedTime = tagGetLong(tagLevel, "InhabitedTime");
|
||||
|
||||
//================== Read params for making the LevelChunk ==================
|
||||
|
||||
UpgradeData upgradeData = UpgradeData.EMPTY;
|
||||
// commented out 2025-06-04 as a test to see if the upgrade data
|
||||
// is actually necessary for DH or if it can be ignored
|
||||
// (if it can't be ignored we'll need to handle null responses from tagGetCompoundTag())
|
||||
//
|
||||
//#if MC_VER < MC_1_17_1
|
||||
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
|
||||
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA))
|
||||
// : UpgradeData.EMPTY;
|
||||
//#elif MC_VER < MC_1_21_5
|
||||
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
|
||||
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level)
|
||||
// : UpgradeData.EMPTY;
|
||||
//#else
|
||||
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA)
|
||||
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level)
|
||||
// : UpgradeData.EMPTY;
|
||||
//#endif
|
||||
|
||||
|
||||
boolean isLightOn = tagGetBoolean(tagLevel, "isLightOn");
|
||||
#if MC_VER < MC_1_18_2
|
||||
ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer(
|
||||
level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY)#if MC_VER >= MC_1_17_1 , level #endif ,
|
||||
chunkPos, level.getLevel().getChunkSource().getGenerator().getBiomeSource(),
|
||||
tagLevel.contains("Biomes", 11) ? tagLevel.getIntArray("Biomes") : null);
|
||||
|
||||
TickList<Block> blockTicks = tagLevel.contains(BLOCK_TICKS_TAG_PRE18, 9)
|
||||
? ChunkTickList.create(tagLevel.getList(BLOCK_TICKS_TAG_PRE18, 10), Registry.BLOCK::getKey, Registry.BLOCK::get)
|
||||
: new ProtoTickList<Block>(block -> (block == null || block.defaultBlockState().isAir()), chunkPos,
|
||||
tagLevel.getList("ToBeTicked", 9)#if MC_VER >= MC_1_17_1 , level #endif );
|
||||
|
||||
TickList<Fluid> fluidTicks = tagLevel.contains(FLUID_TICKS_TAG_PRE18, 9)
|
||||
? ChunkTickList.create(tagLevel.getList(FLUID_TICKS_TAG_PRE18, 10), Registry.FLUID::getKey, Registry.FLUID::get)
|
||||
: new ProtoTickList<Fluid>(fluid -> (fluid == null || fluid == Fluids.EMPTY), chunkPos,
|
||||
tagLevel.getList("LiquidsToBeTicked", 9)#if MC_VER >= MC_1_17_1 , level #endif );
|
||||
#else
|
||||
#if MC_VER < MC_1_19_4
|
||||
LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10),
|
||||
string -> Registry.BLOCK.getOptional(ResourceLocation.tryParse(string)), chunkPos);
|
||||
LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10),
|
||||
string -> Registry.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos);
|
||||
#elif MC_VER < MC_1_21_4
|
||||
LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10),
|
||||
(string -> BuiltInRegistries.BLOCK.getOptional(ResourceLocation.tryParse(string))), chunkPos);
|
||||
LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10),
|
||||
string -> BuiltInRegistries.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos);
|
||||
#else
|
||||
// do we need the ticks for what we're doing?
|
||||
LevelChunkTicks<Block> blockTicks = new LevelChunkTicks<>();
|
||||
LevelChunkTicks<Fluid> fluidTicks = new LevelChunkTicks<>();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
LevelChunkSection[] levelChunkSections = readSections(level, chunkPos, tagLevel);
|
||||
|
||||
// ====================== Make the chunk =========================
|
||||
#if MC_VER < MC_1_18_2
|
||||
LevelChunk chunk = new LevelChunk((Level) level.getLevel(), chunkPos, chunkBiomeContainer, upgradeData, blockTicks,
|
||||
fluidTicks, inhabitedTime, levelChunkSections, null);
|
||||
#else
|
||||
LevelChunk chunk = new LevelChunk((Level) level, chunkPos, upgradeData, blockTicks,
|
||||
fluidTicks, inhabitedTime, levelChunkSections, null, blendingData);
|
||||
#endif
|
||||
// Set some states after object creation
|
||||
chunk.setLightCorrect(isLightOn);
|
||||
readHeightmaps(chunk, chunkData);
|
||||
//readPostPocessings(chunk, chunkData);
|
||||
return chunk;
|
||||
}
|
||||
private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData)
|
||||
{
|
||||
#if MC_VER < MC_1_21_9
|
||||
// BLOCK_STATE_CODEC is created statically
|
||||
// TODO clean up this code separation
|
||||
#else
|
||||
final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainerFactory.create(level.registryAccess()).blockStatesContainerCodec();
|
||||
#endif
|
||||
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
#if MC_VER < MC_1_19_4
|
||||
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
|
||||
#elif MC_VER < MC_1_21_3
|
||||
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registries.BIOME);
|
||||
#else
|
||||
Registry<Biome> biomes = level.registryAccess().lookupOrThrow(Registries.BIOME);
|
||||
#endif
|
||||
#if MC_VER < MC_1_18_2
|
||||
Codec<PalettedContainer<Biome>> biomeCodec = PalettedContainer.codec(
|
||||
biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
|
||||
#elif MC_VER < MC_1_19_2
|
||||
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codec(
|
||||
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
|
||||
#elif MC_VER < MC_1_21_3
|
||||
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
|
||||
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
|
||||
#elif MC_VER < MC_1_21_9
|
||||
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
|
||||
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
|
||||
#else
|
||||
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
|
||||
biomes.holderByNameCodec(), PalettedContainerFactory.create(level.registryAccess()).biomeStrategy(), biomes.getOrThrow(Biomes.PLAINS));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int sectionYIndex = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif
|
||||
LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYIndex];
|
||||
|
||||
ListTag tagSections = tagGetListTag(chunkData, "Sections", 10);
|
||||
if (tagSections == null || tagSections.isEmpty())
|
||||
{
|
||||
tagSections = tagGetListTag(chunkData, "sections", 10);
|
||||
}
|
||||
|
||||
|
||||
if (tagSections != null)
|
||||
{
|
||||
for (int j = 0; j < tagSections.size(); ++j)
|
||||
{
|
||||
CompoundTag tagSection = tagGetCompoundTag(tagSections, j);
|
||||
if (tagSection == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final int sectionYPos = tagGetByte(tagSection, "Y");
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
if (tagSection.contains("Palette", 9) && tagSection.contains("BlockStates", 12))
|
||||
{
|
||||
LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4);
|
||||
levelChunkSection.getStates().read(tagSection.getList("Palette", 10),
|
||||
tagSection.getLongArray("BlockStates"));
|
||||
levelChunkSection.recalcBlockCounts();
|
||||
if (!levelChunkSection.isEmpty())
|
||||
chunkSections[#if MC_VER < MC_1_17_1 sectionYPos #else level.getSectionIndexFromSectionY(sectionYPos) #endif ]
|
||||
= levelChunkSection;
|
||||
}
|
||||
#else
|
||||
int sectionId = level.getSectionIndexFromSectionY(sectionYPos);
|
||||
if (sectionId >= 0 && sectionId < chunkSections.length)
|
||||
{
|
||||
PalettedContainer<BlockState> blockStateContainer;
|
||||
#if MC_VER < MC_1_18_2
|
||||
PalettedContainer<Biome> biomeContainer;
|
||||
#else
|
||||
PalettedContainer<Holder<Biome>> biomeContainer;
|
||||
#endif
|
||||
|
||||
|
||||
boolean containsBlockStates;
|
||||
#if MC_VER < MC_1_21_5
|
||||
containsBlockStates = tagSection.contains("block_states", 10);
|
||||
#else
|
||||
containsBlockStates = tagSection.contains("block_states");
|
||||
#endif
|
||||
|
||||
if (containsBlockStates)
|
||||
{
|
||||
#if MC_VER < MC_1_20_6
|
||||
blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states"))
|
||||
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
|
||||
.getOrThrow(false, (message) -> logParsingWarningOnce(message));
|
||||
#else
|
||||
blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states"))
|
||||
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
|
||||
.getOrThrow((message) -> logErrorAndReturnException(message));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if MC_VER < MC_1_21_9
|
||||
blockStateContainer = new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
||||
#else
|
||||
blockStateContainer = PalettedContainerFactory.create(level.registryAccess()).createForBlockStates();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
biomeContainer = tagSection.contains("biomes", 10)
|
||||
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, (message) -> logWarningOnce(message))
|
||||
: new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
#else
|
||||
|
||||
|
||||
boolean containsBiomes;
|
||||
#if MC_VER < MC_1_21_5
|
||||
containsBiomes = tagSection.contains("biomes", 10);
|
||||
#else
|
||||
containsBiomes = tagSection.contains("biomes");
|
||||
#endif
|
||||
|
||||
if (containsBiomes)
|
||||
{
|
||||
#if MC_VER < MC_1_20_6
|
||||
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes"))
|
||||
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
|
||||
.getOrThrow(false, (message) -> logParsingWarningOnce(message));
|
||||
#else
|
||||
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes"))
|
||||
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
|
||||
.getOrThrow((message) -> logErrorAndReturnException(message));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if MC_VER < MC_1_21_3
|
||||
biomeContainer = new PalettedContainer<Holder<Biome>>(
|
||||
biomes.asHolderIdMap(),
|
||||
biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
#elif MC_VER < MC_1_21_9
|
||||
biomeContainer = new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(),
|
||||
biomes.getOrThrow(Biomes.PLAINS),
|
||||
PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
#else
|
||||
biomeContainer = PalettedContainerFactory.create(level.registryAccess()).createForBiomes();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_20_1
|
||||
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
|
||||
#else
|
||||
chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
return chunkSections;
|
||||
}
|
||||
private static
|
||||
#if MC_VER < MC_1_20_6 ChunkStatus.ChunkType
|
||||
#elif MC_VER < MC_1_21_1 ChunkType
|
||||
#else ChunkType #endif
|
||||
readChunkType(CompoundTag tagLevel)
|
||||
{
|
||||
String statusString = tagGetString(tagLevel,"Status");
|
||||
if (statusString != null)
|
||||
{
|
||||
ChunkStatus chunkStatus = ChunkStatus.byName(statusString);
|
||||
if (chunkStatus != null)
|
||||
{
|
||||
return chunkStatus.getChunkType();
|
||||
}
|
||||
}
|
||||
|
||||
#if MC_VER <= MC_1_20_4
|
||||
return ChunkStatus.ChunkType.PROTOCHUNK;
|
||||
#else
|
||||
return ChunkType.PROTOCHUNK;
|
||||
#endif
|
||||
}
|
||||
private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
|
||||
{
|
||||
CompoundTag tagHeightmaps = tagGetCompoundTag(chunkData, "Heightmaps");
|
||||
if (tagHeightmaps != null)
|
||||
{
|
||||
for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
|
||||
{
|
||||
String heightmap = type.getSerializationKey();
|
||||
#if MC_VER < MC_1_21_5
|
||||
if (tagHeightmaps.contains(heightmap, 12))
|
||||
{
|
||||
chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap));
|
||||
}
|
||||
#else
|
||||
if (tagHeightmaps.contains(heightmap))
|
||||
{
|
||||
Optional<long[]> optionalHeightmap = tagHeightmaps.getLongArray(heightmap);
|
||||
if (optionalHeightmap.isPresent())
|
||||
{
|
||||
chunk.setHeightmap(type, optionalHeightmap.get());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
|
||||
}
|
||||
}
|
||||
// commented out as a test as of 2025-06-04 to see if this is actually necessary for DH
|
||||
// DH probably doesn't need any chunk post-processing data
|
||||
//private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
|
||||
//{
|
||||
// ListTag tagPostProcessings = tagGetListTag(chunkData,"PostProcessing", 9);
|
||||
// if (tagPostProcessings != null)
|
||||
// {
|
||||
// for (int i = 0; i < tagPostProcessings.size(); ++i)
|
||||
// {
|
||||
// ListTag listTag3 = tagGetListTag(tagPostProcessings, i);
|
||||
// for (int j = 0; j < listTag3.size(); ++j)
|
||||
// {
|
||||
// #if MC_VER < MC_1_21_3
|
||||
// chunk.addPackedPostProcess(listTag3.getShort(j), i);
|
||||
// #else
|
||||
// chunk.addPackedPostProcess(ShortList.of(tagGetShort(listTag3, j)), i);
|
||||
// #endif
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
#if MC_VER >= MC_1_18_2
|
||||
private static BlendingData readBlendingData(CompoundTag chunkData)
|
||||
{
|
||||
BlendingData blendingData = null;
|
||||
|
||||
|
||||
boolean containsBlendingData;
|
||||
#if MC_VER < MC_1_21_5
|
||||
containsBlendingData = chunkData.contains("blending_data", 10);
|
||||
#else
|
||||
containsBlendingData = chunkData.contains("blending_data");
|
||||
#endif
|
||||
|
||||
if (containsBlendingData)
|
||||
{
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
Dynamic<CompoundTag> blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data"));
|
||||
|
||||
try
|
||||
{
|
||||
#if MC_VER < MC_1_21_3
|
||||
blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logParsingWarningOnce(message)).orElse(null);
|
||||
#else
|
||||
// blending data appears to have changed as of 1.21.6 causing a class cast exception here due to it being wrapped in a Java.Optional
|
||||
blendingData = BlendingData.unpack(BlendingData.Packed.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logParsingWarningOnce(message)).orElse(null));
|
||||
#endif
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String message = e.getMessage();
|
||||
if (message == null || message.trim().isEmpty())
|
||||
{
|
||||
message = "Failed to parse blending data";
|
||||
}
|
||||
|
||||
logParsingWarningOnce(message, e);
|
||||
}
|
||||
}
|
||||
return blendingData;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//=====================//
|
||||
// read chunk lighting //
|
||||
//=====================//
|
||||
|
||||
/**
|
||||
* https://minecraft.wiki/w/Chunk_format
|
||||
*/
|
||||
public static CombinedChunkLightStorage readLight(ChunkAccess chunk, CompoundTag chunkData)
|
||||
{
|
||||
#if MC_VER <= MC_1_17_1
|
||||
// MC 1.16 and 1.17 doesn't have the necessary NBT info
|
||||
return null;
|
||||
#else
|
||||
|
||||
CombinedChunkLightStorage combinedStorage = new CombinedChunkLightStorage(ChunkWrapper.getInclusiveMinBuildHeight(chunk), ChunkWrapper.getExclusiveMaxBuildHeight(chunk));
|
||||
ChunkLightStorage blockLightStorage = combinedStorage.blockLightStorage;
|
||||
ChunkLightStorage skyLightStorage = combinedStorage.skyLightStorage;
|
||||
|
||||
boolean foundSkyLight = false;
|
||||
|
||||
|
||||
|
||||
//===================//
|
||||
// get NBT tags info //
|
||||
//===================//
|
||||
|
||||
Tag chunkSectionTags = chunkData.get("sections");
|
||||
if (chunkSectionTags == null)
|
||||
{
|
||||
if (!lightingSectionErrorLogged)
|
||||
{
|
||||
lightingSectionErrorLogged = true;
|
||||
LOGGER.error("No sections found for chunk at pos ["+chunk.getPos()+"] chunk data may be out of date.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else if (!(chunkSectionTags instanceof ListTag))
|
||||
{
|
||||
if (!lightingSectionErrorLogged)
|
||||
{
|
||||
lightingSectionErrorLogged = true;
|
||||
LOGGER.error("Chunk section tag list have unexpected type ["+chunkSectionTags.getClass().getName()+"], expected ["+ListTag.class.getName()+"].");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
ListTag chunkSectionListTag = (ListTag) chunkSectionTags;
|
||||
|
||||
|
||||
|
||||
//===================//
|
||||
// get lighting info //
|
||||
//===================//
|
||||
|
||||
for (int sectionIndex = 0; sectionIndex < chunkSectionListTag.size(); sectionIndex++)
|
||||
{
|
||||
Tag chunkSectionTag = chunkSectionListTag.get(sectionIndex);
|
||||
if (!(chunkSectionTag instanceof CompoundTag))
|
||||
{
|
||||
if (!lightingSectionErrorLogged)
|
||||
{
|
||||
lightingSectionErrorLogged = true;
|
||||
LOGGER.error("Chunk section tag has an unexpected type ["+chunkSectionTag.getClass().getName()+"], expected ["+CompoundTag.class.getName()+"].");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
CompoundTag chunkSectionCompoundTag = (CompoundTag) chunkSectionTag;
|
||||
|
||||
|
||||
// if null all lights = 0
|
||||
byte[] blockLightNibbleArray = tagGetByteArray(chunkSectionCompoundTag, "BlockLight");
|
||||
byte[] skyLightNibbleArray = tagGetByteArray(chunkSectionCompoundTag, "SkyLight");
|
||||
|
||||
if (blockLightNibbleArray != null
|
||||
&& skyLightNibbleArray != null)
|
||||
{
|
||||
// if any sky light was found then all lights above will be max brightness
|
||||
if (skyLightNibbleArray.length != 0)
|
||||
{
|
||||
foundSkyLight = true;
|
||||
}
|
||||
|
||||
for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++)
|
||||
{
|
||||
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
|
||||
{
|
||||
// chunk sections are also 16 blocks tall
|
||||
for (int relY = 0; relY < LodUtil.CHUNK_WIDTH; relY++)
|
||||
{
|
||||
int blockPosIndex = relY*16*16 + relZ*16 + relX;
|
||||
byte blockLight = (blockLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(blockLightNibbleArray, blockPosIndex);
|
||||
byte skyLight = (skyLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(skyLightNibbleArray, blockPosIndex);
|
||||
if (skyLightNibbleArray.length == 0 && foundSkyLight)
|
||||
{
|
||||
skyLight = LodUtil.MAX_MC_LIGHT;
|
||||
}
|
||||
|
||||
int y = relY + (sectionIndex * LodUtil.CHUNK_WIDTH) + ChunkWrapper.getInclusiveMinBuildHeight(chunk);
|
||||
blockLightStorage.set(relX, y, relZ, blockLight);
|
||||
skyLightStorage.set(relX, y, relZ, skyLight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return combinedStorage;
|
||||
#endif
|
||||
}
|
||||
/** source: https://minecraft.wiki/w/Chunk_format#Block_Format */
|
||||
private static byte getNibbleAtIndex(byte[] arr, int index)
|
||||
{
|
||||
if (index % 2 == 0)
|
||||
{
|
||||
return (byte)(arr[index/2] & 0x0F);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (byte)((arr[index/2]>>4) & 0x0F);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// logging //
|
||||
//=========//
|
||||
|
||||
private static void logBlockDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
|
||||
{
|
||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||
{
|
||||
LOGGER.warn("Unable to deserialize blocks for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+newMessage+"]. " +
|
||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
}
|
||||
private static void logBiomeDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
|
||||
{
|
||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||
{
|
||||
LOGGER.warn("Unable to deserialize biomes for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+newMessage+"]. " +
|
||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
}
|
||||
|
||||
private static void logParsingWarningOnce(String message) { logParsingWarningOnce(message, null); }
|
||||
private static void logParsingWarningOnce(String message, Exception e)
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||
{
|
||||
LOGGER.warn("Parsing error: ["+newMessage+"]. " +
|
||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.",
|
||||
e);
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
}
|
||||
|
||||
private static RuntimeException logErrorAndReturnException(String message)
|
||||
{
|
||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||
{
|
||||
LOGGER.warn("Parsing error: ["+newMessage+"]. " +
|
||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
|
||||
// Currently we want to ignore these errors, if returning null is a problem, we can change this later
|
||||
return null; //new RuntimeException(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//====================//
|
||||
// tag helper methods //
|
||||
//====================//
|
||||
|
||||
// TODO move into separate file (this file is getting long)
|
||||
// these tag helpers are to simplify tag accessing between MC versions
|
||||
|
||||
/** defaults to "false" if the tag isn't present */
|
||||
private static boolean tagGetBoolean(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getBoolean(key);
|
||||
#else
|
||||
return tag.getBoolean(key).orElse(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to "0" if the tag isn't present */
|
||||
private static byte tagGetByte(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getByte(key);
|
||||
#else
|
||||
return tag.getByte(key).orElse((byte)0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to "0" if the tag isn't present */
|
||||
private static short tagGetShort(ListTag tag, int index)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getShort(index);
|
||||
#else
|
||||
return tag.getShort(index).orElse((short)0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to "0" if the tag isn't present */
|
||||
private static int tagGetInt(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getInt(key);
|
||||
#else
|
||||
return tag.getInt(key).orElse(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to "0" if the tag isn't present */
|
||||
private static long tagGetLong(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getInt(key);
|
||||
#else
|
||||
return tag.getLong(key).orElse(0L);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
private static String tagGetString(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getString(key);
|
||||
#else
|
||||
return tag.getString(key).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
private static byte[] tagGetByteArray(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getByteArray(key);
|
||||
#else
|
||||
return tag.getByteArray(key).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
private static CompoundTag tagGetCompoundTag(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getCompound(key);
|
||||
#else
|
||||
return tag.getCompound(key).orElse(null);
|
||||
#endif
|
||||
}
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
private static CompoundTag tagGetCompoundTag(ListTag tag, int index)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getCompound(index);
|
||||
#else
|
||||
return tag.getCompound(index).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* defaults to null if the tag isn't present
|
||||
* @param elementType unused after MC 1.21.5
|
||||
*/
|
||||
@Nullable
|
||||
private static ListTag tagGetListTag(CompoundTag tag, String key, int elementType)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getList(key, elementType);
|
||||
#else
|
||||
return tag.getList(key).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
private static ListTag tagGetListTag(ListTag tag, int index)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getList(index);
|
||||
#else
|
||||
return tag.getList(index).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
public static class CombinedChunkLightStorage
|
||||
{
|
||||
public ChunkLightStorage blockLightStorage;
|
||||
public ChunkLightStorage skyLightStorage;
|
||||
|
||||
public CombinedChunkLightStorage(int minY, int maxY)
|
||||
{
|
||||
this.blockLightStorage = ChunkLightStorage.createBlockLightStorage(minY, maxY);
|
||||
this.skyLightStorage = ChunkLightStorage.createSkyLightStorage(minY, maxY);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-16
@@ -1,6 +1,6 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling.ChunkFileReader;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
@@ -55,7 +55,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
||||
public RegionFileStorageExternalCache(RegionFileStorage storage) { this.storage = storage; }
|
||||
|
||||
@Nullable
|
||||
public RegionFile getRegionFile(ChunkPos pos) throws IOException
|
||||
public RegionFile getRegionFile(ChunkPos chunkPos) throws IOException
|
||||
{
|
||||
if (this.storage == null)
|
||||
{
|
||||
@@ -70,8 +70,8 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
||||
|
||||
|
||||
|
||||
long posLong = ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ());
|
||||
RegionFile rFile = null;
|
||||
long chunkPosLong = ChunkPos.asLong(chunkPos.getRegionX(), chunkPos.getRegionZ());
|
||||
RegionFile regionFile = null;
|
||||
|
||||
// Check vanilla cache
|
||||
int retryCount = 0;
|
||||
@@ -85,7 +85,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
||||
this.getRegionFileLock.lock();
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
rFile = this.storage.getRegionFile(pos);
|
||||
regionFile = this.storage.getRegionFile(chunkPos);
|
||||
|
||||
// keeping the region cache size low helps prevent concurrency issues
|
||||
if (this.storage.regionCache.size() > 150) // max 256
|
||||
@@ -97,7 +97,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
||||
}
|
||||
}
|
||||
#else
|
||||
rFile = this.storage.regionCache.getOrDefault(posLong, null);
|
||||
regionFile = this.storage.regionCache.getOrDefault(chunkPosLong, null);
|
||||
#endif
|
||||
|
||||
break;
|
||||
@@ -139,19 +139,19 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
||||
|
||||
if (retryCount >= maxRetryCount)
|
||||
{
|
||||
BatchGenerationEnvironment.CHUNK_LOAD_LOGGER.warn("Concurrency issue detected when getting region file for chunk at [" + pos + "].");
|
||||
ChunkFileReader.CHUNK_LOAD_LOGGER.warn("Concurrency issue detected when getting region file for chunk at [" + chunkPos + "].");
|
||||
}
|
||||
|
||||
|
||||
if (rFile != null)
|
||||
if (regionFile != null)
|
||||
{
|
||||
return rFile;
|
||||
return regionFile;
|
||||
}
|
||||
|
||||
// Then check our custom cache
|
||||
for (RegionFileCache cache : this.regionFileCache)
|
||||
{
|
||||
if (cache.pos == posLong)
|
||||
if (cache.pos == chunkPosLong)
|
||||
{
|
||||
return cache.file;
|
||||
}
|
||||
@@ -170,22 +170,22 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
||||
return null;
|
||||
}
|
||||
|
||||
Path regionFilePath = storageFolderPath.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca");
|
||||
Path regionFilePath = storageFolderPath.resolve("r." + chunkPos.getRegionX() + "." + chunkPos.getRegionZ() + ".mca");
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
rFile = new RegionFile(regionFilePath.toFile(), storageFolderPath.toFile(), false);
|
||||
regionFile = new RegionFile(regionFilePath.toFile(), storageFolderPath.toFile(), false);
|
||||
#elif MC_VER <= MC_1_20_4
|
||||
rFile = new RegionFile(regionFilePath, storageFolderPath, false);
|
||||
regionFile = new RegionFile(regionFilePath, storageFolderPath, false);
|
||||
#else
|
||||
rFile = new RegionFile(new RegionStorageInfo("level", null, "level type"), regionFilePath, storageFolderPath, false);
|
||||
regionFile = new RegionFile(new RegionStorageInfo("level", null, "level type"), regionFilePath, storageFolderPath, false);
|
||||
#endif
|
||||
|
||||
this.regionFileCache.add(new RegionFileCache(ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ()), rFile));
|
||||
this.regionFileCache.add(new RegionFileCache(ChunkPos.asLong(chunkPos.getRegionX(), chunkPos.getRegionZ()), regionFile));
|
||||
while (this.regionFileCache.size() > MAX_CACHE_SIZE)
|
||||
{
|
||||
this.regionFileCache.poll().file.close();
|
||||
}
|
||||
|
||||
return rFile;
|
||||
return regionFile;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+48
-23
@@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.params;
|
||||
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
@@ -27,35 +27,50 @@ import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ThreadedLevelLightEngine;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.BiomeManager;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.chunk.storage.ChunkScanAccess;
|
||||
#endif
|
||||
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
||||
#elif MC_VER < MC_1_19_2
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
||||
#else
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
import net.minecraft.world.level.levelgen.RandomState;
|
||||
#if MC_VER >= MC_1_19_4
|
||||
import net.minecraft.world.level.levelgen.WorldOptions;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
#endif
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
#endif
|
||||
import net.minecraft.world.level.storage.WorldData;
|
||||
|
||||
public final class GlobalParameters
|
||||
#if MC_VER < MC_1_19_4
|
||||
#elif MC_VER < MC_1_21_3
|
||||
import net.minecraft.core.registries.Registries;
|
||||
#else
|
||||
import net.minecraft.core.registries.Registries;
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_19_4
|
||||
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
||||
#else
|
||||
import net.minecraft.world.level.levelgen.WorldOptions;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Handles parameters that are relevant for the entire MC world.
|
||||
*
|
||||
* @see ThreadWorldGenParams
|
||||
*/
|
||||
public final class GlobalWorldGenParams
|
||||
{
|
||||
public final ChunkGenerator generator;
|
||||
public final IDhServerLevel lodLevel;
|
||||
public final ServerLevel level;
|
||||
public final IDhServerLevel dhServerLevel;
|
||||
public final ServerLevel mcServerLevel;
|
||||
public final Registry<Biome> biomes;
|
||||
public final RegistryAccess registry;
|
||||
public final long worldSeed;
|
||||
public final DataFixer fixerUpper;
|
||||
public final DataFixer dataFixer;
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
public final StructureManager structures;
|
||||
@@ -72,15 +87,21 @@ public final class GlobalParameters
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
public final BiomeManager biomeManager;
|
||||
public final ChunkScanAccess chunkScanner; // FIXME: Figure out if this is actually needed
|
||||
public final ChunkScanAccess chunkScanner;
|
||||
#endif
|
||||
|
||||
public GlobalParameters(IDhServerLevel lodLevel)
|
||||
{
|
||||
this.lodLevel = lodLevel;
|
||||
|
||||
this.level = ((ServerLevelWrapper) lodLevel.getServerLevelWrapper()).getWrappedMcObject();
|
||||
MinecraftServer server = this.level.getServer();
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public GlobalWorldGenParams(IDhServerLevel dhServerLevel)
|
||||
{
|
||||
this.dhServerLevel = dhServerLevel;
|
||||
|
||||
this.mcServerLevel = ((ServerLevelWrapper) dhServerLevel.getServerLevelWrapper()).getWrappedMcObject();
|
||||
MinecraftServer server = this.mcServerLevel.getServer();
|
||||
WorldData worldData = server.getWorldData();
|
||||
this.registry = server.registryAccess();
|
||||
|
||||
@@ -99,15 +120,19 @@ public final class GlobalParameters
|
||||
#endif
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
this.biomeManager = new BiomeManager(this.level, BiomeManager.obfuscateSeed(this.worldSeed));
|
||||
this.chunkScanner = this.level.getChunkSource().chunkScanner();
|
||||
this.biomeManager = new BiomeManager(this.mcServerLevel, BiomeManager.obfuscateSeed(this.worldSeed));
|
||||
this.chunkScanner = this.mcServerLevel.getChunkSource().chunkScanner();
|
||||
#endif
|
||||
|
||||
this.structures = server.getStructureManager();
|
||||
this.generator = this.level.getChunkSource().getGenerator();
|
||||
this.fixerUpper = server.getFixerUpper();
|
||||
this.generator = this.mcServerLevel.getChunkSource().getGenerator();
|
||||
this.dataFixer = server.getFixerUpper();
|
||||
|
||||
#if MC_VER >= MC_1_19_2
|
||||
this.randomState = this.level.getChunkSource().randomState();
|
||||
this.randomState = this.mcServerLevel.getChunkSource().randomState();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.common.wrappers.worldGeneration.params;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.WorldGenStructFeatManager;
|
||||
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.structure.StructureCheck;
|
||||
#endif
|
||||
|
||||
public final class ThreadWorldGenParams
|
||||
{
|
||||
private static final ThreadLocal<ThreadWorldGenParams> LOCAL_PARAM_REF = new ThreadLocal<>();
|
||||
|
||||
|
||||
final ServerLevel level;
|
||||
public WorldGenStructFeatManager structFeatManager = null;
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
public StructureCheck structCheck;
|
||||
#endif
|
||||
|
||||
boolean isValid = true;
|
||||
|
||||
// used for some older MC versions
|
||||
private static GlobalWorldGenParams previousGlobalWorldGenParams = null;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public static ThreadWorldGenParams getOrMake(GlobalWorldGenParams globalParams)
|
||||
{
|
||||
ThreadWorldGenParams threadParam = LOCAL_PARAM_REF.get();
|
||||
if (threadParam != null
|
||||
&& threadParam.isValid
|
||||
&& threadParam.level == globalParams.mcServerLevel)
|
||||
{
|
||||
return threadParam;
|
||||
}
|
||||
|
||||
threadParam = new ThreadWorldGenParams(globalParams);
|
||||
LOCAL_PARAM_REF.set(threadParam);
|
||||
return threadParam;
|
||||
}
|
||||
|
||||
private ThreadWorldGenParams(GlobalWorldGenParams param)
|
||||
{
|
||||
previousGlobalWorldGenParams = param;
|
||||
|
||||
this.level = param.mcServerLevel;
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
this.structFeatManager = new WorldGenStructFeatManager(param.worldGenSettings, this.level);
|
||||
#elif MC_VER < MC_1_19_2
|
||||
this.structCheck = this.createStructureCheck(param);
|
||||
#else
|
||||
this.structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
||||
param.mcServerLevel.dimension(), param.generator, param.randomState, this.level, param.generator.getBiomeSource(), param.worldSeed,
|
||||
param.dataFixer);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========//
|
||||
// builders //
|
||||
//==========//
|
||||
|
||||
public void makeStructFeatManager(WorldGenLevel genLevel, GlobalWorldGenParams param)
|
||||
{
|
||||
#if MC_VER < MC_1_18_2
|
||||
this.structFeatManager = new WorldGenStructFeatManager(param.worldGenSettings, genLevel);
|
||||
#elif MC_VER < MC_1_19_4
|
||||
this.structFeatManager = new WorldGenStructFeatManager(param.worldGenSettings, genLevel, this.structCheck);
|
||||
#else
|
||||
this.structFeatManager = new WorldGenStructFeatManager(param.worldOptions, genLevel, this.structCheck);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
#elif MC_VER < MC_1_19_2
|
||||
public void recreateStructureCheck()
|
||||
{
|
||||
if (previousGlobalWorldGenParams != null)
|
||||
{
|
||||
this.structCheck = this.createStructureCheck(previousGlobalWorldGenParams);
|
||||
}
|
||||
}
|
||||
private StructureCheck createStructureCheck(GlobalWorldGenParams param)
|
||||
{
|
||||
return new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
||||
param.mcServerLevel.dimension(), param.generator, this.level, param.generator.getBiomeSource(), param.worldSeed,
|
||||
param.dataFixer);
|
||||
}
|
||||
#else
|
||||
public void recreateStructureCheck() { /* do nothing */ }
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}
|
||||
+7
-7
@@ -1,7 +1,7 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
@@ -19,7 +19,7 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
public abstract class AbstractWorldGenStep
|
||||
{
|
||||
public abstract void generateGroup(
|
||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ArrayGridList<ChunkWrapper> chunkWrappers);
|
||||
|
||||
public abstract ChunkStatus getChunkStatus();
|
||||
@@ -27,26 +27,26 @@ public abstract class AbstractWorldGenStep
|
||||
|
||||
|
||||
/** @return the list of chunks that have an earlier status and can be generated */
|
||||
protected ArrayList<ChunkAccess> getChunksToGenerate(List<ChunkWrapper> chunkWrappers)
|
||||
protected ArrayList<ChunkWrapper> getChunkWrappersToGenerate(List<ChunkWrapper> chunkWrappers)
|
||||
{
|
||||
ArrayList<ChunkAccess> chunksToGenerate = new ArrayList<>();
|
||||
ArrayList<ChunkWrapper> chunkWrappersToGenerate = new ArrayList<>(chunkWrappers.size());
|
||||
|
||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
if (chunkWrapper.getStatus().isOrAfter(this.getChunkStatus()))
|
||||
{
|
||||
// this chunk has already generated this step
|
||||
// this chunk has already been generated up to this step
|
||||
continue;
|
||||
}
|
||||
else if (chunk instanceof ProtoChunk)
|
||||
{
|
||||
chunkWrapper.trySetStatus(this.getChunkStatus());
|
||||
chunksToGenerate.add(chunk);
|
||||
chunkWrappersToGenerate.add(chunkWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
return chunksToGenerate;
|
||||
return chunkWrappersToGenerate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+21
-20
@@ -23,13 +23,11 @@ import java.util.ArrayList;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||
@@ -66,47 +64,50 @@ public final class StepBiomes extends AbstractWorldGenStep
|
||||
|
||||
@Override
|
||||
public void generateGroup(
|
||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||
{
|
||||
ArrayList<ChunkAccess> chunksToDo = this.getChunksToGenerate(chunkWrappers);
|
||||
for (ChunkAccess chunk : chunksToDo)
|
||||
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
|
||||
for (ChunkWrapper chunkWrapper : chunksToDo)
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
this.environment.params.generator.createBiomes(this.environment.params.biomes, chunk);
|
||||
this.environment.globalParams.generator.createBiomes(this.environment.globalParams.biomes, chunk);
|
||||
#elif MC_VER < MC_1_19_2
|
||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||
this.environment.params.generator.createBiomes(
|
||||
this.environment.params.biomes,
|
||||
this.environment.globalParams.generator.createBiomes(
|
||||
this.environment.globalParams.biomes,
|
||||
Runnable::run,
|
||||
Blender.of(worldGenRegion),
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
||||
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||
chunk)
|
||||
);
|
||||
#elif MC_VER < MC_1_19_4
|
||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||
this.environment.params.generator.createBiomes(
|
||||
this.environment.params.biomes,
|
||||
this.environment.globalParams.generator.createBiomes(
|
||||
this.environment.globalParams.biomes,
|
||||
Runnable::run,
|
||||
this.environment.params.randomState, Blender.of(worldGenRegion),
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
||||
this.environment.globalParams.randomState, Blender.of(worldGenRegion),
|
||||
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||
chunk)
|
||||
);
|
||||
#elif MC_VER < MC_1_21_1
|
||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||
this.environment.params.generator.createBiomes(
|
||||
this.environment.globalParams.generator.createBiomes(
|
||||
Runnable::run,
|
||||
this.environment.params.randomState,
|
||||
this.environment.globalParams.randomState,
|
||||
Blender.of(worldGenRegion),
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
||||
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||
chunk)
|
||||
);
|
||||
#else
|
||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||
this.environment.params.generator.createBiomes(
|
||||
this.environment.params.randomState,
|
||||
this.environment.globalParams.generator.createBiomes(
|
||||
this.environment.globalParams.randomState,
|
||||
Blender.of(worldGenRegion),
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
||||
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||
chunk)
|
||||
);
|
||||
#endif
|
||||
|
||||
+7
-15
@@ -21,13 +21,12 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
|
||||
@@ -37,6 +36,7 @@ import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
#endif
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.ConcurrentModificationException;
|
||||
|
||||
|
||||
@@ -67,32 +67,24 @@ public final class StepFeatures extends AbstractWorldGenStep
|
||||
|
||||
@Override
|
||||
public void generateGroup(
|
||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||
{
|
||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
|
||||
for (ChunkWrapper chunkWrapper : chunksToDo)
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||
{
|
||||
// this chunk has already generated this step
|
||||
continue;
|
||||
}
|
||||
else if (chunk instanceof ProtoChunk)
|
||||
{
|
||||
chunkWrapper.trySetStatus(STATUS);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
#if MC_VER < MC_1_18_2
|
||||
worldGenRegion.setOverrideCenter(chunk.getPos());
|
||||
environment.params.generator.applyBiomeDecoration(worldGenRegion, tParams.structFeat);
|
||||
environment.globalParams.generator.applyBiomeDecoration(worldGenRegion, tParams.structFeatManager);
|
||||
#else
|
||||
if (worldGenRegion.hasChunk(chunkWrapper.getChunkPos().getX(), chunkWrapper.getChunkPos().getZ()))
|
||||
{
|
||||
this.environment.params.generator.applyBiomeDecoration(worldGenRegion, chunk, tParams.structFeat.forWorldGenRegion(worldGenRegion));
|
||||
this.environment.globalParams.generator.applyBiomeDecoration(worldGenRegion, chunk, tParams.structFeatManager.forWorldGenRegion(worldGenRegion));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+15
-30
@@ -20,18 +20,14 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||
@@ -68,56 +64,45 @@ public final class StepNoise extends AbstractWorldGenStep
|
||||
|
||||
@Override
|
||||
public void generateGroup(
|
||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||
{
|
||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
|
||||
|
||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
|
||||
for (ChunkWrapper chunkWrapper : chunksToDo)
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
chunkWrapper.trySetStatus(STATUS);
|
||||
chunksToDo.add(chunk);
|
||||
}
|
||||
|
||||
for (ChunkAccess chunk : chunksToDo)
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
this.environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk);
|
||||
this.environment.globalParams.generator.fillFromNoise(worldGenRegion, tParams.structFeatManager, chunk);
|
||||
#elif MC_VER < MC_1_18_2
|
||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||
this.environment.params.generator.fillFromNoise(
|
||||
this.environment.globalParams.generator.fillFromNoise(
|
||||
Runnable::run,
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
||||
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||
chunk));
|
||||
#elif MC_VER < MC_1_19_2
|
||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||
this.environment.params.generator.fillFromNoise(
|
||||
this.environment.globalParams.generator.fillFromNoise(
|
||||
Runnable::run,
|
||||
Blender.of(worldGenRegion),
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
||||
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||
chunk));
|
||||
#elif MC_VER < MC_1_21_1
|
||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||
this.environment.params.generator.fillFromNoise(
|
||||
this.environment.globalParams.generator.fillFromNoise(
|
||||
Runnable::run,
|
||||
Blender.of(worldGenRegion),
|
||||
this.environment.params.randomState,
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
||||
this.environment.globalParams.randomState,
|
||||
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||
chunk));
|
||||
#else
|
||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||
this.environment.params.generator.fillFromNoise(
|
||||
this.environment.globalParams.generator.fillFromNoise(
|
||||
Blender.of(worldGenRegion),
|
||||
this.environment.params.randomState,
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
||||
this.environment.globalParams.randomState,
|
||||
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||
chunk));
|
||||
#endif
|
||||
UncheckedInterruptedException.throwIfInterrupted();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-24
@@ -20,17 +20,14 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
|
||||
#if MC_VER <= MC_1_20_4
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
@@ -64,30 +61,14 @@ public final class StepStructureReference extends AbstractWorldGenStep
|
||||
|
||||
@Override
|
||||
public void generateGroup(
|
||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||
{
|
||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
|
||||
|
||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
|
||||
for (ChunkWrapper chunkWrapper : chunksToDo)
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||
{
|
||||
// this chunk has already generated this step
|
||||
continue;
|
||||
}
|
||||
else if (chunk instanceof ProtoChunk)
|
||||
{
|
||||
chunkWrapper.trySetStatus(STATUS);
|
||||
chunksToDo.add(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
for (ChunkAccess chunk : chunksToDo)
|
||||
{
|
||||
// System.out.println("StepStructureReference: "+chunk.getPos());
|
||||
this.environment.params.generator.createReferences(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk);
|
||||
this.environment.globalParams.generator.createReferences(worldGenRegion, tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+58
-57
@@ -20,21 +20,16 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
|
||||
#if MC_VER <= MC_1_20_4
|
||||
@@ -71,74 +66,80 @@ public final class StepStructureStart extends AbstractWorldGenStep
|
||||
|
||||
@Override
|
||||
public void generateGroup(
|
||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||
{
|
||||
ArrayList<ChunkAccess> chunksToDo = this.getChunksToGenerate(chunkWrappers);
|
||||
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
|
||||
|
||||
// TODO should be put in wrapped environment so we can skip some other world gen steps
|
||||
// SURFACE wouldn't need structure generation either
|
||||
#if MC_VER < MC_1_19_2
|
||||
if (this.environment.params.worldGenSettings.generateFeatures())
|
||||
{
|
||||
if (!this.environment.globalParams.worldGenSettings.generateFeatures())
|
||||
#elif MC_VER < MC_1_19_4
|
||||
if (this.environment.params.worldGenSettings.generateStructures())
|
||||
{
|
||||
if (!this.environment.globalParams.worldGenSettings.generateStructures())
|
||||
#else
|
||||
if (this.environment.params.worldOptions.generateStructures())
|
||||
{
|
||||
if (!this.environment.globalParams.worldOptions.generateStructures())
|
||||
#endif
|
||||
for (ChunkAccess chunk : chunksToDo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (ChunkWrapper chunkWrapper : chunksToDo)
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
|
||||
// hopefully this shouldn't cause any performance issues (this step is generally quite quick so hopefully it should be fine)
|
||||
// and should prevent some concurrency issues
|
||||
STRUCTURE_PLACEMENT_LOCK.lock();
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry, tParams.structFeatManager, chunk, this.environment.globalParams.structures,
|
||||
this.environment.globalParams.worldSeed);
|
||||
#elif MC_VER < MC_1_19_4
|
||||
this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry, this.environment.globalParams.randomState, tParams.structFeatManager, chunk, this.environment.globalParams.structures,
|
||||
this.environment.globalParams.worldSeed);
|
||||
#elif MC_VER <= MC_1_21_3
|
||||
this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry,
|
||||
this.environment.globalParams.mcServerLevel.getChunkSource().getGeneratorState(),
|
||||
tParams.structFeatManager, chunk, this.environment.globalParams.structures);
|
||||
#else
|
||||
this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry,
|
||||
this.environment.globalParams.mcServerLevel.getChunkSource().getGeneratorState(),
|
||||
tParams.structFeatManager, chunk, this.environment.globalParams.structures,
|
||||
this.environment.globalParams.mcServerLevel.dimension());
|
||||
#endif
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
try
|
||||
{
|
||||
// hopefully this shouldn't cause any performance issues (this step is generally quite quick so hopefully it should be fine)
|
||||
// and should prevent some concurrency issues
|
||||
STRUCTURE_PLACEMENT_LOCK.lock();
|
||||
tParams.structCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts());
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException firstEx)
|
||||
{
|
||||
// There's a rare issue with StructStart where it throws ArrayIndexOutOfBounds
|
||||
// This means the structFeat is corrupted (For some reason) and I need to reset it.
|
||||
// TODO: Figure out in the future why this happens even though I am using new structFeat - OLD
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
this.environment.params.generator.createStructures(this.environment.params.registry, tParams.structFeat, chunk, this.environment.params.structures,
|
||||
this.environment.params.worldSeed);
|
||||
#elif MC_VER < MC_1_19_4
|
||||
this.environment.params.generator.createStructures(this.environment.params.registry, this.environment.params.randomState, tParams.structFeat, chunk, this.environment.params.structures,
|
||||
this.environment.params.worldSeed);
|
||||
#elif MC_VER <= MC_1_21_3
|
||||
this.environment.params.generator.createStructures(this.environment.params.registry,
|
||||
this.environment.params.level.getChunkSource().getGeneratorState(),
|
||||
tParams.structFeat, chunk, this.environment.params.structures);
|
||||
#else
|
||||
this.environment.params.generator.createStructures(this.environment.params.registry,
|
||||
this.environment.params.level.getChunkSource().getGeneratorState(),
|
||||
tParams.structFeat, chunk, this.environment.params.structures,
|
||||
this.environment.params.level.dimension());
|
||||
#endif
|
||||
// reset the structureStart
|
||||
tParams.recreateStructureCheck();
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
try
|
||||
{
|
||||
// try running the structure logic again
|
||||
tParams.structCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts());
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException firstEx)
|
||||
catch (ArrayIndexOutOfBoundsException secondEx)
|
||||
{
|
||||
// There's a rare issue with StructStart where it throws ArrayIndexOutOfBounds
|
||||
// This means the structFeat is corrupted (For some reason) and I need to reset it.
|
||||
// TODO: Figure out in the future why this happens even though I am using new structFeat - OLD
|
||||
|
||||
// reset the structureStart
|
||||
tParams.recreateStructureCheck();
|
||||
|
||||
try
|
||||
{
|
||||
// try running the structure logic again
|
||||
tParams.structCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts());
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException secondEx)
|
||||
{
|
||||
// the structure logic failed again, log it and move on
|
||||
LOGGER.error("Unable to create structure starts for " + chunk.getPos() + ". This is an error with MC's world generation. Ignoring and continuing generation. Error: " + secondEx.getMessage()); // don't log the full stack trace since it is long and will generally end up in MC's code
|
||||
}
|
||||
// the structure logic failed again, log it and move on
|
||||
LOGGER.error("Unable to create structure starts for " + chunk.getPos() + ". This is an error with MC's world generation. Ignoring and continuing generation. Error: " + secondEx.getMessage()); // don't log the full stack trace since it is long and will generally end up in MC's code
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
STRUCTURE_PLACEMENT_LOCK.unlock();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
STRUCTURE_PLACEMENT_LOCK.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-25
@@ -20,17 +20,14 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
|
||||
#if MC_VER <= MC_1_20_4
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
@@ -64,37 +61,24 @@ public final class StepSurface extends AbstractWorldGenStep
|
||||
|
||||
@Override
|
||||
public void generateGroup(
|
||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||
{
|
||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
|
||||
|
||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
|
||||
for (ChunkWrapper chunkWrapper : chunksToDo)
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||
{
|
||||
// this chunk has already generated this step
|
||||
continue;
|
||||
}
|
||||
else if (chunk instanceof ProtoChunk)
|
||||
{
|
||||
chunkWrapper.trySetStatus(STATUS);
|
||||
chunksToDo.add(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
for (ChunkAccess chunk : chunksToDo)
|
||||
{
|
||||
// System.out.println("StepSurface: "+chunk.getPos());
|
||||
#if MC_VER < MC_1_18_2
|
||||
environment.params.generator.buildSurfaceAndBedrock(worldGenRegion, chunk);
|
||||
this.environment.globalParams.generator.buildSurfaceAndBedrock(worldGenRegion, chunk);
|
||||
#elif MC_VER < MC_1_19_2
|
||||
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk);
|
||||
this.environment.globalParams.generator.buildSurface(worldGenRegion, tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk);
|
||||
#else
|
||||
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), environment.params.randomState, chunk);
|
||||
this.environment.globalParams.generator.buildSurface(worldGenRegion, tParams.structFeatManager.forWorldGenRegion(worldGenRegion), this.environment.globalParams.randomState, chunk);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -18,7 +18,6 @@ accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chu
|
||||
# used for grabbing vanilla rendered chunks
|
||||
accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo
|
||||
accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chunk Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;
|
||||
#accessible field net/minecraft/world/entity/Entity blockPosition Lnet/minecraft/core/BlockPos;
|
||||
|
||||
# lighting
|
||||
accessible field net/minecraft/client/renderer/LightTexture lightPixels Lcom/mojang/blaze3d/platform/NativeImage;
|
||||
@@ -30,8 +29,6 @@ accessible field net/minecraft/world/level/lighting/LevelLightEngine skyEngine L
|
||||
accessible method net/minecraft/world/level/levelgen/Heightmap setHeight (III)V
|
||||
accessible field net/minecraft/world/level/biome/Biome generationSettings Lnet/minecraft/world/level/biome/BiomeGenerationSettings;
|
||||
accessible field net/minecraft/world/level/biome/Biome biomeCategory Lnet/minecraft/world/level/biome/Biome$BiomeCategory;
|
||||
#accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Lnet/minecraft/core/Holder;
|
||||
#accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doCreateBiomes (Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;)V
|
||||
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
|
||||
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
|
||||
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
|
||||
|
||||
@@ -29,8 +29,6 @@ accessible field net/minecraft/world/level/lighting/LevelLightEngine skyEngine L
|
||||
accessible method net/minecraft/world/level/levelgen/Heightmap setHeight (III)V
|
||||
accessible field net/minecraft/world/level/biome/Biome generationSettings Lnet/minecraft/world/level/biome/BiomeGenerationSettings;
|
||||
accessible field net/minecraft/world/level/biome/Biome biomeCategory Lnet/minecraft/world/level/biome/Biome$BiomeCategory;
|
||||
# accessible field net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator settings Lnet/minecraft/core/Holder;
|
||||
#accessible method net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator doCreateBiomes (Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/StructureFeatureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;)V
|
||||
accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
|
||||
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
|
||||
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
|
||||
|
||||
@@ -15,7 +15,6 @@ accessible class net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo
|
||||
accessible field net/minecraft/client/renderer/LevelRenderer$RenderChunkInfo chunk Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$RenderChunk;
|
||||
|
||||
# world generation
|
||||
# accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
|
||||
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
|
||||
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
|
||||
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
|
||||
|
||||
@@ -11,10 +11,7 @@ accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecr
|
||||
# used for grabbing vanilla rendered chunks
|
||||
accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
|
||||
|
||||
#accessible method net/minecraft/client/renderer/LevelRenderer renderSectionLayer (Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V
|
||||
|
||||
# world generation
|
||||
# accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
|
||||
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
|
||||
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
|
||||
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
|
||||
|
||||
@@ -11,10 +11,7 @@ accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecr
|
||||
# used for grabbing vanilla rendered chunks
|
||||
accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
|
||||
|
||||
#accessible method net/minecraft/client/renderer/LevelRenderer renderSectionLayer (Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDDLorg/joml/Matrix4f;)V
|
||||
|
||||
# world generation
|
||||
# accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
|
||||
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
|
||||
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
|
||||
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
|
||||
|
||||
@@ -15,7 +15,6 @@ accessible field net/minecraft/client/renderer/LevelRenderer level Lnet/minecraf
|
||||
accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
|
||||
|
||||
# world generation
|
||||
# accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
|
||||
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
|
||||
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
|
||||
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
accessWidener v1 named
|
||||
|
||||
# used when determining where to save files to
|
||||
accessible field net/minecraft/world/level/storage/DimensionDataStorage dataFolder Ljava/nio/file/Path;
|
||||
# used to help determine what folder a clientLevel is
|
||||
accessible field net/minecraft/world/level/biome/BiomeManager biomeZoomSeed J
|
||||
|
||||
# used when rendering
|
||||
accessible method net/minecraft/client/renderer/GameRenderer getFov (Lnet/minecraft/client/Camera;FZ)F
|
||||
accessible field net/minecraft/client/Minecraft deltaTracker Lnet/minecraft/client/DeltaTracker$Timer;
|
||||
accessible field net/minecraft/client/renderer/LevelRenderer level Lnet/minecraft/client/multiplayer/ClientLevel;
|
||||
|
||||
|
||||
# used for grabbing vanilla rendered chunks
|
||||
accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
|
||||
|
||||
# world generation
|
||||
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
|
||||
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
|
||||
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
|
||||
accessible field net/minecraft/server/level/ServerChunkCache distanceManager Lnet/minecraft/server/level/DistanceManager;
|
||||
accessible method net/minecraft/server/level/ChunkMap getUpdatingChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
|
||||
accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/BooleanSupplier;)V
|
||||
accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;
|
||||
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
|
||||
|
||||
# getting existing chunks outside the main thread
|
||||
accessible method net/minecraft/server/level/ChunkMap getVisibleChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
|
||||
|
||||
# lod generation from save file
|
||||
accessible field net/minecraft/world/level/chunk/storage/SimpleRegionStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
|
||||
accessible field net/minecraft/world/level/chunk/storage/IOWorker storage Lnet/minecraft/world/level/chunk/storage/RegionFileStorage;
|
||||
accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage regionCache Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;
|
||||
accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage folder Ljava/nio/file/Path;
|
||||
|
||||
# grabbing textures
|
||||
accessible class net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture
|
||||
accessible method net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture getFrameX (I)I
|
||||
accessible method net/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture getFrameY (I)I
|
||||
accessible field net/minecraft/client/renderer/texture/SpriteContents animatedTexture Lnet/minecraft/client/renderer/texture/SpriteContents$AnimatedTexture;
|
||||
accessible field net/minecraft/client/renderer/texture/SpriteContents originalImage Lcom/mojang/blaze3d/platform/NativeImage;
|
||||
|
||||
# UI stuff
|
||||
accessible field net/minecraft/client/gui/components/AbstractButton SPRITES Lnet/minecraft/client/gui/components/WidgetSprites;
|
||||
# Handles inserting the config button
|
||||
accessible field net/minecraft/client/gui/layouts/HeaderAndFooterLayout headerFrame Lnet/minecraft/client/gui/layouts/FrameLayout;
|
||||
accessible field net/minecraft/client/gui/layouts/FrameLayout children Ljava/util/List;
|
||||
accessible class net/minecraft/client/gui/layouts/FrameLayout$ChildContainer
|
||||
accessible field net/minecraft/client/gui/layouts/LinearLayout wrapped Lnet/minecraft/client/gui/layouts/GridLayout;
|
||||
accessible method net/minecraft/client/gui/components/debug/DebugScreenEntries register (Ljava/lang/String;Lnet/minecraft/client/gui/components/debug/DebugScreenEntry;)Lnet/minecraft/resources/Identifier;
|
||||
|
||||
# hacky stuff
|
||||
accessible field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
|
||||
mutable field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ accessible field net/minecraft/client/Minecraft deltaTracker Lnet/minecraft/clie
|
||||
accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
|
||||
|
||||
# world generation
|
||||
# accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
|
||||
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
|
||||
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
|
||||
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
|
||||
|
||||
@@ -14,7 +14,6 @@ accessible field net/minecraft/client/Minecraft deltaTracker Lnet/minecraft/clie
|
||||
accessible field net/minecraft/client/renderer/LevelRenderer visibleSections Lit/unimi/dsi/fastutil/objects/ObjectArrayList;
|
||||
|
||||
# world generation
|
||||
# accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSectionData (JLnet/minecraft/world/level/chunk/DataLayer;Z)V
|
||||
accessible field net/minecraft/world/level/chunk/LevelChunk loaded Z
|
||||
accessible field net/minecraft/world/level/lighting/LightEngine storage Lnet/minecraft/world/level/lighting/LayerLightSectionStorage;
|
||||
accessible method net/minecraft/world/level/lighting/LayerLightSectionStorage lightOnInSection (J)Z
|
||||
|
||||
+1
-1
Submodule coreSubProjects updated: b82a59ecbc...4a3c24f39e
+1
-1
@@ -102,7 +102,7 @@ dependencies {
|
||||
|
||||
|
||||
// Mod Menu
|
||||
modImplementation("com.terraformersmc:modmenu:${rootProject.modmenu_version}")
|
||||
addMod("com.terraformersmc:modmenu:${rootProject.modmenu_version}", rootProject.enable_mod_menu)
|
||||
|
||||
// Starlight
|
||||
addMod("curse.maven:starlight-521783:${rootProject.starlight_version_fabric}", rootProject.enable_starlight)
|
||||
|
||||
@@ -22,8 +22,10 @@ package com.seibel.distanthorizons.fabric;
|
||||
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
||||
import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
|
||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
|
||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||
@@ -64,11 +66,13 @@ import java.util.concurrent.AbstractExecutorService;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
||||
#endif
|
||||
|
||||
import com.mojang.blaze3d.platform.InputConstants;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
/**
|
||||
@@ -82,13 +86,12 @@ import org.lwjgl.glfw.GLFW;
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
||||
{
|
||||
private final ClientApi clientApi = ClientApi.INSTANCE;
|
||||
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
// TODO we shouldn't be filtering keys on the Forge/Fabric side, only in ClientApi
|
||||
private static final int[] KEY_TO_CHECK_FOR = { GLFW.GLFW_KEY_F6, GLFW.GLFW_KEY_F8, GLFW.GLFW_KEY_P};
|
||||
private static final MinecraftClientWrapper MC = MinecraftClientWrapper.INSTANCE;
|
||||
private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
|
||||
|
||||
private static final ClientApi clientApi = ClientApi.INSTANCE;
|
||||
|
||||
HashSet<Integer> previouslyPressKeyCodes = new HashSet<>();
|
||||
|
||||
@@ -113,14 +116,6 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// tick events //
|
||||
//=============//
|
||||
|
||||
ClientTickEvents.START_CLIENT_TICK.register((client) -> { ClientApi.INSTANCE.clientTickEvent(); });
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// chunk events //
|
||||
//==============//
|
||||
@@ -223,7 +218,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
||||
// render event //
|
||||
//==============//
|
||||
|
||||
// TODO wait for fabric to re-add their rendering API
|
||||
|
||||
#if MC_VER < MC_1_21_9
|
||||
WorldRenderEvents.AFTER_SETUP.register((renderContext) ->
|
||||
{
|
||||
@@ -344,23 +339,13 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
||||
{
|
||||
HashSet<Integer> currentKeyDown = new HashSet<>();
|
||||
|
||||
// Note: Minecraft's InputConstants is same as GLFW Key values
|
||||
//TODO: Use mixin to hook directly into the GLFW Keyboard event in minecraft KeyboardHandler
|
||||
// Check all keys we need
|
||||
for (int keyCode = GLFW.GLFW_KEY_A; keyCode <= GLFW.GLFW_KEY_Z; keyCode++)
|
||||
// Note: Minecraft's InputConstants are the same as GLFW Key values
|
||||
for (int keyCode = GLFW.GLFW_KEY_0; keyCode <= GLFW.GLFW_KEY_LAST; keyCode++)
|
||||
{
|
||||
//if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), keyCode))
|
||||
//{
|
||||
// currentKeyDown.add(keyCode);
|
||||
//}
|
||||
}
|
||||
|
||||
for (int keyCode : KEY_TO_CHECK_FOR)
|
||||
{
|
||||
//if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), keyCode))
|
||||
//{
|
||||
// currentKeyDown.add(keyCode);
|
||||
//}
|
||||
if (InputConstants.isKeyDown(MC.getGlfwWindowId(), keyCode))
|
||||
{
|
||||
currentKeyDown.add(keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
// Diff and trigger events
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.NativeDialogUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.*;
|
||||
@@ -36,10 +37,8 @@ import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import org.lwjgl.util.tinyfd.TinyFileDialogs;
|
||||
|
||||
#if MC_VER >= MC_1_19_2
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
@@ -47,8 +46,12 @@ import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||
#endif
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
#if MC_VER <= MC_1_21_10
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
#else
|
||||
import net.minecraft.resources.Identifier;
|
||||
#endif
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -58,10 +61,12 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
public class FabricMain extends AbstractModInitializer implements ClientModInitializer, DedicatedServerModInitializer
|
||||
{
|
||||
#if MC_VER >= MC_1_21_1
|
||||
#if MC_VER <= MC_1_20_6
|
||||
private static final ResourceLocation INITIAL_PHASE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.DEDICATED_SERVER_INITIAL_PATH);
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
private static final ResourceLocation INITIAL_PHASE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.DEDICATED_SERVER_INITIAL_PATH);
|
||||
#else
|
||||
private static final ResourceLocation INITIAL_PHASE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.DEDICATED_SERVER_INITIAL_PATH);
|
||||
private static final Identifier INITIAL_PHASE = Identifier.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.DEDICATED_SERVER_INITIAL_PATH);
|
||||
#endif
|
||||
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
@@ -98,7 +103,7 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
|
||||
String indiumMissingMessage = ModInfo.READABLE_NAME + " needs Indium to work with Sodium.\nPlease download Indium from https://modrinth.com/mod/indium";
|
||||
LOGGER.fatal(indiumMissingMessage);
|
||||
|
||||
TinyFileDialogs.tinyfd_messageBox(ModInfo.READABLE_NAME, indiumMissingMessage, "ok", "error", false);
|
||||
NativeDialogUtil.showDialog(ModInfo.READABLE_NAME, indiumMissingMessage, "ok", "error");
|
||||
|
||||
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
String errorMessage = "loading Distant Horizons. Distant Horizons requires Indium in order to run with Sodium.";
|
||||
@@ -110,6 +115,7 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
|
||||
this.tryCreateModCompatAccessor("starlight", IStarlightAccessor.class, StarlightAccessor::new);
|
||||
this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
|
||||
this.tryCreateModCompatAccessor("bclib", IBCLibAccessor.class, BCLibAccessor::new);
|
||||
this.tryCreateModCompatAccessor("c2me", IC2meAccessor.class, C2meAccessor::new);
|
||||
#if MC_VER >= MC_1_19_4
|
||||
// 1.19.4 is the lowest version Iris supports DH
|
||||
this.tryCreateModCompatAccessor("iris", IIrisAccessor.class, IrisAccessor::new);
|
||||
|
||||
@@ -93,10 +93,6 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy
|
||||
|
||||
/* Register the mod needed event callbacks */
|
||||
|
||||
// ServerTickEvent
|
||||
ServerTickEvents.END_SERVER_TICK.register((server) -> SERVER_API.serverTickEvent());
|
||||
|
||||
|
||||
// can be enabled to test overrides/events without having to build a separate API project
|
||||
if (false)
|
||||
{
|
||||
|
||||
+12
@@ -38,15 +38,27 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
#else
|
||||
import com.mojang.blaze3d.textures.GpuSampler;
|
||||
#endif
|
||||
|
||||
@Mixin(ChunkSectionsToRender.class)
|
||||
public class MixinChunkSectionsToRender
|
||||
{
|
||||
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
// needs to fire at HEAD with a lower than normal order (less than 1000)
|
||||
// otherwise it will be canceled by Sodium
|
||||
@Inject(at = @At("HEAD"), method = "renderGroup", order = 800)
|
||||
private void renderDeferredLayer(ChunkSectionLayerGroup chunkSectionLayerGroup, CallbackInfo ci)
|
||||
#else
|
||||
// needs to fire at HEAD with a lower than normal order (less than 1000)
|
||||
// otherwise it will be canceled by Sodium
|
||||
@Inject(at = @At("HEAD"), method = "renderGroup", order = 800)
|
||||
private void renderDeferredLayer(ChunkSectionLayerGroup chunkSectionLayerGroup, GpuSampler gpuSampler, CallbackInfo ci)
|
||||
#endif
|
||||
{
|
||||
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, Minecraft.getInstance().levelRenderer.level);
|
||||
|
||||
|
||||
+4
-1
@@ -160,9 +160,12 @@ public class MixinFogRenderer
|
||||
{
|
||||
#if MC_VER < MC_1_21_6
|
||||
Entity entity = camera.getEntity();
|
||||
#else
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
|
||||
Entity entity = camera.getEntity();
|
||||
#else
|
||||
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
|
||||
Entity entity = camera.entity();
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+32
-25
@@ -28,7 +28,6 @@ import net.minecraft.network.chat.Component;
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
#endif
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -51,6 +50,11 @@ import net.minecraft.client.gui.screens.OptionsScreen;
|
||||
import net.minecraft.client.gui.screens.options.OptionsScreen;
|
||||
#endif
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
#else
|
||||
import net.minecraft.resources.Identifier;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Adds a button to the menu to goto the config
|
||||
@@ -62,13 +66,16 @@ import net.minecraft.client.gui.screens.options.OptionsScreen;
|
||||
public class MixinOptionsScreen extends Screen
|
||||
{
|
||||
/** Texture used for the config opening button */
|
||||
#if MC_VER <= MC_1_20_6
|
||||
@Unique
|
||||
private static final ResourceLocation ICON_TEXTURE =
|
||||
#if MC_VER < MC_1_21_1
|
||||
new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
|
||||
#else
|
||||
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
|
||||
#endif
|
||||
private static final ResourceLocation ICON_TEXTURE = new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
@Unique
|
||||
private static final ResourceLocation ICON_TEXTURE = ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
|
||||
#else
|
||||
@Unique
|
||||
private static final Identifier ICON_TEXTURE = Identifier.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
|
||||
#endif
|
||||
|
||||
|
||||
@Unique
|
||||
@@ -130,24 +137,24 @@ public class MixinOptionsScreen extends Screen
|
||||
if (this.optionsButton == null)
|
||||
{
|
||||
this.optionsButton
|
||||
= new TexturedButtonWidget(
|
||||
// Where the button is on the screen
|
||||
this.width / 2 - 180, this.height / 6 - 12,
|
||||
// Width and height of the button
|
||||
20, 20,
|
||||
// texture UV Offset
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
20, ICON_TEXTURE, 20, 40,
|
||||
// Create the button and tell it where to go
|
||||
// For now it goes to the client option by default
|
||||
(buttonWidget) -> Objects.requireNonNull(this.minecraft).setScreen(GetConfigScreen.getScreen(this)),
|
||||
// Add a title to the button
|
||||
#if MC_VER < MC_1_19_2
|
||||
new TranslatableComponent(ModInfo.ID + ".title"));
|
||||
#else
|
||||
Component.translatable(ModInfo.ID + ".title"));
|
||||
#endif
|
||||
= new TexturedButtonWidget(
|
||||
// Where the button is on the screen
|
||||
this.width / 2 - 180, this.height / 6 - 12,
|
||||
// Width and height of the button
|
||||
20, 20,
|
||||
// texture UV Offset
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
20, ICON_TEXTURE, 20, 40,
|
||||
// Create the button and tell it where to go
|
||||
// For now it goes to the client option by default
|
||||
(buttonWidget) -> Objects.requireNonNull(this.minecraft).setScreen(GetConfigScreen.getScreen(this)),
|
||||
// Add a title to the button
|
||||
#if MC_VER < MC_1_19_2
|
||||
new TranslatableComponent(ModInfo.ID + ".title"));
|
||||
#else
|
||||
Component.translatable(ModInfo.ID + ".title"));
|
||||
#endif
|
||||
}
|
||||
|
||||
return this.optionsButton;
|
||||
|
||||
+2
-9
@@ -13,8 +13,7 @@ public class MixinLevelTicks<T>
|
||||
|
||||
#else
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import net.minecraft.world.ticks.LevelTicks;
|
||||
import net.minecraft.world.ticks.ScheduledTick;
|
||||
|
||||
@@ -26,18 +25,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@Mixin(LevelTicks.class) // available in 1.18.2+, but only needed in 1.21.4+
|
||||
public class MixinLevelTicks<T>
|
||||
{
|
||||
// TODO put in a common location
|
||||
private static boolean isWorldGenThread()
|
||||
{ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); }
|
||||
|
||||
|
||||
|
||||
@Inject(method = "schedule", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void onChunkSave(ScheduledTick<T> tick, CallbackInfo ci)
|
||||
{
|
||||
// In MC 1.21.4 an error check was added to log attempting to schedule ticks for unloaded chunks
|
||||
// this caused a lot of unnecessary errors when generating sand (FallingBlock.class).
|
||||
if (isWorldGenThread())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
+2
-8
@@ -19,6 +19,7 @@
|
||||
|
||||
package com.seibel.distanthorizons.fabric.mixins.server;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@@ -35,10 +36,8 @@ public class MixinTracingExecutor
|
||||
}
|
||||
#else
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
||||
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
||||
import net.minecraft.TracingExecutor;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
@@ -55,16 +54,11 @@ import java.util.concurrent.Executor;
|
||||
@Mixin(TracingExecutor.class)
|
||||
public class MixinTracingExecutor
|
||||
{
|
||||
// TODO put in a common location
|
||||
private static boolean isWorldGenThread()
|
||||
{ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); }
|
||||
|
||||
|
||||
// replaced with TracingExecutor in MC 1.21.3+
|
||||
@Inject(method = "forName(Ljava/lang/String;)Ljava/util/concurrent/Executor;", at = @At("HEAD"), cancellable = true)
|
||||
private void forName(String executorName, CallbackInfoReturnable<Executor> ci)
|
||||
{
|
||||
if (isWorldGenThread())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
// run this task on the current DH thread instead of a new MC thread
|
||||
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
||||
|
||||
+12
-12
@@ -19,19 +19,23 @@
|
||||
|
||||
package com.seibel.distanthorizons.fabric.mixins.server;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
import net.minecraft.Util;
|
||||
#else
|
||||
import net.minecraft.util.Util;
|
||||
#endif
|
||||
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.Util;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
#if MC_VER < MC_1_16_5
|
||||
#elif MC_VER < MC_1_21_3
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.function.Supplier;
|
||||
#else
|
||||
#endif
|
||||
@@ -46,15 +50,11 @@ import java.util.function.Supplier;
|
||||
@Mixin(Util.class)
|
||||
public class MixinUtilBackgroundThread
|
||||
{
|
||||
private static boolean isWorldGenThread()
|
||||
{ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); }
|
||||
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
|
||||
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
|
||||
{
|
||||
if (isWorldGenThread())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
// run this task on the current DH thread instead of a new MC thread
|
||||
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
||||
@@ -70,7 +70,7 @@ public class MixinUtilBackgroundThread
|
||||
at = @At("HEAD"), cancellable = true)
|
||||
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable<Runnable> ci)
|
||||
{
|
||||
if (isWorldGenThread())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
|
||||
ci.setReturnValue(r);
|
||||
@@ -86,7 +86,7 @@ public class MixinUtilBackgroundThread
|
||||
at = @At("HEAD"), cancellable = true)
|
||||
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
|
||||
{
|
||||
if (isWorldGenThread())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
|
||||
ci.setReturnValue(r);
|
||||
|
||||
+1
-3
@@ -23,9 +23,7 @@ import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
|
||||
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||
|
||||
/**
|
||||
* For making the config show up in modmenu
|
||||
*/
|
||||
/** For making the config show up in modmenu */
|
||||
public class ModMenuIntegration implements ModMenuApi
|
||||
{
|
||||
// For the custom config code
|
||||
|
||||
+8
-12
@@ -17,20 +17,16 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers;
|
||||
package com.seibel.distanthorizons.fabric.wrappers.modAccessor;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor;
|
||||
|
||||
public class DependencySetupDoneCheck
|
||||
public class C2meAccessor implements IC2meAccessor
|
||||
{
|
||||
// TODO move to DependencySetup
|
||||
public static boolean isDone = false;
|
||||
/**
|
||||
* This is used so we can override some MC logic when running
|
||||
* in DH's world generator.
|
||||
* Specifically so we can redirect threads to run on DH threads instead
|
||||
* of MC threads.
|
||||
*/
|
||||
public static Supplier<Boolean> getIsCurrentThreadDistantGeneratorThread = (() -> { return false; });
|
||||
@Override
|
||||
public String getModName()
|
||||
{
|
||||
return "c2me";
|
||||
}
|
||||
|
||||
}
|
||||
+4
-12
@@ -34,22 +34,14 @@ import net.irisshaders.iris.api.v0.IrisApi;
|
||||
public class IrisAccessor implements IIrisAccessor
|
||||
{
|
||||
@Override
|
||||
public String getModName()
|
||||
{
|
||||
return Iris.MODID;
|
||||
}
|
||||
public String getModName() { return Iris.MODID; }
|
||||
|
||||
@Override
|
||||
public boolean isShaderPackInUse()
|
||||
{
|
||||
return IrisApi.getInstance().isShaderPackInUse();
|
||||
}
|
||||
public boolean isShaderPackInUse() { return IrisApi.getInstance().isShaderPackInUse(); }
|
||||
|
||||
@Override
|
||||
public boolean isRenderingShadowPass()
|
||||
{
|
||||
return IrisApi.getInstance().isRenderingShadowPass();
|
||||
}
|
||||
public boolean isRenderingShadowPass() { return IrisApi.getInstance().isRenderingShadowPass(); }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+1
-4
@@ -28,9 +28,6 @@ public class OptifineAccessor extends AbstractOptifineAccessor
|
||||
{
|
||||
|
||||
@Override
|
||||
public String getModName()
|
||||
{
|
||||
return "Optifine-Fabric-1.18.X";
|
||||
}
|
||||
public String getModName() { return "Optifine-Fabric"; }
|
||||
|
||||
}
|
||||
|
||||
+8
-2
@@ -26,6 +26,7 @@ import java.lang.invoke.MethodType;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
|
||||
#if MC_VER < MC_1_20_1
|
||||
@@ -50,9 +51,11 @@ public class SodiumAccessor implements ISodiumAccessor
|
||||
*/
|
||||
public static final boolean isSodiumV5OrLess;
|
||||
|
||||
#if MC_VER >= MC_1_20_1
|
||||
#if MC_VER <= MC_1_19_4
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
private static MethodHandle setFogOcclusionMethod;
|
||||
private static Object sodiumPerformanceOptions;
|
||||
#else
|
||||
#endif
|
||||
|
||||
static {
|
||||
@@ -78,7 +81,8 @@ public class SodiumAccessor implements ISodiumAccessor
|
||||
@Override
|
||||
public void setFogOcclusion(boolean occlusionEnabled)
|
||||
{
|
||||
#if MC_VER >= MC_1_20_1
|
||||
#if MC_VER <= MC_1_19_4
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
try
|
||||
{
|
||||
if (sodiumPerformanceOptions == null)
|
||||
@@ -122,6 +126,8 @@ public class SodiumAccessor implements ISodiumAccessor
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
#else
|
||||
// in newer versions of Sodium this doesn't appear to be an issue so it can probably just be ignored
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -107,21 +107,6 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// tick events //
|
||||
//=============//
|
||||
|
||||
@SubscribeEvent
|
||||
public void clientTickEvent(TickEvent.ClientTickEvent event)
|
||||
{
|
||||
if (event.phase == TickEvent.Phase.START)
|
||||
{
|
||||
ClientApi.INSTANCE.clientTickEvent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// world events //
|
||||
//==============//
|
||||
|
||||
@@ -22,17 +22,16 @@ package com.seibel.distanthorizons.forge;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||
|
||||
import com.seibel.distanthorizons.forge.wrappers.modAccessor.ModChecker;
|
||||
import com.seibel.distanthorizons.forge.wrappers.modAccessor.OptifineAccessor;
|
||||
import com.seibel.distanthorizons.forge.wrappers.modAccessor.OculusAccessor;
|
||||
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
@@ -104,6 +103,7 @@ public class ForgeMain extends AbstractModInitializer
|
||||
protected void initializeModCompat()
|
||||
{
|
||||
this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
|
||||
this.tryCreateModCompatAccessor("oculus", IIrisAccessor.class, OculusAccessor::new);
|
||||
|
||||
#if MC_VER < MC_1_17_1
|
||||
ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY,
|
||||
|
||||
@@ -90,16 +90,6 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy
|
||||
// events //
|
||||
//========//
|
||||
|
||||
// ServerTickEvent (at end)
|
||||
@SubscribeEvent
|
||||
public void serverTickEvent(TickEvent.ServerTickEvent event)
|
||||
{
|
||||
if (event.phase == TickEvent.Phase.END)
|
||||
{
|
||||
this.serverApi.serverTickEvent();
|
||||
}
|
||||
}
|
||||
|
||||
// ServerWorldLoadEvent
|
||||
@SubscribeEvent
|
||||
public void dedicatedWorldLoadEvent(#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 FMLServerAboutToStartEvent #else ServerAboutToStartEvent #endif event)
|
||||
|
||||
+5
-3
@@ -67,9 +67,11 @@ public class MixinFogRenderer
|
||||
|
||||
Entity entity = camera.getEntity();
|
||||
boolean isSpecialFog = (entity instanceof LivingEntity) && ((LivingEntity) entity).hasEffect(MobEffects.BLINDNESS);
|
||||
if (!isSpecialFog && cameraNotInFluid && fogMode == FogMode.FOG_TERRAIN
|
||||
&& !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial()
|
||||
&& Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get())
|
||||
if (!isSpecialFog
|
||||
&& cameraNotInFluid
|
||||
&& fogMode == FogMode.FOG_TERRAIN
|
||||
&& !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial()
|
||||
&& !Config.Client.Advanced.Graphics.Fog.enableVanillaFog.get())
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
RenderSystem.fogStart(A_REALLY_REALLY_BIG_VALUE);
|
||||
|
||||
+20
-18
@@ -57,25 +57,27 @@ public class MixinOptionsScreen extends Screen
|
||||
private void lodconfig$init(CallbackInfo ci)
|
||||
{
|
||||
if (Config.Client.showDhOptionsButtonInMinecraftUi.get())
|
||||
{
|
||||
this. #if MC_VER < MC_1_17_1 addButton #else addRenderableWidget #endif
|
||||
(new TexturedButtonWidget(
|
||||
// Where the button is on the screen
|
||||
this.width / 2 - 180, this.height / 6 - 12,
|
||||
// Width and height of the button
|
||||
20, 20,
|
||||
// Offset
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
20, ICON_TEXTURE, 20, 40,
|
||||
// Create the button and tell it where to go
|
||||
// For now it goes to the client option by default
|
||||
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(GetConfigScreen.getScreen(this)),
|
||||
// Add a title to the button
|
||||
#if MC_VER < MC_1_19_2
|
||||
new TranslatableComponent(ModInfo.ID + ".title")));
|
||||
#else
|
||||
Component.translatable(ModInfo.ID + ".title")));
|
||||
#endif
|
||||
(new TexturedButtonWidget(
|
||||
// Where the button is on the screen
|
||||
this.width / 2 - 180, this.height / 6 - 12,
|
||||
// Width and height of the button
|
||||
20, 20,
|
||||
// Offset
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
20, ICON_TEXTURE, 20, 40,
|
||||
// Create the button and tell it where to go
|
||||
// For now it goes to the client option by default
|
||||
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(GetConfigScreen.getScreen(this)),
|
||||
// Add a title to the button
|
||||
#if MC_VER < MC_1_19_2
|
||||
new TranslatableComponent(ModInfo.ID + ".title")));
|
||||
#else
|
||||
Component.translatable(ModInfo.ID + ".title")));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-11
@@ -22,12 +22,15 @@ package com.seibel.distanthorizons.forge.mixins.server;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
||||
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
||||
|
||||
import net.minecraft.Util;
|
||||
@@ -35,17 +38,17 @@ import net.minecraft.Util;
|
||||
@Mixin(Util.class)
|
||||
public class MixinUtilBackgroundThread
|
||||
{
|
||||
private static boolean shouldApplyOverride()
|
||||
{
|
||||
return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get();
|
||||
}
|
||||
@Unique
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().name("MixinUtilBackgroundThread").build();
|
||||
|
||||
|
||||
|
||||
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
|
||||
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
|
||||
{
|
||||
if (shouldApplyOverride())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
//ApiShared.LOGGER.info("util backgroundExecutor triggered");
|
||||
//LOGGER.info("util backgroundExecutor triggered");
|
||||
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
||||
}
|
||||
}
|
||||
@@ -55,21 +58,22 @@ public class MixinUtilBackgroundThread
|
||||
at = @At("HEAD"), cancellable = true)
|
||||
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable<Runnable> ci)
|
||||
{
|
||||
if (shouldApplyOverride())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
|
||||
//LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
|
||||
ci.setReturnValue(r);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
@Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/util/function/Supplier;)Ljava/util/function/Supplier;",
|
||||
at = @At("HEAD"), cancellable = true)
|
||||
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
|
||||
{
|
||||
if (shouldApplyOverride())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
|
||||
//LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
|
||||
ci.setReturnValue(r);
|
||||
}
|
||||
}
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.forge.wrappers.modAccessor;
|
||||
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||
|
||||
public class OculusAccessor implements IIrisAccessor
|
||||
{
|
||||
protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
|
||||
public OculusAccessor()
|
||||
{
|
||||
LOGGER.warn("Partial Oculus support enabled. Some DH features may be disabled or behave strangely, use Iris instead if possible.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getModName()
|
||||
{
|
||||
return "oculus";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShaderPackInUse()
|
||||
{
|
||||
// assume shaders are always active
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRenderingShadowPass()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
"server.MixinUtilBackgroundThread",
|
||||
"server.MixinChunkGenerator",
|
||||
"server.MixinTFChunkGenerator",
|
||||
"server.MixinChunkMap",
|
||||
"server.MixinChunkMap",
|
||||
"server.MixinServerPlayer",
|
||||
"server.MixinEntity"
|
||||
],
|
||||
|
||||
@@ -12,14 +12,13 @@ issueTrackerURL = "${issues}"
|
||||
#//updateJSONURL="https://change.me.example.invalid/updates.json" # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/
|
||||
displayURL = "${homepage}"
|
||||
description = "${description}" #//mandatory. The description text for the mod
|
||||
logoFile = "assets/distanthorizons/logo.png"
|
||||
catalogueImageIcon = "assets/distanthorizons/icon.png"
|
||||
logoFile = "dh_forge_logo.png" #// can't contain a file path due to an old forge limitation https://github.com/MinecraftForge/MinecraftForge/issues/7348
|
||||
catalogueImageIcon = "dh_forge_icon.png" #// can't contain a file path due to an old forge limitation https://github.com/MinecraftForge/MinecraftForge/issues/7348
|
||||
credits = "Massive thanks to all the developers for their hard work to bring Distant Horizons to where it is today. - James"
|
||||
#// if not set defaults to "false"
|
||||
clientSideOnly = "true"
|
||||
#// if not set side defaults to "BOTH"
|
||||
#// TODO change to "BOTH" when we add server support
|
||||
side = "CLIENT"
|
||||
side = "BOTH"
|
||||
#// Allow any version to be present (or not) on the server
|
||||
acceptableRemoteVersions = "*"
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"pack": {
|
||||
"pack_format": 7,
|
||||
"supported_formats": {
|
||||
"min_inclusive": 7,
|
||||
"max_inclusive": 90000
|
||||
},
|
||||
"description": "Distant Horizons"
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -5,8 +5,8 @@ org.gradle.caching=true
|
||||
|
||||
# Mod Info
|
||||
mod_name=DistantHorizons
|
||||
mod_version=2.3.7-b-dev
|
||||
api_version=5.0.0
|
||||
mod_version=2.4.6-b-dev
|
||||
api_version=5.1.0
|
||||
maven_group=com.seibel.distanthorizons
|
||||
mod_readable_name=Distant Horizons
|
||||
mod_description=This mod generates and renders simplified terrain beyond the normal view distance at a low performance cost. Allowing you to see much farther without turning your game into a slideshow.
|
||||
@@ -18,7 +18,7 @@ mod_issues=https://gitlab.com/jeseibel/distant-horizons/-/issues
|
||||
mod_discord=https://discord.gg/xAB8G4cENx
|
||||
|
||||
# Global Plugin Versions
|
||||
manifold_version=2025.1.27
|
||||
manifold_version=2025.1.28
|
||||
# 2023.1.17 can be used if there are mystery Java compiler issues
|
||||
nightconfig_version=3.6.6
|
||||
lz4_version=1.8.0
|
||||
@@ -55,7 +55,7 @@ versionStr=
|
||||
|
||||
# This defines what MC version Intellij will use for the preprocessor
|
||||
# and what version is used automatically by build and run commands
|
||||
mcVer=1.21.10
|
||||
mcVer=1.21.11
|
||||
|
||||
# Defines the maximum amount of memory Minecraft is allowed when run in a development environment
|
||||
#minecraftMemoryJavaArg="-Xmx4G"
|
||||
|
||||
@@ -65,7 +65,10 @@ dependencies {
|
||||
|
||||
// Neoforge
|
||||
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
|
||||
addMod("curse.maven:TerraFirmaCraft-302973:4616004", rootProject.enable_terrafirmacraft)
|
||||
|
||||
// Iris
|
||||
addMod("maven.modrinth:iris:${rootProject.neo_iris_version}", rootProject.neo_enable_iris)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -73,29 +73,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// tick events //
|
||||
//=============//
|
||||
|
||||
#if MC_VER < MC_1_20_6
|
||||
@SubscribeEvent
|
||||
public void clientTickEvent(TickEvent.ClientTickEvent event)
|
||||
{
|
||||
if (event.phase == TickEvent.Phase.START)
|
||||
{
|
||||
ClientApi.INSTANCE.clientTickEvent();
|
||||
}
|
||||
}
|
||||
#else
|
||||
@SubscribeEvent
|
||||
public void clientTickEvent(ClientTickEvent.Pre event)
|
||||
{
|
||||
ClientApi.INSTANCE.clientTickEvent();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// world events //
|
||||
//==============//
|
||||
|
||||
@@ -30,9 +30,13 @@ import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.C2meAccessor;
|
||||
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.IrisAccessor;
|
||||
import com.seibel.distanthorizons.neoforge.wrappers.NeoforgeMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.ModChecker;
|
||||
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.OptifineAccessor;
|
||||
@@ -144,6 +148,12 @@ public class NeoforgeMain extends AbstractModInitializer
|
||||
protected void initializeModCompat()
|
||||
{
|
||||
this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
|
||||
this.tryCreateModCompatAccessor("c2me", IC2meAccessor.class, C2meAccessor::new);
|
||||
|
||||
#if MC_VER >= MC_1_20_6
|
||||
// 1.20.6 is the lowest version Iris supports Neoforge
|
||||
this.tryCreateModCompatAccessor("iris", IIrisAccessor.class, IrisAccessor::new);
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_20_6
|
||||
ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class,
|
||||
|
||||
+1
-19
@@ -31,7 +31,6 @@ import java.util.function.Supplier;
|
||||
#if MC_VER < MC_1_20_6
|
||||
import net.neoforged.neoforge.event.TickEvent;
|
||||
#else
|
||||
import net.neoforged.neoforge.event.tick.ServerTickEvent;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -52,7 +51,7 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy
|
||||
public NeoforgeServerProxy(boolean isDedicated)
|
||||
{
|
||||
this.isDedicated = isDedicated;
|
||||
isGenerationThreadChecker = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread;
|
||||
isGenerationThreadChecker = BatchGenerationEnvironment::isThisDhWorldGenThread;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,23 +67,6 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy
|
||||
// events //
|
||||
//========//
|
||||
|
||||
#if MC_VER < MC_1_20_6
|
||||
@SubscribeEvent
|
||||
public void serverTickEvent(TickEvent.ServerTickEvent event)
|
||||
{
|
||||
if (event.phase == TickEvent.Phase.END)
|
||||
{
|
||||
this.serverApi.serverTickEvent();
|
||||
}
|
||||
}
|
||||
#else
|
||||
@SubscribeEvent
|
||||
public void serverTickEvent(ServerTickEvent.Post event)
|
||||
{
|
||||
this.serverApi.serverTickEvent();
|
||||
}
|
||||
#endif
|
||||
|
||||
// ServerWorldLoadEvent
|
||||
@SubscribeEvent
|
||||
public void dedicatedWorldLoadEvent(ServerAboutToStartEvent event)
|
||||
|
||||
+4
-1
@@ -160,9 +160,12 @@ public class MixinFogRenderer
|
||||
{
|
||||
#if MC_VER < MC_1_21_6
|
||||
Entity entity = camera.getEntity();
|
||||
#else
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
|
||||
Entity entity = camera.getEntity();
|
||||
#else
|
||||
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
|
||||
Entity entity = camera.entity();
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+14
-7
@@ -28,7 +28,6 @@ import net.minecraft.network.chat.Component;
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
#endif
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -51,6 +50,11 @@ import net.minecraft.client.gui.screens.OptionsScreen;
|
||||
import net.minecraft.client.gui.screens.options.OptionsScreen;
|
||||
#endif
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
#else
|
||||
import net.minecraft.resources.Identifier;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Adds a button to the menu to goto the config
|
||||
@@ -62,13 +66,16 @@ import net.minecraft.client.gui.screens.options.OptionsScreen;
|
||||
public class MixinOptionsScreen extends Screen
|
||||
{
|
||||
/** Texture used for the config opening button */
|
||||
#if MC_VER <= MC_1_20_6
|
||||
@Unique
|
||||
private static final ResourceLocation ICON_TEXTURE =
|
||||
#if MC_VER < MC_1_21_1
|
||||
new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
|
||||
#else
|
||||
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
|
||||
#endif
|
||||
private static final ResourceLocation ICON_TEXTURE = new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
@Unique
|
||||
private static final ResourceLocation ICON_TEXTURE = ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
|
||||
#else
|
||||
@Unique
|
||||
private static final Identifier ICON_TEXTURE = Identifier.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
|
||||
#endif
|
||||
|
||||
|
||||
@Unique
|
||||
|
||||
+2
-8
@@ -13,7 +13,7 @@ public class MixinLevelTicks<T>
|
||||
|
||||
#else
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import net.minecraft.world.ticks.LevelTicks;
|
||||
import net.minecraft.world.ticks.ScheduledTick;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -24,18 +24,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@Mixin(LevelTicks.class) // available in 1.18.2+, but only needed in 1.21.4+
|
||||
public class MixinLevelTicks<T>
|
||||
{
|
||||
// TODO put in a common location
|
||||
private static boolean isWorldGenThread()
|
||||
{ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); }
|
||||
|
||||
|
||||
|
||||
@Inject(method = "schedule", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void onChunkSave(ScheduledTick<T> tick, CallbackInfo ci)
|
||||
{
|
||||
// In MC 1.21.4 an error check was added to log attempting to schedule ticks for unloaded chunks
|
||||
// this caused a lot of unnecessary errors when generating sand (FallingBlock.class).
|
||||
if (isWorldGenThread())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
+2
-7
@@ -35,7 +35,7 @@ public class MixinTracingExecutor
|
||||
}
|
||||
#else
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
||||
import net.minecraft.TracingExecutor;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -55,11 +55,6 @@ import java.util.concurrent.Executor;
|
||||
@Mixin(TracingExecutor.class)
|
||||
public class MixinTracingExecutor
|
||||
{
|
||||
// TODO put in a common location
|
||||
private static boolean isWorldGenThread()
|
||||
{ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); }
|
||||
|
||||
|
||||
// Util.backgroundExecutor().forName("init_biomes")
|
||||
// needed for world gen
|
||||
|
||||
@@ -67,7 +62,7 @@ public class MixinTracingExecutor
|
||||
@Inject(method = "forName(Ljava/lang/String;)Ljava/util/concurrent/Executor;", at = @At("HEAD"), cancellable = true)
|
||||
private void forName(String executorName, CallbackInfoReturnable<Executor> ci)
|
||||
{
|
||||
if (isWorldGenThread())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
// run this task on the current DH thread instead of a new MC thread
|
||||
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
||||
|
||||
+15
-12
@@ -19,18 +19,24 @@
|
||||
|
||||
package com.seibel.distanthorizons.neoforge.mixins.server;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
import net.minecraft.Util;
|
||||
#else
|
||||
import net.minecraft.util.Util;
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
||||
|
||||
import net.minecraft.Util;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.function.Supplier;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This is needed for DH's world gen so we can run
|
||||
@@ -42,16 +48,13 @@ import net.minecraft.Util;
|
||||
@Mixin(Util.class)
|
||||
public class MixinUtilBackgroundThread
|
||||
{
|
||||
private static boolean isWorldGenThread()
|
||||
{ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); }
|
||||
|
||||
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
|
||||
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
|
||||
{
|
||||
if (isWorldGenThread())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
// run this task on the current DH thread instead of a new MC thread
|
||||
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
||||
@@ -67,7 +70,7 @@ public class MixinUtilBackgroundThread
|
||||
at = @At("HEAD"), cancellable = true)
|
||||
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable<Runnable> ci)
|
||||
{
|
||||
if (isWorldGenThread())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
|
||||
ci.setReturnValue(r);
|
||||
@@ -83,7 +86,7 @@ public class MixinUtilBackgroundThread
|
||||
at = @At("HEAD"), cancellable = true)
|
||||
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
|
||||
{
|
||||
if (isWorldGenThread())
|
||||
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||
{
|
||||
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
|
||||
ci.setReturnValue(r);
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ public class NeoforgeMinecraftRenderWrapper extends MinecraftRenderWrapper
|
||||
this.depthTextureCastFailLogged = true;
|
||||
LOGGER.error("Unable to cast render Target depth texture to GlTexture. MC or a rendering mod may have changed the object type.", e);
|
||||
}
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -72,7 +72,7 @@ public class NeoforgeMinecraftRenderWrapper extends MinecraftRenderWrapper
|
||||
this.colorTextureCastFailLogged = true;
|
||||
LOGGER.error("Unable to cast render Target color texture to ValidationGpuTexture or GlTexture. MC, Neoforge, or a rendering mod may have changed the object type.", e);
|
||||
}
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
+6
-30
@@ -17,40 +17,16 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.neoforge.wrappers.modAccessor;
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor;
|
||||
|
||||
//FIXME: Move this outside the WorldGenerationStep thingy
|
||||
public class Rolling
|
||||
public class C2meAccessor implements IC2meAccessor
|
||||
{
|
||||
|
||||
private final int size;
|
||||
private double total = 0d;
|
||||
private int index = 0;
|
||||
private final double[] samples;
|
||||
|
||||
public Rolling(int size)
|
||||
@Override
|
||||
public String getModName()
|
||||
{
|
||||
this.size = size;
|
||||
samples = new double[size];
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
samples[i] = 0d;
|
||||
}
|
||||
}
|
||||
|
||||
public void add(double x)
|
||||
{
|
||||
total -= samples[index];
|
||||
samples[index] = x;
|
||||
total += x;
|
||||
if (++index == size)
|
||||
index = 0; // cheaper than modulus
|
||||
}
|
||||
|
||||
public double getAverage()
|
||||
{
|
||||
return size == 0 ? 0 : total / size;
|
||||
return "c2me";
|
||||
}
|
||||
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.neoforge.wrappers.modAccessor;
|
||||
|
||||
// 1.20.6 is the lowest version Iris supports Neoforge
|
||||
#if MC_VER >= MC_1_20_6
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||
|
||||
#if MC_VER != MC_1_21_9
|
||||
import net.irisshaders.iris.Iris;
|
||||
import net.irisshaders.iris.api.v0.IrisApi;
|
||||
#endif
|
||||
|
||||
public class IrisAccessor implements IIrisAccessor
|
||||
{
|
||||
public IrisAccessor()
|
||||
{
|
||||
//#if MC_VER == MC_1_21_11
|
||||
//throw new UnsupportedOperationException("Iris isn't supported on this version of DH. When this version of DH was created Iris wasn't available for Neoforge yet.");
|
||||
//#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getModName()
|
||||
{
|
||||
#if MC_VER == MC_1_21_9 || MC_VER == MC_1_21_11
|
||||
return "iris"; // Iris doesn't support this MC version
|
||||
#else
|
||||
return Iris.MODID;
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShaderPackInUse()
|
||||
{
|
||||
#if MC_VER == MC_1_21_9
|
||||
return true; // Iris doesn't support this MC version
|
||||
#else
|
||||
return IrisApi.getInstance().isShaderPackInUse();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRenderingShadowPass()
|
||||
{
|
||||
#if MC_VER == MC_1_21_9
|
||||
return false; // Iris doesn't support this MC version
|
||||
#else
|
||||
return IrisApi.getInstance().isRenderingShadowPass();
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+1
-4
@@ -28,9 +28,6 @@ public class OptifineAccessor extends AbstractOptifineAccessor
|
||||
{
|
||||
|
||||
@Override
|
||||
public String getModName()
|
||||
{
|
||||
return "Optifine-Forge-1.18.X";
|
||||
}
|
||||
public String getModName() { return "Optifine-Forge"; }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"pack": {
|
||||
"pack_format": 7,
|
||||
"supported_formats": {
|
||||
"min_inclusive": 7,
|
||||
"max_inclusive": 90000
|
||||
},
|
||||
"description": "Distant Horizons"
|
||||
}
|
||||
}
|
||||
@@ -12,15 +12,29 @@ How to add a library's natives:
|
||||
Example:
|
||||
|
||||
```groovy
|
||||
// Relocate the namespace (Java side)
|
||||
relocate "org.sqlite", "dh_sqlite", {
|
||||
// (Specific to SQLite's relocation)
|
||||
// Make sure that native paths are not changed before steps below
|
||||
exclude "org/sqlite/native/**"
|
||||
}
|
||||
// Shadow also replaces strings inside the Java code
|
||||
// See the library's source code to find strings used to call into the native code
|
||||
// This also includes native library paths, if you use mapPaths {} below they will likely need adjustment as well
|
||||
relocate "jdbc:sqlite", "jdbc:dh_sqlite"
|
||||
|
||||
transform(NativeTransformer) {
|
||||
// NativeTransformer configuration
|
||||
rootDir = project.rootDir
|
||||
|
||||
// Match native libraries
|
||||
matchFiles { it.startsWith("org/sqlite") }
|
||||
// Replace paths with ones that won't overlap with other mods
|
||||
// Libraries are the ones choosing the path to use for natives; check the source code to see which paths are acceptable.
|
||||
mapPaths { it.replace("org/sqlite", "dh_sqlite") }
|
||||
|
||||
// Replace native strings, e.g. used in calls back to Java
|
||||
// They must be of the same length or shorter!
|
||||
relocateNative "org/sqlite", "dh_sqlite"
|
||||
// Rename native methods used when calling from Java
|
||||
relocateNative "org_sqlite", "dh_1sqlite"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user