From dafbeb34d4bae514ec1c1ab9d2e2d21ba88e0dc8 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 8 Apr 2020 22:43:02 +0200 Subject: [PATCH] Workaround a bug in OF which incorrectly queues chunks (fixes #123) --- .../shaders/mixin/MixinShaderRenderChunk.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderRenderChunk.java b/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderRenderChunk.java index 4d544576..47295f28 100644 --- a/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderRenderChunk.java +++ b/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaderRenderChunk.java @@ -8,6 +8,10 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +//#if MC>=11500 +import org.spongepowered.asm.mixin.Shadow; +//#endif + //#if MC>=11500 @Mixin(net.minecraft.client.render.chunk.ChunkBuilder.BuiltChunk.class) //#else @@ -17,6 +21,35 @@ public abstract class MixinShaderRenderChunk { private final MinecraftClient mc = MinecraftClient.getInstance(); + //#if MC>=11500 + @Shadow private int rebuildFrame; + + @Shadow public abstract boolean shouldBuild(); + + + /** + * So, for some reason OF though it'd be a good idea to drop the `shouldBuild` check from the chunk traversal in + * the setupTerrain method (see the innermost if of the "iteration" profiler section). + * Hint: It's not a good idea. It'll cause chunks to be queued for building which should not be built. And because + * they don't know any better, they'll even re-queue themselves (which looks like a race condition in vanilla + * MC) causing a live-lock when we try to force-build all chunks (or at least it would cause a lockup if it + * wasn't for the vanilla race condition which slowly causes some of the rebuild tasks to get lost over time, + * eventually, potentially all of them). + * This is the most convenient place to re-introduce the check (setRebuildFrame would normally be called right after + * shouldBuild, if it returns true). + */ + @Inject(method = "setRebuildFrame", at = @At("HEAD"), cancellable = true) + private void replayModCompat_OFHaveYouConsideredWhetherThisChunkShouldEvenBeBuilt(int rebuildFrame, CallbackInfoReturnable ci) { + if (this.rebuildFrame == rebuildFrame) { + // want to keep the fast path + ci.setReturnValue(false); + } else if (!this.shouldBuild()) { + // this is the check which OF removed + ci.setReturnValue(false); + } + } + //#endif + /** * Changes the RenderChunk#isPlayerUpdate method that Optifine adds * to always return true while rendering so no chunks are being added