From 5bc7bd7c71361715ea50277f1ac8783f5fdfaa03 Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Wed, 1 May 2024 01:15:15 +0200
Subject: [PATCH 01/17] - allow reversed hands in seated. - fix spyglass
 rotation on use in standing - allow double spyglass in seated

---
 .../client/gui/settings/GuiSeatedOptions.java |  2 +-
 .../client_vr/provider/nullvr/NullVR.java     |  4 +--
 .../render/VivecraftItemRendering.java        |  2 +-
 .../render/helpers/RenderHelper.java          | 28 ++++++++++---------
 4 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiSeatedOptions.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiSeatedOptions.java
index cd1fcc38c..822afbf01 100644
--- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiSeatedOptions.java
+++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiSeatedOptions.java
@@ -14,7 +14,7 @@ public class GuiSeatedOptions extends GuiVROptionsBase {
         new VROptionEntry(VRSettings.VrOptions.WALK_UP_BLOCKS),
         new VROptionEntry(VRSettings.VrOptions.WORLD_ROTATION_INCREMENT),
         new VROptionEntry(VRSettings.VrOptions.VEHICLE_ROTATION),
-        new VROptionEntry(VRSettings.VrOptions.DUMMY),
+        new VROptionEntry(VRSettings.VrOptions.REVERSE_HANDS),
         new VROptionEntry(VRSettings.VrOptions.SEATED_FREE_MOVE, true),
         new VROptionEntry(VRSettings.VrOptions.RIGHT_CLICK_DELAY, false),
         new VROptionEntry("vivecraft.options.screen.teleport.button", (button, mousePos) -> {
diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVR.java
index 34f57959f..09ff0186b 100644
--- a/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVR.java
+++ b/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVR.java
@@ -95,11 +95,11 @@ public void poll(long frameIndex) {
 
             this.updateAim();
 
-            this.controllerPose[0].M[0][3] = 0.3F;
+            this.controllerPose[0].M[0][3] = this.dh.vrSettings.reverseHands ? -0.3F : 0.3F;
             this.controllerPose[0].M[1][3] = 1.2F;
             this.controllerPose[0].M[2][3] = -0.5F;
 
-            this.controllerPose[1].M[0][3] = -0.3F;
+            this.controllerPose[1].M[0][3] =  this.dh.vrSettings.reverseHands ? 0.3F : -0.3F;
             this.controllerPose[1].M[1][3] = 1.2F;
             this.controllerPose[1].M[2][3] = -0.5F;
 
diff --git a/common/src/main/java/org/vivecraft/client_vr/render/VivecraftItemRendering.java b/common/src/main/java/org/vivecraft/client_vr/render/VivecraftItemRendering.java
index 41a44e037..ed01b175f 100644
--- a/common/src/main/java/org/vivecraft/client_vr/render/VivecraftItemRendering.java
+++ b/common/src/main/java/org/vivecraft/client_vr/render/VivecraftItemRendering.java
@@ -233,7 +233,7 @@ public static void applyFirstPersonItemTransforms(PoseStack pMatrixStack, Vivecr
                 rotation.mul(Axis.XP.rotationDegrees(-45.0F));
                 rotation.mul(Axis.XP.rotationDegrees((float) gunAngle));
             } else if (rendertype == VivecraftItemTransformType.Shield) {
-                boolean reverse = dh.vrSettings.reverseHands && !dh.vrSettings.seated;
+                boolean reverse = dh.vrSettings.reverseHands;
                 if (reverse) {
                     k *= -1;
                 }
diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/RenderHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/RenderHelper.java
index dfc45a291..93ca613f9 100644
--- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/RenderHelper.java
+++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/RenderHelper.java
@@ -83,23 +83,25 @@ public static Vec3 getControllerRenderPos(int c) {
             return dataHolder.vrPlayer.vrdata_world_render.getController(c).getPosition();
         } else {
             Vec3 out = null;
+            int mainHand = InteractionHand.MAIN_HAND.ordinal();
+            if (dataHolder.vrSettings.reverseHands) {
+                c = 1 - c;
+                mainHand = InteractionHand.OFF_HAND.ordinal();
+            }
 
             if (mc.getCameraEntity() != null && mc.level != null) {
                 Vec3 dir = dataHolder.vrPlayer.vrdata_world_render.hmd.getDirection();
                 dir = dir.yRot((float) Math.toRadians(c == 0 ? -35.0D : 35.0D));
                 dir = new Vec3(dir.x, 0.0D, dir.z);
                 dir = dir.normalize();
-                if (TelescopeTracker.isTelescope(mc.player.getUseItem())) {
-                    if (c == 0 && mc.player.getUsedItemHand() == InteractionHand.MAIN_HAND) {
-                        out = dataHolder.vrPlayer.vrdata_world_render.eye0.getPosition()
-                            .add(dataHolder.vrPlayer.vrdata_world_render.hmd.getDirection()
-                                .scale(0.2 * dataHolder.vrPlayer.vrdata_world_render.worldScale));
-                    }
-                    if (c == 1 && mc.player.getUsedItemHand() == InteractionHand.OFF_HAND) {
-                        out = dataHolder.vrPlayer.vrdata_world_render.eye1.getPosition()
-                            .add(dataHolder.vrPlayer.vrdata_world_render.hmd.getDirection()
-                                .scale(0.2 * dataHolder.vrPlayer.vrdata_world_render.worldScale));
-                    }
+                if (TelescopeTracker.isTelescope(mc.player.getUseItem()) && TelescopeTracker.isTelescope(c == mainHand ? mc.player.getMainHandItem() : mc.player.getOffhandItem())) {
+                    // move the controller in front of the eye when using the spyglass
+                    VRData.VRDevicePose eye = c == 0 ? dataHolder.vrPlayer.vrdata_world_render.eye0 :
+                                              dataHolder.vrPlayer.vrdata_world_render.eye1;
+
+                    out = eye.getPosition()
+                        .add(dataHolder.vrPlayer.vrdata_world_render.hmd.getDirection()
+                            .scale(0.2 * dataHolder.vrPlayer.vrdata_world_render.worldScale));
                 }
                 if (out == null) {
                     out = dataHolder.vrPlayer.vrdata_world_render.getEye(RenderPass.CENTER).getPosition().add(
@@ -125,11 +127,11 @@ public static void setupRenderingAtController(int controller, PoseStack matrix)
             getSmoothCameraPosition(dataHolder.currentPass, dataHolder.vrPlayer.getVRDataWorld()));
         matrix.translate(aimSource.x, aimSource.y, aimSource.z);
         float sc = dataHolder.vrPlayer.vrdata_world_render.worldScale;
-        if (mc.level != null && TelescopeTracker.isTelescope(mc.player.getUseItem())) {
+        if (dataHolder.vrSettings.seated && mc.level != null && TelescopeTracker.isTelescope(mc.player.getUseItem()) && TelescopeTracker.isTelescope(controller == 0 ? mc.player.getMainHandItem() : mc.player.getOffhandItem())) {
             matrix.mulPoseMatrix(dataHolder.vrPlayer.vrdata_world_render.hmd.getMatrix().inverted()
                 .transposed().toMCMatrix());
             MethodHolder.rotateDegXp(matrix, 90);
-            matrix.translate(controller == 0 ? 0.075 * sc : -0.075 * sc, -0.025 * sc, 0.0325 * sc);
+            matrix.translate(controller == (dataHolder.vrSettings.reverseHands ? 1 : 0) ? 0.075 * sc : -0.075 * sc, -0.025 * sc, 0.0325 * sc);
         } else {
             matrix.mulPoseMatrix(dataHolder.vrPlayer.vrdata_world_render.getController(controller)
                 .getMatrix().inverted().transposed().toMCMatrix());

From 97d16d9a05075e8a1a7068be6d8637058778b9bc Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Wed, 1 May 2024 02:10:12 +0200
Subject: [PATCH 02/17] reset projection when rendering screens, since some
 mods mess with that

---
 .../vivecraft/client_vr/render/helpers/RenderHelper.java    | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/RenderHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/RenderHelper.java
index 93ca613f9..ec9780d73 100644
--- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/RenderHelper.java
+++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/RenderHelper.java
@@ -231,6 +231,12 @@ public static void drawScreen(float f, Screen screen, GuiGraphics guiGraphics) {
         posestack.translate(0.0D, 0.0D, -11000.0D);
         RenderSystem.applyModelViewMatrix();
 
+        Matrix4f guiProjection = (new Matrix4f()).setOrtho(
+            0.0F, (float) (mc.getWindow().getWidth() / mc.getWindow().getGuiScale()),
+                (float) (mc.getWindow().getHeight() / mc.getWindow().getGuiScale()), 0.0F,
+                1000.0F, 21000.0F);
+        RenderSystem.setProjectionMatrix(guiProjection, VertexSorting.ORTHOGRAPHIC_Z);
+
         RenderSystem.blendFuncSeparate(
             GlStateManager.SourceFactor.SRC_ALPHA,
             GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA,

From 93b489e504e3a16686ecfa96cacf9f092e36dcc4 Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Wed, 1 May 2024 03:04:31 +0200
Subject: [PATCH 03/17] fix some mod overlays being missing on forge/neoforge,
 fixes jade

---
 .../extensions/MinecraftExtension.java        |   1 +
 .../render/helpers/VRPassHelper.java          | 142 +++++++++++++++++
 .../mixin/client_vr/MinecraftVRMixin.java     | 143 +-----------------
 .../fabric/mixin/FabricMinecraftVRMixin.java  |  34 +++++
 .../resources/vivecraft.fabric.mixins.json    |   1 +
 .../forge/mixin/ForgeMinecraftVRMixin.java    |  34 +++++
 .../resources/vivecraft.forge.mixins.json     |   7 +-
 .../mixin/NeoForgeMinecraftVRMixin.java       |  34 +++++
 .../resources/vivecraft.neoforge.mixins.json  |   7 +-
 9 files changed, 260 insertions(+), 143 deletions(-)
 create mode 100644 fabric/src/main/java/org/vivecraft/fabric/mixin/FabricMinecraftVRMixin.java
 create mode 100644 forge/src/main/java/org/vivecraft/forge/mixin/ForgeMinecraftVRMixin.java
 create mode 100644 neoforge/src/main/java/org/vivecraft/neoforge/mixin/NeoForgeMinecraftVRMixin.java

diff --git a/common/src/main/java/org/vivecraft/client_vr/extensions/MinecraftExtension.java b/common/src/main/java/org/vivecraft/client_vr/extensions/MinecraftExtension.java
index 975250b11..6f0d36c6b 100644
--- a/common/src/main/java/org/vivecraft/client_vr/extensions/MinecraftExtension.java
+++ b/common/src/main/java/org/vivecraft/client_vr/extensions/MinecraftExtension.java
@@ -3,4 +3,5 @@
 public interface MinecraftExtension {
 
     void vivecraft$notifyMirror(String buttonDisplayString, boolean b, int i);
+    void vivecraft$drawProfiler();
 }
diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/VRPassHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/VRPassHelper.java
index 7465654ca..5bb494aee 100644
--- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/VRPassHelper.java
+++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/VRPassHelper.java
@@ -4,22 +4,34 @@
 import com.mojang.blaze3d.platform.GlStateManager;
 import com.mojang.blaze3d.shaders.ProgramManager;
 import com.mojang.blaze3d.systems.RenderSystem;
+import com.mojang.blaze3d.vertex.PoseStack;
 import net.minecraft.Util;
 import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiGraphics;
 import net.minecraft.util.Mth;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.level.block.Blocks;
 import org.lwjgl.opengl.GL13C;
 import org.vivecraft.client.Xplat;
 import org.vivecraft.client.extensions.RenderTargetExtension;
+import org.vivecraft.client.utils.Utils;
 import org.vivecraft.client_vr.ClientDataHolderVR;
 import org.vivecraft.client_vr.extensions.GameRendererExtension;
+import org.vivecraft.client_vr.extensions.GuiExtension;
+import org.vivecraft.client_vr.extensions.MinecraftExtension;
+import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler;
+import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler;
+import org.vivecraft.client_vr.render.RenderConfigException;
 import org.vivecraft.client_vr.render.RenderPass;
 import org.vivecraft.client_vr.render.VRShaders;
 import org.vivecraft.client_vr.settings.VRSettings;
+import org.vivecraft.client_xr.render_pass.RenderPassManager;
+import org.vivecraft.client_xr.render_pass.WorldRenderPass;
 import org.vivecraft.mod_compat_vr.iris.IrisHelper;
 import org.vivecraft.mod_compat_vr.optifine.OptifineHelper;
 
+import java.util.List;
+
 public class VRPassHelper {
 
     private static final Minecraft mc = Minecraft.getInstance();
@@ -217,6 +229,136 @@ public static void renderSingleView(RenderPass eye, float partialTicks, long nan
         }
     }
 
+    public static void renderAndSubmit(boolean renderLevel, long nanoTime, float actualPartialTicks) {
+        // still rendering
+        mc.getProfiler().push("gameRenderer");
+
+        mc.getProfiler().push("VR guis");
+
+        // some mods mess with the depth mask?
+        RenderSystem.depthMask(true);
+
+        mc.getProfiler().push("gui cursor");
+        // draw cursor on Gui Layer
+        if (mc.screen != null || !mc.mouseHandler.isMouseGrabbed()) {
+            PoseStack poseStack = RenderSystem.getModelViewStack();
+            poseStack.pushPose();
+            poseStack.setIdentity();
+            poseStack.translate(0.0f, 0.0f, -11000.0f);
+            RenderSystem.applyModelViewMatrix();
+
+            int x = (int) (Minecraft.getInstance().mouseHandler.xpos() * (double) Minecraft.getInstance().getWindow().getGuiScaledWidth() / (double) Minecraft.getInstance().getWindow().getScreenWidth());
+            int y = (int) (Minecraft.getInstance().mouseHandler.ypos() * (double) Minecraft.getInstance().getWindow().getGuiScaledHeight() / (double) Minecraft.getInstance().getWindow().getScreenHeight());
+            ((GuiExtension) mc.gui).vivecraft$drawMouseMenuQuad(x, y);
+
+            poseStack.popPose();
+            RenderSystem.applyModelViewMatrix();
+        }
+
+        mc.getProfiler().popPush("fps pie");
+        // draw debug pie
+        ((MinecraftExtension) mc).vivecraft$drawProfiler();
+
+        // pop pose that we pushed before the gui
+        RenderSystem.getModelViewStack().popPose();
+        RenderSystem.applyModelViewMatrix();
+
+        // generate mipmaps
+        // TODO: does this do anything?
+        mc.mainRenderTarget.bindRead();
+        ((RenderTargetExtension) mc.mainRenderTarget).vivecraft$genMipMaps();
+        mc.mainRenderTarget.unbindRead();
+
+        mc.getProfiler().popPush("2D Keyboard");
+        GuiGraphics guiGraphics = new GuiGraphics(mc, mc.renderBuffers().bufferSource());
+        if (KeyboardHandler.Showing && !dataHolder.vrSettings.physicalKeyboard) {
+            mc.mainRenderTarget = KeyboardHandler.Framebuffer;
+            mc.mainRenderTarget.clear(Minecraft.ON_OSX);
+            mc.mainRenderTarget.bindWrite(true);
+            RenderHelper.drawScreen(actualPartialTicks, KeyboardHandler.UI, guiGraphics);
+            guiGraphics.flush();
+        }
+
+        mc.getProfiler().popPush("Radial Menu");
+        if (RadialHandler.isShowing()) {
+            mc.mainRenderTarget = RadialHandler.Framebuffer;
+            mc.mainRenderTarget.clear(Minecraft.ON_OSX);
+            mc.mainRenderTarget.bindWrite(true);
+            RenderHelper.drawScreen(actualPartialTicks, RadialHandler.UI, guiGraphics);
+            guiGraphics.flush();
+        }
+        mc.getProfiler().pop();
+        checkGLError("post 2d ");
+
+        // done with guis
+        mc.getProfiler().pop();
+
+        // render the different vr passes
+        List<RenderPass> list = dataHolder.vrRenderer.getRenderPasses();
+        dataHolder.isFirstPass = true;
+        for (RenderPass renderpass : list) {
+            dataHolder.currentPass = renderpass;
+
+            switch (renderpass) {
+                case LEFT, RIGHT -> RenderPassManager.setWorldRenderPass(WorldRenderPass.stereoXR);
+                case CENTER -> RenderPassManager.setWorldRenderPass(WorldRenderPass.center);
+                case THIRD -> RenderPassManager.setWorldRenderPass(WorldRenderPass.mixedReality);
+                case SCOPEL -> RenderPassManager.setWorldRenderPass(WorldRenderPass.leftTelescope);
+                case SCOPER -> RenderPassManager.setWorldRenderPass(WorldRenderPass.rightTelescope);
+                case CAMERA -> RenderPassManager.setWorldRenderPass(WorldRenderPass.camera);
+            }
+
+            mc.getProfiler().push("Eye:" + dataHolder.currentPass);
+            mc.getProfiler().push("setup");
+            mc.mainRenderTarget.bindWrite(true);
+            mc.getProfiler().pop();
+            VRPassHelper.renderSingleView(renderpass, actualPartialTicks, nanoTime, renderLevel);
+            mc.getProfiler().pop();
+
+            if (dataHolder.grabScreenShot) {
+                boolean flag;
+
+                if (list.contains(RenderPass.CAMERA)) {
+                    flag = renderpass == RenderPass.CAMERA;
+                } else if (list.contains(RenderPass.CENTER)) {
+                    flag = renderpass == RenderPass.CENTER;
+                } else {
+                    flag = dataHolder.vrSettings.displayMirrorLeftEye ?
+                           renderpass == RenderPass.LEFT :
+                           renderpass == RenderPass.RIGHT;
+                }
+
+                if (flag) {
+                    RenderTarget rendertarget = mc.mainRenderTarget;
+
+                    if (renderpass == RenderPass.CAMERA) {
+                        rendertarget = dataHolder.vrRenderer.cameraFramebuffer;
+                    }
+
+                    mc.mainRenderTarget.unbindWrite();
+                    Utils.takeScreenshot(rendertarget);
+                    mc.getWindow().updateDisplay();
+                    dataHolder.grabScreenShot = false;
+                }
+            }
+
+            dataHolder.isFirstPass = false;
+        }
+        // now we are done with rendering
+        mc.getProfiler().pop();
+
+        dataHolder.vrPlayer.postRender(actualPartialTicks);
+        mc.getProfiler().push("Display/Reproject");
+
+        try {
+            dataHolder.vrRenderer.endFrame();
+        } catch (RenderConfigException exception) {
+            VRSettings.logger.error(exception.toString());
+        }
+        mc.getProfiler().pop();
+        checkGLError("post submit ");
+    }
+
     private static void checkGLError(String string) {
         int i = GlStateManager._getError();
         if (i != 0) {
diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/MinecraftVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/MinecraftVRMixin.java
index f7460f703..9ed574298 100644
--- a/common/src/main/java/org/vivecraft/mixin/client_vr/MinecraftVRMixin.java
+++ b/common/src/main/java/org/vivecraft/mixin/client_vr/MinecraftVRMixin.java
@@ -48,7 +48,6 @@
 import org.spongepowered.asm.mixin.injection.*;
 import org.spongepowered.asm.mixin.injection.At.Shift;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
 import org.vivecraft.client.VRPlayersClient;
 import org.vivecraft.client.VivecraftVRMod;
 import org.vivecraft.client.extensions.RenderTargetExtension;
@@ -63,8 +62,6 @@
 import org.vivecraft.client_vr.VRState;
 import org.vivecraft.client_vr.extensions.*;
 import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler;
-import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler;
-import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler;
 import org.vivecraft.client_vr.gameplay.trackers.TelescopeTracker;
 import org.vivecraft.client_vr.menuworlds.MenuWorldDownloader;
 import org.vivecraft.client_vr.menuworlds.MenuWorldExporter;
@@ -73,12 +70,9 @@
 import org.vivecraft.client_vr.render.RenderPass;
 import org.vivecraft.client_vr.render.VRFirstPersonArmSwing;
 import org.vivecraft.client_vr.render.VRShaders;
-import org.vivecraft.client_vr.render.helpers.RenderHelper;
-import org.vivecraft.client_vr.render.helpers.VRPassHelper;
 import org.vivecraft.client_vr.settings.VRHotkeys;
 import org.vivecraft.client_vr.settings.VRSettings;
 import org.vivecraft.client_xr.render_pass.RenderPassManager;
-import org.vivecraft.client_xr.render_pass.WorldRenderPass;
 import org.vivecraft.common.utils.math.Vector3;
 import org.vivecraft.mod_compat_vr.optifine.OptifineHelper;
 
@@ -392,140 +386,6 @@ public abstract class MinecraftVRMixin implements MinecraftExtension {
         }
     }
 
-    @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;pop()V", ordinal = 4, shift = At.Shift.AFTER), method = "runTick", locals = LocalCapture.CAPTURE_FAILHARD)
-    public void vivecraft$renderVRPasses(boolean renderLevel, CallbackInfo ci, long nanoTime) {
-        if (VRState.vrRunning) {
-            // still rendering
-            this.profiler.push("gameRenderer");
-
-            this.profiler.push("VR guis");
-
-            // some mods mess with the depth mask?
-            RenderSystem.depthMask(true);
-
-            this.profiler.push("gui cursor");
-            // draw cursor on Gui Layer
-            if (this.screen != null || !mouseHandler.isMouseGrabbed()) {
-                PoseStack poseStack = RenderSystem.getModelViewStack();
-                poseStack.pushPose();
-                poseStack.setIdentity();
-                poseStack.translate(0.0f, 0.0f, -11000.0f);
-                RenderSystem.applyModelViewMatrix();
-
-                int x = (int) (Minecraft.getInstance().mouseHandler.xpos() * (double) Minecraft.getInstance().getWindow().getGuiScaledWidth() / (double) Minecraft.getInstance().getWindow().getScreenWidth());
-                int y = (int) (Minecraft.getInstance().mouseHandler.ypos() * (double) Minecraft.getInstance().getWindow().getGuiScaledHeight() / (double) Minecraft.getInstance().getWindow().getScreenHeight());
-                ((GuiExtension) this.gui).vivecraft$drawMouseMenuQuad(x, y);
-
-                poseStack.popPose();
-                RenderSystem.applyModelViewMatrix();
-            }
-
-            this.profiler.popPush("fps pie");
-            // draw debug pie
-            vivecraft$drawProfiler();
-
-            // pop pose that we pushed before the gui
-            RenderSystem.getModelViewStack().popPose();
-            RenderSystem.applyModelViewMatrix();
-
-            // generate mipmaps
-            // TODO: does this do anything?
-            mainRenderTarget.bindRead();
-            ((RenderTargetExtension) mainRenderTarget).vivecraft$genMipMaps();
-            mainRenderTarget.unbindRead();
-
-            this.profiler.popPush("2D Keyboard");
-            float actualPartialTicks = this.pause ? this.pausePartialTick : this.timer.partialTick;
-            GuiGraphics guiGraphics = new GuiGraphics((Minecraft) (Object) this, renderBuffers.bufferSource());
-            if (KeyboardHandler.Showing
-                && !ClientDataHolderVR.getInstance().vrSettings.physicalKeyboard) {
-                this.mainRenderTarget = KeyboardHandler.Framebuffer;
-                this.mainRenderTarget.clear(Minecraft.ON_OSX);
-                this.mainRenderTarget.bindWrite(true);
-                RenderHelper.drawScreen(actualPartialTicks, KeyboardHandler.UI, guiGraphics);
-                guiGraphics.flush();
-            }
-
-            this.profiler.popPush("Radial Menu");
-            if (RadialHandler.isShowing()) {
-                this.mainRenderTarget = RadialHandler.Framebuffer;
-                this.mainRenderTarget.clear(Minecraft.ON_OSX);
-                this.mainRenderTarget.bindWrite(true);
-                RenderHelper.drawScreen(actualPartialTicks, RadialHandler.UI, guiGraphics);
-                guiGraphics.flush();
-            }
-            this.profiler.pop();
-            this.vivecraft$checkGLError("post 2d ");
-
-            // done with guis
-            this.profiler.pop();
-
-            // render the different vr passes
-            List<RenderPass> list = ClientDataHolderVR.getInstance().vrRenderer.getRenderPasses();
-            ClientDataHolderVR.getInstance().isFirstPass = true;
-            for (RenderPass renderpass : list) {
-                ClientDataHolderVR.getInstance().currentPass = renderpass;
-
-                switch (renderpass) {
-                    case LEFT, RIGHT -> RenderPassManager.setWorldRenderPass(WorldRenderPass.stereoXR);
-                    case CENTER -> RenderPassManager.setWorldRenderPass(WorldRenderPass.center);
-                    case THIRD -> RenderPassManager.setWorldRenderPass(WorldRenderPass.mixedReality);
-                    case SCOPEL -> RenderPassManager.setWorldRenderPass(WorldRenderPass.leftTelescope);
-                    case SCOPER -> RenderPassManager.setWorldRenderPass(WorldRenderPass.rightTelescope);
-                    case CAMERA -> RenderPassManager.setWorldRenderPass(WorldRenderPass.camera);
-                }
-
-                this.profiler.push("Eye:" + ClientDataHolderVR.getInstance().currentPass);
-                this.profiler.push("setup");
-                this.mainRenderTarget.bindWrite(true);
-                this.profiler.pop();
-                VRPassHelper.renderSingleView(renderpass, actualPartialTicks, nanoTime, renderLevel);
-                this.profiler.pop();
-
-                if (ClientDataHolderVR.getInstance().grabScreenShot) {
-                    boolean flag;
-
-                    if (list.contains(RenderPass.CAMERA)) {
-                        flag = renderpass == RenderPass.CAMERA;
-                    } else if (list.contains(RenderPass.CENTER)) {
-                        flag = renderpass == RenderPass.CENTER;
-                    } else {
-                        flag = ClientDataHolderVR.getInstance().vrSettings.displayMirrorLeftEye ? renderpass == RenderPass.LEFT
-                                                                                                : renderpass == RenderPass.RIGHT;
-                    }
-
-                    if (flag) {
-                        RenderTarget rendertarget = this.mainRenderTarget;
-
-                        if (renderpass == RenderPass.CAMERA) {
-                            rendertarget = ClientDataHolderVR.getInstance().vrRenderer.cameraFramebuffer;
-                        }
-
-                        this.mainRenderTarget.unbindWrite();
-                        Utils.takeScreenshot(rendertarget);
-                        this.window.updateDisplay();
-                        ClientDataHolderVR.getInstance().grabScreenShot = false;
-                    }
-                }
-
-                ClientDataHolderVR.getInstance().isFirstPass = false;
-            }
-            // now we are done with rendering
-            this.profiler.pop();
-
-            ClientDataHolderVR.getInstance().vrPlayer.postRender(actualPartialTicks);
-            this.profiler.push("Display/Reproject");
-
-            try {
-                ClientDataHolderVR.getInstance().vrRenderer.endFrame();
-            } catch (RenderConfigException exception) {
-                VRSettings.logger.error(exception.toString());
-            }
-            this.profiler.pop();
-            this.vivecraft$checkGLError("post submit ");
-        }
-    }
-
     @Redirect(at = @At(value = "FIELD", target = "Lnet/minecraft/client/Minecraft;fpsPieResults:Lnet/minecraft/util/profiling/ProfileResults;"), method = "runTick")
     public ProfileResults vivecraft$cancelRegularFpsPie(Minecraft instance) {
         return VRState.vrRunning ? null : fpsPieResults;
@@ -968,7 +828,8 @@ public abstract class MinecraftVRMixin implements MinecraftExtension {
     }
 
     @Unique
-    private void vivecraft$drawProfiler() {
+    @Override
+    public void vivecraft$drawProfiler() {
         if (this.fpsPieResults != null) {
             this.profiler.push("fpsPie");
             GuiGraphics guiGraphics = new GuiGraphics((Minecraft) (Object) this, renderBuffers.bufferSource());
diff --git a/fabric/src/main/java/org/vivecraft/fabric/mixin/FabricMinecraftVRMixin.java b/fabric/src/main/java/org/vivecraft/fabric/mixin/FabricMinecraftVRMixin.java
new file mode 100644
index 000000000..f02ac8439
--- /dev/null
+++ b/fabric/src/main/java/org/vivecraft/fabric/mixin/FabricMinecraftVRMixin.java
@@ -0,0 +1,34 @@
+package org.vivecraft.fabric.mixin;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.Timer;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+import org.vivecraft.client_vr.VRState;
+import org.vivecraft.client_vr.render.helpers.VRPassHelper;
+
+@Mixin(Minecraft.class)
+public class FabricMinecraftVRMixin {
+
+    @Shadow
+    @Final
+    private Timer timer;
+
+    @Shadow
+    private volatile boolean pause;
+
+    @Shadow
+    private float pausePartialTick;
+
+    @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;pop()V", ordinal = 4, shift = At.Shift.AFTER), method = "runTick", locals = LocalCapture.CAPTURE_FAILHARD)
+    public void vivecraft$renderVRPassesFabric(boolean renderLevel, CallbackInfo ci, long nanoTime) {
+        if (VRState.vrRunning) {
+            VRPassHelper.renderAndSubmit(renderLevel, nanoTime, this.pause ? this.pausePartialTick : this.timer.partialTick);
+        }
+    }
+}
diff --git a/fabric/src/main/resources/vivecraft.fabric.mixins.json b/fabric/src/main/resources/vivecraft.fabric.mixins.json
index edc2e79ea..2fa46d534 100644
--- a/fabric/src/main/resources/vivecraft.fabric.mixins.json
+++ b/fabric/src/main/resources/vivecraft.fabric.mixins.json
@@ -5,6 +5,7 @@
   "compatibilityLevel": "JAVA_17",
   "client": [
     "FabricGameRendererVRMixin",
+    "FabricMinecraftVRMixin",
     "client.resources.model.FabricModelBakeryMixin",
     "screenhandler.client.FabricClientNetworkingVRMixin",
     "world.level.biome.BiomeAccessor"
diff --git a/forge/src/main/java/org/vivecraft/forge/mixin/ForgeMinecraftVRMixin.java b/forge/src/main/java/org/vivecraft/forge/mixin/ForgeMinecraftVRMixin.java
new file mode 100644
index 000000000..40bf15930
--- /dev/null
+++ b/forge/src/main/java/org/vivecraft/forge/mixin/ForgeMinecraftVRMixin.java
@@ -0,0 +1,34 @@
+package org.vivecraft.forge.mixin;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.Timer;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+import org.vivecraft.client_vr.VRState;
+import org.vivecraft.client_vr.render.helpers.VRPassHelper;
+
+@Mixin(Minecraft.class)
+public class ForgeMinecraftVRMixin {
+
+    @Shadow
+    @Final
+    private Timer timer;
+
+    @Shadow
+    private volatile boolean pause;
+
+    @Shadow
+    private float pausePartialTick;
+
+    @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraftforge/event/ForgeEventFactory;onRenderTickEnd(F)V", shift = At.Shift.AFTER), method = "runTick", locals = LocalCapture.CAPTURE_FAILHARD)
+    public void vivecraft$renderVRPassesForge(boolean renderLevel, CallbackInfo ci, long nanoTime) {
+        if (VRState.vrRunning) {
+            VRPassHelper.renderAndSubmit(renderLevel, nanoTime, this.pause ? this.pausePartialTick : this.timer.partialTick);
+        }
+    }
+}
diff --git a/forge/src/main/resources/vivecraft.forge.mixins.json b/forge/src/main/resources/vivecraft.forge.mixins.json
index 4f0872ea4..4efe9b33e 100644
--- a/forge/src/main/resources/vivecraft.forge.mixins.json
+++ b/forge/src/main/resources/vivecraft.forge.mixins.json
@@ -3,6 +3,11 @@
   "package": "org.vivecraft.forge.mixin",
   "plugin": "org.vivecraft.MixinConfig",
   "compatibilityLevel": "JAVA_17",
-  "client": ["ForgeGameRendererVRMixin", "ForgeIngameGuiVRMixin", "network.ForgeOpenContainerVRMixin"],
+  "client": [
+    "ForgeGameRendererVRMixin",
+    "ForgeIngameGuiVRMixin",
+    "ForgeMinecraftVRMixin",
+    "network.ForgeOpenContainerVRMixin"
+  ],
   "minVersion": "0.8.4"
 }
diff --git a/neoforge/src/main/java/org/vivecraft/neoforge/mixin/NeoForgeMinecraftVRMixin.java b/neoforge/src/main/java/org/vivecraft/neoforge/mixin/NeoForgeMinecraftVRMixin.java
new file mode 100644
index 000000000..230d392d6
--- /dev/null
+++ b/neoforge/src/main/java/org/vivecraft/neoforge/mixin/NeoForgeMinecraftVRMixin.java
@@ -0,0 +1,34 @@
+package org.vivecraft.neoforge.mixin;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.Timer;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+import org.vivecraft.client_vr.VRState;
+import org.vivecraft.client_vr.render.helpers.VRPassHelper;
+
+@Mixin(Minecraft.class)
+public class NeoForgeMinecraftVRMixin {
+
+    @Shadow
+    @Final
+    private Timer timer;
+
+    @Shadow
+    private volatile boolean pause;
+
+    @Shadow
+    private float pausePartialTick;
+
+    @Inject(at = @At(value = "INVOKE", target = "Lnet/neoforged/neoforge/event/EventHooks;onRenderTickEnd(F)V", shift = At.Shift.AFTER), method = "runTick", locals = LocalCapture.CAPTURE_FAILHARD)
+    public void vivecraft$renderVRPassesNeoForge(boolean renderLevel, CallbackInfo ci, long nanoTime) {
+        if (VRState.vrRunning) {
+            VRPassHelper.renderAndSubmit(renderLevel, nanoTime, this.pause ? this.pausePartialTick : this.timer.partialTick);
+        }
+    }
+}
diff --git a/neoforge/src/main/resources/vivecraft.neoforge.mixins.json b/neoforge/src/main/resources/vivecraft.neoforge.mixins.json
index f1b0c57df..853040546 100644
--- a/neoforge/src/main/resources/vivecraft.neoforge.mixins.json
+++ b/neoforge/src/main/resources/vivecraft.neoforge.mixins.json
@@ -3,6 +3,11 @@
   "package": "org.vivecraft.neoforge.mixin",
   "plugin": "org.vivecraft.MixinConfig",
   "compatibilityLevel": "JAVA_17",
-  "client": ["NeoForgeGameRendererVRMixin", "NeoForgeIngameGuiVRMixin", "network.NeoForgeOpenContainerVRMixin"],
+  "client": [
+    "NeoForgeGameRendererVRMixin",
+    "NeoForgeIngameGuiVRMixin",
+    "NeoForgeMinecraftVRMixin",
+    "network.NeoForgeOpenContainerVRMixin"
+  ],
   "minVersion": "0.8.4"
 }

From c412ecd427e40891d6a616af17e14148e054a1e8 Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Wed, 1 May 2024 13:16:07 +0200
Subject: [PATCH 04/17] change Xplat.getModloader to an enum

---
 .../main/java/org/vivecraft/client/Xplat.java    | 16 ++++++++++++++--
 .../vivecraft/client/utils/UpdateChecker.java    |  4 ++--
 .../org/vivecraft/common/CommonDataHolder.java   |  2 +-
 .../org/vivecraft/client/fabric/XplatImpl.java   |  5 +++--
 .../org/vivecraft/client/forge/XplatImpl.java    |  5 +++--
 .../org/vivecraft/client/neoforge/XplatImpl.java |  4 ++--
 6 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/common/src/main/java/org/vivecraft/client/Xplat.java b/common/src/main/java/org/vivecraft/client/Xplat.java
index 4b877d023..ca94523a8 100644
--- a/common/src/main/java/org/vivecraft/client/Xplat.java
+++ b/common/src/main/java/org/vivecraft/client/Xplat.java
@@ -29,6 +29,18 @@ public interface Xplat {
      * <a href="https://plugins.jetbrains.com/plugin/16210-architectury">You should also get the IntelliJ plugin to help with @ExpectPlatform.</a>
      */
 
+    enum ModLoader{
+        FABRIC("fabric"),
+        FORGE("forge"),
+        NEOFORGE("neoforge");
+
+        public final String name;
+
+        ModLoader(String name) {
+            this.name = name;
+        }
+    }
+
     @ExpectPlatform
     static boolean isModLoaded(String name) {
         return false;
@@ -45,8 +57,8 @@ static boolean isDedicatedServer() {
     }
 
     @ExpectPlatform
-    static String getModloader() {
-        return "";
+    static ModLoader getModloader() {
+        throw new AssertionError();
     }
 
     @ExpectPlatform
diff --git a/common/src/main/java/org/vivecraft/client/utils/UpdateChecker.java b/common/src/main/java/org/vivecraft/client/utils/UpdateChecker.java
index dd59bd9c8..326ebf2a3 100644
--- a/common/src/main/java/org/vivecraft/client/utils/UpdateChecker.java
+++ b/common/src/main/java/org/vivecraft/client/utils/UpdateChecker.java
@@ -45,7 +45,7 @@ public static boolean checkForUpdates() {
         }
 
         try {
-            String apiURL = "https://api.modrinth.com/v2/project/vivecraft/version?loaders=[%22" + Xplat.getModloader() + "%22]&game_versions=[%22" + SharedConstants.VERSION_STRING + "%22]";
+            String apiURL = "https://api.modrinth.com/v2/project/vivecraft/version?loaders=[%22" + Xplat.getModloader().name + "%22]&game_versions=[%22" + SharedConstants.VERSION_STRING + "%22]";
             HttpURLConnection conn = (HttpURLConnection) new URL(apiURL).openConnection();
             // 10 seconds read and connect timeout
             conn.setConnectTimeout(10000);
@@ -76,7 +76,7 @@ public static boolean checkForUpdates() {
             // sort the versions, modrinth doesn't guarantee them to be sorted.
             Collections.sort(versions);
 
-            String currentVersionNumber = Xplat.getModVersion() + "-" + Xplat.getModloader();
+            String currentVersionNumber = Xplat.getModVersion() + "-" + Xplat.getModloader().name;
             Version current = new Version(currentVersionNumber, currentVersionNumber, "");
 
             for (Version v : versions) {
diff --git a/common/src/main/java/org/vivecraft/common/CommonDataHolder.java b/common/src/main/java/org/vivecraft/common/CommonDataHolder.java
index 99855b0b8..1edce3be8 100644
--- a/common/src/main/java/org/vivecraft/common/CommonDataHolder.java
+++ b/common/src/main/java/org/vivecraft/common/CommonDataHolder.java
@@ -16,7 +16,7 @@ public CommonDataHolder() {
             modVersion = version[1];
         }
 
-        versionIdentifier = "Vivecraft-" + mcVersion + "-" + Xplat.getModloader() + "-" + modVersion;
+        versionIdentifier = "Vivecraft-" + mcVersion + "-" + Xplat.getModloader().name + "-" + modVersion;
     }
 
     public static CommonDataHolder getInstance() {
diff --git a/fabric/src/main/java/org/vivecraft/client/fabric/XplatImpl.java b/fabric/src/main/java/org/vivecraft/client/fabric/XplatImpl.java
index d46f51d11..550a6f4c3 100644
--- a/fabric/src/main/java/org/vivecraft/client/fabric/XplatImpl.java
+++ b/fabric/src/main/java/org/vivecraft/client/fabric/XplatImpl.java
@@ -21,6 +21,7 @@
 import net.minecraft.world.level.biome.BiomeSpecialEffects;
 import net.minecraft.world.level.block.Blocks;
 import net.minecraft.world.level.material.FluidState;
+import org.vivecraft.client.Xplat;
 import org.vivecraft.fabric.mixin.world.level.biome.BiomeAccessor;
 
 import java.nio.file.Path;
@@ -39,8 +40,8 @@ public static boolean isDedicatedServer() {
         return FabricLoader.getInstance().getEnvironmentType().equals(EnvType.SERVER);
     }
 
-    public static String getModloader() {
-        return "fabric";
+    public static Xplat.ModLoader getModloader() {
+        return Xplat.ModLoader.FABRIC;
     }
 
     public static String getModVersion() {
diff --git a/forge/src/main/java/org/vivecraft/client/forge/XplatImpl.java b/forge/src/main/java/org/vivecraft/client/forge/XplatImpl.java
index 0c467efde..26b20e383 100644
--- a/forge/src/main/java/org/vivecraft/client/forge/XplatImpl.java
+++ b/forge/src/main/java/org/vivecraft/client/forge/XplatImpl.java
@@ -23,6 +23,7 @@
 import net.minecraftforge.fml.loading.FMLLoader;
 import net.minecraftforge.fml.loading.FMLPaths;
 import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
+import org.vivecraft.client.Xplat;
 
 import java.nio.file.Path;
 
@@ -40,8 +41,8 @@ public static boolean isDedicatedServer() {
         return FMLEnvironment.dist == Dist.DEDICATED_SERVER;
     }
 
-    public static String getModloader() {
-        return "forge";
+    public static Xplat.ModLoader getModloader() {
+        return Xplat.ModLoader.FORGE;
     }
 
     public static String getModVersion() {
diff --git a/neoforge/src/main/java/org/vivecraft/client/neoforge/XplatImpl.java b/neoforge/src/main/java/org/vivecraft/client/neoforge/XplatImpl.java
index b93e4494d..e0f9325e5 100644
--- a/neoforge/src/main/java/org/vivecraft/client/neoforge/XplatImpl.java
+++ b/neoforge/src/main/java/org/vivecraft/client/neoforge/XplatImpl.java
@@ -36,8 +36,8 @@ public static boolean isDedicatedServer() {
         return FMLEnvironment.dist == Dist.DEDICATED_SERVER;
     }
 
-    public static String getModloader() {
-        return "neoforge";
+    public static ModLoader getModloader() {
+        return ModLoader.NEOFORGE;
     }
 
     public static String getModVersion() {

From c1814bf0891bfdd5575ace7d00acd966af220f3a Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Wed, 29 May 2024 01:24:24 +0200
Subject: [PATCH 05/17] fix missing spots in the DH projection fix

---
 .../mod_compat_vr/iris/mixin/IrisDHCompatVRMixin.java          | 3 +++
 .../mod_compat_vr/iris/mixin/IrisLodRenderEventsVRMixin.java   | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisDHCompatVRMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisDHCompatVRMixin.java
index 80f738a34..3be1e32a7 100644
--- a/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisDHCompatVRMixin.java
+++ b/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisDHCompatVRMixin.java
@@ -23,6 +23,9 @@ public class IrisDHCompatVRMixin {
 
                 Matrix4f vrProjection = CapturedRenderingState.INSTANCE.getGbufferProjection();
                 Matrix4f dhProjection = cir.getReturnValue();
+
+                dhProjection.m00(vrProjection.m00());
+                dhProjection.m11(vrProjection.m11());
                 dhProjection.m20(vrProjection.m20());
                 dhProjection.m21(vrProjection.m21());
                 cir.setReturnValue(dhProjection);
diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisLodRenderEventsVRMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisLodRenderEventsVRMixin.java
index bec80afda..310b3332e 100644
--- a/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisLodRenderEventsVRMixin.java
+++ b/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisLodRenderEventsVRMixin.java
@@ -33,6 +33,8 @@ public class IrisLodRenderEventsVRMixin {
 
                 Matrix4f vrProjection = CapturedRenderingState.INSTANCE.getGbufferProjection();
 
+                dhProjection.m00(vrProjection.m00());
+                dhProjection.m11(vrProjection.m11());
                 dhProjection.m20(vrProjection.m20());
                 dhProjection.m21(vrProjection.m21());
             }

From 5fef1a4881e327adb5b10118eb41779688f63a52 Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Wed, 29 May 2024 01:24:24 +0200
Subject: [PATCH 06/17] fix missing spots in the DH projection fix

---
 .../mod_compat_vr/iris/mixin/IrisDHCompatVRMixin.java          | 3 +++
 .../mod_compat_vr/iris/mixin/IrisLodRenderEventsVRMixin.java   | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisDHCompatVRMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisDHCompatVRMixin.java
index 80f738a34..3be1e32a7 100644
--- a/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisDHCompatVRMixin.java
+++ b/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisDHCompatVRMixin.java
@@ -23,6 +23,9 @@ public class IrisDHCompatVRMixin {
 
                 Matrix4f vrProjection = CapturedRenderingState.INSTANCE.getGbufferProjection();
                 Matrix4f dhProjection = cir.getReturnValue();
+
+                dhProjection.m00(vrProjection.m00());
+                dhProjection.m11(vrProjection.m11());
                 dhProjection.m20(vrProjection.m20());
                 dhProjection.m21(vrProjection.m21());
                 cir.setReturnValue(dhProjection);
diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisLodRenderEventsVRMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisLodRenderEventsVRMixin.java
index bec80afda..310b3332e 100644
--- a/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisLodRenderEventsVRMixin.java
+++ b/common/src/main/java/org/vivecraft/mod_compat_vr/iris/mixin/IrisLodRenderEventsVRMixin.java
@@ -33,6 +33,8 @@ public class IrisLodRenderEventsVRMixin {
 
                 Matrix4f vrProjection = CapturedRenderingState.INSTANCE.getGbufferProjection();
 
+                dhProjection.m00(vrProjection.m00());
+                dhProjection.m11(vrProjection.m11());
                 dhProjection.m20(vrProjection.m20());
                 dhProjection.m21(vrProjection.m21());
             }

From 73ee002018c72038b34003b7c16899c527cd923e Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Mon, 17 Jun 2024 00:59:05 +0200
Subject: [PATCH 07/17] manually shut down the message scheduler on server
 shutdown, and don't rely on the runtime hook. fixes #283

---
 .../mixin/server/MinecraftServerMixin.java         | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/common/src/main/java/org/vivecraft/mixin/server/MinecraftServerMixin.java b/common/src/main/java/org/vivecraft/mixin/server/MinecraftServerMixin.java
index cd8b93ea4..7e6081eda 100644
--- a/common/src/main/java/org/vivecraft/mixin/server/MinecraftServerMixin.java
+++ b/common/src/main/java/org/vivecraft/mixin/server/MinecraftServerMixin.java
@@ -3,7 +3,13 @@
 import net.minecraft.server.MinecraftServer;
 import org.spongepowered.asm.mixin.Mixin;
 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;
+import org.vivecraft.client.Xplat;
 import org.vivecraft.server.MinecraftServerExt;
+import org.vivecraft.server.ServerNetworking;
+import org.vivecraft.server.ServerUtil;
 import org.vivecraft.server.ServerVivePlayer;
 
 import java.util.HashMap;
@@ -21,4 +27,12 @@ public class MinecraftServerMixin implements MinecraftServerExt {
     public Map<UUID, ServerVivePlayer> vivecraft$getPlayersWithVivecraft() {
         return this.vivecraft$playersWithVivecraft;
     }
+
+    @Inject(at = @At("HEAD"), method = "stopServer")
+    private void vivecraft$stopExecutor(CallbackInfo ci) {
+        if (Xplat.isDedicatedServer()) {
+            ServerNetworking.LOGGER.info("shutting down vivecraft scheduler");
+            ServerUtil.scheduler.shutdownNow();
+        }
+    }
 }

From 41b93133e81c8ea941693fedd39b3224a2c63c38 Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Sat, 29 Jun 2024 01:03:29 +0200
Subject: [PATCH 08/17] move vr player renderer init before vanilla player
 renderer init, to make fabrics layer registration work

---
 .../client/renderer/entity/EntityRenderDispatcherMixin.java     | 2 +-
 .../renderer/entity/EntityRenderDispatcherVRMixin.java          | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/common/src/main/java/org/vivecraft/mixin/client/renderer/entity/EntityRenderDispatcherMixin.java b/common/src/main/java/org/vivecraft/mixin/client/renderer/entity/EntityRenderDispatcherMixin.java
index 2b1b8d9ef..0a2fc9c6e 100644
--- a/common/src/main/java/org/vivecraft/mixin/client/renderer/entity/EntityRenderDispatcherMixin.java
+++ b/common/src/main/java/org/vivecraft/mixin/client/renderer/entity/EntityRenderDispatcherMixin.java
@@ -96,7 +96,7 @@ public abstract class EntityRenderDispatcherMixin implements ResourceManagerRelo
         vivecraft$skinMapVR.clear();
     }
 
-    @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/EntityRenderers;createPlayerRenderers(Lnet/minecraft/client/renderer/entity/EntityRendererProvider$Context;)Ljava/util/Map;", shift = Shift.AFTER),
+    @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/EntityRenderers;createPlayerRenderers(Lnet/minecraft/client/renderer/entity/EntityRendererProvider$Context;)Ljava/util/Map;"),
         method = "onResourceManagerReload", locals = LocalCapture.CAPTURE_FAILEXCEPTION)
     public void vivecraft$reload(ResourceManager p_174004_, CallbackInfo info, EntityRendererProvider.Context context) {
         this.vivecraft$playerRendererVRSeated = new VRPlayerRenderer(context, false, true);
diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/entity/EntityRenderDispatcherVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/entity/EntityRenderDispatcherVRMixin.java
index 39231ead6..77ea8eab5 100644
--- a/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/entity/EntityRenderDispatcherVRMixin.java
+++ b/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/entity/EntityRenderDispatcherVRMixin.java
@@ -62,7 +62,7 @@ public abstract class EntityRenderDispatcherVRMixin implements ResourceManagerRe
         }
     }
 
-    @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/EntityRenderers;createPlayerRenderers(Lnet/minecraft/client/renderer/entity/EntityRendererProvider$Context;)Ljava/util/Map;", shift = At.Shift.AFTER),
+    @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/EntityRenderers;createPlayerRenderers(Lnet/minecraft/client/renderer/entity/EntityRendererProvider$Context;)Ljava/util/Map;"),
         method = "onResourceManagerReload(Lnet/minecraft/server/packs/resources/ResourceManager;)V", locals = LocalCapture.CAPTURE_FAILEXCEPTION)
     public void vivecraft$reload(ResourceManager resourceManager, CallbackInfo ci, EntityRendererProvider.Context context) {
         this.vivecraft$armRenderer = new VRArmRenderer(context, false);

From 678e31147c62626d125e06a726b10021c25ec00f Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Sat, 6 Jul 2024 12:57:58 +0200
Subject: [PATCH 09/17] only override spyglass in VR, fixes #286

---
 .../mixin/client/renderer/entity/ItemRendererVRMixin.java      | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/common/src/main/java/org/vivecraft/mixin/client/renderer/entity/ItemRendererVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client/renderer/entity/ItemRendererVRMixin.java
index 7e2bf71d5..41a3e9d8d 100644
--- a/common/src/main/java/org/vivecraft/mixin/client/renderer/entity/ItemRendererVRMixin.java
+++ b/common/src/main/java/org/vivecraft/mixin/client/renderer/entity/ItemRendererVRMixin.java
@@ -11,6 +11,7 @@
 import org.spongepowered.asm.mixin.injection.At;
 import org.spongepowered.asm.mixin.injection.ModifyVariable;
 import org.vivecraft.client_vr.ClientDataHolderVR;
+import org.vivecraft.client_vr.VRState;
 import org.vivecraft.client_vr.gameplay.trackers.ClimbTracker;
 import org.vivecraft.client_vr.gameplay.trackers.TelescopeTracker;
 
@@ -23,7 +24,7 @@ public class ItemRendererVRMixin {
 
     @ModifyVariable(at = @At(value = "STORE"), method = "getModel")
     public BakedModel vivecraft$modelOverride(BakedModel bakedModel, ItemStack itemStack) {
-        if (itemStack.is(Items.SPYGLASS)) {
+        if (VRState.vrRunning && itemStack.is(Items.SPYGLASS)) {
             return itemModelShaper.getModelManager().getModel(TelescopeTracker.scopeModel);
         }
         if (ClientDataHolderVR.getInstance().climbTracker.isClaws(itemStack)) {

From 3d619008bc1f821c1d4a6d09b47044cb5122a529 Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Sat, 6 Jul 2024 20:05:22 +0200
Subject: [PATCH 10/17] try to not add player renderlayers multiple times

---
 .../client/render/VRPlayerRenderer.java       |  5 +++
 .../entity/LivingEntityRendererMixin.java     | 40 +++++++++++--------
 2 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/common/src/main/java/org/vivecraft/client/render/VRPlayerRenderer.java b/common/src/main/java/org/vivecraft/client/render/VRPlayerRenderer.java
index 27a0f052b..94535cd26 100644
--- a/common/src/main/java/org/vivecraft/client/render/VRPlayerRenderer.java
+++ b/common/src/main/java/org/vivecraft/client/render/VRPlayerRenderer.java
@@ -7,6 +7,7 @@
 import net.minecraft.client.player.AbstractClientPlayer;
 import net.minecraft.client.renderer.MultiBufferSource;
 import net.minecraft.client.renderer.entity.EntityRendererProvider;
+import net.minecraft.client.renderer.entity.layers.RenderLayer;
 import net.minecraft.client.renderer.entity.player.PlayerRenderer;
 import net.minecraft.world.phys.Vec3;
 import org.vivecraft.client.VRPlayersClient;
@@ -34,6 +35,10 @@ public VRPlayerRenderer(EntityRendererProvider.Context context, boolean slim, bo
         this.addLayer(new HMDLayer(this));
     }
 
+    public boolean hasLayerType(RenderLayer<?,?> renderLayer) {
+        return this.layers.stream().anyMatch(layer -> layer.getClass() == renderLayer.getClass());
+    }
+
     @Override
     public void render(AbstractClientPlayer entityIn, float pEntityYaw, float pPartialTicks, PoseStack matrixStackIn, MultiBufferSource pBuffer, int pPackedLight) {
 
diff --git a/common/src/main/java/org/vivecraft/mixin/client/renderer/entity/LivingEntityRendererMixin.java b/common/src/main/java/org/vivecraft/mixin/client/renderer/entity/LivingEntityRendererMixin.java
index 498785933..e0d679d46 100644
--- a/common/src/main/java/org/vivecraft/mixin/client/renderer/entity/LivingEntityRendererMixin.java
+++ b/common/src/main/java/org/vivecraft/mixin/client/renderer/entity/LivingEntityRendererMixin.java
@@ -46,12 +46,14 @@ protected LivingEntityRendererMixin(EntityRendererProvider.Context context) {
         super(context);
     }
 
+    @SuppressWarnings("unchecked")
     @Inject(at = @At("HEAD"), method = "addLayer")
     public void vivecraft$copyLayer(RenderLayer<T, M> renderLayer, CallbackInfoReturnable<Boolean> cir) {
         // check if the layer gets added from the PlayerRenderer, we don't want to copy, if we add it to the VRPlayerRenderer
         // also check that the VRPlayerRenderers were created, this method also gets called in the constructor,
         // those default Layers already are added to the VRPlayerRenderer there
-        if ((Object) this.getClass() == PlayerRenderer.class && !((EntityRenderDispatcherExtension) Minecraft.getInstance().getEntityRenderDispatcher()).vivecraft$getSkinMapVRSeated().isEmpty()) {
+        EntityRenderDispatcherExtension renderExtension = (EntityRenderDispatcherExtension) entityRenderDispatcher;
+        if ((Object) this.getClass() == PlayerRenderer.class && !renderExtension.vivecraft$getSkinMapVRSeated().isEmpty()) {
 
             // try to find a suitable constructor, so we can create a new Object without issues
             Constructor<?> constructor = null;
@@ -80,21 +82,23 @@ protected LivingEntityRendererMixin(EntityRendererProvider.Context context) {
             // if no suitable constructor was found, use do a basic Object.clone call, and replace the parent of the copy
             if (constructor == null) {
                 // do a hacky clone, and replace parent
-                if (((PlayerModel<?>) model).slim) {
-                    vivecraft$addLayerClone(renderLayer, (LivingEntityRenderer<T, M>) ((EntityRenderDispatcherExtension) entityRenderDispatcher).vivecraft$getSkinMapVRSeated().get("slim"));
-                    vivecraft$addLayerClone(renderLayer, (LivingEntityRenderer<T, M>) ((EntityRenderDispatcherExtension) entityRenderDispatcher).vivecraft$getSkinMapVR().get("slim"));
-                } else {
-                    vivecraft$addLayerClone(renderLayer, (LivingEntityRenderer<T, M>) ((EntityRenderDispatcherExtension) entityRenderDispatcher).vivecraft$getSkinMapVRSeated().get("default"));
-                    vivecraft$addLayerClone(renderLayer, (LivingEntityRenderer<T, M>) ((EntityRenderDispatcherExtension) entityRenderDispatcher).vivecraft$getSkinMapVR().get("default"));
+                if (((PlayerModel<?>) model).slim &&
+                    !renderExtension.vivecraft$getSkinMapVRSeated().get("slim").hasLayerType(renderLayer)) {
+                    vivecraft$addLayerClone(renderLayer, (LivingEntityRenderer<T, M>) renderExtension.vivecraft$getSkinMapVRSeated().get("slim"));
+                    vivecraft$addLayerClone(renderLayer, (LivingEntityRenderer<T, M>) renderExtension.vivecraft$getSkinMapVR().get("slim"));
+                } else if (!renderExtension.vivecraft$getSkinMapVRSeated().get("default").hasLayerType(renderLayer)) {
+                    vivecraft$addLayerClone(renderLayer, (LivingEntityRenderer<T, M>) renderExtension.vivecraft$getSkinMapVRSeated().get("default"));
+                    vivecraft$addLayerClone(renderLayer, (LivingEntityRenderer<T, M>) renderExtension.vivecraft$getSkinMapVR().get("default"));
                 }
             } else {
                 // make a new instance with the vr model as parent
-                if (((PlayerModel<?>) model).slim) {
-                    vivecraft$addLayerConstructor(constructor, type, (LivingEntityRenderer<T, M>) ((EntityRenderDispatcherExtension) entityRenderDispatcher).vivecraft$getSkinMapVRSeated().get("slim"));
-                    vivecraft$addLayerConstructor(constructor, type, (LivingEntityRenderer<T, M>) ((EntityRenderDispatcherExtension) entityRenderDispatcher).vivecraft$getSkinMapVR().get("slim"));
-                } else {
-                    vivecraft$addLayerConstructor(constructor, type, (LivingEntityRenderer<T, M>) ((EntityRenderDispatcherExtension) entityRenderDispatcher).vivecraft$getSkinMapVRSeated().get("default"));
-                    vivecraft$addLayerConstructor(constructor, type, (LivingEntityRenderer<T, M>) ((EntityRenderDispatcherExtension) entityRenderDispatcher).vivecraft$getSkinMapVR().get("default"));
+                if (((PlayerModel<?>) model).slim &&
+                    !renderExtension.vivecraft$getSkinMapVRSeated().get("slim").hasLayerType(renderLayer)) {
+                    vivecraft$addLayerConstructor(constructor, type, (LivingEntityRenderer<T, M>) renderExtension.vivecraft$getSkinMapVRSeated().get("slim"));
+                    vivecraft$addLayerConstructor(constructor, type, (LivingEntityRenderer<T, M>) renderExtension.vivecraft$getSkinMapVR().get("slim"));
+                } else if (!renderExtension.vivecraft$getSkinMapVRSeated().get("default").hasLayerType(renderLayer)) {
+                    vivecraft$addLayerConstructor(constructor, type, (LivingEntityRenderer<T, M>) renderExtension.vivecraft$getSkinMapVRSeated().get("default"));
+                    vivecraft$addLayerConstructor(constructor, type, (LivingEntityRenderer<T, M>) renderExtension.vivecraft$getSkinMapVR().get("default"));
                 }
             }
         }
@@ -103,6 +107,7 @@ protected LivingEntityRendererMixin(EntityRendererProvider.Context context) {
     /**
      * does a basic Object.clone() copy
      */
+    @SuppressWarnings("unchecked")
     @Unique
     private void vivecraft$addLayerClone(RenderLayer<T, M> renderLayer, LivingEntityRenderer<T, M> target) {
         try {
@@ -118,6 +123,7 @@ protected LivingEntityRendererMixin(EntityRendererProvider.Context context) {
     /**
      * uses the provided constructor, to create a new RenderLayer Instance
      */
+    @SuppressWarnings("unchecked")
     @Unique
     private void vivecraft$addLayerConstructor(Constructor<?> constructor, RenderLayerTypes.LayerType type, LivingEntityRenderer<T, M> target) {
         try {
@@ -128,12 +134,12 @@ protected LivingEntityRendererMixin(EntityRendererProvider.Context context) {
                 case PARENT_MODEL_MODEL -> {
                     if (((PlayerModel<?>) model).slim) {
                         target.addLayer((RenderLayer<T, M>) constructor.newInstance(target,
-                            new HumanoidModel(Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_SLIM_INNER_ARMOR)),
-                            new HumanoidModel(Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_SLIM_OUTER_ARMOR))));
+                            new HumanoidModel<>(Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_SLIM_INNER_ARMOR)),
+                            new HumanoidModel<>(Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_SLIM_OUTER_ARMOR))));
                     } else {
                         target.addLayer((RenderLayer<T, M>) constructor.newInstance(target,
-                            new HumanoidModel(Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR)),
-                            new HumanoidModel(Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_OUTER_ARMOR))));
+                            new HumanoidModel<>(Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR)),
+                            new HumanoidModel<>(Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_OUTER_ARMOR))));
                     }
                 }
             }

From edd4574588c48706258729eb25770ac2ee007796 Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Sun, 7 Jul 2024 01:05:11 +0200
Subject: [PATCH 11/17] print lwjgl source when the wrong one is loaded

---
 .../src/main/java/org/vivecraft/client_vr/VRState.java | 10 +++++++++-
 .../main/resources/assets/vivecraft/lang/de_de.json    |  2 +-
 .../main/resources/assets/vivecraft/lang/en_us.json    |  2 +-
 3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/common/src/main/java/org/vivecraft/client_vr/VRState.java b/common/src/main/java/org/vivecraft/client_vr/VRState.java
index cd6069139..547804249 100644
--- a/common/src/main/java/org/vivecraft/client_vr/VRState.java
+++ b/common/src/main/java/org/vivecraft/client_vr/VRState.java
@@ -19,6 +19,7 @@
 import org.vivecraft.mod_compat_vr.ShadersHelper;
 import org.vivecraft.mod_compat_vr.optifine.OptifineHelper;
 
+import java.io.File;
 import java.lang.management.ManagementFactory;
 import java.lang.management.MemoryManagerMXBean;
 
@@ -44,7 +45,14 @@ public static void initializeVR() {
                 // TODO: move this into the init, does mean all callocs need to be done later
                 // check that the right lwjgl version is loaded that we ship the openvr part of
                 if (!Version.getVersion().startsWith("3.3.2")) {
-                    throw new RenderConfigException("VR Init Error", Component.translatable("vivecraft.messages.rendersetupfailed", I18n.get("vivecraft.messages.invalidlwjgl", Version.getVersion(), "3.3.2"), "OpenVR_LWJGL"));
+                    String suppliedJar = "";
+                    try {
+                        suppliedJar = new File(Version.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getName();
+                    } catch (Exception e) {
+                        VRSettings.logger.error("couldn't check lwjgl source:", e);
+                    }
+
+                    throw new RenderConfigException("VR Init Error", Component.translatable("vivecraft.messages.rendersetupfailed", I18n.get("vivecraft.messages.invalidlwjgl", Version.getVersion(), "3.3.2", suppliedJar), "OpenVR_LWJGL"));
                 }
 
                 dh.vr = new MCOpenVR(Minecraft.getInstance(), dh);
diff --git a/common/src/main/resources/assets/vivecraft/lang/de_de.json b/common/src/main/resources/assets/vivecraft/lang/de_de.json
index 84d30f280..32c853f13 100644
--- a/common/src/main/resources/assets/vivecraft/lang/de_de.json
+++ b/common/src/main/resources/assets/vivecraft/lang/de_de.json
@@ -396,7 +396,7 @@
   "vivecraft.messages.nosteamvr": "OpenVR runtime nicht erkannt. Ist SteamVR installiert?",
   "vivecraft.messages.outdatedsteamvr": "OpenVR konnte nicht alle benötigten Komponenten initialisieren. Vergewissern Sie sich, dass Sie die neuesten Version von SteamVR verwenden.",
   "vivecraft.messages.steamvrInvalidCharacters": "Ungültige Zeichen im Pfad: \n%s\n\nUm diesen Fehler zu beheben, ändere Minecrafts Spielverzeichnis zu etwas außerhalb des Ordners mit den gekennzeichneten Zeichen.",
-  "vivecraft.messages.invalidlwjgl": "Nicht unterstützte LWJGL Version geladen.\nGeladene Version: §c%s§r\nBenötigte Version: §2%s§r",
+  "vivecraft.messages.invalidlwjgl": "Nicht unterstützte LWJGL Version geladen.\nGeladene Version: §c%s§r\nBenötigte Version: §2%s§r\nFalsche LWJGL Version wurde geladen von: %s",
   "vivecraft.messages.menuworldexportcomplete.1": "Weltexport abgeschlossen... Flächengröße: %d",
   "vivecraft.messages.menuworldexportcomplete.2": "Gespeichert unter %s",
   "vivecraft.messages.menuworldexportclientwarning": "WARNUNG: Speichern der Menüwelt mithilfe einer Clientwelt. Daten können unvollständig sein. Es wird empfohlen, Menüwelten im Einzelspielermodus zu speichern.",
diff --git a/common/src/main/resources/assets/vivecraft/lang/en_us.json b/common/src/main/resources/assets/vivecraft/lang/en_us.json
index 6a7c63b13..5d893bc74 100644
--- a/common/src/main/resources/assets/vivecraft/lang/en_us.json
+++ b/common/src/main/resources/assets/vivecraft/lang/en_us.json
@@ -395,7 +395,7 @@
   "vivecraft.messages.nosteamvr": "OpenVR runtime not detected. Did you install SteamVR?",
   "vivecraft.messages.outdatedsteamvr": "OpenVR failed to initialize needed components. Make sure you are using the latest version of SteamVR.",
   "vivecraft.messages.steamvrInvalidCharacters": "Invalid characters in path: \n%s\n\nTo fix this error, change your Minecraft game directory to somewhere outside the folder with marked characters.",
-  "vivecraft.messages.invalidlwjgl": "Unsupported LWJGL version loaded.\nLoaded version: §c%s§r\nRequired version: §2%s§r",
+  "vivecraft.messages.invalidlwjgl": "Unsupported LWJGL version loaded.\nLoaded version: §c%s§r\nRequired version: §2%s§r\nWrong LWJGL version was loaded by: %s",
   "vivecraft.messages.menuworldexportcomplete.1": "World export complete... area size: %d",
   "vivecraft.messages.menuworldexportcomplete.2": "Saved to %s",
   "vivecraft.messages.menuworldexportclientwarning": "WARNING: Saving menu world using a client world. Data may be incomplete. It is recommended to save menu worlds in singleplayer.",

From 1ffc7fe19e0db8b2bd78ac934d4da1e827a80866 Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Sun, 7 Jul 2024 01:09:44 +0200
Subject: [PATCH 12/17] also print stacktrace on renderconfig errors

---
 common/src/main/java/org/vivecraft/client_vr/VRState.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/common/src/main/java/org/vivecraft/client_vr/VRState.java b/common/src/main/java/org/vivecraft/client_vr/VRState.java
index 547804249..52c412da3 100644
--- a/common/src/main/java/org/vivecraft/client_vr/VRState.java
+++ b/common/src/main/java/org/vivecraft/client_vr/VRState.java
@@ -121,6 +121,7 @@ public static void initializeVR() {
         } catch (RenderConfigException renderConfigException) {
             vrEnabled = false;
             destroyVR(true);
+            renderConfigException.printStackTrace();
             Minecraft.getInstance().setScreen(new ErrorScreen(renderConfigException.title, renderConfigException.error));
         } catch (Throwable e) {
             vrEnabled = false;

From 805fb4f9647353a039ccc3330e5ba4b18186f154 Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Sun, 7 Jul 2024 03:24:41 +0200
Subject: [PATCH 13/17] add setting to disable roomscale block/entity
 interaction

---
 .../vivecraft/client/gui/settings/GuiRoomscaleSettings.java | 4 +++-
 .../client_vr/gameplay/trackers/InteractTracker.java        | 4 ++--
 .../java/org/vivecraft/client_vr/settings/VRSettings.java   | 6 ++++++
 common/src/main/resources/assets/vivecraft/lang/de_de.json  | 4 ++++
 common/src/main/resources/assets/vivecraft/lang/en_us.json  | 4 ++++
 5 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiRoomscaleSettings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiRoomscaleSettings.java
index b9642327e..7f94d5f11 100644
--- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiRoomscaleSettings.java
+++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiRoomscaleSettings.java
@@ -15,7 +15,9 @@ public class GuiRoomscaleSettings extends GuiVROptionsBase {
         VRSettings.VrOptions.BOW_MODE,
         VRSettings.VrOptions.BACKPACK_SWITCH,
         VRSettings.VrOptions.ALLOW_CRAWLING,
-        VRSettings.VrOptions.REALISTIC_DISMOUNT
+        VRSettings.VrOptions.REALISTIC_DISMOUNT,
+        VRSettings.VrOptions.REALISTIC_BLOCK_INTERACT,
+        VRSettings.VrOptions.REALISTIC_ENTITY_INTERACT
     };
 
     public GuiRoomscaleSettings(Screen guiScreen) {
diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/InteractTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/InteractTracker.java
index 3c41bf46e..9fc94d759 100644
--- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/InteractTracker.java
+++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/InteractTracker.java
@@ -186,7 +186,7 @@ public void doProcess(LocalPlayer player) {
                     }
                 }
 
-                if (!this.active[j]) {
+                if (this.dh.vrSettings.realisticEntityInteractEnabled && !this.active[j]) {
                     int k = Mth.floor(vec3.x);
                     int l = Mth.floor(vec3.y);
                     int i = Mth.floor(vec3.z);
@@ -204,7 +204,7 @@ public void doProcess(LocalPlayer player) {
                     }
                 }
 
-                if (!this.active[j]) {
+                if (this.dh.vrSettings.realisticBlockInteractEnabled && !this.active[j]) {
                     BlockPos blockpos = null;
                     blockpos = BlockPos.containing(vec3);
                     BlockState blockstate = this.mc.level.getBlockState(blockpos);
diff --git a/common/src/main/java/org/vivecraft/client_vr/settings/VRSettings.java b/common/src/main/java/org/vivecraft/client_vr/settings/VRSettings.java
index 70c42228a..42e0d3eee 100644
--- a/common/src/main/java/org/vivecraft/client_vr/settings/VRSettings.java
+++ b/common/src/main/java/org/vivecraft/client_vr/settings/VRSettings.java
@@ -271,6 +271,10 @@ public enum UpdateType implements OptionEnum<UpdateType> {
     public boolean realisticRowEnabled = true;
     @SettingField(VrOptions.REALISTIC_DISMOUNT)
     public boolean realisticDismountEnabled = true;
+    @SettingField(VrOptions.REALISTIC_BLOCK_INTERACT)
+    public boolean realisticBlockInteractEnabled = true;
+    @SettingField(VrOptions.REALISTIC_ENTITY_INTERACT)
+    public boolean realisticEntityInteractEnabled = true;
     @SettingField(VrOptions.BACKPACK_SWITCH)
     public boolean backpackSwitching = true;
     @SettingField(VrOptions.PHYSICAL_GUI)
@@ -1624,6 +1628,8 @@ Object loadOption(String value) {
         REALISTIC_SWIM(false, true), // Roomscale Swimming
         REALISTIC_ROW(false, true), // Roomscale Rowing
         REALISTIC_DISMOUNT(false, true), // Roomscale Dismounting
+        REALISTIC_BLOCK_INTERACT(false, true), // Roomscale Block Interaction
+        REALISTIC_ENTITY_INTERACT(false, true), // Roomscale Entity Interaction
         WALK_MULTIPLIER(true, false, 1f, 10f, 0.1f, 1), // Walking Multiplier
         FREEMOVE_MODE(false, true) { // Free Move Type
 
diff --git a/common/src/main/resources/assets/vivecraft/lang/de_de.json b/common/src/main/resources/assets/vivecraft/lang/de_de.json
index 32c853f13..7030aefdb 100644
--- a/common/src/main/resources/assets/vivecraft/lang/de_de.json
+++ b/common/src/main/resources/assets/vivecraft/lang/de_de.json
@@ -155,6 +155,8 @@
   "vivecraft.options.REALISTIC_SWIM": "Raumskala Schwimmen",
   "vivecraft.options.REALISTIC_ROW": "Raumskala Rudern",
   "vivecraft.options.REALISTIC_DISMOUNT": "Raumskala Absteigen",
+  "vivecraft.options.REALISTIC_BLOCK_INTERACT": "Raumskala Blockinteraktion",
+  "vivecraft.options.REALISTIC_ENTITY_INTERACT": "Raumskala Objektinteraktion",
   "vivecraft.options.WALK_MULTIPLIER": "Lauf Multiplikator",
   "vivecraft.options.FREEMOVE_MODE": "Frei Bewegen",
   "vivecraft.options.VEHICLE_ROTATION": "Vehikel Rotation",
@@ -245,6 +247,8 @@
   "vivecraft.options.REALISTIC_SWIM.tooltip": "Falls eingeschaltet, erlauben Sie das Schwimmen durch Brustschwimm-Bewegung mit den Controllern.",
   "vivecraft.options.REALISTIC_ROW.tooltip": "Ruder, Ruder, Ruder dein Boot... wie verrückt mit den Armen.",
   "vivecraft.options.REALISTIC_DISMOUNT.tooltip": "Steige von Objekten ab, indem du dich einen Meter von ihnen entfernst.\nKann Probleme haben mit großen Objekten von anderen Mods.",
+  "vivecraft.options.REALISTIC_BLOCK_INTERACT.tooltip": "Erlaubt das Aktivieren von Hebeln, Knöpfen, Truhen und so weiter, indem Sie ihre Hand in diese halten und die Interaktionstaste drücken.",
+  "vivecraft.options.REALISTIC_ENTITY_INTERACT.tooltip": "Erlaubt das Interagieren mit Objekten, indem Sie ihre Hand in diese halten und die Interaktionstaste drücken.",
   "vivecraft.options.WALK_MULTIPLIER.tooltip": "Multipliziert Ihre Position im Raum mit einem Faktor.\nErlaubt Ihnen, mehr herumzulaufen, kann aber Bewegungsübelkeit verursachen.",
   "vivecraft.options.FREEMOVE_MODE.tooltip": "Die Quelle für die Frei Bewegen-Richtung.\n\n  Controller: Richtung des nicht dominanten Controllers.\n  HMD: Blickrichtung des Headsets.\n  Run-In-Place: Die Neigung basiert auf dem Schwingen der Controller. Pitch ist Ihr Headset.\n  Raum: Die Neigung ist relativ zu Ihrem VR-Raum nach vorne. Neigung: Die Neigung ist basiert auf Ihr Headset. Dieser Modus ist am besten nur für 180 Setups geeignet.",
   "vivecraft.options.VEHICLE_ROTATION.tooltip": "Wenn man in einem Vehikel fährt, dreht sich die Welt, während sich das Vehikel dreht. Kann verwirrend sein.",
diff --git a/common/src/main/resources/assets/vivecraft/lang/en_us.json b/common/src/main/resources/assets/vivecraft/lang/en_us.json
index 5d893bc74..358d93e64 100644
--- a/common/src/main/resources/assets/vivecraft/lang/en_us.json
+++ b/common/src/main/resources/assets/vivecraft/lang/en_us.json
@@ -154,6 +154,8 @@
   "vivecraft.options.REALISTIC_SWIM": "Roomscale Swimming",
   "vivecraft.options.REALISTIC_ROW": "Roomscale Rowing",
   "vivecraft.options.REALISTIC_DISMOUNT": "Roomscale Dismounting",
+  "vivecraft.options.REALISTIC_BLOCK_INTERACT": "Roomscale Block Interact",
+  "vivecraft.options.REALISTIC_ENTITY_INTERACT": "Roomscale Entity Interact",
   "vivecraft.options.WALK_MULTIPLIER": "Walking Multiplier",
   "vivecraft.options.FREEMOVE_MODE": "Free Move Type",
   "vivecraft.options.VEHICLE_ROTATION": "Vehicle Rotation",
@@ -244,6 +246,8 @@
   "vivecraft.options.REALISTIC_SWIM.tooltip": "If turned on, allow swimming by doing the breaststroke with the controllers.",
   "vivecraft.options.REALISTIC_ROW.tooltip": "Row, row, row your boat... by flapping your arms like mad.",
   "vivecraft.options.REALISTIC_DISMOUNT.tooltip": "Dismounts from entities, when walking away 1 meter.\nCan have issues with large modded entities.",
+  "vivecraft.options.REALISTIC_BLOCK_INTERACT.tooltip": "Allows activating levers, buttons, chests and such by holding your hand in them, and pressing the interact button",
+  "vivecraft.options.REALISTIC_ENTITY_INTERACT.tooltip": "Allows interacting with entities by holding your hand in them, and pressing the interact button",
   "vivecraft.options.WALK_MULTIPLIER.tooltip": "Multiplies your position in the room by a factor.\nAllows you to walk around more, but may cause motion sickness.",
   "vivecraft.options.FREEMOVE_MODE.tooltip": "The source for freemove direction.\n\n  Controller: Offhand controller pointing direction.\n  HMD: Headset look direction.\n  Run-In-Place: Yaw is based on how controllers are swinging. Pitch is your Headset.\n  Room: Yaw is relative to your VR room forward. Pitch is your Headset. This mode is best only for 180 setups.",
   "vivecraft.options.VEHICLE_ROTATION.tooltip": "Riding in a vehicle will rotate the world as the vehicle rotates. May be disorienting.",

From c4934447a8d0fb98a8e02eb4fd4d2ecf0ae1eccd Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Sun, 7 Jul 2024 12:27:45 +0200
Subject: [PATCH 14/17] fix HMD rendering when head is invisible

---
 common/src/main/java/org/vivecraft/client/render/HMDLayer.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/common/src/main/java/org/vivecraft/client/render/HMDLayer.java b/common/src/main/java/org/vivecraft/client/render/HMDLayer.java
index bcd7bc515..53c47515c 100644
--- a/common/src/main/java/org/vivecraft/client/render/HMDLayer.java
+++ b/common/src/main/java/org/vivecraft/client/render/HMDLayer.java
@@ -24,7 +24,7 @@ public HMDLayer(RenderLayerParent<AbstractClientPlayer, PlayerModel<AbstractClie
 
     @Override
     public void render(PoseStack poseStack, MultiBufferSource multiBufferSource, int i, AbstractClientPlayer entity, float f, float g, float h, float j, float k, float l) {
-        if (this.getParentModel() instanceof VRPlayerModel<?> vrPlayerModel) {
+        if (this.getParentModel().head.visible && this.getParentModel() instanceof VRPlayerModel<?> vrPlayerModel) {
             VRPlayersClient.RotInfo rotinfo = VRPlayersClient.getInstance().getRotationsForPlayer(entity.getUUID());
             ResourceLocation hmd;
             switch (rotinfo.hmd) {

From 4130790970fe434d93bf908b31b6582a41639743 Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Sun, 7 Jul 2024 13:13:47 +0200
Subject: [PATCH 15/17] bump to 1.1.10

---
 gradle.properties | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gradle.properties b/gradle.properties
index e2b9e2bd5..df004f9a2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -4,7 +4,7 @@ minecraft_version=1.20.4
 enabled_platforms=fabric,forge,neoforge
 
 archives_base_name=vivecraft
-mod_version=1.1.9
+mod_version=1.1.10
 maven_group=org.vivecraft
 
 architectury_version=11.0.5
@@ -13,7 +13,7 @@ fabric_loader_version=0.15.7
 fabric_api_version=0.91.1+1.20.4
 
 forge_version=1.20.4-49.0.30
-neoforge_version=20.4.164-beta
+neoforge_version=20.4.237
 
 
 

From 4227b1f29a54d37b9f32274af18674da50db127c Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Tue, 9 Jul 2024 23:12:33 +0200
Subject: [PATCH 16/17] fix some mods breaking the hud rendering

---
 .../java/org/vivecraft/mixin/client_vr/MinecraftVRMixin.java     | 1 +
 1 file changed, 1 insertion(+)

diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/MinecraftVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/MinecraftVRMixin.java
index 9ed574298..112dafb2f 100644
--- a/common/src/main/java/org/vivecraft/mixin/client_vr/MinecraftVRMixin.java
+++ b/common/src/main/java/org/vivecraft/mixin/client_vr/MinecraftVRMixin.java
@@ -371,6 +371,7 @@ public abstract class MinecraftVRMixin implements MinecraftExtension {
             RenderPassManager.setGUIRenderPass();
             RenderSystem.depthMask(true);
             RenderSystem.colorMask(true, true, true, true);
+            RenderSystem.defaultBlendFunc();
             this.mainRenderTarget.clear(Minecraft.ON_OSX);
             this.mainRenderTarget.bindWrite(true);
 

From eba4f10057b94d1589b599e759ea294424cbc717 Mon Sep 17 00:00:00 2001
From: fayer3 <bayer.florian@aon.at>
Date: Tue, 9 Jul 2024 23:13:27 +0200
Subject: [PATCH 17/17] bump to 1.1.11

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index df004f9a2..d6ee8848b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -4,7 +4,7 @@ minecraft_version=1.20.4
 enabled_platforms=fabric,forge,neoforge
 
 archives_base_name=vivecraft
-mod_version=1.1.10
+mod_version=1.1.11
 maven_group=org.vivecraft
 
 architectury_version=11.0.5