From bab36248d7d5548e29ce95226ab5e8f15132c522 Mon Sep 17 00:00:00 2001
From: Kevin <92656833+kevinthegreat1@users.noreply.github.com>
Date: Mon, 5 Feb 2024 06:30:21 -0500
Subject: [PATCH] Fix WorldRenderEvents.AFTER_TRANSLUCENT (#3563)

* Fix WorldRenderEvents.AFTER_TRANSLUCENT

* Add test for WorldRenderEvents.AFTER_TRANSLUCENT

* Reset matrixStack
---
 .../rendering/v1/WorldRenderContext.java      |  6 +++
 .../rendering/WorldRenderContextImpl.java     | 12 ++++++
 .../client/rendering/WorldRendererMixin.java  | 28 +++++---------
 .../client/WorldRenderEventsTests.java        | 37 ++++++++++++++++++-
 4 files changed, 63 insertions(+), 20 deletions(-)

diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/WorldRenderContext.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/WorldRenderContext.java
index 7dca30f3f..e36cd0603 100644
--- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/WorldRenderContext.java
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/WorldRenderContext.java
@@ -45,6 +45,12 @@ public interface WorldRenderContext {
 	 */
 	WorldRenderer worldRenderer();
 
+	/**
+	 * The matrix stack is only not null in {@link WorldRenderEvents#AFTER_ENTITIES} or later events.
+	 */
+	@Nullable
+	MatrixStack matrixStack();
+
 	float tickDelta();
 
 	long limitTime();
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/WorldRenderContextImpl.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/WorldRenderContextImpl.java
index dd33e3190..224389fe8 100644
--- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/WorldRenderContextImpl.java
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/WorldRenderContextImpl.java
@@ -27,6 +27,7 @@ import net.minecraft.client.render.RenderLayer;
 import net.minecraft.client.render.VertexConsumer;
 import net.minecraft.client.render.VertexConsumerProvider;
 import net.minecraft.client.render.WorldRenderer;
+import net.minecraft.client.util.math.MatrixStack;
 import net.minecraft.client.world.ClientWorld;
 import net.minecraft.entity.Entity;
 import net.minecraft.util.math.BlockPos;
@@ -36,6 +37,7 @@ import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
 
 public final class WorldRenderContextImpl implements WorldRenderContext.BlockOutlineContext, WorldRenderContext {
 	private WorldRenderer worldRenderer;
+	private MatrixStack matrixStack;
 	private float tickDelta;
 	private long limitTime;
 	private boolean blockOutlines;
@@ -75,6 +77,7 @@ public final class WorldRenderContextImpl implements WorldRenderContext.BlockOut
 			ClientWorld world
 	) {
 		this.worldRenderer = worldRenderer;
+		this.matrixStack = null;
 		this.tickDelta = tickDelta;
 		this.limitTime = limitTime;
 		this.blockOutlines = blockOutlines;
@@ -93,6 +96,10 @@ public final class WorldRenderContextImpl implements WorldRenderContext.BlockOut
 		this.frustum = frustum;
 	}
 
+	public void setMatrixStack(MatrixStack matrixStack) {
+		this.matrixStack = matrixStack;
+	}
+
 	public void prepareBlockOutline(
 			Entity entity,
 			double cameraX,
@@ -114,6 +121,11 @@ public final class WorldRenderContextImpl implements WorldRenderContext.BlockOut
 		return worldRenderer;
 	}
 
+	@Override
+	public MatrixStack matrixStack() {
+		return matrixStack;
+	}
+
 	@Override
 	public float tickDelta() {
 		return tickDelta;
diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/WorldRendererMixin.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/WorldRendererMixin.java
index 65333c2ff..e6b597288 100644
--- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/WorldRendererMixin.java
+++ b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/mixin/client/rendering/WorldRendererMixin.java
@@ -16,6 +16,7 @@
 
 package net.fabricmc.fabric.mixin.client.rendering;
 
+import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
 import org.joml.Matrix4f;
 import org.spongepowered.asm.mixin.Final;
 import org.spongepowered.asm.mixin.Mixin;
@@ -58,13 +59,11 @@ public abstract class WorldRendererMixin {
 	@Shadow
 	private MinecraftClient client;
 	@Unique private final WorldRenderContextImpl context = new WorldRenderContextImpl();
-	@Unique private boolean didRenderParticles;
 
 	@Inject(method = "render", at = @At("HEAD"))
 	private void beforeRender(float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f positionMatrix, Matrix4f projectionMatrix, CallbackInfo ci) {
 		context.prepare((WorldRenderer) (Object) this, tickDelta, limitTime, renderBlockOutline, camera, gameRenderer, lightmapTextureManager, projectionMatrix, positionMatrix, bufferBuilders.getEntityVertexConsumers(), world.getProfiler(), transparencyPostProcessor != null, world);
 		WorldRenderEvents.START.invoker().onStart(context);
-		didRenderParticles = false;
 	}
 
 	@Inject(method = "setupTerrain", at = @At("RETURN"))
@@ -86,6 +85,12 @@ public abstract class WorldRendererMixin {
 		WorldRenderEvents.BEFORE_ENTITIES.invoker().beforeEntities(context);
 	}
 
+	@ModifyExpressionValue(method = "render", at = @At(value = "NEW", target = "net/minecraft/client/util/math/MatrixStack"))
+	private MatrixStack setMatrixStack(MatrixStack matrixStack) {
+		context.setMatrixStack(matrixStack);
+		return matrixStack;
+	}
+
 	@Inject(method = "render", at = @At(value = "CONSTANT", args = "stringValue=blockentities", ordinal = 0))
 	private void afterEntities(CallbackInfo ci) {
 		WorldRenderEvents.AFTER_ENTITIES.invoker().afterEntities(context);
@@ -136,24 +141,9 @@ public abstract class WorldRendererMixin {
 		WorldRenderEvents.BEFORE_DEBUG_RENDER.invoker().beforeDebugRender(context);
 	}
 
-	@Inject(
-			method = "render",
-			at = @At(
-				value = "INVOKE",
-				target = "Lnet/minecraft/client/particle/ParticleManager;renderParticles(Lnet/minecraft/client/render/LightmapTextureManager;Lnet/minecraft/client/render/Camera;F)V"
-			)
-	)
-	private void onRenderParticles(CallbackInfo ci) {
-		// set a flag so we know the next pushMatrix call is after particles
-		didRenderParticles = true;
-	}
-
-	@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/MatrixStack;push()V"))
+	@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/GameOptions;getCloudRenderModeValue()Lnet/minecraft/client/option/CloudRenderMode;"))
 	private void beforeClouds(CallbackInfo ci) {
-		if (didRenderParticles) {
-			didRenderParticles = false;
-			WorldRenderEvents.AFTER_TRANSLUCENT.invoker().afterTranslucent(context);
-		}
+		WorldRenderEvents.AFTER_TRANSLUCENT.invoker().afterTranslucent(context);
 	}
 
 	@Inject(
diff --git a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/WorldRenderEventsTests.java b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/WorldRenderEventsTests.java
index 48d752f21..5423abaf8 100644
--- a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/WorldRenderEventsTests.java
+++ b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/WorldRenderEventsTests.java
@@ -16,9 +16,17 @@
 
 package net.fabricmc.fabric.test.rendering.client;
 
+import com.mojang.blaze3d.systems.RenderSystem;
+
 import net.minecraft.block.Blocks;
 import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.render.BufferBuilder;
+import net.minecraft.client.render.GameRenderer;
 import net.minecraft.client.render.OverlayTexture;
+import net.minecraft.client.render.Tessellator;
+import net.minecraft.client.render.VertexFormat;
+import net.minecraft.client.render.VertexFormats;
+import net.minecraft.client.render.WorldRenderer;
 import net.minecraft.client.util.math.MatrixStack;
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.math.Vec3d;
@@ -50,9 +58,36 @@ public class WorldRenderEventsTests implements ClientModInitializer {
 		return true;
 	}
 
-	// Renders a diamond block above diamond blocks when they are looked at.
+	/**
+	 * Renders a translucent box at (0, 100, 0).
+	 */
+	private static void renderAfterTranslucent(WorldRenderContext context) {
+		MatrixStack matrices = context.matrixStack();
+		Vec3d camera = context.camera().getPos();
+		Tessellator tessellator = RenderSystem.renderThreadTesselator();
+		BufferBuilder buffer = tessellator.getBuffer();
+
+		matrices.push();
+		matrices.translate(-camera.x, -camera.y, -camera.z);
+
+		RenderSystem.setShader(GameRenderer::getPositionColorProgram);
+		RenderSystem.setShaderColor(1f, 1f, 1f, 1f);
+		RenderSystem.enableBlend();
+		RenderSystem.defaultBlendFunc();
+
+		buffer.begin(VertexFormat.DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR);
+		WorldRenderer.renderFilledBox(matrices, buffer, 0, 100, 0, 1, 101, 1, 0, 1, 0, 0.5f);
+		tessellator.draw();
+
+		matrices.pop();
+		RenderSystem.disableBlend();
+	}
+
 	@Override
 	public void onInitializeClient() {
+		// Renders a diamond block above diamond blocks when they are looked at.
 		WorldRenderEvents.BLOCK_OUTLINE.register(WorldRenderEventsTests::onBlockOutline);
+		// Renders a translucent box at (0, 100, 0)
+		WorldRenderEvents.AFTER_TRANSLUCENT.register(WorldRenderEventsTests::renderAfterTranslucent);
 	}
 }