diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalFrameBuffer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalFrameBuffer.java new file mode 100644 index 00000000..dffa297b --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalFrameBuffer.java @@ -0,0 +1,287 @@ +package com.minelittlepony.unicopia.client.render.spell; + +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix3f; +import org.joml.Matrix4f; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.effect.PortalSpell; +import com.minelittlepony.unicopia.client.render.RenderLayers; +import com.minelittlepony.unicopia.client.render.model.SphereModel; +import com.minelittlepony.unicopia.client.render.model.TexturedSphereModel; +import com.minelittlepony.unicopia.entity.EntityReference; +import com.minelittlepony.unicopia.entity.mob.UEntities; +import com.minelittlepony.unicopia.mixin.client.MixinMinecraftClient; +import com.mojang.blaze3d.platform.GlConst; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.systems.VertexSorter; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gl.SimpleFramebuffer; +import net.minecraft.client.option.Perspective; +import net.minecraft.client.render.BackgroundRenderer; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.Frustum; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.render.VertexFormats; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.util.Window; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.screen.PlayerScreenHandler; +import net.minecraft.util.math.Vec3d; + +class PortalFrameBuffer implements AutoCloseable { + private static final LoadingCache CACHE = CacheBuilder.newBuilder() + .expireAfterAccess(10, TimeUnit.SECONDS) + .removalListener(n -> n.getValue().close()) + .build(CacheLoader.from(PortalFrameBuffer::new)); + + private static int recursionCount; + + @Nullable + public static PortalFrameBuffer unpool(UUID id) { + try { + return CACHE.get(id); + } catch (ExecutionException e) { + return null; + } + } + + @Nullable + private SimpleFramebuffer framebuffer; + @Nullable + private SimpleFramebuffer backgroundBuffer; + @Nullable + private WorldRenderer renderer; + @Nullable + private ClientWorld world; + + private boolean closed; + + private final MinecraftClient client = MinecraftClient.getInstance(); + + private boolean pendingDraw; + + private final UUID id; + + @Nullable + private Frustum frustum; + + PortalFrameBuffer(UUID id) { + this.id = id; + } + + public void draw(MatrixStack matrices, VertexConsumerProvider vertices) { + matrices.translate(0, -0.001, 0); + + if (!(closed || framebuffer == null)) { + RenderSystem.assertOnRenderThread(); + GlStateManager._colorMask(true, true, true, false); + GlStateManager._enableDepthTest(); + GlStateManager._disableCull(); + Tessellator tessellator = RenderSystem.renderThreadTesselator(); + BufferBuilder buffer = tessellator.getBuffer(); + float uScale = (float)framebuffer.viewportWidth / (float)framebuffer.textureWidth; + float vScale = (float)framebuffer.viewportHeight / (float)framebuffer.textureHeight; + RenderSystem.setShader(GameRenderer::getPositionTexColorProgram); + RenderSystem._setShaderTexture(0, framebuffer.getColorAttachment()); + buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR); + TexturedSphereModel.DISK.render(matrices, buffer, 2F, 1, 1, 1, 1, uScale, vScale); + tessellator.draw(); + + client.getTextureManager().bindTexture(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE); + GlStateManager._enableCull(); + GlStateManager._colorMask(true, true, true, true); + GlStateManager._depthMask(true); + } else { + Vec3d skyColor = client.world.getSkyColor(client.gameRenderer.getCamera().getPos(), client.getTickDelta()); + SphereModel.DISK.render(matrices, vertices.getBuffer(RenderLayers.getMagicShield()), 0, 0, 2, (float)skyColor.x, (float)skyColor.y, (float)skyColor.z, 1); + } + } + + public void build(PortalSpell spell, Caster caster, EntityReference.EntityValues target) { + + if (framebuffer != null && System.currentTimeMillis() % 100 != 0) { + return; + } + + if (pendingDraw && recursionCount > 0) { + innerBuild(spell, caster, target); + return; + } + + if (pendingDraw) { + return; + } + pendingDraw = true; + if (recursionCount > 0) { + innerBuild(spell, caster, target); + } else { + ((MixinMinecraftClient)client).getRenderTaskQueue().add(() -> innerBuild(spell, caster, target)); + } + } + + private void innerBuild(PortalSpell spell, Caster caster, EntityReference.EntityValues target) { + synchronized (client) { + pendingDraw = false; + + if (recursionCount > 2) { + return; + } + recursionCount++; + + try { + if (closed || client.interactionManager == null) { + close(); + return; + } + + var fov = client.options.getFov(); + int originalFov = fov.getValue(); + fov.setValue(110); + + Entity cameraEntity = UEntities.CAST_SPELL.create(caster.asWorld()); + cameraEntity.setPosition(target.pos()); + cameraEntity.setPitch(spell.getTargetPitch()); + cameraEntity.setYaw(spell.getTargetYaw() + 180); + + drawWorld(cameraEntity, 400, 400); + + fov.setValue(originalFov); + } finally { + recursionCount--; + } + } + } + + private void drawWorld(Entity cameraEntity, int width, int height) { + Entity oldCameraEntity = client.cameraEntity; + Window window = client.getWindow(); + + int i = window.getFramebufferWidth(); + int j = window.getFramebufferHeight(); + + width = i; + height = j; + + Perspective perspective = client.options.getPerspective(); + MatrixStack view = RenderSystem.getModelViewStack(); + + Matrix4f proj = RenderSystem.getProjectionMatrix(); + Matrix3f invView = RenderSystem.getInverseViewRotationMatrix(); + + int fbo = client.getFramebuffer().fbo; + Camera camera = client.gameRenderer.getCamera(); + + WorldRenderer globalRenderer = client.worldRenderer; + try { + client.cameraEntity = cameraEntity; + client.getFramebuffer().endWrite(); + + if (framebuffer == null) { + framebuffer = new SimpleFramebuffer(width, height, true, MinecraftClient.IS_SYSTEM_MAC); + framebuffer.setClearColor(0, 0, 0, 0); + framebuffer.clear(MinecraftClient.IS_SYSTEM_MAC); + } + + view.push(); + view.loadIdentity(); + RenderSystem.applyModelViewMatrix(); + + window.setFramebufferWidth(width); + window.setFramebufferHeight(height); + client.getFramebuffer().fbo = framebuffer.fbo; + + client.options.setPerspective(Perspective.FIRST_PERSON); + + RenderSystem.clear(GlConst.GL_DEPTH_BUFFER_BIT | GlConst.GL_COLOR_BUFFER_BIT, MinecraftClient.IS_SYSTEM_MAC); + framebuffer.beginWrite(true); + BackgroundRenderer.clearFog(); + RenderSystem.enableCull(); + + if (renderer == null) { + renderer = new WorldRenderer(client, client.getEntityRenderDispatcher(), client.getBlockEntityRenderDispatcher(), client.getBufferBuilders()); + } + if (client.world != world) { + world = client.world; + renderer.setWorld(client.world); + } + ((MixinMinecraftClient)client).setWorldRenderer(renderer); + + renderer.scheduleBlockRenders((int)cameraEntity.getX() / 16, (int)cameraEntity.getY() / 16, (int)cameraEntity.getZ() / 16); + + client.gameRenderer.setRenderHand(false); + MatrixStack matrices = new MatrixStack(); + + matrices.scale((float)width / height, 1, 1); + + client.gameRenderer.renderWorld(1, 0, matrices); + + // Strip transparency + RenderSystem.colorMask(false, false, false, true); + RenderSystem.clearColor(1, 1, 1, 1); + RenderSystem.clear(GlConst.GL_COLOR_BUFFER_BIT, MinecraftClient.IS_SYSTEM_MAC); + RenderSystem.colorMask(true, true, true, true); + + framebuffer.endWrite(); + } finally { + ((MixinMinecraftClient)client).setWorldRenderer(globalRenderer); + + client.getFramebuffer().fbo = fbo; + client.getFramebuffer().beginWrite(true); + + view.pop(); + RenderSystem.applyModelViewMatrix(); + RenderSystem.setProjectionMatrix(proj, VertexSorter.BY_Z); + RenderSystem.setInverseViewRotationMatrix(invView); + + window.setFramebufferWidth(i); + window.setFramebufferHeight(j); + + client.options.setPerspective(perspective); + client.cameraEntity = oldCameraEntity; + + if (recursionCount <= 1) { + client.gameRenderer.setRenderHand(true); + camera.update(client.world, + client.getCameraEntity() == null ? client.player : client.getCameraEntity(), + perspective.isFirstPerson(), + perspective.isFrontView(), + 1 + ); + } + } + } + + @Override + public void close() { + closed = true; + if (framebuffer != null) { + SimpleFramebuffer fb = framebuffer; + framebuffer = null; + fb.delete(); + } + if (backgroundBuffer != null) { + SimpleFramebuffer fb = backgroundBuffer; + backgroundBuffer = null; + fb.delete(); + } + if (renderer != null) { + renderer.close(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalSpellRenderer.java index ebdf5fc3..4324ef30 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalSpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PortalSpellRenderer.java @@ -1,60 +1,21 @@ package com.minelittlepony.unicopia.client.render.spell; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -import org.jetbrains.annotations.Nullable; -import org.joml.Matrix3f; -import org.joml.Matrix4f; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.minelittlepony.common.util.Color; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.effect.PortalSpell; import com.minelittlepony.unicopia.client.render.RenderLayers; import com.minelittlepony.unicopia.client.render.model.SphereModel; -import com.minelittlepony.unicopia.client.render.model.TexturedSphereModel; import com.minelittlepony.unicopia.entity.EntityReference; -import com.minelittlepony.unicopia.entity.mob.UEntities; -import com.minelittlepony.unicopia.mixin.client.MixinMinecraftClient; -import com.mojang.blaze3d.platform.GlConst; -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.systems.VertexSorter; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.SimpleFramebuffer; -import net.minecraft.client.option.Perspective; -import net.minecraft.client.render.BackgroundRenderer; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.Frustum; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; -import net.minecraft.client.util.Window; import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.Entity; -import net.minecraft.screen.PlayerScreenHandler; -import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RotationAxis; -import net.minecraft.util.math.Vec3d; public class PortalSpellRenderer extends SpellRenderer { - static boolean FANCY_PORTAlS = false; - - private static final LoadingCache FRAME_BUFFERS = CacheBuilder.newBuilder() - .expireAfterAccess(10, TimeUnit.SECONDS) - .removalListener(n -> n.getValue().close()) - .build(CacheLoader.from(uuid -> new PortalFrameBuffer())); + static boolean FANCY_PORTAlS = true; @Override public boolean shouldRenderEffectPass(int pass) { @@ -62,31 +23,21 @@ public class PortalSpellRenderer extends SpellRenderer { } @Override - public void render(MatrixStack matrices, VertexConsumerProvider vertices, PortalSpell spell, Caster caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { - super.render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch); - - if (!spell.isLinked()) { - return; - } - - int color = spell.getType().getColor(); - - float red = Color.r(color); - float green = Color.g(color); - float blue = Color.b(color); + public void render(MatrixStack matrices, VertexConsumerProvider vertices, PortalSpell spell, Caster caster, int light, float strength, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { + super.render(matrices, vertices, spell, caster, light, strength, limbDistance, tickDelta, animationProgress, headYaw, headPitch); VertexConsumer buff = vertices.getBuffer(RenderLayers.getEndGateway()); matrices.push(); matrices.translate(0, 0.02, 0); - SphereModel.DISK.render(matrices, buff, light, 0, 2F, red, green, blue, 1); + SphereModel.DISK.render(matrices, buff, light, 0, 2F * strength, 1, 1, 1, 1); matrices.pop(); - if (!FANCY_PORTAlS) { + if (!FANCY_PORTAlS || !spell.isLinked()) { matrices.push(); matrices.translate(0, -0.02, 0); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(180)); - SphereModel.DISK.render(matrices, buff, light, 0, 2F, red, green, blue, 1); + SphereModel.DISK.render(matrices, buff, light, 0, 2F * strength, 1, 1, 1, 1); matrices.pop(); return; } @@ -94,231 +45,44 @@ public class PortalSpellRenderer extends SpellRenderer { // Fancy portal rendering is disabled for now // Need to fix: // 1. Transparent parts of the sky (because the game sets the clear to (0,0,0,0) - // 2. Chunk flickering at long distances between portals if (caster.asEntity().distanceTo(client.cameraEntity) > 50) { return; // don't bother rendering if too far away } + matrices.push(); + matrices.scale(strength, strength, strength); + spell.getTarget().ifPresent(target -> { - try { - float grown = Math.min(caster.asEntity().age, 20) / 20F; - matrices.push(); - matrices.translate(0, -0.01, 0); - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-spell.getYaw())); - matrices.scale(grown, 1, grown); - PortalFrameBuffer buffer = FRAME_BUFFERS.get(target.uuid()); - buffer.build(spell, caster, target); + float grown = Math.min(caster.asEntity().age, 20) / 20F; + matrices.push(); + matrices.translate(0, -0.01, 0); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-spell.getYaw())); + matrices.scale(grown, 1, grown); + boolean inRange = MinecraftClient.getInstance().player.getPos().distanceTo(target.pos()) < MinecraftClient.getInstance().gameRenderer.getViewDistance(); + + PortalFrameBuffer buffer = PortalFrameBuffer.unpool(target.uuid()); + if (buffer != null) { + if (inRange) { + buffer.build(spell, caster, target); + } buffer.draw(matrices, vertices); - matrices.pop(); - } catch (ExecutionException e) { } + } + if (!inRange) { + buffer = PortalFrameBuffer.unpool(caster.asEntity().getUuid()); + if (buffer != null) { + buffer.build(spell, caster, new EntityReference.EntityValues<>(caster.asEntity())); + } + } + matrices.pop(); }); - } - static class PortalFrameBuffer implements AutoCloseable { - @Nullable - private SimpleFramebuffer framebuffer; - @Nullable - private SimpleFramebuffer backgroundBuffer; - private boolean closed; - - private final MinecraftClient client = MinecraftClient.getInstance(); - - private boolean pendingDraw; - - private static int recursionCount; - - public void draw(MatrixStack matrices, VertexConsumerProvider vertices) { - Vec3d skyColor = client.world.getSkyColor(client.gameRenderer.getCamera().getPos(), client.getTickDelta()); - BackgroundRenderer.setFogBlack(); - SphereModel.DISK.render(matrices, vertices.getBuffer(RenderLayers.getMagicShield()), 0, 0, 2, (float)skyColor.x, (float)skyColor.y, (float)skyColor.z, 1); - matrices.translate(0, -0.001, 0); - - if (!(closed || framebuffer == null)) { - RenderSystem.assertOnRenderThread(); - GlStateManager._colorMask(true, true, true, false); - GlStateManager._enableDepthTest(); - GlStateManager._disableCull(); - Tessellator tessellator = RenderSystem.renderThreadTesselator(); - BufferBuilder buffer = tessellator.getBuffer(); - float uScale = (float)framebuffer.viewportWidth / (float)framebuffer.textureWidth; - float vScale = (float)framebuffer.viewportHeight / (float)framebuffer.textureHeight; - RenderSystem.setShader(GameRenderer::getPositionTexColorProgram); - RenderSystem._setShaderTexture(0, framebuffer.getColorAttachment()); - buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR); - TexturedSphereModel.DISK.render(matrices, buffer, 2F, 1, 1, 1, 1, uScale, vScale); - tessellator.draw(); - - client.getTextureManager().bindTexture(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE); - GlStateManager._enableCull(); - GlStateManager._colorMask(true, true, true, true); - GlStateManager._depthMask(true); - } - } - - public void build(PortalSpell spell, Caster caster, EntityReference.EntityValues target) { - - if (System.currentTimeMillis() % 100 < 50) { - return; - } - - if (pendingDraw && recursionCount > 0) { - innerBuild(spell, caster, target); - return; - } - - if (pendingDraw) { - return; - } - pendingDraw = true; - if (recursionCount > 0) { - innerBuild(spell, caster, target); - } else { - ((MixinMinecraftClient)client).getRenderTaskQueue().add(() -> innerBuild(spell, caster, target)); - } - } - - private void innerBuild(PortalSpell spell, Caster caster, EntityReference.EntityValues target) { - synchronized (client) { - pendingDraw = false; - - if (recursionCount > 2) { - return; - } - recursionCount++; - - try { - if (closed || client.interactionManager == null) { - close(); - return; - } - - var fov = client.options.getFov(); - int originalFov = fov.getValue(); - fov.setValue(110); - - Vec3d offset = new Vec3d(0, 1.8, 0); - float yaw = spell.getYawDifference(); - - offset = offset.rotateY(yaw * MathHelper.RADIANS_PER_DEGREE); - - Entity cameraEntity = UEntities.CAST_SPELL.create(caster.asWorld()); - cameraEntity.setPosition(target.pos().add(offset)); - cameraEntity.setPitch(spell.getTargetPitch()); - cameraEntity.setYaw(spell.getTargetYaw() + 180); - - drawWorld(cameraEntity, 400, 400); - - fov.setValue(originalFov); - } finally { - recursionCount--; - } - } - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private void drawWorld(Entity cameraEntity, int width, int height) { - Entity oldCameraEntity = client.cameraEntity; - client.cameraEntity = cameraEntity; - - Window window = client.getWindow(); - - Perspective perspective = client.options.getPerspective(); - client.options.setPerspective(Perspective.FIRST_PERSON); - - int i = window.getFramebufferWidth(); - int j = window.getFramebufferHeight(); - - width = i; - height = j; - - client.getFramebuffer().endWrite(); - - if (framebuffer == null) { - framebuffer = new SimpleFramebuffer(width, height, true, MinecraftClient.IS_SYSTEM_MAC); - framebuffer.setClearColor(0, 0, 0, 0); - framebuffer.clear(MinecraftClient.IS_SYSTEM_MAC); - } - - window.setFramebufferWidth(width); - window.setFramebufferHeight(height); - - MatrixStack view = RenderSystem.getModelViewStack(); - view.push(); - view.loadIdentity(); - RenderSystem.applyModelViewMatrix(); - Matrix4f proj = RenderSystem.getProjectionMatrix(); - Matrix3f invView = RenderSystem.getInverseViewRotationMatrix(); - - int fbo = client.getFramebuffer().fbo; - client.getFramebuffer().fbo = framebuffer.fbo; - - RenderSystem.clear(GlConst.GL_DEPTH_BUFFER_BIT | GlConst.GL_COLOR_BUFFER_BIT, MinecraftClient.IS_SYSTEM_MAC); - framebuffer.beginWrite(true); - BackgroundRenderer.clearFog(); - RenderSystem.enableCull(); - - Camera camera = client.gameRenderer.getCamera(); - - ObjectArrayList chunkInfos = ((WorldRendererDuck)client.worldRenderer).unicopia_getChunkInfos(); - List backup = new ArrayList<>(chunkInfos); - - client.gameRenderer.setRenderHand(false); - MatrixStack matrices = new MatrixStack(); - - matrices.scale((float)width / height, 1, 1); - - client.gameRenderer.renderWorld(1, 0, matrices); - if (recursionCount <= 1) { - client.gameRenderer.setRenderHand(true); - } - framebuffer.endWrite(); - - client.getFramebuffer().fbo = fbo; - client.getFramebuffer().beginWrite(true); - - chunkInfos.clear(); - chunkInfos.addAll((List)backup); - - view.pop(); - RenderSystem.applyModelViewMatrix(); - - window.setFramebufferWidth(i); - window.setFramebufferHeight(j); - - client.options.setPerspective(perspective); - client.cameraEntity = oldCameraEntity; - - RenderSystem.setProjectionMatrix(proj, VertexSorter.BY_Z); - RenderSystem.setInverseViewRotationMatrix(invView); - - if (recursionCount <= 1) { - camera.update(client.world, - client.getCameraEntity() == null ? client.player : client.getCameraEntity(), - perspective.isFirstPerson(), - perspective.isFrontView(), - 1 - ); - } - } - - @Override - public void close() { - closed = true; - if (framebuffer != null) { - SimpleFramebuffer fb = framebuffer; - framebuffer = null; - fb.delete(); - } - if (backgroundBuffer != null) { - SimpleFramebuffer fb = backgroundBuffer; - backgroundBuffer = null; - fb.delete(); - } - } + matrices.pop(); } public interface WorldRendererDuck { ObjectArrayList unicopia_getChunkInfos(); + + Frustum unicopia_getFrustum(); } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinMinecraftClient.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinMinecraftClient.java index f210faea..848ef7d0 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinMinecraftClient.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinMinecraftClient.java @@ -3,12 +3,18 @@ package com.minelittlepony.unicopia.mixin.client; import java.util.Queue; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.gen.Accessor; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.WorldRenderer; @Mixin(MinecraftClient.class) public interface MixinMinecraftClient { @Accessor("renderTaskQueue") Queue getRenderTaskQueue(); + + @Mutable + @Accessor("worldRenderer") + void setWorldRenderer(WorldRenderer worldRenderer); }