From 20b9f4f1cb64b7dd8b64423d469fb5d2d875ea9a Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sun, 12 Oct 2025 13:58:03 -0500 Subject: [PATCH] Fix stuttering when flying over un-generated chunks --- .../fabric/FabricClientProxy.java | 16 +++++++----- .../client/MixinClientPacketListener.java | 24 ++++++++++++++++-- .../mixins/client/MixinLightTexture.java | 25 ++++++++++++++----- .../neoforge/NeoforgeClientProxy.java | 4 --- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java index 483ba6dc0..455b650db 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java @@ -130,8 +130,16 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy { if (MC.clientConnectedToDedicatedServer()) { - IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level); - SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel); + // executor to prevent locking up the render/event thread + AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor(); + if (executor != null) + { + executor.execute(() -> + { + IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level); + SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel); + }); + } } }); @@ -145,8 +153,6 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy if (SharedApi.isChunkAtBlockPosAlreadyUpdating(blockPos.getX(), blockPos.getZ())) { // 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(); if (executor != null) { @@ -185,8 +191,6 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy if (SharedApi.isChunkAtBlockPosAlreadyUpdating(hitResult.getBlockPos().getX(), hitResult.getBlockPos().getZ())) { // 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(); if (executor != null) { diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientPacketListener.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientPacketListener.java index 5763d7210..05718455c 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientPacketListener.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientPacketListener.java @@ -3,8 +3,10 @@ package com.seibel.distanthorizons.fabric.mixins.client; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.core.api.internal.ClientApi; 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.ClientPacketListener; +import net.minecraft.world.level.chunk.ChunkAccess; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; 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 net.minecraft.world.level.chunk.LevelChunk; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; + +import java.util.concurrent.AbstractExecutorService; #endif @Mixin(ClientPacketListener.class) @@ -45,8 +49,24 @@ public class MixinClientPacketListener @Inject(method = "enableChunkLight", at = @At("TAIL")) void onEnableChunkLight(LevelChunk chunk, int x, int z, CallbackInfo ci) { - IClientLevelWrapper clientLevel = ClientLevelWrapper.getWrapper((ClientLevel) chunk.getLevel()); - SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, clientLevel), clientLevel); + if (chunk == null) + { + 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 diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLightTexture.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLightTexture.java index 577946fed..7b5814da9 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLightTexture.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinLightTexture.java @@ -29,6 +29,7 @@ import net.minecraft.client.renderer.LightTexture; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; 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.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -61,28 +62,40 @@ public class MixinLightTexture private GpuTexture texture; #endif + @Unique + private MinecraftRenderWrapper renderWrapper = null; + @Inject(method = "updateLightTexture(F)V", at = @At("RETURN")) public void updateLightTexture(float partialTicks, CallbackInfo ci) { IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); - if (mc == null || mc.getWrappedClientLevel() == null) + if (mc == null) { return; } - IClientLevelWrapper clientLevel = mc.getWrappedClientLevel(); - MinecraftRenderWrapper renderWrapper = (MinecraftRenderWrapper)SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + 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 - renderWrapper.updateLightmap(this.lightPixels, clientLevel); + this.renderWrapper.updateLightmap(this.lightPixels, clientLevel); #elif MC_VER < MC_1_21_5 - renderWrapper.setLightmapId(this.target.getColorTextureId(), clientLevel); + this.renderWrapper.setLightmapId(this.target.getColorTextureId(), clientLevel); #else GlTexture glTexture = (GlTexture) this.texture; - renderWrapper.setLightmapId(glTexture.glId(), clientLevel); + this.renderWrapper.setLightmapId(glTexture.glId(), clientLevel); #endif } diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeClientProxy.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeClientProxy.java index ac30eadaa..a8ba19213 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeClientProxy.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeClientProxy.java @@ -149,8 +149,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy } // 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(); if (executor != null) { @@ -176,8 +174,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy } // 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(); if (executor != null) {