Compare commits

...

113 Commits

Author SHA1 Message Date
James Seibel f67fb1758d Speed up shutdown and reduce logging 2025-11-14 07:46:10 -06:00
James Seibel 506ba05b34 Don't duplicate adjacent data 2025-11-13 07:18:13 -06:00
James Seibel 70be3f9364 Add varint encoding for full data 2025-11-12 07:22:00 -06:00
James Seibel 3a01151137 re-add GPU upload config including "none" 2025-11-10 07:33:11 -06:00
James Seibel 197051747a put zstd version in main gradle file 2025-11-10 07:31:14 -06:00
James Seibel 45efeb96fa Optimize ColumnBox building 2025-11-08 18:08:10 -06:00
James Seibel e05dff3fb9 Optimize DhTintGetter 2025-11-08 17:51:50 -06:00
James Seibel 106d97e0a1 Revert "minor AbstractDhTintGetter optimization"
This reverts commit 6a418de153.
2025-11-07 07:02:21 -06:00
James Seibel 34412305d0 adjData core changes 2025-11-04 07:48:35 -06:00
James Seibel 6a418de153 minor AbstractDhTintGetter optimization 2025-10-29 21:38:57 -05:00
James Seibel 41c6b2936b Add experimental fast loading option 2025-10-28 07:47:14 -05:00
James Seibel 97130d1535 minor optimization to tint getting 2025-10-28 07:35:26 -05:00
James Seibel d61dcfaab6 optimize BiomeWrapper getting slightly 2025-10-28 07:26:44 -05:00
James Seibel 3c3f1ef41b Add far clip fading 2025-10-25 11:54:44 -05:00
James Seibel ed1d6396fd Fix iris not setting face culling in the MC state manager 2025-10-25 08:38:34 -05:00
James Seibel 518ec18362 framebuffer name consistency fix 2025-10-25 08:37:16 -05:00
James Seibel 5715cd9266 Fixes !82 (replay mod crash during shutdown) 2025-10-23 07:18:04 -05:00
James Seibel 56953efabc disallow writing to ImposterProtoChunks during world gen 2025-10-22 07:31:59 -05:00
James Seibel 351802de4c run occlusion culling whenever saving a LOD
Also run culling for every column in an LOD, which improves compression by about 20%
- Thanks Scaevolus
2025-10-22 07:25:08 -05:00
James Seibel f60e74c838 Merge branch 'main' of gitlab.com:distant-horizons-team/distant-horizons 2025-10-19 16:08:02 -05:00
James Seibel 2007a6af24 Clean up LodRendering logic 2025-10-19 16:06:19 -05:00
s809 4bc199fe14 Merge branch 'feature/server-keys' 2025-10-19 22:58:48 +05:00
James Seibel bcd9a0da2c Make LodRenderer a singleton 2025-10-18 11:43:50 -05:00
James Seibel 50c97e3ca3 Fix Batch generator registries import 2025-10-18 11:43:00 -05:00
James Seibel 7539cb94d4 Fix internal server generation not loading chunks 2025-10-17 07:27:04 -05:00
James Seibel 3a20329096 Dh and level wrapper refactoring and commenting 2025-10-17 07:21:48 -05:00
James Seibel 702002c540 up api version 4.1.0 -> 5.0.0
due to logger enum changes
2025-10-15 17:39:03 -05:00
James Seibel 7f790e2c9c merge loggers and add logger builder 2025-10-15 17:38:43 -05:00
James Seibel b3f8b03fdf up version number 2.3.6 -> 2.3.7 2025-10-13 18:03:26 -05:00
James Seibel 3597d69fa4 remove dev from version number 2025-10-13 17:45:45 -05:00
James Seibel ab10265150 Fix 1.21.9 missing fabric resource loader v1 2025-10-13 17:45:45 -05:00
s809 671ee84136 Handle server keyed level wrappers correctly 2025-10-13 18:07:06 +05:00
James Seibel c489cebae3 Fix world gen progress ui button 2025-10-13 07:43:02 -05:00
James Seibel e55eeda1ac Improve config gui object casting 2025-10-13 07:35:53 -05:00
James Seibel 0086f40053 bug fixing for major config refactoring 2025-10-12 21:11:16 -05:00
James Seibel 71bb151e61 Fix 1.21.10 compile typo 2025-10-12 19:41:42 -05:00
James Seibel a71ceac15d Fix forge compiling 2025-10-12 19:41:03 -05:00
James Seibel ada36c34c7 minor client wrapper refactor for clarity 2025-10-12 15:30:20 -05:00
James Seibel 3cfb4386d9 set default dev version to 1.21.10 2025-10-12 15:07:23 -05:00
James Seibel 352d0f4759 re-add MC 1.21.9 support 2025-10-12 15:04:31 -05:00
James Seibel d158a89592 Fix neoforge rendering 2025-10-12 15:02:09 -05:00
James Seibel 9cc826f8a9 Fix client tinted biomes 2025-10-12 14:49:32 -05:00
James Seibel 22a4c6bc79 Fix neoforge server startup crash 2025-10-12 14:05:27 -05:00
James Seibel 20b9f4f1cb Fix stuttering when flying over un-generated chunks 2025-10-12 13:58:03 -05:00
James Seibel 5c0c1c5e20 up version number 2.3.5 -> 2.3.6 2025-10-11 20:55:45 -05:00
James Seibel 69645994c9 remove dev from version number 2025-10-11 20:54:47 -05:00
James Seibel fdcbb0594d fix version constant 1.21.9 -> 1.21.10 2025-10-11 20:40:06 -05:00
James Seibel e5711b4ddb Fix newer fabric versions needing two resource loaders 2025-10-11 18:42:08 -05:00
James Seibel cb1a617b92 Fix a few old MC versions compiling 2025-10-11 12:04:41 -05:00
James Seibel 4187eaf112 Fix fading when Sodium is installed 2025-10-11 11:14:12 -05:00
James Seibel 084de2b3f1 Fix double pass fading (sodium still breaks it) 2025-10-10 07:44:47 -05:00
James Seibel 7b0a9d4843 Replace 1.21.9 with 1.21.10 2025-10-10 07:35:37 -05:00
James Seibel c42f800db5 add fabric 1.21.9 support 2025-10-10 07:15:27 -05:00
James Seibel 300ef3745f Fix VANILLA_CHUNKS API world gen 2025-10-08 17:27:11 -05:00
James Seibel 5a9fdb3314 Fix neforge texture validation support 2025-10-07 07:43:46 -05:00
James Seibel 8708ca3048 Update to latest neoforge 1.21.9 version 2025-10-07 07:18:32 -05:00
James Seibel 9cfdbdc0ca Fix compiling for MC 1.21.8 and older 2025-10-05 16:27:06 -05:00
James Seibel 48f82b0966 Re-add biome blending 2025-10-05 16:23:27 -05:00
James Seibel 75f7ef0085 Separate DH pool threads and new executor "Render Loader" 2025-10-04 20:11:19 -05:00
James Seibel 270776a782 fix world gen protochunks in 1.21.9 2025-10-04 10:48:50 -05:00
James Seibel 21fff72521 Fix f3 menu for 1.21.9 2025-10-04 10:28:52 -05:00
James Seibel a860a9740d Fix neoforge not rendering 2025-10-02 20:30:18 -05:00
James Seibel a2105699fa Write custom timeout logic for DelayedDataSourceCache 2025-10-02 20:30:16 -05:00
James Seibel ea4838c791 add DhApiChunkProcessingEvent 2025-10-02 18:03:43 -05:00
James Seibel 9168543945 Fix a few compiler errors for old MC versions 2025-10-02 17:34:29 -05:00
James Seibel 460996d8cd add 1.21.9 to the CI list 2025-10-02 07:44:08 -05:00
James Seibel c3948abc40 fix older MC version compiling 2025-10-02 07:42:49 -05:00
James Seibel 8ed902f6f2 rename ChunkLoader -> ChunkFileReader 2025-10-02 07:39:03 -05:00
James Seibel 15dda30050 add neo 1.21.9 support 2025-10-02 07:37:54 -05:00
James Seibel 26428ff905 Fix config UI crashing on older MC versions 2025-09-29 19:06:20 -05:00
James Seibel 4419ab4b8c Manually close compression streams to try reducing GC reliance 2025-09-29 17:21:08 -05:00
James Seibel 5d50994beb cull LOD rendering on the quad tree 2025-09-29 07:28:12 -05:00
James Seibel ce9f843048 config gui refactoring 2025-09-28 16:32:20 -05:00
James Seibel 8c934b4982 config gui refactoring 2025-09-28 16:30:33 -05:00
James Seibel 9ae41865f3 Fix tooltips rendering incorrectly 2025-09-28 16:29:08 -05:00
James Seibel ade7a8d8dc minor config handler refactoring 2025-09-28 16:14:38 -05:00
James Seibel 461dad9fe8 Fix compiling on MC 1.19.4 and older 2025-09-27 22:09:36 -05:00
James Seibel b832e77ac2 Refactor ClassicConfigGUI, add disabled API buttons 2025-09-27 20:58:55 -05:00
James Seibel 66c41e49db update manifold 2025.1.20 -> 2025.1.27 2025-09-27 20:08:30 -05:00
James Seibel 0f968255e0 Move lang missing test back to GetConfigScreen 2025-09-27 20:08:04 -05:00
James Seibel ed50161cfd Fix compiling for pre MC 1.20.6 2025-09-27 08:35:57 -05:00
s809 7e18acdb8f Make lang initialization client only 2025-09-26 21:45:40 +05:00
s809 5c05fdd9fa Add global bandwidth limit setting 2025-09-26 21:45:19 +05:00
James Seibel afca4d837f Force Mac upload method to DATA
Maybe will help with crashing/memory corruption?
Data is the most basic upload method in GL so Mac should be able to support it a lot better than BUFFER_STORAGE.
2025-09-24 07:23:36 -05:00
James Seibel 6db3795fa5 Start refactoring ClassicConfigGUI 2025-09-21 21:30:01 -05:00
James Seibel 21fe38da8e up LWJGL version 3.3.1 -> 3.3.3
Shouldn't actually be used by anything, just for use with unused the Swing GUI
2025-09-21 21:28:12 -05:00
James Seibel 340c0bc586 Move lang test to abstract mod init 2025-09-21 21:26:36 -05:00
James Seibel 77c7ebc0d0 Fix a few UI screens crashing 2025-09-21 21:25:57 -05:00
James Seibel f55cb4b320 maybe fix freebsd OS crashing 2025-09-20 22:40:58 -05:00
James Seibel 9d3c88f0b2 Update coreSubProjects 2025-09-20 16:29:38 -05:00
James Seibel e397a3e47a fix annotation compiling again 2025-09-20 16:29:32 -05:00
James Seibel 4ff315de91 fix missing annotations for compiling 2025-09-20 15:58:40 -05:00
James Seibel 2fb1c43d7c Allow native relocator to run on freebsd 2025-09-20 15:58:19 -05:00
James Seibel 58b5fac20b Add experimental option to maybe help with Mac crashing 2025-09-20 15:11:09 -05:00
James Seibel ec238d29c6 Fix "CUSTOM" quality preset when Iris is present 2025-09-16 07:44:26 -05:00
James Seibel dac36c9e34 include world gen chunk/sec rate in progress log 2025-09-14 08:18:40 -05:00
James Seibel caca05c0f0 up fabric loader/api version for 1.21.8 2025-09-14 08:12:00 -05:00
James Seibel 5ce7eae7c0 Fix DH world gen missing structures 2025-09-14 08:11:47 -05:00
James Seibel 2c38401637 Improve world gen task queue speed slightly 2025-09-13 17:59:52 -05:00
James Seibel 489fe753f5 remove unexplored terrain rendering 2025-09-11 07:07:26 -05:00
James Seibel 2293afc2d3 remove unexplored terrain rendering 2025-09-11 07:06:20 -05:00
James Seibel b48adeb3e3 Add unexplored ocean for overworld 2025-09-10 07:46:31 -05:00
James Seibel 438186cb70 improve lod load time slightly 2025-09-07 16:16:33 -05:00
James Seibel c86ff4acae fix api jar version 4.0.0 -> 4.1.0 2025-09-06 12:18:00 -05:00
James Seibel e27e1bc2d7 add unexplored fog 2025-09-06 12:00:00 -05:00
James Seibel 336bf2ea26 Don't merge blocks that get colored by blocks above into columns 2025-09-06 08:53:30 -05:00
James Seibel e72c08b0bc Fix LOD-only rendering mode 2025-09-06 08:38:39 -05:00
James Seibel 4ced316304 add (native) ZStd compression as default compressor 2025-09-03 07:40:24 -05:00
s809 c84ee721e3 Bump protocol version 2025-08-16 21:01:49 +05:00
s809 c46c056980 Add a server keys feature 2025-08-16 20:59:34 +05:00
s809 d486878876 Replace pooled buffers with unpooled 2025-08-07 17:55:27 +05:00
s809 b0b0b38bf8 Reduce network logging by default 2025-07-27 23:21:30 +05:00
James Seibel 9e43896864 up version number 2.3.4 -> 2.3.5 2025-07-19 14:59:19 -05:00
82 changed files with 2833 additions and 1754 deletions
+8 -1
View File
@@ -35,7 +35,14 @@ build:
stage: build stage: build
parallel: parallel:
matrix: matrix:
- MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6", "1.21.1", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.8"] - 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.20.6", "1.20.4", "1.20.2", "1.20.1",
"1.19.4", "1.19.2",
"1.18.2",
"1.17.1",
"1.16.5"
]
script: script:
# this both runs the unit tests and assembles the code # this both runs the unit tests and assembles the code
- ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/; - ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
+4 -3
View File
@@ -19,7 +19,7 @@ plugins {
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha" id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
// Architectury is used here only as a replacement for forge's own loom // Architectury is used here only as a replacement for forge's own loom
id "dev.architectury.loom" version "1.10-SNAPSHOT" apply false id "dev.architectury.loom" version "1.11-SNAPSHOT" apply false
} }
@@ -43,7 +43,9 @@ def writeBuildGradlePredefine(List<String> mcVers, int mcIndex)
sb.append("MC_" + verStr + "=" + i.toString() + "\n"); sb.append("MC_" + verStr + "=" + i.toString() + "\n");
if (mcIndex == i) if (mcIndex == i)
{
sb.append("MC_VER=" + i.toString() + "\n"); sb.append("MC_VER=" + i.toString() + "\n");
}
} }
@@ -246,8 +248,7 @@ subprojects { p ->
// We cannot relocate this library since we call some MC classes that reference it // We cannot relocate this library since we call some MC classes that reference it
implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}") implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}")
//forgeShadowMe("com.github.luben:zstd-jni:1.5.7-3") forgeShadowMe("com.github.luben:zstd-jni:${rootProject.zstd_version}")
//forgeShadowMe("org.apache.commons:commons-compress:1.27.1")
// Compression // Compression
forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4 forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4
+4 -1
View File
@@ -34,7 +34,10 @@ class NativeRelocator
{ {
processBuilder.command("powershell", "-ExecutionPolicy", "Bypass", "./prepare.ps1"); processBuilder.command("powershell", "-ExecutionPolicy", "Bypass", "./prepare.ps1");
} }
else if (os.contains("nix") || os.contains("nux") || os.contains("mac")) else if (os.contains("nix")
|| os.contains("nux")
|| os.contains("mac")
|| os.contains("freebsd"))
{ {
processBuilder.command("./prepare.sh"); processBuilder.command("./prepare.sh");
} }
@@ -5,11 +5,12 @@ import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDh
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
import com.seibel.distanthorizons.common.commands.CommandInitializer; import com.seibel.distanthorizons.common.commands.CommandInitializer;
import com.seibel.distanthorizons.common.wrappers.DependencySetup; import com.seibel.distanthorizons.common.wrappers.DependencySetup;
import com.seibel.distanthorizons.common.wrappers.gui.DhDebugScreenEntry;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigBase; import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler; import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
@@ -23,7 +24,7 @@ import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.dedicated.DedicatedServer;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -35,7 +36,7 @@ import java.util.function.Supplier;
*/ */
public abstract class AbstractModInitializer public abstract class AbstractModInitializer
{ {
protected static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName()); protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
private CommandInitializer commandInitializer; private CommandInitializer commandInitializer;
@@ -45,7 +46,8 @@ public abstract class AbstractModInitializer
// abstract methods // // abstract methods //
//==================// //==================//
protected abstract void createInitialBindings(); protected abstract void createInitialSharedBindings();
protected abstract void createInitialClientBindings();
protected abstract IEventProxy createClientProxy(); protected abstract IEventProxy createClientProxy();
protected abstract IEventProxy createServerProxy(boolean isDedicated); protected abstract IEventProxy createServerProxy(boolean isDedicated);
protected abstract void initializeModCompat(); protected abstract void initializeModCompat();
@@ -65,6 +67,7 @@ public abstract class AbstractModInitializer
public void onInitializeClient() public void onInitializeClient()
{ {
DependencySetup.createClientBindings(); DependencySetup.createClientBindings();
this.createInitialClientBindings();
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " client, firing DhApiBeforeDhInitEvent..."); LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " client, firing DhApiBeforeDhInitEvent...");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null); ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
@@ -83,6 +86,12 @@ public abstract class AbstractModInitializer
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized."); LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
#if MC_VER < MC_1_21_9
// debug screen rendering handled via a mixin
#else
DhDebugScreenEntry.register();
#endif
this.subscribeClientStartedEvent(this::postInit); this.subscribeClientStartedEvent(this::postInit);
} }
@@ -133,7 +142,7 @@ public abstract class AbstractModInitializer
{ {
DependencySetup.createSharedBindings(); DependencySetup.createSharedBindings();
SharedApi.init(); SharedApi.init();
this.createInitialBindings(); this.createInitialSharedBindings();
} }
private void logBuildInfo() private void logBuildInfo()
@@ -161,8 +170,9 @@ public abstract class AbstractModInitializer
private void initConfig() private void initConfig()
{ {
ConfigBase.INSTANCE = new ConfigBase(ModInfo.ID, ModInfo.NAME, Config.class, ModInfo.CONFIG_FILE_VERSION); ConfigHandler.tryRunFirstTimeSetup();
Config.completeDelayedSetup(); Config.completeDelayedSetup();
DhLogger.runDelayedConfigSetup();
} }
private void checkForUpdates() private void checkForUpdates()
@@ -183,6 +193,12 @@ public abstract class AbstractModInitializer
{ {
LOGGER.info("Running Delayed setup..."); LOGGER.info("Running Delayed setup...");
this.runDelayedSetup(); this.runDelayedSetup();
if (ConfigHandler.INSTANCE == null)
{
throw new IllegalStateException("Config was not initialized. Make sure to call LodCommonMain.initConfig() before calling this method.");
}
LOGGER.info("Delayed setup complete, firing DhApiAfterDhInitEvent event..."); LOGGER.info("Delayed setup complete, firing DhApiAfterDhInitEvent event...");
// should be fired after all delayed setup so singletons and config can be accessed // should be fired after all delayed setup so singletons and config can be accessed
@@ -1,8 +1,8 @@
package com.seibel.distanthorizons.common; package com.seibel.distanthorizons.common;
import com.seibel.distanthorizons.core.config.Config; 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.ConfigBasedLogger; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent; import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent;
import com.seibel.distanthorizons.core.network.event.internal.ProtocolErrorInternalEvent; import com.seibel.distanthorizons.core.network.event.internal.ProtocolErrorInternalEvent;
import com.seibel.distanthorizons.core.network.messages.MessageRegistry; import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
@@ -15,15 +15,15 @@ import io.netty.buffer.ByteBufUtil;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import org.apache.logging.log4j.LogManager;
import java.io.IOException; import java.io.IOException;
import java.util.Objects; import java.util.Objects;
public abstract class AbstractPluginPacketSender implements IPluginPacketSender public abstract class AbstractPluginPacketSender implements IPluginPacketSender
{ {
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(), private static final DhLogger LOGGER = new DhLoggerBuilder()
() -> Config.Common.Logging.logNetworkEvent.get()); .fileLevelConfig(Config.Common.Logging.logNetworkEventToFile)
.build();
#if MC_VER >= MC_1_21_1 #if MC_VER >= MC_1_21_1
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH); public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
@@ -3,8 +3,8 @@ package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.arguments.*; import com.mojang.brigadier.arguments.*;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
import com.seibel.distanthorizons.core.config.ConfigBase; import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.types.AbstractConfigType; import com.seibel.distanthorizons.core.config.types.AbstractConfigBase;
import com.seibel.distanthorizons.core.config.types.ConfigEntry; import com.seibel.distanthorizons.core.config.types.ConfigEntry;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
@@ -43,7 +43,7 @@ public class ConfigCommand extends AbstractCommand
LiteralArgumentBuilder<CommandSourceStack> builder = literal("config"); LiteralArgumentBuilder<CommandSourceStack> builder = literal("config");
HashSet<String> addedCommands = new HashSet<>(); HashSet<String> addedCommands = new HashSet<>();
for (AbstractConfigType<?, ?> type : ConfigBase.INSTANCE.entries) for (AbstractConfigBase<?> type : ConfigHandler.INSTANCE.configBaseList)
{ {
// Skip non-config entries // Skip non-config entries
if (!(type instanceof ConfigEntry)) if (!(type instanceof ConfigEntry))
@@ -17,9 +17,9 @@ public class CrashCommand extends AbstractCommand
.requires(this::isPlayerSource) .requires(this::isPlayerSource)
.then(literal("encode") .then(literal("encode")
.executes(c -> { .executes(c -> {
assert SharedApi.getIDhServerWorld() != null; assert SharedApi.tryGetDhServerWorld() != null;
ServerPlayerState serverPlayerState = SharedApi.getIDhServerWorld().getServerPlayerStateManager() ServerPlayerState serverPlayerState = SharedApi.tryGetDhServerWorld().getServerPlayerStateManager()
.getConnectedPlayer(this.getSourcePlayer(c)); .getConnectedPlayer(this.getSourcePlayer(c));
if (serverPlayerState != null) if (serverPlayerState != null)
{ {
@@ -29,9 +29,9 @@ public class CrashCommand extends AbstractCommand
})) }))
.then(literal("decode") .then(literal("decode")
.executes(c -> { .executes(c -> {
assert SharedApi.getIDhServerWorld() != null; assert SharedApi.tryGetDhServerWorld() != null;
ServerPlayerState serverPlayerState = SharedApi.getIDhServerWorld().getServerPlayerStateManager() ServerPlayerState serverPlayerState = SharedApi.tryGetDhServerWorld().getServerPlayerStateManager()
.getConnectedPlayer(this.getSourcePlayer(c)); .getConnectedPlayer(this.getSourcePlayer(c));
if (serverPlayerState != null) if (serverPlayerState != null)
{ {
@@ -59,13 +59,9 @@ public class DependencySetup
DependencySetupDoneCheck.isDone = true; DependencySetupDoneCheck.isDone = true;
} }
//@Environment(EnvType.SERVER)
public static void createServerBindings() public static void createServerBindings()
{ { SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftServerWrapper.INSTANCE); }
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftServerWrapper.INSTANCE);
}
//@Environment(EnvType.CLIENT)
public static void createClientBindings() public static void createClientBindings()
{ {
SingletonInjector.INSTANCE.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE); SingletonInjector.INSTANCE.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE);
@@ -78,6 +78,11 @@ public class VersionConstants implements IVersionConstants
return "1.21.6"; return "1.21.6";
#elif MC_VER == MC_1_21_8 #elif MC_VER == MC_1_21_8
return "1.21.8"; return "1.21.8";
#elif MC_VER == MC_1_21_9
return "1.21.9";
#elif MC_VER == MC_1_21_10
return "1.21.10";
#else #else
ERROR MC version constant missing ERROR MC version constant missing
#endif #endif
@@ -0,0 +1,335 @@
package com.seibel.distanthorizons.common.wrappers.block;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.BlockBiomeWrapperPair;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable;
import com.seibel.distanthorizons.core.util.ColorUtil;
import com.seibel.distanthorizons.core.util.FullDataPointUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.biome.Biome;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
#if MC_VER >= MC_1_18_2
import net.minecraft.core.Holder;
#endif
public abstract class AbstractDhTintGetter implements BlockAndTintGetter
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
#if MC_VER < MC_1_18_2
private static final ConcurrentHashMap<String, Biome> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>();
#else
private static final ConcurrentHashMap<String, Holder<Biome>> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>();
#endif
private static final ConcurrentHashMap<BlockBiomeWrapperPair, Integer> COLOR_BY_BLOCK_BIOME_PAIR = new ConcurrentHashMap<>();
/** returned if the color cache is incomplete */
public static final int INVALID_COLOR = Integer.MIN_VALUE;
protected BiomeWrapper biomeWrapper;
protected BlockStateWrapper blockStateWrapper;
protected FullDataSourceV2 fullDataSource;
protected int smoothingRadiusInBlocks;
protected IClientLevelWrapper clientLevelWrapper;
//=============//
// constructor //
//=============//
public AbstractDhTintGetter() { }
/**
* Mutates this getter so we can access the necessary
* variables for tint getting.
*/
public void update(BiomeWrapper biomeWrapper, BlockStateWrapper blockStateWrapper, FullDataSourceV2 fullDataSource, IClientLevelWrapper clientLevelWrapper)
{
this.biomeWrapper = biomeWrapper;
this.blockStateWrapper = blockStateWrapper;
this.fullDataSource = fullDataSource;
this.clientLevelWrapper = clientLevelWrapper;
this.smoothingRadiusInBlocks = Config.Client.Advanced.Graphics.Quality.lodBiomeBlending.get();
}
//================//
// shared methods //
//================//
/** Called by MC's tint getter */
@Override
public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver)
{
DhBlockPosMutable mutableBlockPos = new DhBlockPosMutable(blockPos.getX(), blockPos.getY(), blockPos.getZ());
return this.tryGetBlockTint(mutableBlockPos, colorResolver);
}
/**
* Can be called by DH directly, skipping some of MC's logic
* to speed up tint getting slightly.
*
* @return {@link AbstractDhTintGetter#INVALID_COLOR} if any of the biomes needed for this position
* were not cached. In that case calling {@link AbstractDhTintGetter#getBlockTint(BlockPos, ColorResolver)}
* will need to be called by MC's ColorResolver so we can
* populate the color cache.
*/
public int tryGetBlockTint(DhBlockPosMutable mutableBlockPos)
{ return this.tryGetBlockTint(mutableBlockPos, null); }
private int tryGetBlockTint(DhBlockPosMutable mutableBlockPos, @Nullable ColorResolver colorResolver)
{
// determine how wide this data source is so we can determine
// if blending should be used
byte dataSourceDetailLevel = DhSectionPos.getDetailLevel(this.fullDataSource.getPos());
// convert from section detail level to absolute detail level
dataSourceDetailLevel = (byte)(dataSourceDetailLevel - DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL);
int dataSourceLodWidthInBlocks = DhSectionPos.getDetailLevelWidthInBlocks(dataSourceDetailLevel);
// don't do any smoothing if smoothing is disabled or if the LOD
// is to large for block-based smoothing to show up
if (this.smoothingRadiusInBlocks == 0
|| dataSourceLodWidthInBlocks > this.smoothingRadiusInBlocks)
{
return this.tryGetClientBiomeColor(colorResolver, this.biomeWrapper);
}
// use a rolling average to calculate the color
int dataPointCount = 0;
int rollingRed = 0;
int rollingGreen = 0;
int rollingBlue = 0;
int xMin = mutableBlockPos.getX() - this.smoothingRadiusInBlocks;
int xMax = mutableBlockPos.getX() + this.smoothingRadiusInBlocks;
int zMin = mutableBlockPos.getZ() - this.smoothingRadiusInBlocks;
int zMax = mutableBlockPos.getZ() + this.smoothingRadiusInBlocks;
for (int x = xMin; x < xMax; x++)
{
for (int z = zMin; z < zMax; z++)
{
mutableBlockPos.setX(x);
mutableBlockPos.setZ(z);
// 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);
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);
int color = this.tryGetClientBiomeColor(colorResolver, biomeWrapper);
if (color == INVALID_COLOR)
{
return INVALID_COLOR;
}
// rolling average
rollingRed += ColorUtil.getRed(color);
rollingGreen += ColorUtil.getGreen(color);
rollingBlue += ColorUtil.getBlue(color);
dataPointCount++;
}
}
// if no data was present (rarely possible)
// just use the default center's color
if (dataPointCount == 0)
{
return this.tryGetClientBiomeColor(colorResolver, this.biomeWrapper);
}
int colorInt = ColorUtil.argbToInt(
255, // blending often ignores alpha, having it always 255 prevents multiplication issues later
rollingRed / dataPointCount,
rollingGreen / dataPointCount,
rollingBlue / dataPointCount);
return colorInt;
}
/**
* If given a ColorResolver this will always succeed. <Br>
* If not it will attempt to use the cached color.
*/
private int tryGetClientBiomeColor(@Nullable ColorResolver colorResolver, BiomeWrapper biomeWrapper)
{
BlockBiomeWrapperPair pair = BlockBiomeWrapperPair.get(this.blockStateWrapper, biomeWrapper);
// use the cached color if possible
Integer cachedColor = COLOR_BY_BLOCK_BIOME_PAIR.get(pair); // explicit Integer return here reduces unnecessary allocations
if (cachedColor != null)
{
return cachedColor;
}
if (colorResolver == null)
{
// no color resolver is present,
// the cache needs to be populated before
// we can use the fast path
return INVALID_COLOR;
}
int color = colorResolver.getColor(unwrapClientBiome(biomeWrapper), 0, 0);
COLOR_BY_BLOCK_BIOME_PAIR.put(pair, color);
return color;
}
protected static Biome unwrapClientBiome(BiomeWrapper biomeWrapper)
{
String biomeString = biomeWrapper.getSerialString();
if (biomeString == null
|| biomeString.isEmpty()
|| biomeString.equals(BiomeWrapper.EMPTY_BIOME_STRING))
{
// default to "plains" for empty/invalid biomes
biomeString = "minecraft:plains";
}
return unwrapBiome(getClientBiome(biomeString));
}
protected static Biome unwrapBiome(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
{
#if MC_VER >= MC_1_18_2
return biome.value();
#else
return biome;
#endif
}
/**
* <p>Previously, this class might have immediately unwrapped the Holder like this:</p>
* <pre>{@code
* // Inside constructor (OLD WAY - PROBLEMATIC):
* Holder<Biome> biomeHolder = getTheHolderFromSomewhere();
* this.biome = biomeHolder.value(); // <-- PROBLEM HERE
* }</pre>
*
* <p>This approach is problematic because the {@link net.minecraft.core.Holder} system,
* particularly {@code Holder.Reference}, is designed for <strong>late binding</strong>. Here's why storing
* the Holder itself is now necessary:</p>
* <ol>
* <li>A {@code Holder.Reference<Biome>} might be created initially just with a
* {@link net.minecraft.resources.ResourceKey} (like {@code minecraft:plains}), but its actual
* {@link net.minecraft.core.Holder#value() value()} (the {@code Biome} object itself) might be {@code null}
* at construction time.</li>
* <li>Later, during game loading, registry population, or potentially due to modifications by other mods
* (e.g., Polytone), the system calls internal binding methods (like {@code bindValue(Biome)})
* on the {@code Holder} instance. This sets or <strong>updates</strong> the internal reference to the
* actual {@code Biome} object.</li>
* <li>Crucially, the binding process might assign a completely <strong>new</strong> {@code Biome} object
* instance to the {@code Holder} reference, replacing any previous one.</li>
* </ol>
*
* <p>If we unwrapped the {@code Holder} using {@code .value()} within the constructor (the old way),
* our class's internal {@code biome} field would permanently store a reference to whatever {@code Biome}
* object the {@code Holder} pointed to *at that exact moment*. It would have no link back to the
* {@code Holder} and would be unaware if the {@code Holder} was later updated to point to a different
* (or the initially missing) {@code Biome} object. This would lead to using stale or even {@code null} data.</p>
*
* <p>By storing the {@code Holder<Biome>} itself, this class can call {@link net.minecraft.core.Holder#value()}
* whenever the biome information is needed, ensuring it always retrieves the most current {@code Biome}
* instance associated with the holder at that time.</p>
*/
private static #if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif getClientBiome(String biomeResourceString)
{
#if MC_VER < MC_1_18_2
Biome biome;
#else
Holder<Biome> biome;
#endif
// calling get instead of compute is slightly faster for already
// computed values
biome = BIOME_BY_RESOURCE_STRING.get(biomeResourceString);
if (biome != null)
{
return biome;
}
// cache the client biomes so we don't have to re-parse the resource location every time
return BIOME_BY_RESOURCE_STRING.compute(biomeResourceString,
(resourceString, existingBiome) ->
{
if (existingBiome != null)
{
return existingBiome;
}
ClientLevel clientLevel = Minecraft.getInstance().level;
if (clientLevel == null)
{
// shouldn't happen, but just in case
throw new IllegalStateException("Attempted to get client biome when no client level was loaded.");
}
BiomeWrapper.BiomeDeserializeResult result;
try
{
result = BiomeWrapper.deserializeBiome(resourceString, clientLevel.registryAccess());
}
catch (Exception e)
{
LOGGER.warn("Unable to deserialize client biome ["+resourceString+"], using fallback...");
try
{
result = BiomeWrapper.deserializeBiome(BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING, clientLevel.registryAccess());
}
catch (IOException ex)
{
// should never happen, if it does this log will explode, but just in case
LOGGER.error("Unable to deserialize fallback client biome ["+BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING+"], returning NULL.");
return null;
}
}
if (result.success)
{
existingBiome = result.biome;
}
return existingBiome;
});
}
}
@@ -26,10 +26,11 @@ import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
@@ -57,7 +58,7 @@ import net.minecraft.world.level.biome.Biomes;
public class BiomeWrapper implements IBiomeWrapper public class BiomeWrapper implements IBiomeWrapper
{ {
// must be defined before AIR, otherwise a null pointer will be thrown // must be defined before AIR, otherwise a null pointer will be thrown
private static final Logger LOGGER = LogManager.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
@@ -103,7 +104,7 @@ public class BiomeWrapper implements IBiomeWrapper
// constructors // // constructors //
//==============// //==============//
static public IBiomeWrapper getBiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome, ILevelWrapper levelWrapper) public static BiomeWrapper getBiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome, ILevelWrapper levelWrapper)
{ {
if (biome == null) if (biome == null)
{ {
@@ -111,9 +112,10 @@ public class BiomeWrapper implements IBiomeWrapper
} }
if (WRAPPER_BY_BIOME.containsKey(biome)) BiomeWrapper biomeWrapper = WRAPPER_BY_BIOME.get(biome);
if (biomeWrapper != null)
{ {
return WRAPPER_BY_BIOME.get(biome); return biomeWrapper;
} }
else else
{ {
@@ -299,7 +301,7 @@ public class BiomeWrapper implements IBiomeWrapper
} }
foundWrapper = (BiomeWrapper) getBiomeWrapper(deserializeResult.biome, levelWrapper); foundWrapper = getBiomeWrapper(deserializeResult.biome, levelWrapper);
return foundWrapper; return foundWrapper;
} }
catch (Exception e) catch (Exception e)
@@ -35,7 +35,7 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import java.awt.*; import java.awt.*;
import java.io.IOException; import java.io.IOException;
@@ -72,7 +72,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
// must be defined before AIR, otherwise a null pointer will be thrown // must be defined before AIR, otherwise a null pointer will be thrown
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
public static final ConcurrentHashMap<BlockState, BlockStateWrapper> WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>(); public static final ConcurrentHashMap<BlockState, BlockStateWrapper> WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>();
public static final ConcurrentHashMap<String, BlockStateWrapper> WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>(); public static final ConcurrentHashMap<String, BlockStateWrapper> WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>();
@@ -81,6 +81,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
public static final BlockStateWrapper AIR = new BlockStateWrapper(null, null); public static final BlockStateWrapper AIR = new BlockStateWrapper(null, null);
public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt"; public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt";
public static final String WATER_RESOURCE_LOCATION_STRING = "minecraft:water";
public static HashSet<IBlockStateWrapper> rendererIgnoredBlocks = null; public static HashSet<IBlockStateWrapper> rendererIgnoredBlocks = null;
public static HashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null; public static HashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null;
@@ -20,15 +20,16 @@
package com.seibel.distanthorizons.common.wrappers.block; package com.seibel.distanthorizons.common.wrappers.block;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter; import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable;
import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.core.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.FlowerBlock; import net.minecraft.world.level.block.FlowerBlock;
import net.minecraft.world.level.block.LeavesBlock; import net.minecraft.world.level.block.LeavesBlock;
@@ -39,7 +40,7 @@ import net.minecraft.util.RandomSource;
import java.util.Random; import java.util.Random;
#endif #endif
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
@@ -61,7 +62,7 @@ import net.minecraft.client.renderer.block.model.BlockModelPart;
*/ */
public class ClientBlockStateColorCache public class ClientBlockStateColorCache
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final HashSet<BlockState> BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>(); private static final HashSet<BlockState> BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>();
private static final HashSet<BlockState> BROKEN_BLOCK_STATES = new HashSet<>(); private static final HashSet<BlockState> BROKEN_BLOCK_STATES = new HashSet<>();
@@ -93,11 +94,10 @@ public class ClientBlockStateColorCache
private final IClientLevelWrapper clientLevelWrapper; private final IClientLevelWrapper clientLevelWrapper;
private final BlockState blockState; private final BlockState blockState;
private final LevelReader level; private final BlockStateWrapper blockStateWrapper;
private boolean isColorResolved = false; private boolean isColorResolved = false;
private int baseColor = 0; private int baseColor = 0;
private boolean needShade = true;
private boolean needPostTinting = false; private boolean needPostTinting = false;
private int tintIndex = 0; private int tintIndex = 0;
@@ -165,17 +165,21 @@ public class ClientBlockStateColorCache
0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f 0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f
}; };
private static final ThreadLocal<TintWithoutLevelOverrider> TintWithoutLevelOverrideGetter = ThreadLocal.withInitial(() -> new TintWithoutLevelOverrider());
private static final ThreadLocal<TintGetterOverride> TintOverrideGetter = ThreadLocal.withInitial(() -> new TintGetterOverride());
//=============// //=============//
// constructor // // constructor //
//=============// //=============//
public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper samplingLevel) public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper clientLevelWrapper)
{ {
this.blockState = blockState; this.blockState = blockState;
this.clientLevelWrapper = samplingLevel; this.blockStateWrapper = BlockStateWrapper.fromBlockState(blockState, clientLevelWrapper);
this.level = (LevelReader) samplingLevel.getWrappedMcObject(); this.clientLevelWrapper = clientLevelWrapper;
this.resolveColors(); this.resolveColors();
} }
@@ -228,32 +232,29 @@ public class ClientBlockStateColorCache
this.needPostTinting = firstQuad.isTinted(); this.needPostTinting = firstQuad.isTinted();
#if MC_VER <= MC_1_21_4 #if MC_VER <= MC_1_21_4
this.needShade = firstQuad.isShade();
this.tintIndex = firstQuad.getTintIndex(); this.tintIndex = firstQuad.getTintIndex();
#else #else
this.needShade = firstQuad.shade();
this.tintIndex = firstQuad.tintIndex(); this.tintIndex = firstQuad.tintIndex();
#endif #endif
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
this.baseColor = calculateColorFromTexture( this.baseColor = calculateColorFromTexture(
firstQuad.sprite, firstQuad.sprite,
ColorMode.getColorMode(this.blockState.getBlock())); EColorMode.getColorMode(this.blockState.getBlock()));
#elif MC_VER < MC_1_21_5 #elif MC_VER < MC_1_21_5
this.baseColor = calculateColorFromTexture( this.baseColor = calculateColorFromTexture(
firstQuad.getSprite(), firstQuad.getSprite(),
ColorMode.getColorMode(this.blockState.getBlock())); EColorMode.getColorMode(this.blockState.getBlock()));
#else #else
this.baseColor = calculateColorFromTexture( this.baseColor = calculateColorFromTexture(
firstQuad.sprite(), firstQuad.sprite(),
ColorMode.getColorMode(this.blockState.getBlock())); EColorMode.getColorMode(this.blockState.getBlock()));
#endif #endif
} }
else else
{ {
// Backup method. // Backup method.
this.needPostTinting = false; this.needPostTinting = false;
this.needShade = false;
this.tintIndex = 0; this.tintIndex = 0;
this.baseColor = this.getParticleIconColor(); this.baseColor = this.getParticleIconColor();
} }
@@ -262,11 +263,11 @@ public class ClientBlockStateColorCache
{ {
// Liquid Block // Liquid Block
this.needPostTinting = true; this.needPostTinting = true;
this.needShade = false;
this.tintIndex = 0; this.tintIndex = 0;
this.baseColor = this.getParticleIconColor(); this.baseColor = this.getParticleIconColor();
} }
this.isColorResolved = true; this.isColorResolved = true;
} }
finally finally
@@ -304,7 +305,7 @@ public class ClientBlockStateColorCache
} }
//TODO: Perhaps make this not just use the first frame? //TODO: Perhaps make this not just use the first frame?
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode) private static int calculateColorFromTexture(TextureAtlasSprite texture, EColorMode colorMode)
{ {
int count = 0; int count = 0;
int alpha = 0; int alpha = 0;
@@ -314,8 +315,8 @@ public class ClientBlockStateColorCache
int tempColor; int tempColor;
// don't render Chiseled blocks. // don't render Chiseled blocks.
// Since ColorMode is set per block, you only need to check this once. // Since EColorMode is set per block, you only need to check this once.
if (colorMode != ColorMode.Chisel) if (colorMode != EColorMode.Chisel)
{ {
// textures normally use u and v instead of x and y // textures normally use u and v instead of x and y
for (int v = 0; v < getTextureHeight(texture); v++) for (int v = 0; v < getTextureHeight(texture); v++)
@@ -333,7 +334,7 @@ public class ClientBlockStateColorCache
int b = (tempColor & 0x00FF0000) >>> 16; int b = (tempColor & 0x00FF0000) >>> 16;
int a = (tempColor & 0xFF000000) >>> 24; int a = (tempColor & 0xFF000000) >>> 24;
int scale = 1; int scale = 1;
if (colorMode == ColorMode.Leaves) if (colorMode == EColorMode.Leaves)
{ {
//switch (//FIXME add config option) //switch (//FIXME add config option)
// case BLACK: // case BLACK:
@@ -352,11 +353,11 @@ public class ClientBlockStateColorCache
// break; //do nothing, let it count towards transparency // break; //do nothing, let it count towards transparency
} }
else if (a == 0 && colorMode != ColorMode.Glass) else if (a == 0 && colorMode != EColorMode.Glass)
{ {
continue; continue;
} }
else if (colorMode == ColorMode.Flower && (g + 25 < b || g + 25 < r)) else if (colorMode == EColorMode.Flower && (g + 25 < b || g + 25 < r))
{ {
scale = FLOWER_COLOR_SCALE; scale = FLOWER_COLOR_SCALE;
} }
@@ -414,16 +415,18 @@ public class ClientBlockStateColorCache
* This method was suggested by IMS from the Iris/Sodium team. * This method was suggested by IMS from the Iris/Sodium team.
* That's where the numbers and code are based. * That's where the numbers and code are based.
*/ */
private static int linearToSrgb(float c) private static int linearToSrgb(float color)
{ {
if (!(c > MIN_SRGB_BOUND)) { if (!(color > MIN_SRGB_BOUND))
c = MIN_SRGB_BOUND; {
color = MIN_SRGB_BOUND;
} }
if (c > MAX_SRGB_BOUND) { if (color > MAX_SRGB_BOUND)
c = MAX_SRGB_BOUND; {
color = MAX_SRGB_BOUND;
} }
int inputBits = Float.floatToRawIntBits(c); int inputBits = Float.floatToRawIntBits(color);
int entry = linearToSrgbTable[((inputBits - MIN_SRGB_BITS) >> 20)]; int entry = linearToSrgbTable[((inputBits - MIN_SRGB_BITS) >> 20)];
int bias = (entry >>> 16) << 9; int bias = (entry >>> 16) << 9;
@@ -437,7 +440,7 @@ public class ClientBlockStateColorCache
{ {
return calculateColorFromTexture( return calculateColorFromTexture(
Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState), Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState),
ColorMode.getColorMode(this.blockState.getBlock())); EColorMode.getColorMode(this.blockState.getBlock()));
} }
@@ -446,7 +449,7 @@ public class ClientBlockStateColorCache
// public getter // // public getter //
//===============// //===============//
public int getColor(BiomeWrapper biome, DhBlockPos pos) public int getColor(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, DhBlockPos blockPos)
{ {
// only get the tint if the block needs to be tinted // only get the tint if the block needs to be tinted
if (!this.needPostTinting) if (!this.needPostTinting)
@@ -470,13 +473,27 @@ public class ClientBlockStateColorCache
{ {
try try
{ {
tintColor = Minecraft.getInstance().getBlockColors() TintWithoutLevelOverrider tintOverride = TintWithoutLevelOverrideGetter.get();
.getColor(this.blockState, new TintWithoutLevelOverrider(biome, this.clientLevelWrapper), McObjectConverter.Convert(pos), this.tintIndex); tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper);
// try using DH's cached tint values first if possible
tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos));
if (tintColor == AbstractDhTintGetter.INVALID_COLOR)
{
// one or more tint values weren't calculated,
// we need MC's color resolver
tintColor = Minecraft.getInstance()
.getBlockColors()
.getColor(this.blockState,
tintOverride,
McObjectConverter.Convert(blockPos),
this.tintIndex);
}
} }
catch (UnsupportedOperationException e) catch (UnsupportedOperationException e)
{ {
// this exception generally occurs if the tint requires other blocks besides itself // this exception generally occurs if the tint requires other blocks besides itself
LOGGER.debug("Unable to use ["+TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e); LOGGER.debug("Unable to use ["+ TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e);
BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState); BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState);
} }
} }
@@ -484,10 +501,22 @@ public class ClientBlockStateColorCache
// use the level logic only if requested // use the level logic only if requested
if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState)) if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
{ {
// this logic can't be used all the time due to it breaking some blocks tinting // the level shouldn't be used all the time due to it breaking some blocks tinting
// specifically oceans don't render correctly // specifically oceans don't render correctly
tintColor = Minecraft.getInstance().getBlockColors()
.getColor(this.blockState, new TintGetterOverrideFast(this.level), McObjectConverter.Convert(pos), this.tintIndex); TintGetterOverride tintOverride = TintOverrideGetter.get();
tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper);
tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos));
if (tintColor == AbstractDhTintGetter.INVALID_COLOR)
{
tintColor = Minecraft.getInstance()
.getBlockColors()
.getColor(this.blockState,
tintOverride,
McObjectConverter.Convert(blockPos),
this.tintIndex);
}
} }
} }
catch (Exception e) catch (Exception e)
@@ -495,7 +524,7 @@ public class ClientBlockStateColorCache
// only display the error once per block/biome type to reduce log spam // only display the error once per block/biome type to reduce log spam
if (!BROKEN_BLOCK_STATES.contains(this.blockState)) if (!BROKEN_BLOCK_STATES.contains(this.blockState))
{ {
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e); LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
BROKEN_BLOCK_STATES.add(this.blockState); BROKEN_BLOCK_STATES.add(this.blockState);
} }
} }
@@ -519,7 +548,7 @@ public class ClientBlockStateColorCache
// helper classes // // helper classes //
//================// //================//
enum ColorMode private enum EColorMode
{ {
Default, Default,
Flower, Flower,
@@ -527,7 +556,7 @@ public class ClientBlockStateColorCache
Chisel, Chisel,
Glass; Glass;
static ColorMode getColorMode(Block block) static EColorMode getColorMode(Block block)
{ {
if (block instanceof LeavesBlock) return Leaves; if (block instanceof LeavesBlock) return Leaves;
if (block instanceof FlowerBlock) return Flower; if (block instanceof FlowerBlock) return Flower;
@@ -19,10 +19,11 @@
package com.seibel.distanthorizons.common.wrappers.block; package com.seibel.distanthorizons.common.wrappers.block;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.level.*; import net.minecraft.world.level.*;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
@@ -38,9 +39,9 @@ import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
public class TintGetterOverrideFast implements BlockAndTintGetter public class TintGetterOverride extends AbstractDhTintGetter
{ {
LevelReader parent; private LevelReader parent;
@@ -48,7 +49,13 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
// constructor // // constructor //
//=============// //=============//
public TintGetterOverrideFast(LevelReader parent) { this.parent = parent; } public TintGetterOverride() { }
public void update(LevelReader parent, BiomeWrapper biomeWrapper, BlockStateWrapper blockStateWrapper, FullDataSourceV2 fullDataSource, IClientLevelWrapper clientLevelWrapper)
{
super.update(biomeWrapper, blockStateWrapper, fullDataSource, clientLevelWrapper);
this.parent = parent;
}
@@ -56,18 +63,6 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
// methods // // methods //
//=========// //=========//
private Biome _getBiome(BlockPos pos)
{
#if MC_VER >= MC_1_18_2
return this.parent.getBiome(pos).value();
#else
return parent.getBiome(pos);
#endif
}
@Override
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) { return colorResolver.getColor(this._getBiome(blockPos), blockPos.getX(), blockPos.getZ()); }
@Override @Override
public float getShade(Direction direction, boolean bl) { return this.parent.getShade(direction, bl); } public float getShade(Direction direction, boolean bl) { return this.parent.getShade(direction, bl); }
@@ -87,7 +82,6 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
@Nullable @Nullable
public BlockEntity getBlockEntity(BlockPos blockPos) { return this.parent.getBlockEntity(blockPos); } public BlockEntity getBlockEntity(BlockPos blockPos) { return this.parent.getBlockEntity(blockPos); }
@Override @Override
public BlockState getBlockState(BlockPos blockPos) { return this.parent.getBlockState(blockPos); } public BlockState getBlockState(BlockPos blockPos) { return this.parent.getBlockState(blockPos); }
@@ -99,26 +93,25 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
#if MC_VER < MC_1_21_3 #if MC_VER < MC_1_21_3
@Override @Override
public int getMaxLightLevel() { return parent.getMaxLightLevel(); } public int getMaxLightLevel() { return this.parent.getMaxLightLevel(); }
#else #else
#endif #endif
@Override @Override
public Stream<BlockState> getBlockStates(AABB aABB) public Stream<BlockState> getBlockStates(AABB aABB) { return this.parent.getBlockStates(aABB); }
{ return this.parent.getBlockStates(aABB); }
@Override @Override
public BlockHitResult clip(ClipContext clipContext) public BlockHitResult clip(ClipContext clipContext) { return this.parent.clip(clipContext); }
{ return this.parent.clip(clipContext); }
@Override @Override
@Nullable @Nullable
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState) public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState)
{ return this.parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState); } {
return this.parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
}
@Override @Override
public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier) public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier) { return this.parent.getBlockFloorHeight(voxelShape, supplier); }
{ return this.parent.getBlockFloorHeight(voxelShape, supplier); }
@Override @Override
public double getBlockFloorHeight(BlockPos blockPos) { return this.parent.getBlockFloorHeight(blockPos); } public double getBlockFloorHeight(BlockPos blockPos) { return this.parent.getBlockFloorHeight(blockPos); }
@@ -131,20 +124,12 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
public int getMaxY() { return this.parent.getMaxY(); } public int getMaxY() { return this.parent.getMaxY(); }
#endif #endif
//==============//
// post MC 1.17 //
//==============//
#if MC_VER >= MC_1_17_1 #if MC_VER >= MC_1_17_1
@Override @Override
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) { return this.parent.getBlockEntity(blockPos, blockEntityType); }
{ return this.parent.getBlockEntity(blockPos, blockEntityType); }
@Override @Override
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) { return this.parent.isBlockInLine(clipBlockStateContext); }
{ return this.parent.isBlockInLine(clipBlockStateContext); }
@Override @Override
public int getHeight() { return this.parent.getHeight(); } public int getHeight() { return this.parent.getHeight(); }
@@ -165,7 +150,7 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
public int getMinSection() { return this.parent.getMinSection(); } public int getMinSection() { return this.parent.getMinSection(); }
#else #else
@Override @Override
public int getMinSectionY() { return BlockAndTintGetter.super.getMinSectionY(); } public int getMinSectionY() { return super.getMinSectionY(); }
#endif #endif
#if MC_VER < MC_1_21_3 #if MC_VER < MC_1_21_3
@@ -191,4 +176,7 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
@Override @Override
public int getSectionYFromSectionIndex(int i) { return this.parent.getSectionYFromSectionIndex(i); } public int getSectionYFromSectionIndex(int i) { return this.parent.getSectionYFromSectionIndex(i); }
#endif #endif
} }
@@ -1,214 +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.block;
import com.seibel.distanthorizons.core.util.LodUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Cursor3D;
import net.minecraft.core.Direction;
import net.minecraft.world.level.*;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class TintGetterOverrideSmooth implements BlockAndTintGetter
{
LevelReader parent;
public int smoothingRange;
//=============//
// constructor //
//=============//
public TintGetterOverrideSmooth(LevelReader parent, int smoothingRange)
{
this.parent = parent;
this.smoothingRange = smoothingRange;
}
//=========//
// methods //
//=========//
private Biome _getBiome(BlockPos pos)
{
#if MC_VER >= MC_1_18_2
return this.parent.getBiome(pos).value();
#else
return parent.getBiome(pos);
#endif
}
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
{
int i = smoothingRange;
if (i == 0)
return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ());
int j = (i * 2 + 1) * (i * 2 + 1);
int k = 0;
int l = 0;
int m = 0;
Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i);
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
while (cursor3D.advance())
{
mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
int n = colorResolver.getColor(this._getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
k += (n & 0xFF0000) >> 16;
l += (n & 0xFF00) >> 8;
m += n & 0xFF;
}
return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
}
@Override
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) { return this.calculateBlockTint(blockPos, colorResolver); }
@Override
public float getShade(Direction direction, boolean bl) { return this.parent.getShade(direction, bl); }
@Override
public LevelLightEngine getLightEngine() { return this.parent.getLightEngine(); }
@Override
public int getBrightness(LightLayer lightLayer, BlockPos blockPos) { return this.parent.getBrightness(lightLayer, blockPos); }
@Override
public int getRawBrightness(BlockPos blockPos, int i) { return this.parent.getRawBrightness(blockPos, i); }
@Override
public boolean canSeeSky(BlockPos blockPos) { return this.parent.canSeeSky(blockPos); }
@Override
@Nullable
public BlockEntity getBlockEntity(BlockPos blockPos) { return this.parent.getBlockEntity(blockPos); }
@Override
public BlockState getBlockState(BlockPos blockPos) { return this.parent.getBlockState(blockPos); }
@Override
public FluidState getFluidState(BlockPos blockPos) { return this.parent.getFluidState(blockPos); }
@Override
public int getLightEmission(BlockPos blockPos) { return this.parent.getLightEmission(blockPos); }
#if MC_VER < MC_1_21_3
@Override
public int getMaxLightLevel() { return this.parent.getMaxLightLevel(); }
#else
#endif
@Override
public Stream<BlockState> getBlockStates(AABB aABB) { return this.parent.getBlockStates(aABB); }
@Override
public BlockHitResult clip(ClipContext clipContext) { return this.parent.clip(clipContext); }
@Override
@Nullable
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState)
{
return this.parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
}
@Override
public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier) { return this.parent.getBlockFloorHeight(voxelShape, supplier); }
@Override
public double getBlockFloorHeight(BlockPos blockPos) { return this.parent.getBlockFloorHeight(blockPos); }
#if MC_VER < MC_1_21_3
@Override
public int getMaxBuildHeight() { return this.parent.getMaxBuildHeight(); }
#else
@Override
public int getMaxY() { return this.parent.getMaxY(); }
#endif
#if MC_VER >= MC_1_17_1
@Override
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) { return this.parent.getBlockEntity(blockPos, blockEntityType); }
@Override
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) { return this.parent.isBlockInLine(clipBlockStateContext); }
@Override
public int getHeight() { return this.parent.getHeight(); }
#if MC_VER < MC_1_21_3
@Override
public int getMinBuildHeight() { return this.parent.getMinBuildHeight(); }
#else
@Override
public int getMinY() { return this.parent.getMinY(); }
#endif
@Override
public int getSectionsCount() { return this.parent.getSectionsCount(); }
#if MC_VER < MC_1_21_3
@Override
public int getMinSection() { return this.parent.getMinSection(); }
#else
@Override
public int getMinSectionY() { return BlockAndTintGetter.super.getMinSectionY(); }
#endif
#if MC_VER < MC_1_21_3
@Override
public int getMaxSection() { return this.parent.getMaxSection(); }
#else
@Override
public int getMaxSectionY() { return this.parent.getMaxSectionY(); }
#endif
@Override
public boolean isOutsideBuildHeight(BlockPos blockPos) { return this.parent.isOutsideBuildHeight(blockPos); }
@Override
public boolean isOutsideBuildHeight(int i) { return this.parent.isOutsideBuildHeight(i); }
@Override
public int getSectionIndex(int i) { return this.parent.getSectionIndex(i); }
@Override
public int getSectionIndexFromSectionY(int i) { return this.parent.getSectionIndexFromSectionY(i); }
@Override
public int getSectionYFromSectionIndex(int i) { return this.parent.getSectionYFromSectionIndex(i); }
#endif
}
@@ -19,52 +19,26 @@
package com.seibel.distanthorizons.common.wrappers.block; package com.seibel.distanthorizons.common.wrappers.block;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.level.*; import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.FluidState;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
#if MC_VER >= MC_1_18_2 public class TintWithoutLevelOverrider extends AbstractDhTintGetter
import net.minecraft.core.Holder;
#endif
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class TintWithoutLevelOverrider implements BlockAndTintGetter
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
#if MC_VER < MC_1_18_2
public static final ConcurrentMap<String, Biome> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>();
#else
public static final ConcurrentMap<String, Holder<Biome>> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>();
#endif
@NotNull
private final BiomeWrapper biomeWrapper;
//=============// //=============//
// constructor // // constructor //
//=============// //=============//
public TintWithoutLevelOverrider(@NotNull BiomeWrapper biomeWrapper, IClientLevelWrapper clientLevelWrapper) public TintWithoutLevelOverrider()
{ this.biomeWrapper = biomeWrapper; } { }
@@ -73,145 +47,22 @@ public class TintWithoutLevelOverrider implements BlockAndTintGetter
//=========// //=========//
@Override @Override
public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver) public float getShade(Direction direction, boolean shade)
{ { throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only."); }
String biomeString = this.biomeWrapper.getSerialString();
if (biomeString == null
|| biomeString.isEmpty()
|| biomeString.equals(BiomeWrapper.EMPTY_BIOME_STRING))
{
// default to "plains" for empty/invalid biomes
biomeString = "minecraft:plains";
}
return colorResolver.getColor(unwrap(getClientBiome(biomeString)), blockPos.getX(), blockPos.getZ());
}
private static Biome unwrap(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
{
#if MC_VER >= MC_1_18_2
return biome.value();
#else
return biome;
#endif
}
/**
* <p>Previously, this class might have immediately unwrapped the Holder like this:</p>
* <pre>{@code
* // Inside constructor (OLD WAY - PROBLEMATIC):
* Holder<Biome> biomeHolder = getTheHolderFromSomewhere();
* this.biome = biomeHolder.value(); // <-- PROBLEM HERE
* }</pre>
*
* <p>This approach is problematic because the {@link net.minecraft.core.Holder} system,
* particularly {@code Holder.Reference}, is designed for <strong>late binding</strong>. Here's why storing
* the Holder itself is now necessary:</p>
* <ol>
* <li>A {@code Holder.Reference<Biome>} might be created initially just with a
* {@link net.minecraft.resources.ResourceKey} (like {@code minecraft:plains}), but its actual
* {@link net.minecraft.core.Holder#value() value()} (the {@code Biome} object itself) might be {@code null}
* at construction time.</li>
* <li>Later, during game loading, registry population, or potentially due to modifications by other mods
* (e.g., Polytone), the system calls internal binding methods (like {@code bindValue(Biome)})
* on the {@code Holder} instance. This sets or <strong>updates</strong> the internal reference to the
* actual {@code Biome} object.</li>
* <li>Crucially, the binding process might assign a completely <strong>new</strong> {@code Biome} object
* instance to the {@code Holder} reference, replacing any previous one.</li>
* </ol>
*
* <p>If we unwrapped the {@code Holder} using {@code .value()} within the constructor (the old way),
* our class's internal {@code biome} field would permanently store a reference to whatever {@code Biome}
* object the {@code Holder} pointed to *at that exact moment*. It would have no link back to the
* {@code Holder} and would be unaware if the {@code Holder} was later updated to point to a different
* (or the initially missing) {@code Biome} object. This would lead to using stale or even {@code null} data.</p>
*
* <p>By storing the {@code Holder<Biome>} itself, this class can call {@link net.minecraft.core.Holder#value()}
* whenever the biome information is needed, ensuring it always retrieves the most current {@code Biome}
* instance associated with the holder at that time.</p>
*/
private static #if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif getClientBiome(String biomeResourceString)
{
// cache the client biomes so we don't have to re-parse the resource location every time
return BIOME_BY_RESOURCE_STRING.compute(biomeResourceString,
(resourceString, existingBiome) ->
{
if (existingBiome != null)
{
return existingBiome;
}
ClientLevel clientLevel = Minecraft.getInstance().level;
if (clientLevel == null)
{
// shouldn't happen, but just in case
throw new IllegalStateException("Attempted to get client biome when no client level was loaded.");
}
BiomeWrapper.BiomeDeserializeResult result;
try
{
result = BiomeWrapper.deserializeBiome(resourceString, clientLevel.registryAccess());
}
catch (Exception e)
{
LOGGER.warn("Unable to deserialize client biome ["+resourceString+"], using fallback...");
try
{
result = BiomeWrapper.deserializeBiome("minecraft:plains", clientLevel.registryAccess());
}
catch (IOException ex)
{
// should never happen, if it does this log will explode, but just in case
LOGGER.error("Unable to deserialize fallback client biome [minecraft:plains], returning NULL.");
return null;
}
}
if (result.success)
{
existingBiome = result.biome;
}
return existingBiome;
});
}
//================//
// unused methods //
//================//
@Override @Override
public float getShade(@NotNull Direction direction, boolean shade) public LevelLightEngine getLightEngine()
{ { throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only."); }
throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override
public @NotNull LevelLightEngine getLightEngine()
{
throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Nullable @Nullable
@Override @Override
public BlockEntity getBlockEntity(@NotNull BlockPos pos) public BlockEntity getBlockEntity(BlockPos pos)
{ { throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only."); }
throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override @Override
public @NotNull BlockState getBlockState(@NotNull BlockPos pos) public BlockState getBlockState(BlockPos pos)
{ { throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only."); }
throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
@Override @Override
public @NotNull FluidState getFluidState(@NotNull BlockPos pos) public FluidState getFluidState(BlockPos pos)
{ { throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only."); }
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
//==============// //==============//
@@ -227,7 +78,7 @@ public class TintWithoutLevelOverrider implements BlockAndTintGetter
#if MC_VER < MC_1_21_3 #if MC_VER < MC_1_21_3
@Override @Override
public int getMinBuildHeight() public int getMinBuildHeight()
{ throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only."); } { throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
#else #else
@Override @Override
public int getMinY() public int getMinY()
@@ -1,144 +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.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import org.jetbrains.annotations.Nullable;
#if MC_VER >= MC_1_18_2
import net.minecraft.core.Holder;
#endif
public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter
{
final BiomeWrapper biome;
public int smoothingRange;
//=============//
// constructor //
//=============//
public TintWithoutLevelSmoothOverrider(BiomeWrapper biome, int smoothingRange)
{
this.biome = biome;
this.smoothingRange = smoothingRange;
}
//=========//
// methods //
//=========//
@Override
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
{
return colorResolver.getColor(_unwrap(biome.biome), blockPos.getX(), blockPos.getZ());
}
private Biome _unwrap(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
{
#if MC_VER >= MC_1_18_2
return biome.value();
#else
return biome;
#endif
}
// public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
// {
// int i = smoothingRange;
// if (i == 0)
// return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ());
// int j = (i * 2 + 1) * (i * 2 + 1);
// int k = 0;
// int l = 0;
// int m = 0;
// Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i);
// BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
// while (cursor3D.advance())
// {
// mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
// int n;
// if (LodCommonMain.forgeMethodCaller != null) {
// n = LodCommonMain.forgeMethodCaller.colorResolverGetColor(colorResolver, _getBiome(mutableBlockPos),
// mutableBlockPos.getX(), mutableBlockPos.getZ());
// } else {
// n = colorResolver.getColor(_getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
// }
//
// k += (n & 0xFF0000) >> 16;
// l += (n & 0xFF00) >> 8;
// m += n & 0xFF;
// }
// return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
// }
@Override
public float getShade(Direction direction, boolean shade)
{ throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
@Override
public LevelLightEngine getLightEngine()
{ throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
@Nullable
@Override
public BlockEntity getBlockEntity(BlockPos pos)
{ throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
@Override
public BlockState getBlockState(BlockPos pos)
{ throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
@Override
public FluidState getFluidState(BlockPos pos)
{ throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
//==============//
// post MC 1.17 //
//==============//
#if MC_VER >= MC_1_17_1
@Override
public int getHeight()
{ throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
#if MC_VER < MC_1_21_3
@Override
public int getMinBuildHeight()
{ throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
#else
@Override
public int getMinY()
{ throw new UnsupportedOperationException("ERROR: getMinY() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
#endif
#endif
}
@@ -38,7 +38,7 @@ import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.Heightmap;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import java.util.*; import java.util.*;
@@ -75,7 +75,7 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
public class ChunkWrapper implements IChunkWrapper public class ChunkWrapper implements IChunkWrapper
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
/** can be used for interactions with the underlying chunk where creating new BlockPos objects could cause issues for the garbage collector. */ /** can be used for interactions with the underlying chunk where creating new BlockPos objects could cause issues for the garbage collector. */
private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos()); private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos());
@@ -0,0 +1,89 @@
package com.seibel.distanthorizons.common.wrappers.gui;
#if MC_VER < MC_1_21_9
// not supported for older MC versions
#else
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import com.seibel.distanthorizons.coreapi.ModInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
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;
#endif
#if MC_VER < MC_1_21_9
// not supported for older MC versions
public class DhDebugScreenEntry
{}
#else
public class DhDebugScreenEntry implements net.minecraft.client.gui.components.debug.DebugScreenEntry
{
public static void register()
{
// This method is private, so its access will need to be widened
DebugScreenEntries.register(
// The id, this will be displayed on the options screen
ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, "distant_horizons"),
// The screen entry
new DhDebugScreenEntry()
);
}
@Override
public void display(@NotNull DebugScreenDisplayer displayer, @Nullable Level level, @Nullable LevelChunk clientChunk, @Nullable LevelChunk serverChunk)
{
List<String> messageList = new ArrayList<>();
F3Screen.addStringToDisplay(messageList);
for (String message : messageList)
{
displayer.addLine(message);
}
//// The following will display like so if it is the only entry on the screen:
//// First left! First Right!
////
//// Hello world! Random text!
//// Lorem ipsum.
//// I am another group!
//// I am one group This will appear after with no line breaks!
//// All in a row
//// Provided in a list.
////
//
//displayer.addLine("Hello world!");
//displayer.addLine("Lorem ipsum.");
//displayer.addLine("Random text!");
//
//// These will be displayed first
//displayer.addPriorityLine("First left!");
//displayer.addPriorityLine("First right!");
//
//// These will be grouped separately based on the key
//displayer.addToGroup(GROUP_ONE, List.of(
// "I am one group",
// "All in a row",
// "Provided in a list."
//));
//
//displayer.addToGroup(GROUP_TWO, "I am another group!");
//displayer.addToGroup(GROUP_TWO, "This will appear after with no line breaks!");
}
@Override
public boolean isAllowed(boolean reducedDebugInfo)
{
// Always show regardless of accessibility option
return true;
}
}
#endif
@@ -1,40 +1,52 @@
package com.seibel.distanthorizons.common.wrappers.gui; package com.seibel.distanthorizons.common.wrappers.gui;
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.config.gui.ConfigScreen;
import com.seibel.distanthorizons.core.config.gui.JavaScreenHandlerScreen; import com.seibel.distanthorizons.core.config.gui.JavaScreenHandlerScreen;
import com.seibel.distanthorizons.core.config.gui.OpenGLConfigScreen;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import com.seibel.distanthorizons.core.logging.DhLogger;
public class GetConfigScreen public class GetConfigScreen
{ {
public static type useScreen = type.Classic; protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
public enum type public static EType useScreen = EType.Classic;
public enum EType
{ {
Classic, Classic,
@Deprecated JavaSwing;
OpenGL, // This was just an attempt, it didn't work out, and we are going to change to javafx soon (as soon as that works)
JavaFX;
} }
public static Screen getScreen(Screen parent) public static Screen getScreen(Screen parent)
{ {
// Generate the language // TODO it'd be nice to have this run automatically on startup
// This shouldn't be here, but I need a way to test it after Minecraft inits its assets // but this will only work once MC has added our lang file,
//System.out.println(ConfigBase.INSTANCE.generateLang(false, true)); // which won't be for sure added until we request a GUI
if (ModInfo.IS_DEV_BUILD)
{
String missingLangEntries = ConfigHandler.INSTANCE.generateLang(true, true);
// trim to remove any newlines/spaces
// that may be present when no lang entries need changing
// then we can check length != 0 if any items are missing and need adding
String trimmedMissingEntries = missingLangEntries.trim();
if (!trimmedMissingEntries.isEmpty())
{
LOGGER.warn("One or more language entries is missing:");
LOGGER.warn(missingLangEntries);
}
}
switch (useScreen) switch (useScreen)
{ {
case Classic: case Classic:
return ClassicConfigGUI.getScreen(ConfigBase.INSTANCE, parent, "client"); return ClassicConfigGUI.getScreen(parent, "client");
case OpenGL: case JavaSwing:
MinecraftScreen.getScreen(parent, new OpenGLConfigScreen(), ModInfo.ID + ".title"); //return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new ConfigScreen()), ModInfo.ID + ".title");
return null; return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new JavaScreenHandlerScreen.ExampleScreen()), ModInfo.ID + ".title");
// case JavaFX -> MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new JavaScreenHandlerScreen.ExampleScreen()), ModInfo.ID + ".title");
case JavaFX:
return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new ConfigScreen()), ModInfo.ID + ".title");
default: default:
throw new IllegalArgumentException("No config screen implementation defined for ["+useScreen+"]."); throw new IllegalArgumentException("No config screen implementation defined for ["+useScreen+"].");
} }
@@ -24,26 +24,26 @@ public class MinecraftScreen
private static class ConfigScreenRenderer extends DhScreen private static class ConfigScreenRenderer extends DhScreen
{ {
private final Screen parent; private final Screen parent;
private ConfigListWidget list; private ConfigListWidget configListWidget;
private AbstractScreen screen; private AbstractScreen screen;
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
public static net.minecraft.network.chat.TranslatableComponent translate(String str, Object... args) public static net.minecraft.network.chat.TranslatableComponent translate(String str, Object... args)
{ { return new net.minecraft.network.chat.TranslatableComponent(str, args); }
return new net.minecraft.network.chat.TranslatableComponent(str, args);
}
#else #else
public static net.minecraft.network.chat.MutableComponent translate(String str, Object... args) public static net.minecraft.network.chat.MutableComponent translate(String str, Object... args)
{ { return net.minecraft.network.chat.Component.translatable(str, args); }
return net.minecraft.network.chat.Component.translatable(str, args); #endif
}
#endif
protected ConfigScreenRenderer(Screen parent, AbstractScreen screen, String translationName) protected ConfigScreenRenderer(Screen parent, AbstractScreen screen, String translationName)
{ {
super(translate(translationName)); super(translate(translationName));
#if MC_VER < MC_1_21_9
screen.minecraftWindow = Minecraft.getInstance().getWindow().getWindow(); screen.minecraftWindow = Minecraft.getInstance().getWindow().getWindow();
#else
screen.minecraftWindow = Minecraft.getInstance().getWindow().handle();
#endif
this.parent = parent; this.parent = parent;
this.screen = screen; this.screen = screen;
} }
@@ -53,20 +53,22 @@ public class MinecraftScreen
{ {
super.init(); // Init Minecraft's screen super.init(); // Init Minecraft's screen
Window mcWindow = this.minecraft.getWindow(); Window mcWindow = this.minecraft.getWindow();
screen.width = mcWindow.getWidth(); this.screen.width = mcWindow.getWidth();
screen.height = mcWindow.getHeight(); this.screen.height = mcWindow.getHeight();
screen.scaledWidth = this.width; this.screen.scaledWidth = this.width;
screen.scaledHeight = this.height; this.screen.scaledHeight = this.height;
screen.init(); // Init our own config screen this.screen.init(); // Init our own config screen
this.list = new ConfigListWidget(this.minecraft, this.width, this.height, 0, 0, 25); // Select the area to tint this.configListWidget = new ConfigListWidget(this.minecraft, this.width, this.height, 0, 0, 25); // Select the area to tint
#if MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+ #if MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
if (this.minecraft != null && this.minecraft.level != null) // Check if in game if (this.minecraft != null && this.minecraft.level != null) // Check if in game
this.list.setRenderBackground(false); // Disable from rendering {
this.configListWidget.setRenderBackground(false); // Disable from rendering
}
#endif #endif
this.addWidget(this.list); // Add the tint to the things to be rendered this.addWidget(this.configListWidget); // Add the tint to the things to be rendered
} }
@Override @Override
@@ -78,14 +80,17 @@ public class MinecraftScreen
{ {
#if MC_VER < MC_1_20_2 #if MC_VER < MC_1_20_2
this.renderBackground(matrices); // Render background this.renderBackground(matrices); // Render background
#else #elif MC_VER < MC_1_21_6
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
#else
// background blur is already being rendered, rendering again causes the game to crash
#endif #endif
this.list.render(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
screen.mouseX = mouseX; this.configListWidget.render(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
screen.mouseY = mouseY;
screen.render(delta); // Render everything on the main screen this.screen.mouseX = mouseX;
this.screen.mouseY = mouseY;
this.screen.render(delta); // Render everything on the main screen
super.render(matrices, mouseX, mouseY, delta); // Render the vanilla stuff (currently only used for the background and tint) super.render(matrices, mouseX, mouseY, delta); // Render the vanilla stuff (currently only used for the background and tint)
} }
@@ -95,41 +100,39 @@ public class MinecraftScreen
{ {
super.resize(mc, width, height); // Resize Minecraft's screen super.resize(mc, width, height); // Resize Minecraft's screen
Window mcWindow = this.minecraft.getWindow(); Window mcWindow = this.minecraft.getWindow();
screen.width = mcWindow.getWidth(); this.screen.width = mcWindow.getWidth();
screen.height = mcWindow.getHeight(); this.screen.height = mcWindow.getHeight();
screen.scaledWidth = this.width; this.screen.scaledWidth = this.width;
screen.scaledHeight = this.height; this.screen.scaledHeight = this.height;
screen.onResize(); // Resize our screen this.screen.onResize(); // Resize our screen
} }
@Override @Override
public void tick() public void tick()
{ {
super.tick(); // Tick Minecraft's screen super.tick(); // Tick Minecraft's screen
screen.tick(); // Tick our screen this.screen.tick(); // Tick our screen
if (screen.close) // If we decide to close the screen, then actually close the screen if (this.screen.close) // If we decide to close the screen, then actually close the screen
onClose(); {
this.onClose();
}
} }
@Override @Override
public void onClose() public void onClose()
{ {
screen.onClose(); // Close our screen this.screen.onClose(); // Close our screen
Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen Objects.requireNonNull(this.minecraft).setScreen(this.parent); // Goto the parent screen
} }
@Override @Override
public void onFilesDrop(@NotNull List<Path> files) public void onFilesDrop(@NotNull List<Path> files)
{ { this.screen.onFilesDrop(files); }
screen.onFilesDrop(files);
}
// For checking if it should close when you press the escape key // For checking if it should close when you press the escape key
@Override @Override
public boolean shouldCloseOnEsc() public boolean shouldCloseOnEsc()
{ { return this.screen.shouldCloseOnEsc; }
return screen.shouldCloseOnEsc;
}
} }
@@ -0,0 +1,33 @@
package com.seibel.distanthorizons.common.wrappers.gui.config;
import com.seibel.distanthorizons.core.config.gui.IConfigGuiInfo;
import com.seibel.distanthorizons.core.config.types.AbstractConfigBase;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.Nullable;
import java.util.AbstractMap;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* holds information needed by the config GUI for rendering.
*
* @see AbstractConfigBase
*/
public class ConfigGuiInfo implements IConfigGuiInfo
{
/**
* Used to display validation errors.
* Null if no error is present.
*/
@Nullable
public Component errorMessage;
public BiFunction<EditBox, Button, Predicate<String>> tooltipFunction;
/** determines which options the button will show */
public AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>> buttonOptionMap;
}
@@ -14,7 +14,7 @@ import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
#if MC_VER >= MC_1_17_1 #if MC_VER >= MC_1_17_1
import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.narration.NarratableEntry;
@@ -41,7 +41,7 @@ import java.util.*;
// TODO: Make this // TODO: Make this
public class ChangelogScreen extends DhScreen public class ChangelogScreen extends DhScreen
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private Screen parent; private Screen parent;
@@ -74,6 +74,7 @@ public class ChangelogScreen extends DhScreen
{ {
return; return;
} }
try try
{ {
this.setupChangelog(versionID); this.setupChangelog(versionID);
@@ -175,9 +176,12 @@ public class ChangelogScreen extends DhScreen
{ {
#if MC_VER < MC_1_20_2 #if MC_VER < MC_1_20_2
this.renderBackground(matrices); // Render background this.renderBackground(matrices); // Render background
#else #elif MC_VER < MC_1_21_6
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
#else
// background blur is already being rendered, rendering again causes the game to crash
#endif #endif
if (!this.usable) if (!this.usable)
{ {
return; return;
@@ -249,42 +253,35 @@ public class ChangelogScreen extends DhScreen
private final Component text; private final Component text;
private final List<AbstractWidget> children = new ArrayList<>(); private final List<AbstractWidget> children = new ArrayList<>();
private ButtonEntry(Component text) private ButtonEntry(Component text) { this.text = text; }
{
this.text = text;
}
public static ButtonEntry create(Component text) public static ButtonEntry create(Component text)
{ { return new ButtonEntry(text); }
return new ButtonEntry(text);
}
#if MC_VER < MC_1_20_1 #if MC_VER < MC_1_20_1
@Override @Override
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
{ { GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF); }
GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF); #elif MC_VER < MC_1_21_9
}
#else
@Override @Override
public void render(GuiGraphics matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) public void render(GuiGraphics matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
{ { matrices.drawString(textRenderer, this.text, 12, y + 5, 0xFFFFFF); }
matrices.drawString(textRenderer, this.text, 12, y + 5, 0xFFFFFF); #else
} @Override
public void renderContent(GuiGraphics matrices, int y, int x, boolean hovered, float tickDelta)
{ matrices.drawString(textRenderer, this.text, 12, y + 5, 0xFFFFFF); }
#endif #endif
@Override @Override
public List<? extends GuiEventListener> children() public List<? extends GuiEventListener> children() { return this.children; }
{
return this.children;
}
#if MC_VER >= MC_1_17_1 #if MC_VER >= MC_1_17_1
@Override @Override
public List<? extends NarratableEntry> narratables() public List<? extends NarratableEntry> narratables() { return this.children; }
{
return this.children;
}
#endif #endif
} }
} }
@@ -16,7 +16,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
#endif #endif
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*; import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
@@ -31,7 +31,7 @@ import java.util.*;
// and also maybe add this suggestion https://discord.com/channels/881614130614767666/1035863487110467625/1035949054485594192 // and also maybe add this suggestion https://discord.com/channels/881614130614767666/1035863487110467625/1035949054485594192
public class UpdateModScreen extends DhScreen public class UpdateModScreen extends DhScreen
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private Screen parent; private Screen parent;
@@ -36,9 +36,9 @@ public class KeyedClientLevelManager implements IKeyedClientLevelManager
public IServerKeyedClientLevel getServerKeyedLevel() { return this.serverKeyedLevel; } public IServerKeyedClientLevel getServerKeyedLevel() { return this.serverKeyedLevel; }
@Override @Override
public IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String levelKey) public IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String serverKey, String levelKey)
{ {
IServerKeyedClientLevel keyedLevel = new ServerKeyedClientLevel((ClientLevel) clientLevel.getWrappedMcObject(), levelKey); IServerKeyedClientLevel keyedLevel = new ServerKeyedClientLevelWrapper((ClientLevel) clientLevel.getWrappedMcObject(), serverKey, levelKey);
this.serverKeyedLevel = keyedLevel; this.serverKeyedLevel = keyedLevel;
this.enabled = true; this.enabled = true;
return keyedLevel; return keyedLevel;
@@ -2,24 +2,36 @@ package com.seibel.distanthorizons.common.wrappers.level;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.coreapi.util.StringUtil;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
public class ServerKeyedClientLevel extends ClientLevelWrapper implements IServerKeyedClientLevel public class ServerKeyedClientLevelWrapper extends ClientLevelWrapper implements IServerKeyedClientLevel
{ {
/** Returns the folder name the server wants the client to use. */
private final String serverKey;
/** A unique identifier (generally the level's name) for differentiating multiverse levels */ /** A unique identifier (generally the level's name) for differentiating multiverse levels */
private final String serverLevelKey; private final String serverLevelKey;
public ServerKeyedClientLevel(ClientLevel level, String serverLevelKey) //=============//
// constructor //
//=============//
public ServerKeyedClientLevelWrapper(ClientLevel level, String serverKey, String serverLevelKey)
{ {
super(level); super(level);
this.serverKey = serverKey;
this.serverLevelKey = serverLevelKey; this.serverLevelKey = serverLevelKey;
} }
@Override
public String getServerKey() { return this.serverKey; }
//======================//
// level identification //
//======================//
@Override @Override
public String getServerLevelKey() { return this.serverLevelKey; } public String getServerLevelKey() { return this.serverLevelKey; }
@@ -27,4 +39,6 @@ public class ServerKeyedClientLevel extends ClientLevelWrapper implements IServe
@Override @Override
public String getDhIdentifier() { return this.getServerLevelKey(); } public String getDhIdentifier() { return this.getServerLevelKey(); }
} }
@@ -33,6 +33,7 @@ import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure; import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
import com.seibel.distanthorizons.core.render.glObject.GLProxy;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -56,7 +57,7 @@ import net.minecraft.network.chat.TextComponent;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
#if MC_VER < MC_1_21_3 #if MC_VER < MC_1_21_3
@@ -71,7 +72,7 @@ import net.minecraft.util.profiling.Profiler;
*/ */
public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecraftSharedWrapper public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecraftSharedWrapper
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName()); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final Minecraft MINECRAFT = Minecraft.getInstance(); private static final Minecraft MINECRAFT = Minecraft.getInstance();
public static final MinecraftClientWrapper INSTANCE = new MinecraftClientWrapper(); public static final MinecraftClientWrapper INSTANCE = new MinecraftClientWrapper();
@@ -157,9 +158,17 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
@Override @Override
public boolean hasSinglePlayerServer() { return MINECRAFT.hasSingleplayerServer(); } public boolean hasSinglePlayerServer() { return MINECRAFT.hasSingleplayerServer(); }
@Override @Override
public boolean clientConnectedToDedicatedServer() { return MINECRAFT.getCurrentServer() != null && !this.hasSinglePlayerServer(); } public boolean clientConnectedToDedicatedServer()
{
return MINECRAFT.getCurrentServer() != null
&& !this.hasSinglePlayerServer();
}
@Override @Override
public boolean connectedToReplay() { return !MINECRAFT.hasSingleplayerServer() && MINECRAFT.getCurrentServer() == null; } public boolean connectedToReplay()
{
return MINECRAFT.getCurrentServer() == null
&& !this.hasSinglePlayerServer() ;
}
@Override @Override
public String getCurrentServerName() public String getCurrentServerName()
@@ -306,10 +315,22 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
return; return;
} }
if (!GLProxy.hasInstance())
{
// rendering setup hasn't finished
return;
}
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
player.sendMessage(new TextComponent(string), getPlayer().getUUID()); player.sendMessage(new TextComponent(string), getPlayer().getUUID());
#else #elif MC_VER < MC_1_21_9
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false); 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 #endif
} }
@@ -21,14 +21,14 @@ package com.seibel.distanthorizons.common.wrappers.minecraft;
#if MC_VER < MC_1_21_5 #if MC_VER < MC_1_21_5
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
#elif MC_VER >= MC_1_21_5 #else
import com.mojang.blaze3d.opengl.GlStateManager; import com.mojang.blaze3d.opengl.GlStateManager;
#endif #endif
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.lwjgl.opengl.GL32; import org.lwjgl.opengl.GL32;
@@ -54,7 +54,7 @@ public class MinecraftGLWrapper implements IMinecraftGLWrapper
{ {
public static final MinecraftGLWrapper INSTANCE = new MinecraftGLWrapper(); public static final MinecraftGLWrapper INSTANCE = new MinecraftGLWrapper();
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@@ -25,7 +25,6 @@ import java.util.concurrent.ConcurrentHashMap;
import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.pipeline.RenderTarget;
import com.mojang.blaze3d.platform.NativeImage; import com.mojang.blaze3d.platform.NativeImage;
import com.seibel.distanthorizons.common.wrappers.WrapperFactory;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper; import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
@@ -60,6 +59,12 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAc
import net.minecraft.client.Camera; import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.world.effect.MobEffects; import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.phys.Vec3;
import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.NotNull;
import org.joml.Vector4f;
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
import net.minecraft.tags.FluidTags; import net.minecraft.tags.FluidTags;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
@@ -68,29 +73,22 @@ import org.lwjgl.opengl.GL15;
#else #else
import net.minecraft.world.level.material.FogType; import net.minecraft.world.level.material.FogType;
#endif #endif
import net.minecraft.world.phys.Vec3;
import org.apache.logging.log4j.Logger;
import org.joml.Vector4f;
#if MC_VER >= MC_1_21_5 #if MC_VER >= MC_1_21_5
import com.mojang.blaze3d.opengl.GlTexture; import com.mojang.blaze3d.opengl.GlTexture;
#else
#endif #endif
/** /**
* A singleton that contains everything * A singleton that contains everything
* related to rendering in Minecraft. * related to rendering in Minecraft.
*
* @author James Seibel
* @version 12-12-2021
*/ */
//@Environment(EnvType.CLIENT)
public class MinecraftRenderWrapper implements IMinecraftRenderWrapper public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
{ {
public static final MinecraftRenderWrapper INSTANCE = new MinecraftRenderWrapper(); public static final MinecraftRenderWrapper INSTANCE = new MinecraftRenderWrapper();
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName()); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final Minecraft MC = Minecraft.getInstance(); private static final Minecraft MC = Minecraft.getInstance();
private static final IWrapperFactory FACTORY = WrapperFactory.INSTANCE;
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class); private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
@@ -300,7 +298,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
return height; return height;
} }
private RenderTarget getRenderTarget() { return MC.getMainRenderTarget(); } protected RenderTarget getRenderTarget() { return MC.getMainRenderTarget(); }
@Override @Override
public boolean mcRendersToFrameBuffer() public boolean mcRendersToFrameBuffer()
@@ -323,7 +321,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
} }
@Override @Override
public int getTargetFrameBuffer() public int getTargetFramebuffer()
{ {
// used so we can access the framebuffer shaders end up rendering to // used so we can access the framebuffer shaders end up rendering to
if (AbstractOptifineAccessor.optifinePresent()) if (AbstractOptifineAccessor.optifinePresent())
@@ -359,8 +357,9 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
} }
return glTexture.glId(); return glTexture.glId();
} }
catch (ClassCastException e) catch (Exception e)
{ {
// only log this error once per session // only log this error once per session
if (!this.depthTextureCastFailLogged) if (!this.depthTextureCastFailLogged)
@@ -389,7 +388,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
return glTexture.glId(); return glTexture.glId();
} }
catch (ClassCastException e) catch (Exception e)
{ {
// only log this error once per session // only log this error once per session
if (!this.colorTextureCastFailLogged) if (!this.colorTextureCastFailLogged)
@@ -403,19 +402,27 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
} }
@Override @Override
public int getTargetFrameBufferViewportWidth() public int getTargetFramebufferViewportWidth()
{ {
#if MC_VER < MC_1_21_9
return this.getRenderTarget().viewWidth; return this.getRenderTarget().viewWidth;
#else
return this.getRenderTarget().width;
#endif
} }
@Override @Override
public int getTargetFrameBufferViewportHeight() public int getTargetFramebufferViewportHeight()
{ {
#if MC_VER < MC_1_21_9
return this.getRenderTarget().viewHeight; return this.getRenderTarget().viewHeight;
#else
return this.getRenderTarget().height;
#endif
} }
@Override @Override
public ILightMapWrapper getLightmapWrapper(ILevelWrapper level) { return this.lightmapByDimensionType.get(level.getDimensionType()); } public ILightMapWrapper getLightmapWrapper(@NotNull ILevelWrapper level) { return this.lightmapByDimensionType.get(level.getDimensionType()); }
@Override @Override
public boolean isFogStateSpecial() public boolean isFogStateSpecial()
@@ -24,7 +24,7 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.lwjgl.opengl.GL32; import org.lwjgl.opengl.GL32;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -32,7 +32,7 @@ import java.nio.ByteBuffer;
public class LightMapWrapper implements ILightMapWrapper public class LightMapWrapper implements ILightMapWrapper
{ {
private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class); private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class);
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private int textureId = 0; private int textureId = 0;
@@ -71,26 +71,6 @@ public class ServerPlayerWrapper implements IServerPlayerWrapper
return new Vec3d(position.x, position.y, position.z); return new Vec3d(position.x, position.y, position.z);
} }
@Override
public int getViewDistance()
{
#if MC_VER < MC_1_21_6
return this.getServerPlayer().server.getPlayerList().getViewDistance();
#else
return this.getServerPlayer().getServer().getPlayerList().getViewDistance();
#endif
}
@Override
public SocketAddress getRemoteAddress()
{
#if MC_VER >= MC_1_19_4
return this.getServerPlayer().connection.getRemoteAddress();
#else // < 1.19.4
return this.getServerPlayer().connection.connection.getRemoteAddress();
#endif
}
//================// //================//
@@ -2,11 +2,11 @@ package com.seibel.distanthorizons.common.wrappers.world;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister; import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
import com.seibel.distanthorizons.common.wrappers.block.ClientBlockStateColorCache; import com.seibel.distanthorizons.common.wrappers.block.ClientBlockStateColorCache;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.level.*; import com.seibel.distanthorizons.core.level.*;
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
@@ -24,8 +24,7 @@ import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -53,7 +52,7 @@ import com.seibel.distanthorizons.core.util.ColorUtil;
public class ClientLevelWrapper implements IClientLevelWrapper public class ClientLevelWrapper implements IClientLevelWrapper
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(ClientLevelWrapper.class.getSimpleName()); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
/** /**
* weak references are to prevent rare issues * weak references are to prevent rare issues
* where, upon world closure, some levels aren't shutdown/removed properly * where, upon world closure, some levels aren't shutdown/removed properly
@@ -65,16 +64,14 @@ public class ClientLevelWrapper implements IClientLevelWrapper
private static final Minecraft MINECRAFT = Minecraft.getInstance(); private static final Minecraft MINECRAFT = Minecraft.getInstance();
private final ClientLevel level; private final ClientLevel level;
private final ConcurrentHashMap<BlockState, ClientBlockStateColorCache> blockCache = new ConcurrentHashMap<>(); private final ConcurrentHashMap<BlockState, ClientBlockStateColorCache> blockColorCacheByBlockState = new ConcurrentHashMap<>();
/** cached method reference to reduce GC overhead */ /** cached method reference to reduce GC overhead */
private final Function<BlockState, ClientBlockStateColorCache> cachedBlockColorCacheFunction = (blockState) -> this.createBlockColorCache(blockState); private final Function<BlockState, ClientBlockStateColorCache> createCachedBlockColorCacheFunc = (blockState) -> new ClientBlockStateColorCache(blockState, this);
private BlockStateWrapper dirtBlockWrapper; private BlockStateWrapper dirtBlockWrapper;
private BiomeWrapper plainsBiomeWrapper; private IDhLevel dhLevel;
@Deprecated // TODO circular references are bad
private IDhLevel parentDhLevel;
@@ -90,6 +87,29 @@ public class ClientLevelWrapper implements IClientLevelWrapper
// instance methods // // instance methods //
//==================// //==================//
/**
* can be used when speed is important and the same level is likely to be passed in,
* IE rendering.
*/
@Nullable
public static IClientLevelWrapper getWrapperIfDifferent(@Nullable IClientLevelWrapper levelWrapper, @NotNull ClientLevel level)
{
if (KEYED_CLIENT_LEVEL_MANAGER.isEnabled() && KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel() != levelWrapper)
{
return getWrapper(level);
}
ClientLevelWrapper clientLevelWrapper = (ClientLevelWrapper)levelWrapper;
if (clientLevelWrapper == null
|| clientLevelWrapper.level != level)
{
return getWrapper(level);
}
return clientLevelWrapper;
}
@Nullable
public static IClientLevelWrapper getWrapper(@NotNull ClientLevel level) { return getWrapper(level, false); } public static IClientLevelWrapper getWrapper(@NotNull ClientLevel level) { return getWrapper(level, false); }
@Nullable @Nullable
@@ -143,13 +163,17 @@ public class ClientLevelWrapper implements IClientLevelWrapper
{ {
try try
{ {
// this method only makes sense if we are running a single-player server
if (MINECRAFT.getSingleplayerServer() == null)
{
return null;
}
Iterable<ServerLevel> serverLevels = MINECRAFT.getSingleplayerServer().getAllLevels(); Iterable<ServerLevel> serverLevels = MINECRAFT.getSingleplayerServer().getAllLevels();
// attempt to find the server level with the same dimension type // attempt to find the server level with the same dimension type
// TODO this assumes only one level per dimension type, the SubDimensionLevelMatcher will need to be added for supporting multiple levels per dimension // Note: this assumes only one level per dimension type, multiverse servers may not behave correctly
ServerLevelWrapper foundLevelWrapper = null; ServerLevelWrapper foundLevelWrapper = null;
// TODO: Surely there is a more efficient way to write this code
for (ServerLevel serverLevel : serverLevels) for (ServerLevel serverLevel : serverLevels)
{ {
if (serverLevel.dimension() == this.level.dimension()) if (serverLevel.dimension() == this.level.dimension())
@@ -175,16 +199,18 @@ public class ClientLevelWrapper implements IClientLevelWrapper
//====================// //====================//
@Override @Override
public int getBlockColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockWrapper) public int getBlockColor(DhBlockPos blockPos, IBiomeWrapper biome, FullDataSourceV2 fullDataSource, IBlockStateWrapper blockWrapper)
{ {
ClientBlockStateColorCache blockColorCache = this.blockCache.computeIfAbsent( ClientBlockStateColorCache blockColorCache = this.blockColorCacheByBlockState.get(((BlockStateWrapper) blockWrapper).blockState);
((BlockStateWrapper) blockWrapper).blockState, if (blockColorCache == null)
this.cachedBlockColorCacheFunction); {
blockColorCache = this.blockColorCacheByBlockState.computeIfAbsent(
((BlockStateWrapper) blockWrapper).blockState,
this.createCachedBlockColorCacheFunc);
}
return blockColorCache.getColor((BiomeWrapper) biome, pos); return blockColorCache.getColor((BiomeWrapper) biome, fullDataSource, blockPos);
} }
/** used by {@link ClientLevelWrapper#cachedBlockColorCacheFunction} */
private ClientBlockStateColorCache createBlockColorCache(BlockState block) { return new ClientBlockStateColorCache(block, this); }
@Override @Override
@@ -204,31 +230,11 @@ public class ClientLevelWrapper implements IClientLevelWrapper
} }
} }
return this.getBlockColor(DhBlockPos.ZERO,BiomeWrapper.EMPTY_WRAPPER, this.dirtBlockWrapper); return this.getBlockColor(DhBlockPos.ZERO, BiomeWrapper.EMPTY_WRAPPER, null, this.dirtBlockWrapper);
} }
@Override @Override
public void clearBlockColorCache() { this.blockCache.clear(); } public void clearBlockColorCache() { this.blockColorCacheByBlockState.clear(); }
@Override
public IBiomeWrapper getPlainsBiomeWrapper()
{
if (this.plainsBiomeWrapper == null)
{
try
{
this.plainsBiomeWrapper = (BiomeWrapper) BiomeWrapper.deserialize(BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING, this);
}
catch (IOException e)
{
// shouldn't happen, but just in case
LOGGER.warn("Unable to get planes biome with resource location ["+BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING+"] with level ["+this+"].", e);
return null;
}
}
return this.plainsBiomeWrapper;
}
@Override @Override
public IDimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); } public IDimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); }
@@ -286,20 +292,6 @@ public class ClientLevelWrapper implements IClientLevelWrapper
return new ChunkWrapper(chunk, this); return new ChunkWrapper(chunk, this);
} }
@Override
public boolean hasChunkLoaded(int chunkX, int chunkZ)
{
ChunkSource source = this.level.getChunkSource();
return source.hasChunk(chunkX, chunkZ);
}
@Override
public IBlockStateWrapper getBlockState(DhBlockPos pos)
{ return BlockStateWrapper.fromBlockState(this.level.getBlockState(McObjectConverter.Convert(pos)), this); }
@Override
public IBiomeWrapper getBiome(DhBlockPos pos) { return BiomeWrapper.getBiomeWrapper(this.level.getBiome(McObjectConverter.Convert(pos)), this); }
@Override @Override
public ClientLevel getWrappedMcObject() { return this.level; } public ClientLevel getWrappedMcObject() { return this.level; }
@@ -307,18 +299,18 @@ public class ClientLevelWrapper implements IClientLevelWrapper
public void onUnload() public void onUnload()
{ {
LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.remove(this.level); LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.remove(this.level);
this.parentDhLevel = null; this.dhLevel = null;
} }
@Override @Override
public File getDhSaveFolder() public File getDhSaveFolder()
{ {
if (this.parentDhLevel == null) if (this.dhLevel == null)
{ {
return null; return null;
} }
return this.parentDhLevel.getSaveStructure().getSaveFolder(this); return this.dhLevel.getSaveStructure().getSaveFolder(this);
} }
@@ -329,17 +321,19 @@ public class ClientLevelWrapper implements IClientLevelWrapper
//===================// //===================//
@Override @Override
public void setParentLevel(IDhLevel parentLevel) { this.parentDhLevel = parentLevel; } public void setDhLevel(IDhLevel dhLevel) { this.dhLevel = dhLevel; }
@Override
public IDhLevel getDhLevel() { return this.dhLevel; }
@Override @Override
public IDhApiCustomRenderRegister getRenderRegister() public IDhApiCustomRenderRegister getRenderRegister()
{ {
if (this.parentDhLevel == null) if (this.dhLevel == null)
{ {
return null; return null;
} }
return this.parentDhLevel.getGenericRenderer(); return this.dhLevel.getGenericRenderer();
} }
@Override @Override
@@ -24,21 +24,18 @@ import java.lang.ref.WeakReference;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister; import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.level.IDhLevel;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage;
import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.world.EWorldEnvironment;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@@ -52,16 +49,12 @@ import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif #endif
#if MC_VER < MC_1_21_3 import com.seibel.distanthorizons.core.logging.DhLogger;
#else import org.jetbrains.annotations.Nullable;
import java.nio.file.Path;
#endif
import org.apache.logging.log4j.Logger;
public class ServerLevelWrapper implements IServerLevelWrapper public class ServerLevelWrapper implements IServerLevelWrapper
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
/** /**
* weak references are to prevent rare issues * weak references are to prevent rare issues
* where, upon world closure, some levels aren't shutdown/removed properly * where, upon world closure, some levels aren't shutdown/removed properly
@@ -69,8 +62,13 @@ public class ServerLevelWrapper implements IServerLevelWrapper
private static final Map<ServerLevel, WeakReference<ServerLevelWrapper>> LEVEL_WRAPPER_REF_BY_SERVER_LEVEL = Collections.synchronizedMap(new WeakHashMap<>()); private static final Map<ServerLevel, WeakReference<ServerLevelWrapper>> LEVEL_WRAPPER_REF_BY_SERVER_LEVEL = Collections.synchronizedMap(new WeakHashMap<>());
private final ServerLevel level; private final ServerLevel level;
@Deprecated // TODO circular references are bad private IDhLevel dhLevel;
private IDhLevel parentDhLevel;
/**
* this name is cached to prevent issues during shutdown where
* the server variables needed may no longer be available.
*/
private final String KeyedLevelDimensionName;
@@ -95,7 +93,11 @@ public class ServerLevelWrapper implements IServerLevelWrapper
}).get(); }).get();
} }
public ServerLevelWrapper(ServerLevel level) { this.level = level; } public ServerLevelWrapper(ServerLevel level)
{
this.level = level;
this.KeyedLevelDimensionName = this.createKeyedLevelDimensionName();
}
@@ -114,16 +116,60 @@ public class ServerLevelWrapper implements IServerLevelWrapper
} }
@Override @Override
public String getWorldFolderName() public String getKeyedLevelDimensionName() { return this.KeyedLevelDimensionName; }
{
// Need specifically overworld since it's the only dimension that is stored in a server root folder
#if MC_VER >= MC_1_21_3 private String createKeyedLevelDimensionName()
return this.level.getServer().getLevel(Level.OVERWORLD).getChunkSource().getDataStorage().dataFolder.getParent().getFileName().toString(); {
#else // <= 1.21.3 String dimensionName = this.getDhIdentifier();
return this.level.getServer().getLevel(Level.OVERWORLD).getChunkSource().getDataStorage().dataFolder.getParentFile().getName();
#endif if (Config.Server.sendLevelKeys.get())
{
String levelKeyPrefix = Config.Server.levelKeyPrefix.get();
if (SharedApi.getEnvironment() == EWorldEnvironment.CLIENT_SERVER)
{
String cleanWorldFolderName = this.getWorldFolderName()
.replaceAll("[^" + LevelInitMessage.ALLOWED_CHARS_REGEX + " ]", "")
.replaceAll(" ", "_");
levelKeyPrefix += (!levelKeyPrefix.isEmpty() ? "_" : "") + cleanWorldFolderName
+ "_" + this.getHashedSeedEncoded();
}
if (levelKeyPrefix.isEmpty())
{
levelKeyPrefix = this.getHashedSeedEncoded();
}
String mainPart = "@" + dimensionName;
return levelKeyPrefix.substring(0, Math.min(
LevelInitMessage.MAX_LENGTH - mainPart.length(),
levelKeyPrefix.length()
)) + mainPart;
}
return dimensionName;
} }
private String getWorldFolderName()
{
try
{
// We use the overworld since it's the only dimension that is stored in the server root folder
#if MC_VER >= MC_1_21_3
return this.level.getServer().getLevel(Level.OVERWORLD).getChunkSource().getDataStorage().dataFolder.getParent().getFileName().toString();
#else // <= 1.21.3
return this.level.getServer().getLevel(Level.OVERWORLD).getChunkSource().getDataStorage().dataFolder.getParentFile().getName();
#endif
}
catch (Exception e)
{
LOGGER.warn("Unable to get world folder name. LODs may not load or save correctly. Error: ["+e.getMessage()+"].", e);
return "unknown_world";
}
}
@Override @Override
public DimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); } public DimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); }
@@ -180,26 +226,6 @@ public class ServerLevelWrapper implements IServerLevelWrapper
return new ChunkWrapper(chunk, this); return new ChunkWrapper(chunk, this);
} }
@Override
public boolean hasChunkLoaded(int chunkX, int chunkZ)
{
// world.hasChunk(chunkX, chunkZ); THIS DOES NOT WORK FOR CLIENT LEVEL CAUSE MOJANG ALWAYS RETURN TRUE FOR THAT!
ChunkSource source = this.level.getChunkSource();
return source.hasChunk(chunkX, chunkZ);
}
@Override
public IBlockStateWrapper getBlockState(DhBlockPos pos)
{
return BlockStateWrapper.fromBlockState(this.level.getBlockState(McObjectConverter.Convert(pos)), this);
}
@Override
public IBiomeWrapper getBiome(DhBlockPos pos)
{
return BiomeWrapper.getBiomeWrapper(this.level.getBiome(McObjectConverter.Convert(pos)), this);
}
@Override @Override
public ServerLevel getWrappedMcObject() { return this.level; } public ServerLevel getWrappedMcObject() { return this.level; }
@@ -208,28 +234,31 @@ public class ServerLevelWrapper implements IServerLevelWrapper
@Override @Override
public void setParentLevel(IDhLevel parentLevel) { this.parentDhLevel = parentLevel; } public void setDhLevel(IDhLevel dhLevel) { this.dhLevel = dhLevel; }
@Override
@Nullable
public IDhLevel getDhLevel() { return this.dhLevel; }
@Override @Override
public IDhApiCustomRenderRegister getRenderRegister() public IDhApiCustomRenderRegister getRenderRegister()
{ {
if (this.parentDhLevel == null) if (this.dhLevel == null)
{ {
return null; return null;
} }
return this.parentDhLevel.getGenericRenderer(); return this.dhLevel.getGenericRenderer();
} }
@Override @Override
public File getDhSaveFolder() public File getDhSaveFolder()
{ {
if (this.parentDhLevel == null) if (this.dhLevel == null)
{ {
return null; return null;
} }
return this.parentDhLevel.getSaveStructure().getSaveFolder(this); return this.dhLevel.getSaveStructure().getSaveFolder(this);
} }
@@ -29,8 +29,8 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.generation.DhLightingEngine; import com.seibel.distanthorizons.core.generation.DhLightingEngine;
import com.seibel.distanthorizons.core.level.IDhServerLevel; import com.seibel.distanthorizons.core.level.IDhServerLevel;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.ConfigBasedSpamLogger; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.util.objects.EventTimer; import com.seibel.distanthorizons.core.util.objects.EventTimer;
import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.LodUtil;
@@ -42,6 +42,8 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.Abstrac
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.ClosedChannelException;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@@ -50,6 +52,9 @@ import java.util.function.Function;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck; import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepBiomes; import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepBiomes;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepFeatures; import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepFeatures;
@@ -60,10 +65,7 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepSurfa
import net.minecraft.server.level.*; import net.minecraft.server.level.*;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.*;
import net.minecraft.world.level.chunk.ChunkGenerator;
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.IOWorker;
import net.minecraft.world.level.chunk.storage.RegionFileStorage; import net.minecraft.world.level.chunk.storage.RegionFileStorage;
import net.minecraft.world.level.levelgen.DebugLevelSource; import net.minecraft.world.level.levelgen.DebugLevelSource;
@@ -71,21 +73,21 @@ import net.minecraft.world.level.levelgen.FlatLevelSource;
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import org.apache.logging.log4j.LogManager;
#if MC_VER >= MC_1_19_4 #if MC_VER <= MC_1_17_1
import net.minecraft.core.registries.Registries; #elif MC_VER <= MC_1_19_2
#else
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
#elif MC_VER <= MC_1_19_4
import net.minecraft.core.registries.Registries;
#elif MC_VER < MC_1_21_3
import net.minecraft.core.registries.Registries;
#endif #endif
#if MC_VER <= MC_1_20_4 #if MC_VER <= MC_1_20_4
import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ChunkStatus;
import org.jetbrains.annotations.Nullable;
#else #else
import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStatus;
import javax.annotation.Nullable;
#endif #endif
/* /*
@@ -103,26 +105,32 @@ Lod Generation: 0.269023348s
*/ */
public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnvironmentWrapper public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnvironmentWrapper
{ {
public static final ConfigBasedSpamLogger PREF_LOGGER = public static final DhLogger PREF_LOGGER = new DhLoggerBuilder()
new ConfigBasedSpamLogger(LogManager.getLogger("LodWorldGen"), .name("LOD World Gen")
() -> Config.Common.Logging.logWorldGenPerformance.get(), 1); .fileLevelConfig(Config.Common.Logging.logWorldGenPerformanceToFile)
public static final ConfigBasedLogger EVENT_LOGGER = .maxCountPerSecond(1)
new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"), .build();
() -> Config.Common.Logging.logWorldGenEvent.get()); public static final DhLogger EVENT_LOGGER = new DhLoggerBuilder()
public static final ConfigBasedLogger LOAD_LOGGER = .name("LOD World Gen")
new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"), .fileLevelConfig(Config.Common.Logging.logWorldGenEventToFile)
() -> Config.Common.Logging.logWorldGenLoadEvent.get()); .build();
public static final DhLogger CHUNK_LOAD_LOGGER = new DhLoggerBuilder()
.name("LOD World Gen")
.fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile)
.build();
#if MC_VER < MC_1_21_5 #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)); private static final TicketType<ChunkPos> DH_SERVER_GEN_TICKET = TicketType.create("dh_server_gen_ticket", Comparator.comparingLong(ChunkPos::toLong));
#else #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); 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 #endif
private static final IModChecker MOD_CHECKER = SingletonInjector.INSTANCE.get(IModChecker.class); private static final IModChecker MOD_CHECKER = SingletonInjector.INSTANCE.get(IModChecker.class);
private final IDhServerLevel serverlevel; private final IDhServerLevel serverLevel;
/** /**
* will be true if C2ME is installed (since they require us to * will be true if C2ME is installed (since they require us to
@@ -174,6 +182,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
// constructors // // constructors //
//==============// //==============//
@NotNull
public static final ImmutableMap<EDhApiWorldGenerationStep, Integer> WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP; public static final ImmutableMap<EDhApiWorldGenerationStep, Integer> WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP;
public static final int MAX_WORLD_GEN_CHUNK_BORDER_NEEDED; public static final int MAX_WORLD_GEN_CHUNK_BORDER_NEEDED;
@@ -205,23 +214,24 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
builder.put(EDhApiWorldGenerationStep.LIGHT, 0); builder.put(EDhApiWorldGenerationStep.LIGHT, 0);
WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP = builder.build(); WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP = builder.build();
// TODO this is a test to see if the additional boarder is actually necessary or not. // in James' testing as of 2025-09-13 a border here of 2
// If world generators end up having infinite loops or other unexplained issues, // and a getChunkPosToGenerateStream() radius of 14 provided more accurate
// this should be set back to the commented out logic below // structure generation, however it also caused extreme server lag
// a border of 0 here and a getChunkPosToGenerateStream() radius of 8 provided
// good-enough structure generation while not lagging the server
MAX_WORLD_GEN_CHUNK_BORDER_NEEDED = 0; MAX_WORLD_GEN_CHUNK_BORDER_NEEDED = 0;
//MAX_WORLD_GEN_CHUNK_BORDER_NEEDED = WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP.values().stream().mapToInt(Integer::intValue).max().getAsInt();
} }
public BatchGenerationEnvironment(IDhServerLevel serverlevel) public BatchGenerationEnvironment(IDhServerLevel serverLevel)
{ {
super(serverlevel); super(serverLevel);
this.serverlevel = serverlevel; this.serverLevel = serverLevel;
EVENT_LOGGER.info("================WORLD_GEN_STEP_INITING============="); EVENT_LOGGER.info("================WORLD_GEN_STEP_INITING=============");
serverlevel.getServerLevelWrapper().getDimensionType(); serverLevel.getServerLevelWrapper().getDimensionType();
ChunkGenerator generator = ((ServerLevelWrapper) (serverlevel.getServerLevelWrapper())).getLevel().getChunkSource().getGenerator(); ChunkGenerator generator = ((ServerLevelWrapper) (serverLevel.getServerLevelWrapper())).getLevel().getChunkSource().getGenerator();
if (!(generator instanceof NoiseBasedChunkGenerator || if (!(generator instanceof NoiseBasedChunkGenerator ||
generator instanceof DebugLevelSource || generator instanceof DebugLevelSource ||
generator instanceof FlatLevelSource)) generator instanceof FlatLevelSource))
@@ -249,7 +259,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
this.pullExistingChunkUsingMcAsyncMethod = true; this.pullExistingChunkUsingMcAsyncMethod = true;
} }
this.params = new GlobalParameters(serverlevel); this.params = new GlobalParameters(serverLevel);
} }
@@ -309,7 +319,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
try try
{ {
event.future.get(); // Should throw exception event.future.get(); // Should throw exception
LodUtil.assertNotReach(); LodUtil.assertNotReach("Exceptionally completed world gen Future should have thrown an exception.");
} }
catch (Exception e) catch (Exception e)
{ {
@@ -388,6 +398,8 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
// future chain for generation // future chain for generation
return CompletableFuture.runAsync(() -> return CompletableFuture.runAsync(() ->
{
try
{ {
// offset 1 chunk in both X and Z direction so we can generate an even number of chunks wide // offset 1 chunk in both X and Z direction so we can generate an even number of chunks wide
// while still submitting an odd number width to MC's internal generators // while still submitting an odd number width to MC's internal generators
@@ -412,8 +424,8 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
// get/create the list of chunks we're going to generate // get/create the list of chunks we're going to generate
IEmptyChunkRetrievalFunc fallbackFunc = IEmptyChunkRetrievalFunc fallbackFunc =
(chunkPosX, chunkPosZ) -> Objects.requireNonNull( (chunkPosX, chunkPosZ) -> Objects.requireNonNull(
generatedChunkByDhPos.get(new DhChunkPos(chunkPosX, chunkPosZ)), generatedChunkByDhPos.get(new DhChunkPos(chunkPosX, chunkPosZ)),
() -> String.format("Requested chunk [%d, %d] unavailable during world generation", chunkPosX, chunkPosZ)); () -> String.format("Requested chunk [%d, %d] unavailable during world generation", chunkPosX, chunkPosZ));
ArrayGridList<ChunkAccess> regionChunks = new ArrayGridList<>( ArrayGridList<ChunkAccess> regionChunks = new ArrayGridList<>(
refSize, refSize,
@@ -435,7 +447,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
// this method shouldn't be necessary since we're passing in a pre-populated // this method shouldn't be necessary since we're passing in a pre-populated
// list of chunks, but just in case // list of chunks, but just in case
fallbackFunc fallbackFunc
); );
lightGetterAdaptor.setRegion(region); lightGetterAdaptor.setRegion(region);
genEvent.threadedParam.makeStructFeat(region, this.params); genEvent.threadedParam.makeStructFeat(region, this.params);
@@ -461,7 +473,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
else if (chunk != null) else if (chunk != null)
{ {
// wrap the chunk // wrap the chunk
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.serverlevel.getLevelWrapper()); ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.serverLevel.getLevelWrapper());
chunkWrapperList.set(relX, relZ, chunkWrapper); chunkWrapperList.set(relX, relZ, chunkWrapper);
// try setting the wrapper's lighting // try setting the wrapper's lighting
@@ -519,12 +531,17 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
genEvent.timer.complete(); genEvent.timer.complete();
genEvent.refreshTimeout(); genEvent.refreshTimeout();
if (PREF_LOGGER.canMaybeLog()) if (PREF_LOGGER.canLog())
{ {
genEvent.threadedParam.perf.recordEvent(genEvent.timer); genEvent.threadedParam.perf.recordEvent(genEvent.timer);
PREF_LOGGER.debugInc(genEvent.timer.toString()); PREF_LOGGER.debug(genEvent.timer.toString());
} }
}, executor); }
catch (Exception e)
{
EVENT_LOGGER.error("Unexpected error during world gen for min chunk pos ["+genEvent.minPos+"], error: ["+e.getMessage()+"].", e);
}
}, executor);
} }
/** @param extraRadius in both the positive and negative directions */ /** @param extraRadius in both the positive and negative directions */
private static Stream<ChunkPos> getChunkPosToGenerateStream(int genMinX, int genMinZ, int width, int extraRadius) private static Stream<ChunkPos> getChunkPosToGenerateStream(int genMinX, int genMinZ, int width, int extraRadius)
@@ -563,7 +580,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
if (Config.Common.LodBuilding.pullLightingForPregeneratedChunks.get()) if (Config.Common.LodBuilding.pullLightingForPregeneratedChunks.get())
{ {
// attempt to get chunk lighting // attempt to get chunk lighting
ChunkLoader.CombinedChunkLightStorage combinedLights = ChunkLoader.readLight(newChunk, chunkData); ChunkFileReader.CombinedChunkLightStorage combinedLights = ChunkFileReader.readLight(newChunk, chunkData);
if (combinedLights != null) if (combinedLights != null)
{ {
chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage); chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage);
@@ -666,15 +683,28 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
actualThrowable = completionException.getCause(); actualThrowable = completionException.getCause();
} }
LOAD_LOGGER.warn("DistantHorizons: Couldn't load or make chunk ["+chunkPos+"], error: ["+actualThrowable.getMessage()+"].", actualThrowable); // interrupts mean the world generator is being shut down, no need to log that
boolean isShutdownException =
actualThrowable instanceof InterruptedException
|| actualThrowable instanceof ClosedByInterruptException;
if (!isShutdownException)
{
CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load or make chunk ["+chunkPos+"], error: ["+actualThrowable.getMessage()+"].", actualThrowable);
}
return null; return null;
}); });
} }
#endif #endif
} }
catch (ClosedByInterruptException ignore)
{
// this just means the world generator is being shut down
return CompletableFuture.completedFuture(null);
}
catch (Exception e) catch (Exception e)
{ {
LOAD_LOGGER.warn("DistantHorizons: Couldn't load or make chunk [" + chunkPos + "]. Error: [" + e.getMessage() + "].", e); CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load or make chunk [" + chunkPos + "]. Error: [" + e.getMessage() + "].", e);
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
} }
@@ -690,10 +720,10 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
{ {
try try
{ {
LOAD_LOGGER.debug("DistantHorizons: Loading chunk [" + chunkPos + "] from disk."); CHUNK_LOAD_LOGGER.debug("DistantHorizons: Loading chunk [" + chunkPos + "] from disk.");
@Nullable @Nullable
ChunkAccess chunk = ChunkLoader.read(level, chunkPos, chunkData); ChunkAccess chunk = ChunkFileReader.read(level, chunkPos, chunkData);
if (chunk != null) if (chunk != null)
{ {
if (Config.Common.LodBuilding.assumePreExistingChunksAreFinished.get()) if (Config.Common.LodBuilding.assumePreExistingChunksAreFinished.get())
@@ -712,7 +742,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
} }
catch (Exception e) catch (Exception e)
{ {
LOAD_LOGGER.error( CHUNK_LOAD_LOGGER.error(
"DistantHorizons: couldn't load or make chunk at [" + chunkPos + "]." + "DistantHorizons: couldn't load or make chunk at [" + chunkPos + "]." +
"Please try optimizing your world to fix this issue. \n" + "Please try optimizing your world to fix this issue. \n" +
"World optimization can be done from the singleplayer world selection screen.\n" + "World optimization can be done from the singleplayer world selection screen.\n" +
@@ -735,8 +765,10 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null); return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null);
#elif MC_VER < MC_1_21_3 #elif MC_VER < MC_1_21_3
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null); return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null);
#else #elif MC_VER < MC_1_21_9
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().lookupOrThrow(Registries.BIOME), null); 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 #endif
} }
@@ -772,12 +804,12 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
if (throwable != null) if (throwable != null)
{ {
LOAD_LOGGER.warn("DistantHorizons: Couldn't load chunk [" + chunkPos + "] from server, error: [" + actualThrowable.getMessage() + "].", actualThrowable); CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load chunk [" + chunkPos + "] from server, error: [" + actualThrowable.getMessage() + "].", actualThrowable);
} }
if (chunk != null) if (chunk != null)
{ {
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.serverlevel.getLevelWrapper()); ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.serverLevel.getLevelWrapper());
chunkWrappersByDhPos.put(new DhChunkPos(chunkPos.x, chunkPos.z), chunkWrapper); chunkWrappersByDhPos.put(new DhChunkPos(chunkPos.x, chunkPos.z), chunkWrapper);
} }
}, runnableQueue::add); }, runnableQueue::add);
@@ -791,7 +823,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
{ {
// generate chunk lighting using DH's lighting engine // generate chunk lighting using DH's lighting engine
genEvent.timer.nextEvent("light"); genEvent.timer.nextEvent("light");
int maxSkyLight = this.serverlevel.getServerLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT; int maxSkyLight = this.serverLevel.getServerLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT;
ArrayList<IChunkWrapper> generatedChunks = new ArrayList<>(chunkWrappersByDhPos.values()); ArrayList<IChunkWrapper> generatedChunks = new ArrayList<>(chunkWrappersByDhPos.values());
for (IChunkWrapper iChunkWrapper : generatedChunks) for (IChunkWrapper iChunkWrapper : generatedChunks)
@@ -804,7 +836,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
DhLightingEngine.INSTANCE.bakeChunkBlockLighting(iChunkWrapper, generatedChunks, maxSkyLight); DhLightingEngine.INSTANCE.bakeChunkBlockLighting(iChunkWrapper, generatedChunks, maxSkyLight);
} }
this.serverlevel.updateBeaconBeamsForChunk(iChunkWrapper, generatedChunks); this.serverLevel.updateBeaconBeamsForChunk(iChunkWrapper, generatedChunks);
} }
genEvent.timer.nextEvent("cleanup"); genEvent.timer.nextEvent("cleanup");
@@ -827,10 +859,10 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
genEvent.timer.complete(); genEvent.timer.complete();
genEvent.refreshTimeout(); genEvent.refreshTimeout();
if (PREF_LOGGER.canMaybeLog()) if (PREF_LOGGER.canLog())
{ {
genEvent.threadedParam.perf.recordEvent(genEvent.timer); genEvent.threadedParam.perf.recordEvent(genEvent.timer);
PREF_LOGGER.debugInc(genEvent.timer.toString()); PREF_LOGGER.debug(genEvent.timer.toString());
} }
}); });
@@ -1035,7 +1067,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
// generate lighting using DH's lighting engine // generate lighting using DH's lighting engine
int maxSkyLight = this.serverlevel.getServerLevelWrapper().hasSkyLight() ? 15 : 0; int maxSkyLight = this.serverLevel.getServerLevelWrapper().hasSkyLight() ? 15 : 0;
// only light generated chunks, // only light generated chunks,
// attempting to light un-generated chunks will cause lighting issues on bordering generated chunks // attempting to light un-generated chunks will cause lighting issues on bordering generated chunks
@@ -1071,15 +1103,15 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
DhLightingEngine.INSTANCE.bakeChunkBlockLighting(centerChunk, iChunkWrapperList, maxSkyLight); DhLightingEngine.INSTANCE.bakeChunkBlockLighting(centerChunk, iChunkWrapperList, maxSkyLight);
} }
this.serverlevel.updateBeaconBeamsForChunk(centerChunk, iChunkWrapperList); this.serverLevel.updateBeaconBeamsForChunk(centerChunk, iChunkWrapperList);
} }
genEvent.refreshTimeout(); genEvent.refreshTimeout();
} }
} }
private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, int border) { return new ArrayGridList<>(total, border, total.gridSize - border); } private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, int border) { return new ArrayGridList<>(total, border, total.gridSize - border); }
//private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, EDhApiWorldGenerationStep step) { return GetCutoutFrom(total, MaxBorderNeeded - WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP.get(step)); } private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, EDhApiWorldGenerationStep step) { return GetCutoutFrom(total, WORLD_GEN_CHUNK_BORDER_NEEDED_BY_GEN_STEP.get(step)); }
private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, EDhApiWorldGenerationStep step) { return GetCutoutFrom(total, 0); } //private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, EDhApiWorldGenerationStep step) { return GetCutoutFrom(total, 0); }
@Override @Override
@@ -1107,9 +1139,10 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
{ {
regionStorage.close(); regionStorage.close();
} }
catch (ClosedChannelException ignore) { /* world generator is being shut down */ }
catch (IOException e) catch (IOException e)
{ {
EVENT_LOGGER.error("Failed to close region file storage cache!", e); EVENT_LOGGER.error("Failed to close region file storage cache, error: ["+e.getMessage()+"].", e);
} }
} }
@@ -32,11 +32,11 @@ import com.seibel.distanthorizons.core.util.objects.EventTimer;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
public final class GenerationEvent public final class GenerationEvent
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName()); private static final DhLogger LOGGER = new DhLoggerBuilder().build();;
private static int generationFutureDebugIDs = 0; private static int generationFutureDebugIDs = 0;
public final int id; public final int id;
@@ -24,7 +24,7 @@ import com.mojang.serialization.Dynamic;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
@@ -89,22 +89,27 @@ import net.minecraft.world.level.material.Fluid;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public class ChunkLoader public class ChunkFileReader
{ {
private static final AtomicBoolean ZERO_CHUNK_POS_ERROR_LOGGED_REF = new AtomicBoolean(false); 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_19_2
#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()); 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 #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()); 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 #endif
private static final String TAG_UPGRADE_DATA = "UpgradeData"; private static final String TAG_UPGRADE_DATA = "UpgradeData";
private static final String BLOCK_TICKS_TAG_18 = "block_ticks"; private static final String BLOCK_TICKS_TAG_18 = "block_ticks";
private static final String FLUID_TICKS_TAG_18 = "fluid_ticks"; private static final String FLUID_TICKS_TAG_18 = "fluid_ticks";
private static final String BLOCK_TICKS_TAG_PRE18 = "TileTicks"; private static final String BLOCK_TICKS_TAG_PRE18 = "TileTicks";
private static final String FLUID_TICKS_TAG_PRE18 = "LiquidTicks"; private static final String FLUID_TICKS_TAG_PRE18 = "LiquidTicks";
private static final ConfigBasedLogger LOGGER = BatchGenerationEnvironment.LOAD_LOGGER;
private static boolean lightingSectionErrorLogged = false; private static boolean lightingSectionErrorLogged = false;
@@ -259,6 +264,14 @@ public class ChunkLoader
} }
private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData) 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_18_2
#if MC_VER < MC_1_19_4 #if MC_VER < MC_1_19_4
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
@@ -276,9 +289,12 @@ public class ChunkLoader
#elif MC_VER < MC_1_21_3 #elif MC_VER < MC_1_21_3
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW( Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS)); biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
#else #elif MC_VER < MC_1_21_9
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW( Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS)); 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
#endif #endif
@@ -348,7 +364,11 @@ public class ChunkLoader
} }
else else
{ {
#if MC_VER < MC_1_21_9
blockStateContainer = new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); blockStateContainer = new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
#else
blockStateContainer = PalettedContainerFactory.create(level.registryAccess()).createForBlockStates();
#endif
} }
@@ -380,13 +400,18 @@ public class ChunkLoader
} }
else 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(), biomeContainer = new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(),
#if MC_VER < MC_1_21_3
biomes.getHolderOrThrow(Biomes.PLAINS),
#else
biomes.getOrThrow(Biomes.PLAINS), biomes.getOrThrow(Biomes.PLAINS),
#endif
PalettedContainer.Strategy.SECTION_BIOMES); PalettedContainer.Strategy.SECTION_BIOMES);
#else
biomeContainer = PalettedContainerFactory.create(level.registryAccess()).createForBiomes();
#endif
} }
#endif #endif
@@ -28,7 +28,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.LodUtil;
import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.SpawnerBlock; import net.minecraft.world.level.block.SpawnerBlock;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -78,7 +78,7 @@ import net.minecraft.world.ticks.LevelTickAccess;
public class DhLitWorldGenRegion extends WorldGenRegion public class DhLitWorldGenRegion extends WorldGenRegion
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName()); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static ChunkStatus debugTriggeredForStatus = null; private static ChunkStatus debugTriggeredForStatus = null;
@@ -352,7 +352,7 @@ public class DhLitWorldGenRegion extends WorldGenRegion
ChunkAccess chunk = this.getChunkAccess(chunkX, chunkZ, chunkStatus, returnNonNull); ChunkAccess chunk = this.getChunkAccess(chunkX, chunkZ, chunkStatus, returnNonNull);
if (chunk instanceof LevelChunk) if (chunk instanceof LevelChunk)
{ {
chunk = new ImposterProtoChunk((LevelChunk) chunk #if MC_VER >= MC_1_18_2 , true #endif ); chunk = new ImposterProtoChunk((LevelChunk) chunk #if MC_VER >= MC_1_18_2 ,/* allow writes */ false #endif );
} }
return chunk; return chunk;
} }
@@ -392,10 +392,11 @@ public class DhLitWorldGenRegion extends WorldGenRegion
} }
} }
if (chunkStatus != ChunkStatus.EMPTY && chunkStatus != debugTriggeredForStatus) if (chunkStatus != ChunkStatus.EMPTY
&& chunkStatus != debugTriggeredForStatus)
{ {
LOGGER.info("WorldGen requiring " + chunkStatus LOGGER.info("WorldGen requiring [" + chunkStatus + "]"
+ " outside expected range detected. Force passing EMPTY chunk and seeing if it works."); + " is outside the expected range. Returning EMPTY chunk.");
debugTriggeredForStatus = chunkStatus; debugTriggeredForStatus = chunkStatus;
} }
@@ -7,7 +7,7 @@ import net.minecraft.nbt.NbtIo;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.storage.RegionFile; import net.minecraft.world.level.chunk.storage.RegionFile;
import net.minecraft.world.level.chunk.storage.RegionFileStorage; import net.minecraft.world.level.chunk.storage.RegionFileStorage;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.DataInputStream; import java.io.DataInputStream;
@@ -29,7 +29,7 @@ import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
*/ */
public class RegionFileStorageExternalCache implements AutoCloseable public class RegionFileStorageExternalCache implements AutoCloseable
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
/** Can be null due to the C2ME mod */ /** Can be null due to the C2ME mod */
@Nullable @Nullable
@@ -139,7 +139,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable
if (retryCount >= maxRetryCount) if (retryCount >= maxRetryCount)
{ {
BatchGenerationEnvironment.LOAD_LOGGER.warn("Concurrency issue detected when getting region file for chunk at [" + pos + "]."); BatchGenerationEnvironment.CHUNK_LOAD_LOGGER.warn("Concurrency issue detected when getting region file for chunk at [" + pos + "].");
} }
@@ -0,0 +1,54 @@
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.mimicObject.DhLitWorldGenRegion;
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk;
import java.util.ArrayList;
import java.util.List;
#if MC_VER <= MC_1_20_4
import net.minecraft.world.level.chunk.ChunkStatus;
#else
import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif
public abstract class AbstractWorldGenStep
{
public abstract void generateGroup(
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
ArrayGridList<ChunkWrapper> chunkWrappers);
public abstract ChunkStatus getChunkStatus();
/** @return the list of chunks that have an earlier status and can be generated */
protected ArrayList<ChunkAccess> getChunksToGenerate(List<ChunkWrapper> chunkWrappers)
{
ArrayList<ChunkAccess> chunksToGenerate = new ArrayList<>();
for (ChunkWrapper chunkWrapper : chunkWrappers)
{
ChunkAccess chunk = chunkWrapper.getChunk();
if (chunkWrapper.getStatus().isOrAfter(this.getChunkStatus()))
{
// this chunk has already generated this step
continue;
}
else if (chunk instanceof ProtoChunk)
{
chunkWrapper.trySetStatus(this.getChunkStatus());
chunksToGenerate.add(chunk);
}
}
return chunksToGenerate;
}
}
@@ -20,12 +20,13 @@
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step; package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
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.server.level.WorldGenRegion;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.ProtoChunk;
@@ -40,39 +41,35 @@ import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif #endif
public final class StepBiomes public final class StepBiomes extends AbstractWorldGenStep
{ {
public static final ChunkStatus STATUS = ChunkStatus.BIOMES;
private final BatchGenerationEnvironment environment; private final BatchGenerationEnvironment environment;
public static final ChunkStatus STATUS = ChunkStatus.BIOMES;
//=============//
// constructor //
//=============//
public StepBiomes(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; } public StepBiomes(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; }
//==================//
// abstract methods //
//==================//
@Override
public ChunkStatus getChunkStatus() { return STATUS; }
@Override
public void generateGroup( public void generateGroup(
ThreadedParameters tParams, WorldGenRegion worldGenRegion, ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
List<ChunkWrapper> chunkWrappers) ArrayGridList<ChunkWrapper> chunkWrappers)
{ {
ArrayList<ChunkAccess> chunksToDo = this.getChunksToGenerate(chunkWrappers);
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
for (ChunkWrapper chunkWrapper : chunkWrappers)
{
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) for (ChunkAccess chunk : chunksToDo)
{ {
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
@@ -29,7 +29,7 @@ import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.Heightmap;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
#if MC_VER <= MC_1_20_4 #if MC_VER <= MC_1_20_4
import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ChunkStatus;
@@ -37,10 +37,12 @@ import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif #endif
import java.util.ConcurrentModificationException;
public final class StepFeatures
public final class StepFeatures extends AbstractWorldGenStep
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
public static final ChunkStatus STATUS = ChunkStatus.FEATURES; public static final ChunkStatus STATUS = ChunkStatus.FEATURES;
@@ -48,10 +50,22 @@ public final class StepFeatures
//=============//
// constructor //
//=============//
public StepFeatures(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; } public StepFeatures(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; }
//==================//
// abstract methods //
//==================//
@Override
public ChunkStatus getChunkStatus() { return STATUS; }
@Override
public void generateGroup( public void generateGroup(
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion, ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
ArrayGridList<ChunkWrapper> chunkWrappers) ArrayGridList<ChunkWrapper> chunkWrappers)
@@ -88,6 +102,10 @@ public final class StepFeatures
Heightmap.primeHeightmaps(chunk, STATUS.heightmapsAfter()); Heightmap.primeHeightmaps(chunk, STATUS.heightmapsAfter());
} }
catch (ConcurrentModificationException e) // ReportedException
{
// TODO
}
catch (Exception e) catch (Exception e)
{ {
LOGGER.warn("Unexpected issue when generating features for chunk at pos ["+chunkWrapper.getChunkPos()+"], error: ["+e.getMessage()+"].", e); LOGGER.warn("Unexpected issue when generating features for chunk at pos ["+chunkWrapper.getChunkPos()+"], error: ["+e.getMessage()+"].", e);
@@ -26,6 +26,8 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
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 com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
import net.minecraft.server.level.WorldGenRegion; import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
@@ -41,7 +43,7 @@ import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif #endif
public final class StepNoise public final class StepNoise extends AbstractWorldGenStep
{ {
private static final ChunkStatus STATUS = ChunkStatus.NOISE; private static final ChunkStatus STATUS = ChunkStatus.NOISE;
@@ -49,15 +51,26 @@ public final class StepNoise
//=============//
// constructor //
//=============//
public StepNoise(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; } public StepNoise(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; }
public void generateGroup( //==================//
ThreadedParameters tParams, WorldGenRegion worldGenRegion, // abstract methods //
List<ChunkWrapper> chunkWrappers) //==================//
{
@Override
public ChunkStatus getChunkStatus() { return STATUS; }
@Override
public void generateGroup(
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
ArrayGridList<ChunkWrapper> chunkWrappers)
{
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>(); ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
for (ChunkWrapper chunkWrapper : chunkWrappers) for (ChunkWrapper chunkWrapper : chunkWrappers)
@@ -26,6 +26,8 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
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.server.level.WorldGenRegion;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.ProtoChunk;
@@ -37,7 +39,7 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif #endif
public final class StepStructureReference public final class StepStructureReference extends AbstractWorldGenStep
{ {
private static final ChunkStatus STATUS = ChunkStatus.STRUCTURE_REFERENCES; private static final ChunkStatus STATUS = ChunkStatus.STRUCTURE_REFERENCES;
@@ -45,15 +47,26 @@ public final class StepStructureReference
//=============//
// constructor //
//=============//
public StepStructureReference(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; } public StepStructureReference(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; }
public void generateGroup( //==================//
ThreadedParameters tParams, WorldGenRegion worldGenRegion, // abstract methods //
List<ChunkWrapper> chunkWrappers) //==================//
{
@Override
public ChunkStatus getChunkStatus() { return STATUS; }
@Override
public void generateGroup(
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
ArrayGridList<ChunkWrapper> chunkWrappers)
{
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>(); ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
for (ChunkWrapper chunkWrapper : chunkWrappers) for (ChunkWrapper chunkWrapper : chunkWrappers)
@@ -67,6 +80,7 @@ public final class StepStructureReference
else if (chunk instanceof ProtoChunk) else if (chunk instanceof ProtoChunk)
{ {
chunkWrapper.trySetStatus(STATUS); chunkWrapper.trySetStatus(STATUS);
chunksToDo.add(chunk);
} }
} }
@@ -27,13 +27,15 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.WorldGenRegion; import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.ProtoChunk;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
#if MC_VER <= MC_1_20_4 #if MC_VER <= MC_1_20_4
import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ChunkStatus;
@@ -42,9 +44,9 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif #endif
public final class StepStructureStart public final class StepStructureStart extends AbstractWorldGenStep
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final ChunkStatus STATUS = ChunkStatus.STRUCTURE_STARTS; private static final ChunkStatus STATUS = ChunkStatus.STRUCTURE_STARTS;
private static final ReentrantLock STRUCTURE_PLACEMENT_LOCK = new ReentrantLock(); private static final ReentrantLock STRUCTURE_PLACEMENT_LOCK = new ReentrantLock();
@@ -52,42 +54,27 @@ public final class StepStructureStart
//=============//
// constructor //
//=============//
public StepStructureStart(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; } public StepStructureStart(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; }
public static class StructStartCorruptedException extends RuntimeException //==================//
{ // abstract methods //
private static final long serialVersionUID = -8987434342051563358L; //==================//
public StructStartCorruptedException(ArrayIndexOutOfBoundsException e) @Override
{ public ChunkStatus getChunkStatus() { return STATUS; }
super("StructStartCorruptedException");
super.initCause(e);
fillInStackTrace();
}
}
@Override
public void generateGroup( public void generateGroup(
ThreadedParameters tParams, WorldGenRegion worldGenRegion, ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
List<ChunkWrapper> chunkWrappers) throws InterruptedException ArrayGridList<ChunkWrapper> chunkWrappers)
{ {
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>(); ArrayList<ChunkAccess> chunksToDo = this.getChunksToGenerate(chunkWrappers);
for (ChunkWrapper chunkWrapper : chunkWrappers)
{
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);
}
}
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
if (this.environment.params.worldGenSettings.generateFeatures()) if (this.environment.params.worldGenSettings.generateFeatures())
@@ -101,12 +88,6 @@ public final class StepStructureStart
#endif #endif
for (ChunkAccess chunk : chunksToDo) for (ChunkAccess chunk : chunksToDo)
{ {
// System.out.println("StepStructureStart: "+chunk.getPos());
// there are a few cases where the structure generator call may lock up (either due to teleporting or leaving the world).
// hopefully allowing interrupts here will prevent that from happening.
BatchGenerationEnvironment.throwIfThreadInterrupted();
// hopefully this shouldn't cause any performance issues (this step is generally quite quick so hopefully it should be fine) // 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 // and should prevent some concurrency issues
STRUCTURE_PLACEMENT_LOCK.lock(); STRUCTURE_PLACEMENT_LOCK.lock();
@@ -151,8 +132,6 @@ public final class StepStructureStart
{ {
// the structure logic failed again, log it and move on // 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 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
//throw new StepStructureStart.StructStartCorruptedException(secondEx);
} }
} }
@@ -26,6 +26,8 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters; import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
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.server.level.WorldGenRegion;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.ProtoChunk;
@@ -37,7 +39,7 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif #endif
public final class StepSurface public final class StepSurface extends AbstractWorldGenStep
{ {
private static final ChunkStatus STATUS = ChunkStatus.SURFACE; private static final ChunkStatus STATUS = ChunkStatus.SURFACE;
@@ -45,13 +47,25 @@ public final class StepSurface
//=============//
// constructor //
//=============//
public StepSurface(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; } public StepSurface(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; }
//==================//
// abstract methods //
//==================//
@Override
public ChunkStatus getChunkStatus() { return STATUS; }
@Override
public void generateGroup( public void generateGroup(
ThreadedParameters tParams, WorldGenRegion worldGenRegion, ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
List<ChunkWrapper> chunkWrappers) ArrayGridList<ChunkWrapper> chunkWrappers)
{ {
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>(); ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
@@ -0,0 +1,54 @@
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 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
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;
# lod generation from save file
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage 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 (Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/gui/components/debug/DebugScreenEntry;)Lnet/minecraft/resources/ResourceLocation;
# hacky stuff
accessible field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
mutable field net/minecraft/util/ThreadingDetector lock Ljava/util/concurrent/Semaphore;
+50 -6
View File
@@ -19,7 +19,9 @@ loom {
"-Dminecraft.api.session.host=https://nope.invalid", "-Dminecraft.api.session.host=https://nope.invalid",
"-Dminecraft.api.services.host=https://nope.invalid", "-Dminecraft.api.services.host=https://nope.invalid",
// https://netty.io/wiki/reference-counted-objects.html#leak-detection-levels // https://netty.io/wiki/reference-counted-objects.html#leak-detection-levels
"-Dio.netty.leakDetection.level=advanced" "-Dio.netty.leakDetection.level=advanced",
"-XX:+UseZGC",
"-XX:+ZGenerational"
) )
programArgs("--username", "Dev") programArgs("--username", "Dev")
} }
@@ -76,15 +78,23 @@ dependencies {
// Fabric API // Fabric API
addModJar(fabricApi.module("fabric-api-base", rootProject.fabric_api_version)) addModJar(fabricApi.module("fabric-api-base", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-lifecycle-events-v1", rootProject.fabric_api_version)) addModJar(fabricApi.module("fabric-lifecycle-events-v1", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) if (buildVersionBefore(minecraft_version, "1.21.9"))
{
addModJar(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version))
}
else // > 1.21.9
{
addModJar(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-resource-loader-v1", rootProject.fabric_api_version))
}
addModJar(fabricApi.module("fabric-events-interaction-v0", rootProject.fabric_api_version)) addModJar(fabricApi.module("fabric-events-interaction-v0", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-rendering-v1", rootProject.fabric_api_version)) // TODO: Remove this as it is only needed in 1 line (FabricClientProxy) addModJar(fabricApi.module("fabric-rendering-v1", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-networking-api-v1", rootProject.fabric_api_version)) addModJar(fabricApi.module("fabric-networking-api-v1", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-entity-events-v1", rootProject.fabric_api_version)) addModJar(fabricApi.module("fabric-entity-events-v1", rootProject.fabric_api_version))
if (minecraft_version >= "1.19.2") if (buildVersionBefore(minecraft_version, "1.19.2"))
addModJar(fabricApi.module("fabric-command-api-v2", rootProject.fabric_api_version))
else // < 1.19.2
addModJar(fabricApi.module("fabric-command-api-v1", rootProject.fabric_api_version)) addModJar(fabricApi.module("fabric-command-api-v1", rootProject.fabric_api_version))
else
addModJar(fabricApi.module("fabric-command-api-v2", rootProject.fabric_api_version))
// used by mod menu in MC 1.20.6+ // used by mod menu in MC 1.20.6+
addModJar(fabricApi.module("fabric-screen-api-v1", rootProject.fabric_api_version)) addModJar(fabricApi.module("fabric-screen-api-v1", rootProject.fabric_api_version))
@@ -143,6 +153,40 @@ dependencies {
} }
} }
private static boolean buildVersionBefore(String minecraft_version, String compareVersion)
{
int sortValue = sortSemanticVersionOldestToNewest(minecraft_version, compareVersion);
return sortValue == -1;
}
/**
* input format: "major.minor.patch"
* needed so we can sort versions with different length strings
* IE: 1.21.1 should come before 1.21.10
*/
private static int sortSemanticVersionOldestToNewest(String version1, String version2)
{
String[] parts1 = version1.split("\\.");
String[] parts2 = version2.split("\\.");
int major1 = Integer.parseInt(parts1[0]);
int major2 = Integer.parseInt(parts2[0]);
if (major1 != major2)
{
return Integer.compare(major1, major2);
}
int minor1 = Integer.parseInt(parts1[1]);
int minor2 = Integer.parseInt(parts2[1]);
if (minor1 != minor2)
{
return Integer.compare(minor1, minor2);
}
int patch1 = Integer.parseInt(parts1[2]);
int patch2 = Integer.parseInt(parts2[2]);
return Integer.compare(patch1, patch2);
}
task deleteResources(type: Delete) { task deleteResources(type: Delete) {
delete file("build/resources/main") delete file("build/resources/main")
@@ -24,26 +24,24 @@ import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter; import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.mojang.blaze3d.platform.InputConstants;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.fabric.wrappers.modAccessor.SodiumAccessor; import com.seibel.distanthorizons.fabric.wrappers.modAccessor.SodiumAccessor;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback; import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@@ -61,13 +59,16 @@ import java.nio.FloatBuffer;
#endif #endif
import java.util.HashSet; import java.util.HashSet;
import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
#if MC_VER < MC_1_21_9
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
#endif
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
/** /**
@@ -84,7 +85,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
private final ClientApi clientApi = ClientApi.INSTANCE; private final ClientApi clientApi = ClientApi.INSTANCE;
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); 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 AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
// TODO we shouldn't be filtering keys on the Forge/Fabric side, only in ClientApi // 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 int[] KEY_TO_CHECK_FOR = { GLFW.GLFW_KEY_F6, GLFW.GLFW_KEY_F8, GLFW.GLFW_KEY_P};
@@ -103,6 +104,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
LOGGER.info("Registering Fabric Client Events"); LOGGER.info("Registering Fabric Client Events");
//========================// //========================//
// register mod accessors // // register mod accessors //
//========================// //========================//
@@ -128,8 +130,16 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
{ {
if (MC.clientConnectedToDedicatedServer()) if (MC.clientConnectedToDedicatedServer())
{ {
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level); // executor to prevent locking up the render/event thread
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel); AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
executor.execute(() ->
{
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level);
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel);
});
}
} }
}); });
@@ -143,8 +153,6 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(blockPos.getX(), blockPos.getZ())) if (SharedApi.isChunkAtBlockPosAlreadyUpdating(blockPos.getX(), blockPos.getZ()))
{ {
// executor to prevent locking up the render/event thread // executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected
// (which can be caused by certain mods)
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor(); AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null) if (executor != null)
{ {
@@ -183,8 +191,6 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(hitResult.getBlockPos().getX(), hitResult.getBlockPos().getZ())) if (SharedApi.isChunkAtBlockPosAlreadyUpdating(hitResult.getBlockPos().getX(), hitResult.getBlockPos().getZ()))
{ {
// executor to prevent locking up the render/event thread // executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected
// (which can be caused by certain mods)
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor(); AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null) if (executor != null)
{ {
@@ -217,95 +223,83 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
// render event // // render event //
//==============// //==============//
// TODO wait for fabric to re-add their rendering API
#if MC_VER < MC_1_21_9
WorldRenderEvents.AFTER_SETUP.register((renderContext) -> WorldRenderEvents.AFTER_SETUP.register((renderContext) ->
{ {
Mat4f projectionMatrix = McObjectConverter.Convert(renderContext.projectionMatrix()); ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(renderContext.projectionMatrix());
Mat4f modelViewMatrix;
#if MC_VER < MC_1_20_6 #if MC_VER < MC_1_20_6
modelViewMatrix = McObjectConverter.Convert(renderContext.matrixStack().last().pose()); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(renderContext.matrixStack().last().pose());
#else #else
modelViewMatrix = McObjectConverter.Convert(renderContext.positionMatrix()); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(renderContext.positionMatrix());
#endif #endif
#if MC_VER < MC_1_21_1
ClientApi.RENDER_STATE.frameTime = renderContext.tickDelta();
#else
ClientApi.RENDER_STATE.frameTime = renderContext.tickCounter().getGameTimeDeltaTicks();
#endif
//LOGGER.info("\n\n" + ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, renderContext.world());
// "Level Render\n" +
// "Mc MVM: \n" + modelViewMatrix.toString() + "\n" +
// "Mc Proj: \n" + projectionMatrix.toString()
//);
this.clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()), this.clientApi.renderLods();
modelViewMatrix,
projectionMatrix,
#if MC_VER < MC_1_21_1
renderContext.tickDelta()
#else
renderContext.tickCounter().getGameTimeDeltaTicks()
#endif
);
}); });
// TODO add to forge and neo
WorldRenderEvents.AFTER_ENTITIES.register((renderContext) -> WorldRenderEvents.AFTER_ENTITIES.register((renderContext) ->
{ {
Mat4f projectionMatrix = McObjectConverter.Convert(renderContext.projectionMatrix()); ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(renderContext.projectionMatrix());
Mat4f modelViewMatrix;
#if MC_VER < MC_1_20_6 #if MC_VER < MC_1_20_6
modelViewMatrix = McObjectConverter.Convert(renderContext.matrixStack().last().pose()); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(renderContext.matrixStack().last().pose());
#else #else
modelViewMatrix = McObjectConverter.Convert(renderContext.positionMatrix()); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(renderContext.positionMatrix());
#endif #endif
this.clientApi.renderFadeOpaque( #if MC_VER < MC_1_21_1
modelViewMatrix, ClientApi.RENDER_STATE.frameTime = renderContext.tickDelta();
projectionMatrix, #else
#if MC_VER < MC_1_21_1 ClientApi.RENDER_STATE.frameTime = renderContext.tickCounter().getGameTimeDeltaTicks();
renderContext.tickDelta(), #endif
#else
renderContext.tickCounter().getGameTimeDeltaTicks(), ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, renderContext.world());
#endif
ClientLevelWrapper.getWrapper(renderContext.world())
); this.clientApi.renderFadeOpaque();
}); });
// TODO add to forge and neo
WorldRenderEvents.AFTER_TRANSLUCENT.register((renderContext) -> WorldRenderEvents.AFTER_TRANSLUCENT.register((renderContext) ->
{ {
Mat4f projectionMatrix = McObjectConverter.Convert(renderContext.projectionMatrix()); ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(renderContext.projectionMatrix());
Mat4f modelViewMatrix;
#if MC_VER < MC_1_20_6 #if MC_VER < MC_1_20_6
modelViewMatrix = McObjectConverter.Convert(renderContext.matrixStack().last().pose()); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(renderContext.matrixStack().last().pose());
#else #else
modelViewMatrix = McObjectConverter.Convert(renderContext.positionMatrix()); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(renderContext.positionMatrix());
#endif #endif
#if MC_VER < MC_1_21_1
ClientApi.RENDER_STATE.frameTime = renderContext.tickDelta();
#else
ClientApi.RENDER_STATE.frameTime = renderContext.tickCounter().getGameTimeDeltaTicks();
#endif
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, renderContext.world());
#if MC_VER < MC_1_21_6 #if MC_VER < MC_1_21_6
// rendered in MixinLevelRenderer // rendered in MixinLevelRenderer
#else #else
ClientApi.INSTANCE.renderDeferredLodsForShaders(ClientLevelWrapper.getWrapper(renderContext.world()), ClientApi.INSTANCE.renderDeferredLodsForShaders();
ClientApi.RENDER_STATE.mcModelViewMatrix,
ClientApi.RENDER_STATE.mcProjectionMatrix,
ClientApi.RENDER_STATE.frameTime
);
#endif #endif
this.clientApi.renderFade( this.clientApi.renderFadeTransparent();
modelViewMatrix,
projectionMatrix,
#if MC_VER < MC_1_21_1
renderContext.tickDelta(),
#else
renderContext.tickCounter().getGameTimeDeltaTicks(),
#endif
ClientLevelWrapper.getWrapper(renderContext.world())
);
}); });
#endif
// Debug keyboard event // Debug keyboard event
@@ -355,18 +349,18 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
// Check all keys we need // Check all keys we need
for (int keyCode = GLFW.GLFW_KEY_A; keyCode <= GLFW.GLFW_KEY_Z; keyCode++) for (int keyCode = GLFW.GLFW_KEY_A; keyCode <= GLFW.GLFW_KEY_Z; keyCode++)
{ {
if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), keyCode)) //if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), keyCode))
{ //{
currentKeyDown.add(keyCode); // currentKeyDown.add(keyCode);
} //}
} }
for (int keyCode : KEY_TO_CHECK_FOR) for (int keyCode : KEY_TO_CHECK_FOR)
{ {
if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), keyCode)) //if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), keyCode))
{ //{
currentKeyDown.add(keyCode); // currentKeyDown.add(keyCode);
} //}
} }
// Diff and trigger events // Diff and trigger events
@@ -20,10 +20,8 @@
package com.seibel.distanthorizons.fabric; package com.seibel.distanthorizons.fabric;
import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.CommandDispatcher;
import com.seibel.distanthorizons.api.enums.config.EDhApiMcRenderingFadeMode;
import com.seibel.distanthorizons.common.AbstractModInitializer; import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -40,7 +38,7 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.lwjgl.util.tinyfd.TinyFileDialogs; import org.lwjgl.util.tinyfd.TinyFileDialogs;
#if MC_VER >= MC_1_19_2 #if MC_VER >= MC_1_19_2
@@ -66,16 +64,19 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
private static final ResourceLocation INITIAL_PHASE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.DEDICATED_SERVER_INITIAL_PATH); private static final ResourceLocation INITIAL_PHASE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.DEDICATED_SERVER_INITIAL_PATH);
#endif #endif
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@Override @Override
protected void createInitialBindings() protected void createInitialSharedBindings()
{ {
SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new FabricPluginPacketSender()); SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new FabricPluginPacketSender());
} }
@Override
protected void createInitialClientBindings() { /* no additional setup needed currently */ }
@Override @Override
protected IEventProxy createClientProxy() { return new FabricClientProxy(); } protected IEventProxy createClientProxy() { return new FabricClientProxy(); }
@@ -153,11 +154,6 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class).setFogOcclusion(false); ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class).setFogOcclusion(false);
} }
#endif #endif
if (ConfigBase.INSTANCE == null)
{
throw new IllegalStateException("Config was not initialized. Make sure to call LodCommonMain.initConfig() before calling this method.");
}
} }
} }
@@ -1,5 +1,7 @@
package com.seibel.distanthorizons.fabric; package com.seibel.distanthorizons.fabric;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiChunkProcessingEvent;
import com.seibel.distanthorizons.api.methods.events.DhApiEventRegister; import com.seibel.distanthorizons.api.methods.events.DhApiEventRegister;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent;
import com.seibel.distanthorizons.common.AbstractModInitializer; import com.seibel.distanthorizons.common.AbstractModInitializer;
@@ -7,7 +9,6 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper; import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.core.api.internal.ServerApi; import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.common.AbstractPluginPacketSender; import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
@@ -15,6 +16,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.fabric.testing.TestChunkInputReplacerEvent;
import com.seibel.distanthorizons.fabric.testing.TestWorldGenBindingEvent; import com.seibel.distanthorizons.fabric.testing.TestWorldGenBindingEvent;
import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents; import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
@@ -28,7 +30,7 @@ import net.minecraft.client.gui.screens.TitleScreen;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
#if MC_VER >= MC_1_20_6 #if MC_VER >= MC_1_20_6
import com.seibel.distanthorizons.common.CommonPacketPayload; import com.seibel.distanthorizons.common.CommonPacketPayload;
@@ -37,8 +39,6 @@ import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage; import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
#endif #endif
import java.util.function.Supplier;
/** /**
* This handles all events sent to the server, * This handles all events sent to the server,
* and is the starting point for most of the mod. * and is the starting point for most of the mod.
@@ -52,7 +52,7 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy
private static final ServerApi SERVER_API = ServerApi.INSTANCE; private static final ServerApi SERVER_API = ServerApi.INSTANCE;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class); private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private final boolean isDedicatedServer; private final boolean isDedicatedServer;
@@ -97,10 +97,11 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy
ServerTickEvents.END_SERVER_TICK.register((server) -> SERVER_API.serverTickEvent()); ServerTickEvents.END_SERVER_TICK.register((server) -> SERVER_API.serverTickEvent());
// can be enabled to test world gen overrides without having to build a separate API project // can be enabled to test overrides/events without having to build a separate API project
if (false) if (false)
{ {
DhApiEventRegister.on(DhApiLevelLoadEvent.class, new TestWorldGenBindingEvent()); DhApiEventRegister.on(DhApiLevelLoadEvent.class, new TestWorldGenBindingEvent());
DhApi.events.bind(DhApiChunkProcessingEvent.class, new TestChunkInputReplacerEvent());
} }
@@ -0,0 +1,70 @@
/*
* 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.fabric.mixins.client;
#if MC_VER < MC_1_21_9
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(Entity.class)
public class MixinChunkSectionsToRender
{ /* rendering before was handled via Fabric API events */ }
#else
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.chunk.ChunkSectionLayerGroup;
import net.minecraft.client.renderer.chunk.ChunkSectionsToRender;
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.CallbackInfo;
@Mixin(ChunkSectionsToRender.class)
public class MixinChunkSectionsToRender
{
// 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)
{
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, Minecraft.getInstance().levelRenderer.level);
if (chunkSectionLayerGroup == ChunkSectionLayerGroup.TRANSLUCENT)
{
ClientApi.INSTANCE.renderFadeTransparent();
ClientApi.INSTANCE.renderDeferredLodsForShaders();
}
else if (chunkSectionLayerGroup == ChunkSectionLayerGroup.TRIPWIRE)
{
ClientApi.INSTANCE.renderFadeOpaque();
}
}
}
#endif
@@ -3,8 +3,10 @@ package com.seibel.distanthorizons.fabric.mixins.client;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.world.level.chunk.ChunkAccess;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
@@ -16,6 +18,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import java.util.concurrent.AbstractExecutorService;
#endif #endif
@Mixin(ClientPacketListener.class) @Mixin(ClientPacketListener.class)
@@ -45,8 +49,24 @@ public class MixinClientPacketListener
@Inject(method = "enableChunkLight", at = @At("TAIL")) @Inject(method = "enableChunkLight", at = @At("TAIL"))
void onEnableChunkLight(LevelChunk chunk, int x, int z, CallbackInfo ci) void onEnableChunkLight(LevelChunk chunk, int x, int z, CallbackInfo ci)
{ {
IClientLevelWrapper clientLevel = ClientLevelWrapper.getWrapper((ClientLevel) chunk.getLevel()); if (chunk == null)
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, clientLevel), clientLevel); {
return;
}
// executor to prevent locking up the render thread
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor == null)
{
return;
}
executor.execute(() ->
{
IClientLevelWrapper clientLevel = ClientLevelWrapper.getWrapper((ClientLevel) this.level);
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, clientLevel), clientLevel);
});
} }
#endif #endif
@@ -12,12 +12,15 @@ import java.util.List;
@Mixin(DebugScreenOverlay.class) @Mixin(DebugScreenOverlay.class)
public class MixinDebugScreenOverlay public class MixinDebugScreenOverlay
{ {
#if MC_VER < MC_1_21_9
@Inject(method = "getSystemInformation", at = @At("RETURN")) @Inject(method = "getSystemInformation", at = @At("RETURN"))
private void addCustomF3(CallbackInfoReturnable<List<String>> cir) private void addCustomF3(CallbackInfoReturnable<List<String>> cir)
{ {
List<String> messages = cir.getReturnValue(); List<String> messages = cir.getReturnValue();
F3Screen.addStringToDisplay(messages); F3Screen.addStringToDisplay(messages);
} }
#else
// handled by DhDebugScreenEntry for MC versions after 1.21.10
#endif
} }
@@ -30,9 +30,34 @@ import net.minecraft.client.renderer.RenderType;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
#else #elif MC_VER < MC_1_21_9
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.framegraph.FrameGraphBuilder;
import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
import net.minecraft.client.Camera;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.renderer.chunk.ChunkSectionsToRender; import net.minecraft.client.renderer.chunk.ChunkSectionsToRender;
import net.minecraft.client.renderer.culling.Frustum;
import net.minecraft.util.profiling.ProfilerFiller;
import org.joml.Matrix4f;
import org.joml.Matrix4fc; import org.joml.Matrix4fc;
import org.joml.Vector4f;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
#else
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.framegraph.FrameGraphBuilder;
import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
import net.minecraft.client.Camera;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.renderer.chunk.ChunkSectionsToRender;
import net.minecraft.client.renderer.culling.Frustum;
import net.minecraft.client.renderer.state.LevelRenderState;
import net.minecraft.util.profiling.ProfilerFiller;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector4f;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
#endif #endif
@@ -41,11 +66,9 @@ import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.fabric.FabricClientProxy;
import com.seibel.distanthorizons.core.util.math.Mat4f; import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import com.seibel.distanthorizons.core.config.Config;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.LevelRenderer;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@@ -54,7 +77,8 @@ import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
@Mixin(LevelRenderer.class) @Mixin(LevelRenderer.class)
@@ -64,7 +88,7 @@ public class MixinLevelRenderer
private ClientLevel level; private ClientLevel level;
@Unique @Unique
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
@@ -92,9 +116,16 @@ public class MixinLevelRenderer
method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;DDDLorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V", method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;DDDLorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V",
cancellable = true) cancellable = true)
private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f projectionMatrix, Matrix4f frustumMatrix, CallbackInfo callback) private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f projectionMatrix, Matrix4f frustumMatrix, CallbackInfo callback)
#else #elif MC_VER < MC_1_21_9
@Inject(at = @At("HEAD"), method = "prepareChunkRenders", cancellable = true) @Inject(at = @At("HEAD"), method = "prepareChunkRenders", cancellable = true)
private void prepareChunkRenders(Matrix4fc projectionMatrix, double d, double e, double f, CallbackInfoReturnable<ChunkSectionsToRender> callback) private void prepareChunkRenders(Matrix4fc projectionMatrix, double d, double e, double f, CallbackInfoReturnable<ChunkSectionsToRender> callback)
#else
@Inject(at = @At("HEAD"), method = "renderLevel")
private void renderLevel(
GraphicsResourceAllocator resourceAllocator, DeltaTracker deltaTracker,
boolean renderBlockOutline, Camera camera,
Matrix4f positionMatrix, Matrix4f projectionMatrix, Matrix4f idkMatrix, GpuBufferSlice gpuBufferSlice,
Vector4f skyColor, boolean thinFog, CallbackInfo callback)
#endif #endif
{ {
#if MC_VER == MC_1_16_5 #if MC_VER == MC_1_16_5
@@ -110,11 +141,14 @@ public class MixinLevelRenderer
// get the matrices directly from MC // get the matrices directly from MC
ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose()); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose());
ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix); ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
#else #elif MC_VER < MC_1_21_9
// MC combined the model view and projection matricies // MC combined the model view and projection matricies
ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(projectionMatrix); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(projectionMatrix);
ClientApi.RENDER_STATE.mcProjectionMatrix = new Mat4f(); ClientApi.RENDER_STATE.mcProjectionMatrix = new Mat4f();
ClientApi.RENDER_STATE.mcProjectionMatrix.setIdentity(); ClientApi.RENDER_STATE.mcProjectionMatrix.setIdentity();
#else
ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(positionMatrix);
ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
#endif #endif
// TODO move this into a common place // TODO move this into a common place
@@ -126,34 +160,45 @@ public class MixinLevelRenderer
ClientApi.RENDER_STATE.frameTime = Minecraft.getInstance().deltaTracker.getRealtimeDeltaTicks(); ClientApi.RENDER_STATE.frameTime = Minecraft.getInstance().deltaTracker.getRealtimeDeltaTicks();
#endif #endif
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, this.level);
//LOGGER.info("\n\n" +
// "Level Mixin\n" +
// "Mc MVM: \n" + mcModelViewMatrix.toString() + "\n" +
// "Mc Proj: \n" + mcProjectionMatrix.toString()
//);
#if MC_VER < MC_1_21_6 #if MC_VER < MC_1_21_6
if (renderType.equals(RenderType.translucent())) if (renderType.equals(RenderType.translucent()))
{ {
ClientApi.INSTANCE.renderDeferredLodsForShaders(ClientLevelWrapper.getWrapper(this.level), ClientApi.INSTANCE.renderDeferredLodsForShaders();
ClientApi.RENDER_STATE.mcModelViewMatrix,
ClientApi.RENDER_STATE.mcProjectionMatrix,
ClientApi.RENDER_STATE.frameTime
);
} }
#elif MC_VER < MC_1_21_9
// rendering handled via Fabric Api render event
#else #else
// rendering handled via Fabric Api render event // handled here and in MixinChunkSectionsToRender
#endif #endif
// FIXME completely disables rendering when sodium is installed
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
{
callback.cancel();
}
} }
#if MC_VER < MC_1_21_9
// rendering handled via Fabric Api render event
#else
@Inject(at = @At("HEAD"), method = "prepareChunkRenders")
private void prepareChunkRenders(Matrix4fc modelViewMatrix, double d, double e, double f, CallbackInfoReturnable<ChunkSectionsToRender> callback)
{
ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrix);
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, this.level);
// only crash during development
if (ModInfo.IS_DEV_BUILD)
{
ClientApi.RENDER_STATE.canRenderOrThrow();
}
ClientApi.INSTANCE.renderLods();
}
#endif
} }
@@ -22,12 +22,14 @@ package com.seibel.distanthorizons.fabric.mixins.client;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.LightTexture;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -60,27 +62,40 @@ public class MixinLightTexture
private GpuTexture texture; private GpuTexture texture;
#endif #endif
@Unique
private MinecraftRenderWrapper renderWrapper = null;
@Inject(method = "updateLightTexture(F)V", at = @At("RETURN")) @Inject(method = "updateLightTexture(F)V", at = @At("RETURN"))
public void updateLightTexture(float partialTicks, CallbackInfo ci) public void updateLightTexture(float partialTicks, CallbackInfo ci)
{ {
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
if (mc == null || mc.getWrappedClientLevel() == null) if (mc == null)
{ {
return; return;
} }
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel(); IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
if (clientLevel == null)
{
return;
}
// lazy initialization to make sure we don't call this too early
if (this.renderWrapper == null)
{
this.renderWrapper = (MinecraftRenderWrapper)SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
}
#if MC_VER < MC_1_21_3 #if MC_VER < MC_1_21_3
MinecraftRenderWrapper.INSTANCE.updateLightmap(this.lightPixels, clientLevel); this.renderWrapper.updateLightmap(this.lightPixels, clientLevel);
#elif MC_VER < MC_1_21_5 #elif MC_VER < MC_1_21_5
MinecraftRenderWrapper.INSTANCE.setLightmapId(this.target.getColorTextureId(), clientLevel); this.renderWrapper.setLightmapId(this.target.getColorTextureId(), clientLevel);
#else #else
GlTexture glTexture = (GlTexture) this.texture; GlTexture glTexture = (GlTexture) this.texture;
MinecraftRenderWrapper.INSTANCE.setLightmapId(glTexture.glId(), clientLevel); this.renderWrapper.setLightmapId(glTexture.glId(), clientLevel);
#endif #endif
} }
@@ -16,7 +16,7 @@ import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.client.gui.screens.TitleScreen;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
@@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public abstract class MixinMinecraft public abstract class MixinMinecraft
{ {
@Unique @Unique
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MixinMinecraft.class.getSimpleName()); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@Shadow @Shadow
@@ -0,0 +1,64 @@
package com.seibel.distanthorizons.fabric.testing;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiChunkProcessingEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.logging.DhLogger;
import java.io.IOException;
public class TestChunkInputReplacerEvent extends DhApiChunkProcessingEvent
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final String REPLACEMENT_BLOCK_STATE_NAMESPACE = "minecraft:stone";
private IDhApiBlockStateWrapper stoneBlockWrapper = null;
private boolean initialBlockSetupComplete = false;
@Override
public void blockOrBiomeChangedDuringChunkProcessing(DhApiEventParam<EventParam> event)
{
if (!this.initialBlockSetupComplete)
{
// this method can be called on multiple threads
synchronized (this)
{
this.initialBlockSetupComplete = true;
try
{
this.stoneBlockWrapper = DhApi.Delayed.wrapperFactory.getDefaultBlockStateWrapper(REPLACEMENT_BLOCK_STATE_NAMESPACE, event.value.levelWrapper);
}
catch (IOException e)
{
LOGGER.error("Unable to get ["+REPLACEMENT_BLOCK_STATE_NAMESPACE+"] block replacement cannot continue and is now disabled, error: ["+e.getMessage()+"].", e);
DhApi.events.unbind(DhApiChunkProcessingEvent.class, this.getClass());
}
}
}
// will happen if the initial setup fails until the unbind call is processed
// which likely won't happen until the current chunk has finished processing
if (this.stoneBlockWrapper == null)
{
return;
}
// replace any dirt or grass block with stone
IDhApiBlockStateWrapper block = event.value.currentBlock;
if (block.getSerialString().contains("grass_block")
|| block.getSerialString().contains("dirt"))
{
event.value.setBlockOverride(this.stoneBlockWrapper);
}
}
}
@@ -10,11 +10,9 @@ import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
import com.seibel.distanthorizons.api.objects.data.DhApiChunk; import com.seibel.distanthorizons.api.objects.data.DhApiChunk;
import com.seibel.distanthorizons.api.objects.data.DhApiTerrainDataPoint; import com.seibel.distanthorizons.api.objects.data.DhApiTerrainDataPoint;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList; import java.util.ArrayList;
@@ -13,7 +13,7 @@ import com.seibel.distanthorizons.api.objects.data.IDhApiFullDataSource;
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@@ -23,7 +23,7 @@ import java.util.function.Consumer;
public class TestGenericWorldGenerator implements IDhApiWorldGenerator public class TestGenericWorldGenerator implements IDhApiWorldGenerator
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private final IDhApiLevelWrapper levelWrapper; private final IDhApiLevelWrapper levelWrapper;
@@ -6,12 +6,12 @@ import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLo
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
// TODO add to API example once Builderb0y has given the all-clear // TODO add to API example once Builderb0y has given the all-clear
public class TestWorldGenBindingEvent extends DhApiLevelLoadEvent public class TestWorldGenBindingEvent extends DhApiLevelLoadEvent
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@Override @Override
public void onLevelLoad(DhApiEventParam<DhApiLevelLoadEvent.EventParam> event) public void onLevelLoad(DhApiEventParam<DhApiLevelLoadEvent.EventParam> event)
@@ -17,6 +17,7 @@
"client.MixinDebugScreenOverlay", "client.MixinDebugScreenOverlay",
"client.MixinFogRenderer", "client.MixinFogRenderer",
"client.MixinLevelRenderer", "client.MixinLevelRenderer",
"client.MixinChunkSectionsToRender",
"client.MixinLightTexture", "client.MixinLightTexture",
"client.MixinMinecraft", "client.MixinMinecraft",
"client.MixinOptionsScreen", "client.MixinOptionsScreen",
@@ -55,7 +55,7 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
@@ -81,7 +81,7 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
{ {
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final ForgePluginPacketSender PACKET_SENDER = (ForgePluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class); private static final ForgePluginPacketSender PACKET_SENDER = (ForgePluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
@@ -86,11 +86,13 @@ public class ForgeMain extends AbstractModInitializer
} }
@Override @Override
protected void createInitialBindings() protected void createInitialSharedBindings()
{ {
SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new ForgePluginPacketSender()); SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new ForgePluginPacketSender());
} }
@Override
protected void createInitialClientBindings() { /* no additional setup needed currently */ }
@Override @Override
protected IEventProxy createClientProxy() { return new ForgeClientProxy(); } protected IEventProxy createClientProxy() { return new ForgeClientProxy(); }
@@ -47,7 +47,7 @@ import net.minecraftforge.event.server.ServerStoppingEvent;
#endif #endif
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import java.util.function.Supplier; import java.util.function.Supplier;
@@ -129,34 +129,35 @@ public class MixinLevelRenderer
// get the matrices from the OpenGL fixed pipeline // get the matrices from the OpenGL fixed pipeline
float[] mcProjMatrixRaw = new float[16]; float[] mcProjMatrixRaw = new float[16];
GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw); GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
Mat4f mcProjectionMatrix = new Mat4f(mcProjMatrixRaw); ClientApi.RENDER_STATE.mcProjectionMatrix = new Mat4f(mcProjMatrixRaw);
mcProjectionMatrix.transpose(); ClientApi.RENDER_STATE.mcProjectionMatrix.transpose();
Mat4f mcModelViewMatrix = McObjectConverter.Convert(matrixStackIn.last().pose()); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(matrixStackIn.last().pose());
#else #else
// get the matrices directly from MC // get the matrices directly from MC
Mat4f mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose()); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose());
Mat4f mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix); ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
#endif #endif
float frameTime;
#if MC_VER < MC_1_21_1 #if MC_VER < MC_1_21_1
frameTime = Minecraft.getInstance().getFrameTime(); ClientApi.RENDER_STATE.frameTime = Minecraft.getInstance().getFrameTime();
#else #else
frameTime = Minecraft.getInstance().getTimer().getRealtimeDeltaTicks(); ClientApi.RENDER_STATE.frameTime = Minecraft.getInstance().getTimer().getRealtimeDeltaTicks();
#endif #endif
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, this.level);
// only render before solid blocks // only render before solid blocks
if (renderType.equals(RenderType.solid())) if (renderType.equals(RenderType.solid()))
{ {
ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, frameTime); ClientApi.INSTANCE.renderLods();
} }
else if (renderType.equals(RenderType.translucent())) else if (renderType.equals(RenderType.translucent()))
{ {
ClientApi.INSTANCE.renderDeferredLodsForShaders(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, frameTime); ClientApi.INSTANCE.renderDeferredLodsForShaders();
} }
// render fade // render fade
@@ -165,27 +166,11 @@ public class MixinLevelRenderer
// we need to trigger for the renderType after those passes are done // we need to trigger for the renderType after those passes are done
if (renderType.equals(RenderType.cutout())) if (renderType.equals(RenderType.cutout()))
{ {
ClientApi.INSTANCE.renderFadeOpaque( ClientApi.INSTANCE.renderFadeOpaque();
mcModelViewMatrix,
mcProjectionMatrix,
frameTime,
ClientLevelWrapper.getWrapper(this.level)
);
} }
else if (renderType.equals(RenderType.tripwire())) else if (renderType.equals(RenderType.tripwire()))
{ {
ClientApi.INSTANCE.renderFade( ClientApi.INSTANCE.renderFadeTransparent();
mcModelViewMatrix,
mcProjectionMatrix,
frameTime,
ClientLevelWrapper.getWrapper(this.level)
);
}
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
{
callback.cancel();
} }
} }
@@ -12,7 +12,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.client.gui.screens.TitleScreen;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@@ -29,7 +29,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class MixinMinecraft public class MixinMinecraft
{ {
@Unique @Unique
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MixinMinecraft.class.getSimpleName()); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
+9 -5
View File
@@ -5,8 +5,8 @@ org.gradle.caching=true
# Mod Info # Mod Info
mod_name=DistantHorizons mod_name=DistantHorizons
mod_version=2.3.4-b mod_version=2.3.7-b-dev
api_version=4.0.0 api_version=5.0.0
maven_group=com.seibel.distanthorizons maven_group=com.seibel.distanthorizons
mod_readable_name=Distant Horizons 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. 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,11 +18,12 @@ mod_issues=https://gitlab.com/jeseibel/distant-horizons/-/issues
mod_discord=https://discord.gg/xAB8G4cENx mod_discord=https://discord.gg/xAB8G4cENx
# Global Plugin Versions # Global Plugin Versions
manifold_version=2025.1.20 manifold_version=2025.1.27
# 2023.1.17 can be used if there are mystery Java compiler issues # 2023.1.17 can be used if there are mystery Java compiler issues
nightconfig_version=3.6.6 nightconfig_version=3.6.6
lz4_version=1.8.0 lz4_version=1.8.0
xz_version=1.9 xz_version=1.9
zstd_version=1.5.7-6
# Before updating, read relocate_natives/README.md # Before updating, read relocate_natives/README.md
sqlite_jdbc_version=3.47.2.0 sqlite_jdbc_version=3.47.2.0
# 8.2.1 is the newest version we can use since that's the version MC 1.16.5 uses # 8.2.1 is the newest version we can use since that's the version MC 1.16.5 uses
@@ -31,7 +32,10 @@ fastutil_version=8.2.1
# Minecraft related libraries (included in MC's jar) # Minecraft related libraries (included in MC's jar)
log4j_version=2.23.1 log4j_version=2.23.1
lwjgl_version=3.3.1 # if we actually want to use LWJGL methods, this needs to be a MC version variable
# since different MC versions have different LWJGL versions that aren't compatible
# 3.3.3 is for MC 1.21.8
lwjgl_version=3.3.3
joml_version=1.10.2 joml_version=1.10.2
# Architectury config # Architectury config
@@ -51,7 +55,7 @@ versionStr=
# This defines what MC version Intellij will use for the preprocessor # This defines what MC version Intellij will use for the preprocessor
# and what version is used automatically by build and run commands # and what version is used automatically by build and run commands
mcVer=1.21.8 mcVer=1.21.10
# Defines the maximum amount of memory Minecraft is allowed when run in a development environment # Defines the maximum amount of memory Minecraft is allowed when run in a development environment
#minecraftMemoryJavaArg="-Xmx4G" #minecraftMemoryJavaArg="-Xmx4G"
@@ -21,16 +21,13 @@ package com.seibel.distanthorizons.neoforge;
import com.seibel.distanthorizons.common.AbstractModInitializer; import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.util.ProxyUtil; import com.seibel.distanthorizons.common.util.ProxyUtil;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
@@ -40,13 +37,12 @@ import net.minecraft.world.level.LevelAccessor;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.neoforged.neoforge.client.event.RenderLevelStageEvent; import net.neoforged.neoforge.client.event.RenderLevelStageEvent;
import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.level.ChunkEvent;
import net.neoforged.neoforge.event.level.LevelEvent; import net.neoforged.neoforge.event.level.LevelEvent;
import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
@@ -62,21 +58,13 @@ import net.neoforged.neoforge.event.TickEvent;
import net.neoforged.neoforge.client.event.ClientTickEvent; import net.neoforged.neoforge.client.event.ClientTickEvent;
import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
#endif #endif
/**
* This handles all events sent to the client,
* and is the starting point for most of the mod.
*
* @author James_Seibel
* @version 2023-7-27
*/
public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
{ {
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@@ -161,8 +149,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
} }
// executor to prevent locking up the render/event thread // executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected
// (which can be caused by certain mods)
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor(); AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null) if (executor != null)
{ {
@@ -188,8 +174,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
} }
// executor to prevent locking up the render/event thread // executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected
// (which can be caused by certain mods)
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor(); AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null) if (executor != null)
{ {
@@ -262,28 +246,38 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
@SubscribeEvent @SubscribeEvent
public void afterLevelEntityRenderEvent(RenderLevelStageEvent.AfterEntities event) public void afterLevelEntityRenderEvent(RenderLevelStageEvent.AfterEntities event)
{ {
ClientApi.INSTANCE.renderFade( #if MC_VER < MC_1_21_9
ClientApi.RENDER_STATE.mcModelViewMatrix, ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, (ClientLevel)event.getLevel());
ClientApi.RENDER_STATE.mcProjectionMatrix, #else
ClientApi.RENDER_STATE.frameTime, ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, event.getLevelRenderer().level);
ClientLevelWrapper.getWrapper((ClientLevel)event.getLevel()) #endif
);
ClientApi.INSTANCE.renderFadeTransparent();
} }
@SubscribeEvent @SubscribeEvent
public void afterLevelTranslucentRenderEvent(RenderLevelStageEvent.AfterTranslucentBlocks event) public void afterLevelTranslucentRenderEvent(RenderLevelStageEvent.AfterTranslucentBlocks event)
{ {
ClientApi.INSTANCE.renderDeferredLodsForShaders(ClientLevelWrapper.getWrapper((ClientLevel)event.getLevel()), #if MC_VER < MC_1_21_9
ClientApi.RENDER_STATE.mcModelViewMatrix, ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, (ClientLevel)event.getLevel());
ClientApi.RENDER_STATE.mcProjectionMatrix, #else
ClientApi.RENDER_STATE.frameTime ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, event.getLevelRenderer().level);
); #endif
ClientApi.INSTANCE.renderDeferredLodsForShaders();
} }
@SubscribeEvent @SubscribeEvent
public void afterLevelRenderEvent(RenderLevelStageEvent.AfterLevel event) public void afterLevelRenderEvent(RenderLevelStageEvent.AfterLevel event)
{ {
#if MC_VER < MC_1_21_9
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, (ClientLevel)event.getLevel());
#else
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, event.getLevelRenderer().level);
#endif
try try
{ {
// should generally only need to be set once per game session // should generally only need to be set once per game session
@@ -297,24 +291,11 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
} }
ClientApi.INSTANCE.renderFadeOpaque( ClientApi.INSTANCE.renderFadeOpaque();
ClientApi.RENDER_STATE.mcModelViewMatrix,
ClientApi.RENDER_STATE.mcProjectionMatrix,
ClientApi.RENDER_STATE.frameTime,
ClientLevelWrapper.getWrapper((ClientLevel)event.getLevel())
);
} }
#endif #endif
//================//
// helper methods //
//================//
private static LevelAccessor GetEventLevel(LevelEvent e) { return e.getLevel(); }
} }
@@ -22,15 +22,18 @@ package com.seibel.distanthorizons.neoforge;
import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.CommandDispatcher;
import com.seibel.distanthorizons.common.AbstractModInitializer; import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen; import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.ServerApi; import com.seibel.distanthorizons.core.api.internal.ServerApi;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage; 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.IPluginPacketSender;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.neoforge.wrappers.NeoforgeMinecraftRenderWrapper;
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.ModChecker; import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.ModChecker;
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.OptifineAccessor; import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.OptifineAccessor;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
@@ -121,11 +124,18 @@ public class NeoforgeMain extends AbstractModInitializer
protected IEventProxy createServerProxy(boolean isDedicated) { return new NeoforgeServerProxy(isDedicated); } protected IEventProxy createServerProxy(boolean isDedicated) { return new NeoforgeServerProxy(isDedicated); }
@Override @Override
protected void createInitialBindings() protected void createInitialSharedBindings()
{ {
SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new NeoforgePluginPacketSender()); SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new NeoforgePluginPacketSender());
} }
@Override
protected void createInitialClientBindings()
{
// replace MC RenderWrapper with more specific neoforge version
SingletonInjector.INSTANCE.unbind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE); // TODO replace with a replaceOrBind for simplicity
SingletonInjector.INSTANCE.bind(IMinecraftRenderWrapper.class, NeoforgeMinecraftRenderWrapper.INSTANCE);
}
@Override @Override
protected IEventProxy createClientProxy() { return new NeoforgeClientProxy(); } protected IEventProxy createClientProxy() { return new NeoforgeClientProxy(); }
@@ -24,7 +24,7 @@ import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.neoforge.event.server.ServerAboutToStartEvent; import net.neoforged.neoforge.event.server.ServerAboutToStartEvent;
import net.neoforged.neoforge.event.server.ServerStoppingEvent; import net.neoforged.neoforge.event.server.ServerStoppingEvent;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import java.util.function.Supplier; import java.util.function.Supplier;
@@ -40,7 +40,7 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy
private static LevelAccessor GetEventLevel(LevelEvent e) { return e.getLevel(); } private static LevelAccessor GetEventLevel(LevelEvent e) { return e.getLevel(); }
private final ServerApi serverApi = ServerApi.INSTANCE; private final ServerApi serverApi = ServerApi.INSTANCE;
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private final boolean isDedicated; private final boolean isDedicated;
public static Supplier<Boolean> isGenerationThreadChecker = null; public static Supplier<Boolean> isGenerationThreadChecker = null;
@@ -152,8 +152,12 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy
private static ServerLevelWrapper getServerLevelWrapper(ServerLevel level) { return ServerLevelWrapper.getWrapper(level); } private static ServerLevelWrapper getServerLevelWrapper(ServerLevel level) { return ServerLevelWrapper.getWrapper(level); }
private static ServerLevelWrapper getServerLevelWrapper(ResourceKey<Level> resourceKey, PlayerEvent event) private static ServerLevelWrapper getServerLevelWrapper(ResourceKey<Level> resourceKey, PlayerEvent event)
{ {
#if MC_VER < MC_1_21_9
//noinspection DataFlowIssue (possible NPE after getServer()) //noinspection DataFlowIssue (possible NPE after getServer())
return getServerLevelWrapper(event.getEntity().getServer().getLevel(resourceKey)); return getServerLevelWrapper(event.getEntity().getServer().getLevel(resourceKey));
#else
return getServerLevelWrapper(event.getEntity().level().getServer().getLevel(resourceKey));
#endif
} }
private static ServerPlayerWrapper getServerPlayerWrapper(PlayerEvent event) { return ServerPlayerWrapper.getWrapper((ServerPlayer) event.getEntity()); } private static ServerPlayerWrapper getServerPlayerWrapper(PlayerEvent event) { return ServerPlayerWrapper.getWrapper((ServerPlayer) event.getEntity()); }
@@ -1,5 +1,6 @@
package com.seibel.distanthorizons.neoforge.mixins.client; package com.seibel.distanthorizons.neoforge.mixins.client;
#if MC_VER < MC_1_21_9
import com.seibel.distanthorizons.core.logging.f3.F3Screen; import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import net.minecraft.client.gui.components.DebugScreenOverlay; import net.minecraft.client.gui.components.DebugScreenOverlay;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@@ -8,16 +9,24 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List; import java.util.List;
#else
import org.spongepowered.asm.mixin.Mixin;
import net.minecraft.client.gui.components.DebugScreenOverlay;
#endif
@Mixin(DebugScreenOverlay.class) @Mixin(DebugScreenOverlay.class)
public class MixinDebugScreenOverlay public class MixinDebugScreenOverlay
{ {
#if MC_VER < MC_1_21_9
@Inject(method = "getSystemInformation", at = @At("RETURN")) @Inject(method = "getSystemInformation", at = @At("RETURN"))
private void addCustomF3(CallbackInfoReturnable<List<String>> cir) private void addCustomF3(CallbackInfoReturnable<List<String>> cir)
{ {
List<String> messages = cir.getReturnValue(); List<String> messages = cir.getReturnValue();
F3Screen.addStringToDisplay(messages); F3Screen.addStringToDisplay(messages);
} }
#else
// handled by DhDebugScreenEntry for MC versions after 1.21.10
#endif
} }
@@ -48,7 +48,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.neoforge.NeoforgeClientProxy; import com.seibel.distanthorizons.neoforge.NeoforgeClientProxy;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter; import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
@@ -66,15 +66,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* This class is used to mix in DH's rendering code
* before Minecraft starts rendering blocks.
* If this wasn't done, and we used Forge's
* render last event, the LODs would render on top
* of the normal terrain. <br><br>
*
* This is also the mixin for rendering the clouds
*/
@Mixin(LevelRenderer.class) @Mixin(LevelRenderer.class)
public class MixinLevelRenderer public class MixinLevelRenderer
{ {
@@ -85,16 +76,27 @@ public class MixinLevelRenderer
private ClientLevel level; private ClientLevel level;
@Unique @Unique
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
#if MC_VER < MC_1_21_6 #if MC_VER < MC_1_21_6
@Inject(at = @At("HEAD"), method = "renderSectionLayer", cancellable = true) @Inject(at = @At("HEAD"), method = "renderSectionLayer")
private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f modelViewMatrix, Matrix4f projectionMatrix, CallbackInfo callback) private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f modelViewMatrix, Matrix4f projectionMatrix, CallbackInfo callback)
#elif MC_VER < MC_1_21_9
@Inject(at = @At("HEAD"), method = "renderLevel")
private void onRenderLevel(
GraphicsResourceAllocator resourceAllocator, DeltaTracker deltaTracker,
boolean renderBlockOutline, Camera camera,
Matrix4f positionMatrix, Matrix4f projectionMatrix, GpuBufferSlice gpuBufferSlice,
Vector4f skyColor, boolean thinFog, CallbackInfo callback)
#else #else
@Inject(at = @At("HEAD"), method = "renderLevel", cancellable = true) @Inject(at = @At("HEAD"), method = "renderLevel")
private void onRenderLevel(GraphicsResourceAllocator resourceAllocator, DeltaTracker deltaTracker, boolean renderBlockOutline, Camera camera, Matrix4f positionMatrix, Matrix4f projectionMatrix, GpuBufferSlice gpuBufferSlice, Vector4f skyColor, boolean thinFog, CallbackInfo callback) private void renderLevel(
GraphicsResourceAllocator resourceAllocator, DeltaTracker deltaTracker,
boolean renderBlockOutline, Camera camera,
Matrix4f positionMatrix, Matrix4f projectionMatrix, Matrix4f idkMatrix, GpuBufferSlice gpuBufferSlice,
Vector4f skyColor, boolean thinFog, CallbackInfo callback)
#endif #endif
{ {
#if MC_VER < MC_1_21_6 #if MC_VER < MC_1_21_6
@@ -105,12 +107,6 @@ public class MixinLevelRenderer
ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix); ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
#endif #endif
//LOGGER.info("\n\n" +
// "Level Mixin\n" +
// "Mc MVM: \n" + ClientApi.RENDER_STATE.mcModelViewMatrix.toString() + "\n" +
// "Mc Proj: \n" + ClientApi.RENDER_STATE.mcProjectionMatrix.toString()
//);
#if MC_VER < MC_1_21_1 #if MC_VER < MC_1_21_1
@@ -121,6 +117,8 @@ public class MixinLevelRenderer
ClientApi.RENDER_STATE.frameTime = Minecraft.getInstance().deltaTracker.getRealtimeDeltaTicks(); ClientApi.RENDER_STATE.frameTime = Minecraft.getInstance().deltaTracker.getRealtimeDeltaTicks();
#endif #endif
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, this.level);
#if MC_VER < MC_1_21_6 #if MC_VER < MC_1_21_6
@@ -133,17 +131,11 @@ public class MixinLevelRenderer
// render LODs // render LODs
if (renderType.equals(RenderType.solid())) if (renderType.equals(RenderType.solid()))
{ {
ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(this.level), ClientApi.INSTANCE.renderLods();
ClientApi.RENDER_STATE.mcModelViewMatrix,
ClientApi.RENDER_STATE.mcProjectionMatrix,
ClientApi.RENDER_STATE.frameTime);
} }
else if (renderType.equals(RenderType.translucent())) else if (renderType.equals(RenderType.translucent()))
{ {
ClientApi.INSTANCE.renderDeferredLodsForShaders(ClientLevelWrapper.getWrapper(this.level), ClientApi.INSTANCE.renderDeferredLodsForShaders();
ClientApi.RENDER_STATE.mcModelViewMatrix,
ClientApi.RENDER_STATE.mcProjectionMatrix,
ClientApi.RENDER_STATE.frameTime);
} }
// render fade // render fade
@@ -152,28 +144,13 @@ public class MixinLevelRenderer
// we need to trigger for the renderType after those passes are done // we need to trigger for the renderType after those passes are done
if (renderType.equals(RenderType.cutout())) if (renderType.equals(RenderType.cutout()))
{ {
ClientApi.INSTANCE.renderFadeOpaque( ClientApi.INSTANCE.renderFadeOpaque();
ClientApi.RENDER_STATE.mcModelViewMatrix,
ClientApi.RENDER_STATE.mcProjectionMatrix,
ClientApi.RENDER_STATE.frameTime,
ClientLevelWrapper.getWrapper(this.level)
);
} }
else if (renderType.equals(RenderType.tripwire())) else if (renderType.equals(RenderType.tripwire()))
{ {
ClientApi.INSTANCE.renderFade( ClientApi.INSTANCE.renderFadeTransparent();
ClientApi.RENDER_STATE.mcModelViewMatrix,
ClientApi.RENDER_STATE.mcProjectionMatrix,
ClientApi.RENDER_STATE.frameTime,
ClientLevelWrapper.getWrapper(this.level)
);
} }
#endif #endif
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
{
callback.cancel();
}
} }
@@ -182,10 +159,11 @@ public class MixinLevelRenderer
// formerly handled in renderChunkLayer() // formerly handled in renderChunkLayer()
#else #else
@Inject(at = @At("HEAD"), method = "prepareChunkRenders", cancellable = true) @Inject(at = @At("HEAD"), method = "prepareChunkRenders")
private void renderChunkLayer(Matrix4fc modelViewMatrix, double d, double e, double f, CallbackInfoReturnable<ChunkSectionsToRender> callback) private void renderChunkLayer(Matrix4fc modelViewMatrix, double d, double e, double f, CallbackInfoReturnable<ChunkSectionsToRender> callback)
{ {
ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrix); ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrix);
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, this.level);
// only crash during development // only crash during development
if (ModInfo.IS_DEV_BUILD) if (ModInfo.IS_DEV_BUILD)
@@ -193,10 +171,7 @@ public class MixinLevelRenderer
ClientApi.RENDER_STATE.canRenderOrThrow(); ClientApi.RENDER_STATE.canRenderOrThrow();
} }
ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(this.level), ClientApi.INSTANCE.renderLods();
ClientApi.RENDER_STATE.mcModelViewMatrix,
ClientApi.RENDER_STATE.mcProjectionMatrix,
ClientApi.RENDER_STATE.frameTime);
} }
#endif #endif
@@ -22,7 +22,9 @@ package com.seibel.distanthorizons.neoforge.mixins.client;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.neoforge.wrappers.NeoforgeTextureUnwrapper;
import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.LightTexture;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
@@ -36,10 +38,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.mojang.blaze3d.platform.NativeImage; import com.mojang.blaze3d.platform.NativeImage;
#elif MC_VER < MC_1_21_5 #elif MC_VER < MC_1_21_5
import com.mojang.blaze3d.pipeline.TextureTarget; import com.mojang.blaze3d.pipeline.TextureTarget;
#else #elif MC_VER < MC_1_21_9
import com.mojang.blaze3d.opengl.GlTexture; import com.mojang.blaze3d.opengl.GlTexture;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.GpuTexture; import com.mojang.blaze3d.textures.GpuTexture;
#else
import net.neoforged.neoforge.client.blaze3d.validation.ValidationGpuTexture;
import com.mojang.blaze3d.opengl.GlTexture;
import com.mojang.blaze3d.textures.GpuTexture;
#endif #endif
@Mixin(LightTexture.class) @Mixin(LightTexture.class)
@@ -70,14 +76,18 @@ public class MixinLightTexture
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel(); IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
MinecraftRenderWrapper renderWrapper = (MinecraftRenderWrapper)SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
#if MC_VER < MC_1_21_3 #if MC_VER < MC_1_21_3
MinecraftRenderWrapper.INSTANCE.updateLightmap(this.lightPixels, clientLevel); renderWrapper.updateLightmap(this.lightPixels, clientLevel);
#elif MC_VER < MC_1_21_5 #elif MC_VER < MC_1_21_5
MinecraftRenderWrapper.INSTANCE.setLightmapId(this.target.getColorTextureId(), clientLevel); renderWrapper.setLightmapId(this.target.getColorTextureId(), clientLevel);
#else #elif MC_VER < MC_1_21_9
GlTexture glTexture = (GlTexture) this.texture; GlTexture glTexture = (GlTexture) this.texture;
MinecraftRenderWrapper.INSTANCE.setLightmapId(glTexture.glId(), clientLevel); renderWrapper.setLightmapId(glTexture.glId(), clientLevel);
#else
int id = NeoforgeTextureUnwrapper.getGlTextureIdFromGpuTexture(this.texture);
renderWrapper.setLightmapId(id, clientLevel);
#endif #endif
} }
@@ -12,7 +12,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.client.gui.screens.TitleScreen;
import org.apache.logging.log4j.Logger; import com.seibel.distanthorizons.core.logging.DhLogger;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@@ -29,7 +29,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class MixinMinecraft public class MixinMinecraft
{ {
@Unique @Unique
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MixinMinecraft.class.getSimpleName()); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
/** /**
* Can be enabled for testing the auto updater UI. <br/> * Can be enabled for testing the auto updater UI. <br/>
@@ -0,0 +1,82 @@
package com.seibel.distanthorizons.neoforge.wrappers;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import net.minecraft.client.Minecraft;
import com.seibel.distanthorizons.core.logging.DhLogger;
#if MC_VER < MC_1_21_9
#else
import com.mojang.blaze3d.opengl.GlTexture;
import com.mojang.blaze3d.textures.GpuTexture;
import net.neoforged.neoforge.client.blaze3d.validation.ValidationGpuTexture;
#endif
import java.lang.invoke.MethodHandles;
public class NeoforgeMinecraftRenderWrapper extends MinecraftRenderWrapper
{
public static final NeoforgeMinecraftRenderWrapper INSTANCE = new NeoforgeMinecraftRenderWrapper();
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final Minecraft MC = Minecraft.getInstance();
@Override
public int getDepthTextureId()
{
#if MC_VER < MC_1_21_9
// no special handling required,
// both neo/fabric uses the same back end objects
return super.getDepthTextureId();
#else
try
{
GpuTexture gpuTexture = this.getRenderTarget().getDepthTexture();
int id = NeoforgeTextureUnwrapper.getGlTextureIdFromGpuTexture(gpuTexture);
return id;
}
catch (Exception e)
{
// only log this error once per session
if (!this.depthTextureCastFailLogged)
{
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;
}
#endif
}
@Override
public int getColorTextureId()
{
#if MC_VER < MC_1_21_9
// no special handling required,
// both neo/fabric uses the same back end objects
return super.getColorTextureId();
#else
try
{
GpuTexture gpuTexture = this.getRenderTarget().getColorTexture();
int id = NeoforgeTextureUnwrapper.getGlTextureIdFromGpuTexture(gpuTexture);
return id;
}
catch (Exception e)
{
// only log this error once per session
if (!this.colorTextureCastFailLogged)
{
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;
}
#endif
}
}
@@ -0,0 +1,39 @@
package com.seibel.distanthorizons.neoforge.wrappers;
#if MC_VER < MC_1_21_9
public class NeoforgeTextureUnwrapper
{ /* not needed for older MC versions */ }
#else
import com.mojang.blaze3d.opengl.GlTexture;
import com.mojang.blaze3d.textures.GpuTexture;
import net.neoforged.neoforge.client.blaze3d.validation.ValidationGpuTexture;
public class NeoforgeTextureUnwrapper
{
/**
* if Neoforge texture validation is enabled the GlTexture object will be wrapped with a
* Neoforge specific ValidationGpuTexture object.
* This helper allows us to get the underlying OpenGL texture ID
* regardless of what Neoforge returns.
*/
public static int getGlTextureIdFromGpuTexture(GpuTexture gpuTexture) throws ClassCastException
{
GlTexture glTexture;
if (gpuTexture instanceof ValidationGpuTexture)
{
ValidationGpuTexture validationTexture = (ValidationGpuTexture) gpuTexture;
glTexture = (GlTexture)validationTexture.getRealTexture();
}
else
{
glTexture = (GlTexture) gpuTexture;
}
int id = glTexture.glId();
return id;
}
}
#endif
+42 -6
View File
@@ -59,24 +59,31 @@ If you still need help with compiling, please read the Readme.md
/** Loads the VersionProperties fiel for the currently selected Minecraft version. */ /** Loads the VersionProperties fiel for the currently selected Minecraft version. */
def loadProperties() { def loadProperties()
{
def defaultMcVersion = "1.20.1" // 1.20.1 is our current most stable version so we use that if no version was defined def defaultMcVersion = "1.20.1" // 1.20.1 is our current most stable version so we use that if no version was defined
def mcVersion = "" def mcVersion = ""
def mcVers = fileTree("versionProperties").files.name // Get all the files in "versionProperties" def mcVers = fileTree("versionProperties").files.name // Get all the files in "versionProperties"
for (int i = 0; i < mcVers.size(); i++) { for (int i = 0; i < mcVers.size(); i++)
mcVers[i] = mcVers[i].replaceAll("\\.properties", "") // As we are getting the file names, we should remove the ".properties" at the end to get the versions {
String version = mcVers[i];
version = version.replaceAll("\\.properties", "") // As we are getting the file names, we should remove the ".properties" at the end to get the versions
mcVers[i] = version;
} }
mcVers.sort() // Sort so it always goes from oldest to newest mcVers.sort((a,b) -> sortSemanticVersionOldestToNewest(a,b)) // Sort so it always goes from oldest to newest
int mcIndex = -1 int mcIndex = -1
println "Avalible MC versions: ${mcVers}" println "Avalible MC versions: ${mcVers}"
if (hasProperty("mcVer")) { if (hasProperty("mcVer"))
{
mcVersion = mcVer mcVersion = mcVer
mcIndex = mcVers.indexOf(mcVer) mcIndex = mcVers.indexOf(mcVer)
} }
if (mcIndex == -1) {
if (mcIndex == -1)
{
println "No mcVer set or the set mcVer is invalid! Defaulting to ${defaultMcVersion}." println "No mcVer set or the set mcVer is invalid! Defaulting to ${defaultMcVersion}."
println "Tip: Use -PmcVer=\"${defaultMcVersion}\" in cmd arg to set mcVer." println "Tip: Use -PmcVer=\"${defaultMcVersion}\" in cmd arg to set mcVer."
mcVersion = defaultMcVersion mcVersion = defaultMcVersion
@@ -95,6 +102,35 @@ def loadProperties() {
gradle.ext.mcVers = mcVers gradle.ext.mcVers = mcVers
gradle.ext.mcIndex = mcIndex gradle.ext.mcIndex = mcIndex
} }
/**
* input format: "major.minor.patch"
* needed so we can sort versions with different length strings
* IE: 1.21.1 should come before 1.21.10
*/
private static int sortSemanticVersionOldestToNewest(String version1, String version2)
{
String[] parts1 = version1.split("\\.");
String[] parts2 = version2.split("\\.");
int major1 = Integer.parseInt(parts1[0]);
int major2 = Integer.parseInt(parts2[0]);
if (major1 != major2)
{
return Integer.compare(major1, major2);
}
int minor1 = Integer.parseInt(parts1[1]);
int minor2 = Integer.parseInt(parts2[1]);
if (minor1 != minor2)
{
return Integer.compare(minor1, minor2);
}
int patch1 = Integer.parseInt(parts1[2]);
int patch2 = Integer.parseInt(parts2[2]);
return Integer.compare(patch1, patch2);
}
loadProperties() loadProperties()
+57
View File
@@ -0,0 +1,57 @@
# 1.21.10 version
java_version=21
minecraft_version=1.21.10
parchment_version=1.21:2024.07.28
compatible_minecraft_versions=["1.21.10"]
accessWidenerVersion=1_21_10
builds_for=fabric,neoforge
# forge is broken due to gradle/build script issues
# Netty
netty_version=4.1.97.Final
# Fabric loader
fabric_loader_version=0.17.3
fabric_api_version=0.135.0+1.21.10
modmenu_version=16.0.0-rc.1
starlight_version_fabric=
phosphor_version_fabric=
lithium_version=
sodium_version=mc1.21.10-0.7.2-fabric
iris_version=1.9.6+1.21.10-fabric
bclib_version=
immersive_portals_version=
canvas_version=
fabric_incompatibility_list={ }
fabric_recommend_list={}
# Fabric mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_sodium=1
enable_lithium=0
enable_iris=1
enable_bclib=0
enable_immersive_portals=0
enable_canvas=0
# (Neo)Forge loader
forge_version=
neoforge_version=21.10.6-beta
neoforge_version_range=[21.10.6-beta,)
# (Neo)Forge mod versions
starlight_version_forge=
terraforged_version=
# (Neo)Forge mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
enable_terrafirmacraft=0
+3 -3
View File
@@ -1,4 +1,4 @@
# 1.21.7 version # 1.21.8 version
java_version=21 java_version=21
minecraft_version=1.21.8 minecraft_version=1.21.8
parchment_version=1.21:2024.07.28 parchment_version=1.21:2024.07.28
@@ -11,8 +11,8 @@ builds_for=fabric,neoforge
netty_version=4.1.97.Final netty_version=4.1.97.Final
# Fabric loader # Fabric loader
fabric_loader_version=0.16.13 fabric_loader_version=0.17.2
fabric_api_version=0.129.0+1.21.8 fabric_api_version=0.133.4+1.21.8
modmenu_version=15.0.0-beta.3 modmenu_version=15.0.0-beta.3
starlight_version_fabric= starlight_version_fabric=
phosphor_version_fabric= phosphor_version_fabric=
+59
View File
@@ -0,0 +1,59 @@
# 1.21.9 version
java_version=21
minecraft_version=1.21.9
parchment_version=1.21:2024.07.28
compatible_minecraft_versions=["1.21.9"]
accessWidenerVersion=1_21_10
builds_for=fabric,neoforge
# forge is broken due to gradle/build script issues
# Netty
netty_version=4.1.97.Final
# Fabric loader
fabric_loader_version=0.17.3
fabric_api_version=0.134.0+1.21.9
modmenu_version=16.0.0-rc.1
starlight_version_fabric=
phosphor_version_fabric=
lithium_version=
sodium_version=mc1.21.10-0.7.2-fabric
iris_version=1.9.3+1.21.9-fabric
bclib_version=
immersive_portals_version=
canvas_version=
fabric_incompatibility_list={ }
fabric_recommend_list={}
# Fabric mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_sodium=1
enable_lithium=0
enable_iris=1
enable_bclib=0
enable_immersive_portals=0
enable_canvas=0
# (Neo)Forge loader
forge_version=
neoforge_version=21.9.15-beta
# sometime before 21.9.15-beta Neoforge changed how their rendering API events handle levels
# so we can't support both versions at once
neoforge_version_range=[21.9.15-beta,)
# (Neo)Forge mod versions
starlight_version_forge=
terraforged_version=
# (Neo)Forge mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
enable_terrafirmacraft=0