From 56cbd57b00a4c3e43ccfe9a7a2afd9715ce71bab Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Thu, 1 Aug 2024 23:35:12 +0200 Subject: [PATCH 01/76] [WIP] Add openXR support (#230) Add first attempt OpenXR support TODO - Test on all different OpenXR platforms - Figure out key binding system - Verify all functionality Co-authored-by: The Judge <53906078+thejudge156@users.noreply.github.com> Co-authored-by: fayer3 --- build.gradle | 5 + .../extensions/RenderTargetExtension.java | 2 + .../gui/settings/GuiRenderOpticsSettings.java | 2 +- .../java/org/vivecraft/client_vr/VRState.java | 36 +- .../vivecraft/client_vr/VRTextureTarget.java | 15 +- .../vivecraft/client_vr/gui/GuiRadial.java | 2 +- .../client_vr/provider/ActionParams.java | 2 +- .../vivecraft/client_vr/provider/MCVR.java | 126 +- .../client_vr/provider/VRRenderer.java | 60 +- .../control/HapticMusicPlayer.java | 10 +- .../control/TrackpadSwipeSampler.java | 8 +- .../VRInputAction.java | 13 +- .../control/VRInputActionSet.java | 2 +- .../control/VivecraftMovementInput.java | 11 + .../client_vr/provider/nullvr/NullVR.java | 7 +- .../provider/nullvr/NullVRStereoRenderer.java | 51 +- .../provider/openvr_lwjgl/MCOpenVR.java | 124 +- .../openvr_lwjgl/OpenVRStereoRenderer.java | 52 +- .../control/VivecraftMovementInput.java | 12 - .../client_vr/provider/openxr/MCOpenXR.java | 1494 +++++++++++++++++ .../openxr/OpenXRHapticSchedular.java | 47 + .../provider/openxr/OpenXRStereoRenderer.java | 182 ++ .../client_vr/provider/openxr/OpenXRUtil.java | 50 + .../client_vr/provider/openxr/XRBindings.java | 137 ++ .../render/helpers/VRPassHelper.java | 11 +- .../client_vr/settings/VRSettings.java | 14 +- .../client/blaze3d/RenderTargetMixin.java | 5 + .../mixin/client_vr/KeyboardInputVRMixin.java | 4 +- .../mixin/client_vr/MinecraftVRMixin.java | 20 +- .../assets/vivecraft/lang/en_us.json | 4 + fabric/build.gradle | 4 + forge/build.gradle | 8 + neoforge/build.gradle | 8 + 33 files changed, 2278 insertions(+), 250 deletions(-) rename common/src/main/java/org/vivecraft/client_vr/provider/{openvr_lwjgl => }/control/HapticMusicPlayer.java (77%) rename common/src/main/java/org/vivecraft/client_vr/provider/{openvr_lwjgl => }/control/TrackpadSwipeSampler.java (88%) rename common/src/main/java/org/vivecraft/client_vr/provider/{openvr_lwjgl => control}/VRInputAction.java (96%) rename common/src/main/java/org/vivecraft/client_vr/provider/{openvr_lwjgl => }/control/VRInputActionSet.java (96%) create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/control/VivecraftMovementInput.java delete mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VivecraftMovementInput.java create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticSchedular.java create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRUtil.java create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java diff --git a/build.gradle b/build.gradle index b7eaa2889..83ac7389a 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,11 @@ subprojects { implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-linux") implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") + + implementation("org.lwjgl:lwjgl-openxr:3.3.2") + implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") + //implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-macos") + implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") } tasks.withType(JavaCompile) { diff --git a/common/src/main/java/org/vivecraft/client/extensions/RenderTargetExtension.java b/common/src/main/java/org/vivecraft/client/extensions/RenderTargetExtension.java index 43b951e49..ff1c98e07 100644 --- a/common/src/main/java/org/vivecraft/client/extensions/RenderTargetExtension.java +++ b/common/src/main/java/org/vivecraft/client/extensions/RenderTargetExtension.java @@ -17,6 +17,8 @@ public interface RenderTargetExtension { void vivecraft$setTextid(int texid); + void vivecraft$setColorid(int colorid); + void vivecraft$setUseStencil(boolean useStencil); boolean vivecraft$getUseStencil(); diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiRenderOpticsSettings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiRenderOpticsSettings.java index cf80cbd19..610d5771b 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiRenderOpticsSettings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiRenderOpticsSettings.java @@ -24,7 +24,7 @@ public class GuiRenderOpticsSettings extends GuiVROptionsBase { VRSettings.VrOptions.HANDHELD_CAMERA_RENDER_SCALE, VRSettings.VrOptions.HANDHELD_CAMERA_FOV, VRSettings.VrOptions.RELOAD_EXTERNAL_CAMERA, - VRSettings.VrOptions.MIRROR_EYE + VRSettings.VrOptions.MIRROR_EYE, }; static VRSettings.VrOptions[] MROptions = new VRSettings.VrOptions[]{ VRSettings.VrOptions.MIXED_REALITY_UNITY_LIKE, 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 52c412da3..16b32f9da 100644 --- a/common/src/main/java/org/vivecraft/client_vr/VRState.java +++ b/common/src/main/java/org/vivecraft/client_vr/VRState.java @@ -13,6 +13,7 @@ import org.vivecraft.client_vr.menuworlds.MenuWorldRenderer; import org.vivecraft.client_vr.provider.nullvr.NullVR; import org.vivecraft.client_vr.provider.openvr_lwjgl.MCOpenVR; +import org.vivecraft.client_vr.provider.openxr.MCOpenXR; import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.client_xr.render_pass.RenderPassManager; @@ -40,25 +41,26 @@ public static void initializeVR() { vrInitialized = true; ClientDataHolderVR dh = ClientDataHolderVR.getInstance(); - if (dh.vrSettings.stereoProviderPluginID == VRSettings.VRProvider.OPENVR) { - // make sure the lwjgl version is the right one - // 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")) { - 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")); + Minecraft instance = Minecraft.getInstance(); + // make sure the lwjgl version is the right one + // 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")) { + 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); } - dh.vr = new MCOpenVR(Minecraft.getInstance(), dh); - } else { - dh.vr = new NullVR(Minecraft.getInstance(), dh); + throw new RenderConfigException("VR Init Error", Component.translatable("vivecraft.messages.rendersetupfailed", I18n.get("vivecraft.messages.invalidlwjgl", Version.getVersion(), "3.3.2", suppliedJar), "OpenVR_LWJGL")); } + switch (dh.vrSettings.stereoProviderPluginID) { + case OPENVR -> dh.vr = new MCOpenVR(instance, dh); + case OPENXR -> dh.vr = new MCOpenXR(instance, dh); + default -> dh.vr = new NullVR(instance, dh); + } + if (!dh.vr.init()) { throw new RenderConfigException("VR Init Error", Component.translatable("vivecraft.messages.rendersetupfailed", dh.vr.initStatus, dh.vr.getName())); } @@ -66,7 +68,7 @@ public static void initializeVR() { dh.vrRenderer = dh.vr.createVRRenderer(); dh.vrRenderer.lastGuiScale = Minecraft.getInstance().options.guiScale().get(); - dh.vrRenderer.setupRenderConfiguration(); + dh.vrRenderer.setupRenderConfiguration(false); //TODO look into why I have the boolean RenderPassManager.setVanillaRenderPass(); dh.vrPlayer = new VRPlayer(); diff --git a/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java b/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java index b29b88b88..4195de565 100644 --- a/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java +++ b/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java @@ -1,14 +1,16 @@ package org.vivecraft.client_vr; import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; +import org.lwjgl.opengl.GL30; import org.vivecraft.client.Xplat; import org.vivecraft.client.extensions.RenderTargetExtension; public class VRTextureTarget extends RenderTarget { private final String name; - public VRTextureTarget(String name, int width, int height, boolean usedepth, boolean onMac, int texid, boolean depthtex, boolean linearFilter, boolean useStencil) { super(usedepth); this.name = name; @@ -23,6 +25,17 @@ public VRTextureTarget(String name, int width, int height, boolean usedepth, boo this.setClearColor(0, 0, 0, 0); } + public VRTextureTarget(String name, int width, int height, int colorid, int index) { + super(true); + this.name = name; + RenderSystem.assertOnGameThreadOrInit(); + this.resize(width, height, Minecraft.ON_OSX); + ((RenderTargetExtension) this).vivecraft$setColorid(colorid); + GlStateManager._glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferId); + GL30.glFramebufferTextureLayer(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, colorid, 0, index); + this.setClearColor(0, 0, 0, 0); + } + @Override public String toString() { StringBuilder stringbuilder = new StringBuilder(); diff --git a/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java b/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java index a68a9d3d0..16bbfeb2d 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java +++ b/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java @@ -7,7 +7,7 @@ import net.minecraft.network.chat.Component; import org.vivecraft.client.gui.framework.TwoHandedScreen; import org.vivecraft.client_vr.provider.MCVR; -import org.vivecraft.client_vr.provider.openvr_lwjgl.VRInputAction; +import org.vivecraft.client_vr.provider.control.VRInputAction; public class GuiRadial extends TwoHandedScreen { private boolean isShift = false; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/ActionParams.java b/common/src/main/java/org/vivecraft/client_vr/provider/ActionParams.java index 5586e4994..5b4015eaa 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/ActionParams.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/ActionParams.java @@ -1,6 +1,6 @@ package org.vivecraft.client_vr.provider; -import org.vivecraft.client_vr.provider.openvr_lwjgl.control.VRInputActionSet; +import org.vivecraft.client_vr.provider.control.VRInputActionSet; public class ActionParams { public final VRInputActionSet actionSetOverride; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java index 6f78158b7..fd9508569 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java @@ -1,5 +1,6 @@ package org.vivecraft.client_vr.provider; +import com.mojang.blaze3d.platform.InputConstants; import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.ChatScreen; @@ -25,9 +26,10 @@ 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.provider.openvr_lwjgl.VRInputAction; -import org.vivecraft.client_vr.provider.openvr_lwjgl.control.VRInputActionSet; -import org.vivecraft.client_vr.provider.openvr_lwjgl.control.VivecraftMovementInput; +import org.vivecraft.client_vr.provider.control.TrackpadSwipeSampler; +import org.vivecraft.client_vr.provider.control.VRInputAction; +import org.vivecraft.client_vr.provider.control.VRInputActionSet; +import org.vivecraft.client_vr.provider.control.VivecraftMovementInput; import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.settings.VRHotkeys; @@ -108,6 +110,8 @@ public abstract class MCVR { protected int quickTorchPreviousSlot; protected Map inputActions = new HashMap<>(); protected Map inputActionsByKeyBinding = new HashMap<>(); + protected final Map trackpadSwipeSamplers = new HashMap<>(); + protected boolean inputInitialized; public MCVR(Minecraft mc, ClientDataHolderVR dh, VivecraftVRMod vrMod) { this.mc = mc; @@ -131,7 +135,50 @@ public static MCVR get() { public abstract String getID(); - public abstract void processInputs(); + public void processInputs() { + if (!this.dh.vrSettings.seated && !ClientDataHolderVR.viewonly && this.inputInitialized) { + for (VRInputAction vrinputaction : this.inputActions.values()) { + if (vrinputaction.isHanded()) { + for (ControllerType controllertype : ControllerType.values()) { + vrinputaction.setCurrentHand(controllertype); + this.processInputAction(vrinputaction); + } + } else { + this.processInputAction(vrinputaction); + } + } + + this.processScrollInput(GuiHandler.keyScrollAxis, () -> + { + InputSimulator.scrollMouse(0.0D, 1.0D); + }, () -> + { + InputSimulator.scrollMouse(0.0D, -1.0D); + }); + this.processScrollInput(VivecraftVRMod.INSTANCE.keyHotbarScroll, () -> + { + this.changeHotbar(-1); + }, () -> + { + this.changeHotbar(1); + }); + this.processSwipeInput(VivecraftVRMod.INSTANCE.keyHotbarSwipeX, () -> + { + this.changeHotbar(1); + }, () -> + { + this.changeHotbar(-1); + }, null, null); + this.processSwipeInput(VivecraftVRMod.INSTANCE.keyHotbarSwipeY, null, null, () -> + { + this.changeHotbar(-1); + }, () -> + { + this.changeHotbar(1); + }); + this.ignorePressesNextFrame = false; + } + } public abstract void destroy(); @@ -1145,6 +1192,76 @@ protected void changeHotbar(int dir) { } } + protected void processInputAction(VRInputAction action) { + if (action.isActive() && action.isEnabledRaw() + // try to prevent double left clicks + && (!ClientDataHolderVR.getInstance().vrSettings.ingameBindingsInGui + || !(action.actionSet == VRInputActionSet.INGAME && action.keyBinding.key.getType() == InputConstants.Type.MOUSE && action.keyBinding.key.getValue() == 0 && mc.screen != null))) { + if (action.isButtonChanged()) { + if (action.isButtonPressed() && action.isEnabled()) { + if (!this.ignorePressesNextFrame) { + action.pressBinding(); + } + } else { + action.unpressBinding(); + } + } + } else { + action.unpressBinding(); + } + } + + protected void processScrollInput(KeyMapping keyBinding, Runnable upCallback, Runnable downCallback) { + VRInputAction vrinputaction = this.getInputAction(keyBinding); + + if (vrinputaction.isEnabled() && vrinputaction.getLastOrigin() != 0L && vrinputaction.getAxis2D(true).getY() != 0.0F) { + float f = vrinputaction.getAxis2D(false).getY(); + + if (f > 0.0F) { + upCallback.run(); + } else if (f < 0.0F) { + downCallback.run(); + } + } + } + + protected void processSwipeInput(KeyMapping keyBinding, Runnable leftCallback, Runnable rightCallback, Runnable upCallback, Runnable downCallback) { + VRInputAction vrinputaction = this.getInputAction(keyBinding); + + if (vrinputaction.isEnabled() && vrinputaction.getLastOrigin() != 0L) { + ControllerType controllertype = this.findActiveBindingControllerType(keyBinding); + + if (controllertype != null) { + if (!this.trackpadSwipeSamplers.containsKey(keyBinding.getName())) { + this.trackpadSwipeSamplers.put(keyBinding.getName(), new TrackpadSwipeSampler()); + } + + TrackpadSwipeSampler trackpadswipesampler = this.trackpadSwipeSamplers.get(keyBinding.getName()); + trackpadswipesampler.update(controllertype, vrinputaction.getAxis2D(false)); + + if (trackpadswipesampler.isSwipedUp() && upCallback != null) { + this.triggerHapticPulse(controllertype, 0.001F, 400.0F, 0.5F); + upCallback.run(); + } + + if (trackpadswipesampler.isSwipedDown() && downCallback != null) { + this.triggerHapticPulse(controllertype, 0.001F, 400.0F, 0.5F); + downCallback.run(); + } + + if (trackpadswipesampler.isSwipedLeft() && leftCallback != null) { + this.triggerHapticPulse(controllertype, 0.001F, 400.0F, 0.5F); + leftCallback.run(); + } + + if (trackpadswipesampler.isSwipedRight() && rightCallback != null) { + this.triggerHapticPulse(controllertype, 0.001F, 400.0F, 0.5F); + rightCallback.run(); + } + } + } + } + private void addActionParams(Map map, KeyMapping keyBinding, String requirement, String type, VRInputActionSet actionSetOverride) { ActionParams actionparams = new ActionParams(requirement, type, actionSetOverride); map.put(keyBinding.getName(), actionparams); @@ -1174,6 +1291,7 @@ private void addActionParams(Map map, KeyMapping keyBindin public abstract boolean isActive(); + public abstract ControllerType getOriginControllerType(long i); public boolean capFPS() { return false; } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java index baca749ed..228c029bc 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java @@ -55,8 +55,6 @@ public abstract class VRRenderer { protected int dispLastWidth; protected int dispLastHeight; public Matrix4f[] eyeproj = new Matrix4f[2]; - public RenderTarget framebufferEye0; - public RenderTarget framebufferEye1; public RenderTarget framebufferMR; public RenderTarget framebufferUndistorted; public RenderTarget framebufferVrRender; @@ -75,8 +73,6 @@ public abstract class VRRenderer { public int lastRenderDistanceChunks = -1; public long lastWindow = 0L; public float lastWorldScale = 0.0F; - protected int LeftEyeTextureId = -1; - protected int RightEyeTextureId = -1; public int mirrorFBHeight; public int mirrorFBWidth; protected boolean reinitFramebuffers = true; @@ -101,7 +97,7 @@ protected void checkGLError(String message) { } } - public abstract void createRenderTexture(int var1, int var2); + public abstract void createRenderTexture(int var1, int var2) throws RenderConfigException; public abstract Matrix4f getProjectionMatrix(int var1, float var2, float var3); @@ -109,17 +105,8 @@ protected void checkGLError(String message) { public abstract boolean providesStencilMask(); - public void deleteRenderTextures() { - if (this.LeftEyeTextureId > 0) { - RenderSystem.deleteTexture(this.LeftEyeTextureId); - } - - if (this.RightEyeTextureId > 0) { - RenderSystem.deleteTexture(this.RightEyeTextureId); - } - - this.LeftEyeTextureId = this.RightEyeTextureId = -1; - } + public abstract RenderTarget getLeftEyeTarget(); + public abstract RenderTarget getRightEyeTarget(); public void doStencil(boolean inverse) { Minecraft minecraft = Minecraft.getInstance(); @@ -437,7 +424,7 @@ public void resizeFrameBuffers(String cause) { this.resizeFrameBuffers = true; } - public void setupRenderConfiguration() throws Exception { + public void setupRenderConfiguration(boolean render) throws Exception { Minecraft minecraft = Minecraft.getInstance(); ClientDataHolderVR dataholder = ClientDataHolderVR.getInstance(); @@ -529,6 +516,10 @@ public void setupRenderConfiguration() throws Exception { } } + //for OPENXR, it needs to reinit + this.eyeproj[0] = this.getProjectionMatrix(0, ((GameRendererExtension) minecraft.gameRenderer).vivecraft$getMinClipDistance(), ((GameRendererExtension) minecraft.gameRenderer).vivecraft$getClipDistance()); + this.eyeproj[1] = this.getProjectionMatrix(1, ((GameRendererExtension) minecraft.gameRenderer).vivecraft$getMinClipDistance(), ((GameRendererExtension) minecraft.gameRenderer).vivecraft$getClipDistance()); + if (this.reinitFramebuffers) { this.reinitShadersFlag = true; this.checkGLError("Start Init"); @@ -568,30 +559,7 @@ public void setupRenderConfiguration() throws Exception { destroy(); - if (this.LeftEyeTextureId == -1) { - this.createRenderTexture(eyew, eyeh); - - if (this.LeftEyeTextureId == -1) { - throw new RenderConfigException("Failed to initialise stereo rendering plugin: " + this.getName(), Component.literal(this.getLastError())); - } - - dataholder.print("Provider supplied render texture IDs: " + this.LeftEyeTextureId + " " + this.RightEyeTextureId); - dataholder.print("Provider supplied texture resolution: " + eyew + " x " + eyeh); - } - - this.checkGLError("Render Texture setup"); - - if (this.framebufferEye0 == null) { - this.framebufferEye0 = new VRTextureTarget("L Eye", eyew, eyeh, false, false, this.LeftEyeTextureId, false, true, false); - dataholder.print(this.framebufferEye0.toString()); - this.checkGLError("Left Eye framebuffer setup"); - } - - if (this.framebufferEye1 == null) { - this.framebufferEye1 = new VRTextureTarget("R Eye", eyew, eyeh, false, false, this.RightEyeTextureId, false, true, false); - dataholder.print(this.framebufferEye1.toString()); - this.checkGLError("Right Eye framebuffer setup"); - } + this.createRenderTexture(eyew, eyeh); float resolutionScale = ResolutionControlHelper.isLoaded() ? ResolutionControlHelper.getCurrentScaleFactor() : 1.0F; @@ -826,15 +794,5 @@ public void destroy() { this.fsaaLastPassResultFBO.destroyBuffers(); this.fsaaLastPassResultFBO = null; } - - if (this.framebufferEye0 != null) { - this.framebufferEye0.destroyBuffers(); - this.framebufferEye0 = null; - } - - if (this.framebufferEye1 != null) { - this.framebufferEye1.destroyBuffers(); - this.framebufferEye1 = null; - } } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/HapticMusicPlayer.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/HapticMusicPlayer.java similarity index 77% rename from common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/HapticMusicPlayer.java rename to common/src/main/java/org/vivecraft/client_vr/provider/control/HapticMusicPlayer.java index 27cb7081e..33859b11b 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/HapticMusicPlayer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/HapticMusicPlayer.java @@ -1,7 +1,7 @@ -package org.vivecraft.client_vr.provider.openvr_lwjgl.control; +package org.vivecraft.client_vr.provider.control; +import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.provider.ControllerType; -import org.vivecraft.client_vr.provider.openvr_lwjgl.MCOpenVR; import javax.annotation.Nullable; import java.util.HashMap; @@ -62,10 +62,10 @@ public void play() { if (object instanceof Note hapticmusicplayer$music$note) { if (hapticmusicplayer$music$note.controller != null) { - MCOpenVR.get().triggerHapticPulse(hapticmusicplayer$music$note.controller, hapticmusicplayer$music$note.durationSeconds, hapticmusicplayer$music$note.frequency, hapticmusicplayer$music$note.amplitude, f); + ClientDataHolderVR.getInstance().vr.triggerHapticPulse(hapticmusicplayer$music$note.controller, hapticmusicplayer$music$note.durationSeconds, hapticmusicplayer$music$note.frequency, hapticmusicplayer$music$note.amplitude, f); } else { - MCOpenVR.get().triggerHapticPulse(ControllerType.RIGHT, hapticmusicplayer$music$note.durationSeconds, hapticmusicplayer$music$note.frequency, hapticmusicplayer$music$note.amplitude, f); - MCOpenVR.get().triggerHapticPulse(ControllerType.LEFT, hapticmusicplayer$music$note.durationSeconds, hapticmusicplayer$music$note.frequency, hapticmusicplayer$music$note.amplitude, f); + ClientDataHolderVR.getInstance().vr.get().triggerHapticPulse(ControllerType.RIGHT, hapticmusicplayer$music$note.durationSeconds, hapticmusicplayer$music$note.frequency, hapticmusicplayer$music$note.amplitude, f); + ClientDataHolderVR.getInstance().vr.get().triggerHapticPulse(ControllerType.LEFT, hapticmusicplayer$music$note.durationSeconds, hapticmusicplayer$music$note.frequency, hapticmusicplayer$music$note.amplitude, f); } } else if (object instanceof Delay hapticmusicplayer$music$delay) { f += hapticmusicplayer$music$delay.durationSeconds; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/TrackpadSwipeSampler.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java similarity index 88% rename from common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/TrackpadSwipeSampler.java rename to common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java index fd581e0b5..0c3079d62 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/TrackpadSwipeSampler.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java @@ -1,8 +1,8 @@ -package org.vivecraft.client_vr.provider.openvr_lwjgl.control; +package org.vivecraft.client_vr.provider.control; import org.vivecraft.client.VivecraftVRMod; +import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.provider.ControllerType; -import org.vivecraft.client_vr.provider.openvr_lwjgl.MCOpenVR; import org.vivecraft.common.utils.lwjgl.Vector2f; import org.vivecraft.common.utils.math.Vector2; @@ -25,9 +25,9 @@ public TrackpadSwipeSampler() { } public void update(ControllerType hand, Vector2 position) { - MCOpenVR.get().getInputAction(VivecraftVRMod.INSTANCE.keyTrackpadTouch).setCurrentHand(hand); + ClientDataHolderVR.getInstance().vr.getInputAction(VivecraftVRMod.INSTANCE.keyTrackpadTouch).setCurrentHand(hand); - if (MCOpenVR.get().getInputAction(VivecraftVRMod.INSTANCE.keyTrackpadTouch).isButtonPressed()) { + if (ClientDataHolderVR.getInstance().vr.getInputAction(VivecraftVRMod.INSTANCE.keyTrackpadTouch).isButtonPressed()) { this.buffer[this.index].set(position.getX(), position.getY()); if (++this.index >= this.buffer.length) { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/VRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java similarity index 96% rename from common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/VRInputAction.java rename to common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java index 0dca0469d..5da8cf5d0 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/VRInputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java @@ -1,13 +1,12 @@ -package org.vivecraft.client_vr.provider.openvr_lwjgl; +package org.vivecraft.client_vr.provider.control; import com.mojang.blaze3d.platform.InputConstants; import net.minecraft.client.KeyMapping; import org.vivecraft.client.VivecraftVRMod; +import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.provider.ControllerType; import org.vivecraft.client_vr.provider.HandedKeyBinding; import org.vivecraft.client_vr.provider.InputSimulator; -import org.vivecraft.client_vr.provider.MCVR; -import org.vivecraft.client_vr.provider.openvr_lwjgl.control.VRInputActionSet; import org.vivecraft.common.utils.math.Vector2; import org.vivecraft.common.utils.math.Vector3; @@ -219,17 +218,17 @@ public VRInputAction setPriority(int priority) { public boolean isEnabled() { if (!this.isEnabledRaw(this.currentHand)) { return false; - } else if (MCOpenVR.get() == null) { + } else if (ClientDataHolderVR.getInstance().vr == null) { return false; } else { long i = this.getLastOrigin(); - ControllerType controllertype = MCOpenVR.get().getOriginControllerType(i); + ControllerType controllertype = ClientDataHolderVR.getInstance().vr.getOriginControllerType(i); if (controllertype == null && this.isHanded()) { return false; } else { - for (VRInputAction vrinputaction : MCOpenVR.get().getInputActions()) { - if (vrinputaction != this && vrinputaction.isEnabledRaw(controllertype) && vrinputaction.isActive() && vrinputaction.getPriority() > this.getPriority() && MCVR.get().getOrigins(vrinputaction).contains(i)) { + for (VRInputAction vrinputaction : ClientDataHolderVR.getInstance().vr.getInputActions()) { + if (vrinputaction != this && vrinputaction.isEnabledRaw(controllertype) && vrinputaction.isActive() && vrinputaction.getPriority() > this.getPriority() && ClientDataHolderVR.getInstance().vr.getOrigins(vrinputaction).contains(i)) { if (vrinputaction.isHanded()) { return !((HandedKeyBinding) vrinputaction.keyBinding).isPriorityOnController(controllertype); } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VRInputActionSet.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputActionSet.java similarity index 96% rename from common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VRInputActionSet.java rename to common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputActionSet.java index b99331369..7cdec10d8 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VRInputActionSet.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputActionSet.java @@ -1,4 +1,4 @@ -package org.vivecraft.client_vr.provider.openvr_lwjgl.control; +package org.vivecraft.client_vr.provider.control; import net.minecraft.client.KeyMapping; import org.vivecraft.client.VivecraftVRMod; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/VivecraftMovementInput.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/VivecraftMovementInput.java new file mode 100644 index 000000000..79de67246 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/VivecraftMovementInput.java @@ -0,0 +1,11 @@ +package org.vivecraft.client_vr.provider.control; + +import net.minecraft.client.KeyMapping; +import org.vivecraft.client_vr.ClientDataHolderVR; + +public class VivecraftMovementInput { + public static float getMovementAxisValue(KeyMapping keyBinding) { + VRInputAction vrinputaction = ClientDataHolderVR.getInstance().vr.getInputAction(keyBinding); + return Math.abs(vrinputaction.getAxis1DUseTracked()); + } +} 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 09ff0186b..e01ebb089 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 @@ -12,7 +12,7 @@ import org.vivecraft.client_vr.provider.ControllerType; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.VRRenderer; -import org.vivecraft.client_vr.provider.openvr_lwjgl.VRInputAction; +import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.common.utils.math.Matrix4f; import java.util.List; @@ -195,6 +195,11 @@ public boolean isActive() { return vrActive; } + @Override + public ControllerType getOriginControllerType(long i) { + return ControllerType.LEFT; + } + @Override public boolean capFPS() { return true; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRStereoRenderer.java index b8d020266..74c847c87 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRStereoRenderer.java @@ -1,16 +1,27 @@ package org.vivecraft.client_vr.provider.nullvr; +import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.TextureUtil; import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.network.chat.Component; import net.minecraft.util.Tuple; import org.joml.Matrix4f; import org.lwjgl.opengl.GL11; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.VRTextureTarget; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.VRRenderer; +import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.render.RenderPass; public class NullVRStereoRenderer extends VRRenderer { + + protected int LeftEyeTextureId = -1; + protected int RightEyeTextureId = -1; + public RenderTarget framebufferEye0; + public RenderTarget framebufferEye1; + public NullVRStereoRenderer(MCVR vr) { super(vr); } @@ -40,7 +51,7 @@ public String getLastError() { } @Override - public void createRenderTexture(int lwidth, int lheight) { + public void createRenderTexture(int lwidth, int lheight) throws RenderConfigException { this.LeftEyeTextureId = GlStateManager._genTexture(); int i = GlStateManager._getInteger(GL11.GL_TEXTURE_BINDING_2D); RenderSystem.bindTexture(this.LeftEyeTextureId); @@ -56,6 +67,25 @@ public void createRenderTexture(int lwidth, int lheight) { RenderSystem.texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); GlStateManager._texImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, lwidth, lheight, 0, GL11.GL_RGBA, GL11.GL_INT, null); RenderSystem.bindTexture(i); + + ClientDataHolderVR dataholder = ClientDataHolderVR.getInstance(); + if (this.LeftEyeTextureId == -1) { + throw new RenderConfigException("Failed to initialise stereo rendering plugin: " + this.getName(), Component.literal(this.getLastError())); + } + + this.checkGLError("Render Texture setup"); + + if (this.framebufferEye0 == null) { + this.framebufferEye0 = new VRTextureTarget("L Eye", lwidth, lheight, false, false, this.LeftEyeTextureId, false, true, false); + dataholder.print(this.framebufferEye0.toString()); + this.checkGLError("Left Eye framebuffer setup"); + } + + if (this.framebufferEye1 == null) { + this.framebufferEye1 = new VRTextureTarget("R Eye", lwidth, lheight, false, false, this.RightEyeTextureId, false, true, false); + dataholder.print(this.framebufferEye1.toString()); + this.checkGLError("Right Eye framebuffer setup"); + } } @Override @@ -67,6 +97,16 @@ public boolean providesStencilMask() { return false; } + @Override + public RenderTarget getLeftEyeTarget() { + return framebufferEye0; + } + + @Override + public RenderTarget getRightEyeTarget() { + return framebufferEye1; + } + @Override public float[] getStencilMask(RenderPass eye) { @@ -91,6 +131,15 @@ public String getinitError() { @Override public void destroy() { super.destroy(); + if (this.framebufferEye0 != null) { + this.framebufferEye0.destroyBuffers(); + this.framebufferEye0 = null; + } + + if (this.framebufferEye1 != null) { + this.framebufferEye1.destroyBuffers(); + this.framebufferEye1 = null; + } if (this.LeftEyeTextureId > -1) { TextureUtil.releaseTextureId(this.LeftEyeTextureId); this.LeftEyeTextureId = -1; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index 6c967a0fe..5e466cc39 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -24,8 +24,9 @@ import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler; import org.vivecraft.client_vr.provider.*; -import org.vivecraft.client_vr.provider.openvr_lwjgl.control.TrackpadSwipeSampler; -import org.vivecraft.client_vr.provider.openvr_lwjgl.control.VRInputActionSet; +import org.vivecraft.client_vr.provider.control.TrackpadSwipeSampler; +import org.vivecraft.client_vr.provider.control.VRInputAction; +import org.vivecraft.client_vr.provider.control.VRInputActionSet; import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.settings.VRHotkeys; import org.vivecraft.client_vr.settings.VRSettings; @@ -76,7 +77,6 @@ public class MCOpenVR extends MCVR { private final IntBuffer hmdErrorStore = MemoryUtil.memCallocInt(1); private IntBuffer hmdErrorStoreBuf; private TrackedDevicePose.Buffer hmdTrackedDevicePoses; - private boolean inputInitialized; private long leftControllerHandle; private long leftHapticHandle; private long leftPoseHandle; @@ -87,7 +87,6 @@ public class MCOpenVR extends MCVR { private long rightHapticHandle; private long rightPoseHandle; private final VRTextureBounds texBounds = VRTextureBounds.calloc(); - private final Map trackpadSwipeSamplers = new HashMap<>(); private boolean tried; private final Queue vrEvents = new LinkedList<>(); final Texture texType0 = Texture.calloc(); @@ -367,51 +366,6 @@ public void poll(long frameIndex) { } } - public void processInputs() { - if (!this.dh.vrSettings.seated && !ClientDataHolderVR.viewonly && this.inputInitialized) { - for (VRInputAction vrinputaction : this.inputActions.values()) { - if (vrinputaction.isHanded()) { - for (ControllerType controllertype : ControllerType.values()) { - vrinputaction.setCurrentHand(controllertype); - this.processInputAction(vrinputaction); - } - } else { - this.processInputAction(vrinputaction); - } - } - - this.processScrollInput(GuiHandler.keyScrollAxis, () -> - { - InputSimulator.scrollMouse(0.0D, 1.0D); - }, () -> - { - InputSimulator.scrollMouse(0.0D, -1.0D); - }); - this.processScrollInput(VivecraftVRMod.INSTANCE.keyHotbarScroll, () -> - { - this.changeHotbar(-1); - }, () -> - { - this.changeHotbar(1); - }); - this.processSwipeInput(VivecraftVRMod.INSTANCE.keyHotbarSwipeX, () -> - { - this.changeHotbar(1); - }, () -> - { - this.changeHotbar(-1); - }, null, null); - this.processSwipeInput(VivecraftVRMod.INSTANCE.keyHotbarSwipeY, null, null, () -> - { - this.changeHotbar(-1); - }, () -> - { - this.changeHotbar(1); - }); - this.ignorePressesNextFrame = false; - } - } - @Deprecated protected void triggerBindingHapticPulse(KeyMapping binding, int duration) { ControllerType controllertype = this.findActiveBindingControllerType(binding); @@ -1002,76 +956,6 @@ private void pollVREvents() { } } - private void processInputAction(VRInputAction action) { - if (action.isActive() && action.isEnabledRaw() - // try to prevent double left clicks - && (!ClientDataHolderVR.getInstance().vrSettings.ingameBindingsInGui - || !(action.actionSet == VRInputActionSet.INGAME && action.keyBinding.key.getType() == InputConstants.Type.MOUSE && action.keyBinding.key.getValue() == 0 && mc.screen != null))) { - if (action.isButtonChanged()) { - if (action.isButtonPressed() && action.isEnabled()) { - if (!this.ignorePressesNextFrame) { - action.pressBinding(); - } - } else { - action.unpressBinding(); - } - } - } else { - action.unpressBinding(); - } - } - - private void processScrollInput(KeyMapping keyBinding, Runnable upCallback, Runnable downCallback) { - VRInputAction vrinputaction = this.getInputAction(keyBinding); - - if (vrinputaction.isEnabled() && vrinputaction.getLastOrigin() != 0L && vrinputaction.getAxis2D(true).getY() != 0.0F) { - float f = vrinputaction.getAxis2D(false).getY(); - - if (f > 0.0F) { - upCallback.run(); - } else if (f < 0.0F) { - downCallback.run(); - } - } - } - - private void processSwipeInput(KeyMapping keyBinding, Runnable leftCallback, Runnable rightCallback, Runnable upCallback, Runnable downCallback) { - VRInputAction vrinputaction = this.getInputAction(keyBinding); - - if (vrinputaction.isEnabled() && vrinputaction.getLastOrigin() != 0L) { - ControllerType controllertype = this.findActiveBindingControllerType(keyBinding); - - if (controllertype != null) { - if (!this.trackpadSwipeSamplers.containsKey(keyBinding.getName())) { - this.trackpadSwipeSamplers.put(keyBinding.getName(), new TrackpadSwipeSampler()); - } - - TrackpadSwipeSampler trackpadswipesampler = this.trackpadSwipeSamplers.get(keyBinding.getName()); - trackpadswipesampler.update(controllertype, vrinputaction.getAxis2D(false)); - - if (trackpadswipesampler.isSwipedUp() && upCallback != null) { - this.triggerHapticPulse(controllertype, 0.001F, 400.0F, 0.5F); - upCallback.run(); - } - - if (trackpadswipesampler.isSwipedDown() && downCallback != null) { - this.triggerHapticPulse(controllertype, 0.001F, 400.0F, 0.5F); - downCallback.run(); - } - - if (trackpadswipesampler.isSwipedLeft() && leftCallback != null) { - this.triggerHapticPulse(controllertype, 0.001F, 400.0F, 0.5F); - leftCallback.run(); - } - - if (trackpadswipesampler.isSwipedRight() && rightCallback != null) { - this.triggerHapticPulse(controllertype, 0.001F, 400.0F, 0.5F); - rightCallback.run(); - } - } - } - } - private void processVREvents() { while (!this.vrEvents.isEmpty()) { VREvent vrevent = this.vrEvents.poll(); @@ -1272,7 +1156,7 @@ long getInputSourceHandle(String path) { } } - ControllerType getOriginControllerType(long inputValueHandle) { + public ControllerType getOriginControllerType(long inputValueHandle) { if (inputValueHandle == 0L) { return null; } else { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java index 1d386114e..8b31b1875 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java @@ -1,5 +1,6 @@ package org.vivecraft.client_vr.provider.openvr_lwjgl; +import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.TextureUtil; import com.mojang.blaze3d.systems.RenderSystem; @@ -14,7 +15,8 @@ import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; import org.vivecraft.client.utils.Utils; -import org.vivecraft.client_vr.provider.MCVR; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.VRTextureTarget; import org.vivecraft.client_vr.provider.VRRenderer; import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.render.RenderPass; @@ -26,10 +28,14 @@ public class OpenVRStereoRenderer extends VRRenderer { private final HiddenAreaMesh[] hiddenMeshes = new HiddenAreaMesh[2]; private final MCOpenVR openvr; + protected int LeftEyeTextureId = -1; + protected int RightEyeTextureId = -1; + public RenderTarget framebufferEye0; + public RenderTarget framebufferEye1; - public OpenVRStereoRenderer(MCVR vr) { + public OpenVRStereoRenderer(MCOpenVR vr) { super(vr); - this.openvr = (MCOpenVR) vr; + this.openvr = vr; hiddenMeshes[0] = HiddenAreaMesh.calloc(); hiddenMeshes[1] = HiddenAreaMesh.calloc(); } @@ -85,7 +91,7 @@ public String getLastError() { return ""; } - public void createRenderTexture(int lwidth, int lheight) { + public void createRenderTexture(int lwidth, int lheight) throws RenderConfigException { this.LeftEyeTextureId = GlStateManager._genTexture(); int i = GlStateManager._getInteger(GL11.GL_TEXTURE_BINDING_2D); RenderSystem.bindTexture(this.LeftEyeTextureId); @@ -107,6 +113,25 @@ public void createRenderTexture(int lwidth, int lheight) { this.openvr.texType1.handle(this.RightEyeTextureId); this.openvr.texType1.eColorSpace(VR.EColorSpace_ColorSpace_Gamma); this.openvr.texType1.eType(VR.ETextureType_TextureType_OpenGL); + + ClientDataHolderVR dataholder = ClientDataHolderVR.getInstance(); + if (this.LeftEyeTextureId == -1) { + throw new RenderConfigException("Failed to initialise stereo rendering plugin: " + this.getName(), Component.literal(this.getLastError())); + } + + this.checkGLError("Render Texture setup"); + + if (this.framebufferEye0 == null) { + this.framebufferEye0 = new VRTextureTarget("L Eye", lwidth, lheight, false, false, this.LeftEyeTextureId, false, true, false); + dataholder.print(this.framebufferEye0.toString()); + this.checkGLError("Left Eye framebuffer setup"); + } + + if (this.framebufferEye1 == null) { + this.framebufferEye1 = new VRTextureTarget("R Eye", lwidth, lheight, false, false, this.RightEyeTextureId, false, true, false); + dataholder.print(this.framebufferEye1.toString()); + this.checkGLError("Right Eye framebuffer setup"); + } } public boolean endFrame(RenderPass eye) { @@ -169,6 +194,16 @@ public boolean providesStencilMask() { return true; } + @Override + public RenderTarget getLeftEyeTarget() { + return framebufferEye0; + } + + @Override + public RenderTarget getRightEyeTarget() { + return framebufferEye1; + } + public float[] getStencilMask(RenderPass eye) { if (this.hiddenMesheVertecies != null && (eye == RenderPass.LEFT || eye == RenderPass.RIGHT)) { return eye == RenderPass.LEFT ? this.hiddenMesheVertecies[0] : this.hiddenMesheVertecies[1]; @@ -192,6 +227,15 @@ public String getinitError() { @Override public void destroy() { super.destroy(); + if (this.framebufferEye0 != null) { + this.framebufferEye0.destroyBuffers(); + this.framebufferEye0 = null; + } + + if (this.framebufferEye1 != null) { + this.framebufferEye1.destroyBuffers(); + this.framebufferEye1 = null; + } if (this.LeftEyeTextureId > -1) { TextureUtil.releaseTextureId(this.LeftEyeTextureId); this.LeftEyeTextureId = -1; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VivecraftMovementInput.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VivecraftMovementInput.java deleted file mode 100644 index e61de8da0..000000000 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VivecraftMovementInput.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.vivecraft.client_vr.provider.openvr_lwjgl.control; - -import net.minecraft.client.KeyMapping; -import org.vivecraft.client_vr.provider.MCVR; -import org.vivecraft.client_vr.provider.openvr_lwjgl.VRInputAction; - -public class VivecraftMovementInput { - public static float getMovementAxisValue(KeyMapping keyBinding) { - VRInputAction vrinputaction = MCVR.get().getInputAction(keyBinding); - return Math.abs(vrinputaction.getAxis1DUseTracked()); - } -} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java new file mode 100644 index 000000000..90444000a --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -0,0 +1,1494 @@ +package org.vivecraft.client_vr.provider.openxr; + +import com.mojang.blaze3d.platform.Window; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; +import org.apache.commons.lang3.tuple.Pair; +import org.joml.Vector2f; +import org.lwjgl.PointerBuffer; +import org.lwjgl.glfw.*; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL21; +import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GL31; +import org.lwjgl.openxr.*; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.Platform; +import org.lwjgl.system.Struct; +import org.lwjgl.system.linux.X11; +import org.lwjgl.system.windows.User32; +import org.vivecraft.client.VivecraftVRMod; +import org.vivecraft.client.utils.Utils; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; +import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler; +import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.InputSimulator; +import org.vivecraft.client_vr.provider.MCVR; +import org.vivecraft.client_vr.provider.VRRenderer; +import org.vivecraft.client_vr.provider.control.VRInputAction; +import org.vivecraft.client_vr.provider.control.VRInputActionSet; +import org.vivecraft.client_vr.render.RenderConfigException; +import org.vivecraft.client_vr.render.RenderPass; +import org.vivecraft.client_vr.settings.VRSettings; +import org.vivecraft.client_xr.render_pass.RenderPassManager; +import org.vivecraft.common.utils.lwjgl.Vector3f; +import org.vivecraft.common.utils.math.Matrix4f; +import org.vivecraft.common.utils.math.Vector3; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.nio.LongBuffer; +import java.util.*; + +import static org.lwjgl.opengl.GLX13.*; +import static org.lwjgl.system.MemoryStack.*; +import static org.lwjgl.system.MemoryUtil.*; + +public class MCOpenXR extends MCVR { + + private static MCOpenXR ome; + public XrInstance instance; + public XrSession session; + public XrSpace xrAppSpace; + public XrSpace xrViewSpace; + public XrSwapchain swapchain; + public final XrEventDataBuffer eventDataBuffer = XrEventDataBuffer.calloc(); + public long time; + private boolean tried; + private long systemID; + public XrView.Buffer viewBuffer; + public int width; + public int height; + //TODO either move to MCVR, Or make special for OpenXR holding the instance itself. + private final Map actionSetHandles = new EnumMap<>(VRInputActionSet.class); + //TODO Move to MCVR + private XrActiveActionSet.Buffer activeActionSetsBuffer; + private boolean isActive; + private final HashMap paths = new HashMap<>(); + private final long[] grip = new long[2]; + private final long[] aim = new long[2]; + private final XrSpace[] gripSpace = new XrSpace[2]; + private final XrSpace[] aimSpace = new XrSpace[2]; + public static final XrPosef POSE_IDENTITY = XrPosef.calloc().set( + XrQuaternionf.calloc().set(0, 0, 0, 1), + XrVector3f.calloc() + ); + public boolean shouldRender = true; + public long[] haptics = new long[2]; + public String systemName; + + + public MCOpenXR(Minecraft mc, ClientDataHolderVR dh) { + super(mc, dh, VivecraftVRMod.INSTANCE); + ome = this; + this.hapticScheduler = new OpenXRHapticSchedular(); + + } + + @Override + public String getName() { + return "OpenXR"; + } + + @Override + public String getID() { + return "openxr"; + } + + @Override + public void destroy() { + int error; + //Not sure if we need the action sets one here, as we are shutting down + for (Long inputActionSet : actionSetHandles.values()){ + error = XR10.xrDestroyActionSet(new XrActionSet(inputActionSet, instance)); + logError(error, "xrDestroyActionSet", ""); + } + if (swapchain != null) { + error = XR10.xrDestroySwapchain(swapchain); + logError(error, "xrDestroySwapchain", ""); + } + if (viewBuffer != null) { + viewBuffer.close(); + } + if (xrAppSpace != null) { + error = XR10.xrDestroySpace(xrAppSpace); + logError(error, "xrDestroySpace", "xrAppSpace"); + } + if (xrViewSpace != null) { + error = XR10.xrDestroySpace(xrViewSpace); + logError(error, "xrDestroySpace", "xrViewSpace"); + } + if (session != null){ + error = XR10.xrDestroySession(session); + logError(error, "xrDestroySession", ""); + } + if (instance != null){ + error = XR10.xrDestroyInstance(instance); + logError(error, "xrDestroyInstance", ""); + } + eventDataBuffer.close(); + } + + @Override + protected void triggerBindingHapticPulse(KeyMapping binding, int duration) { + ControllerType controllertype = this.findActiveBindingControllerType(binding); + + if (controllertype != null) { + this.triggerHapticPulse(controllertype, duration); + } + } + + @Override + protected ControllerType findActiveBindingControllerType(KeyMapping binding) { + if (!this.inputInitialized) { + return null; + } else { + long path = this.getInputAction(binding).getLastOrigin(); + try (MemoryStack stack = MemoryStack.stackPush()) { + IntBuffer buf = stack.callocInt(1); + int error = XR10.xrPathToString(instance, path, buf, null); + logError(error, "xrPathToString", "get string length for", binding.getName()); + + int size = buf.get(); + if (size <= 0) { + return null; + } + + buf = stack.callocInt(size); + ByteBuffer byteBuffer = stack.calloc(size); + error = XR10.xrPathToString(instance, path, buf, byteBuffer); + logError(error, "xrPathToString", "get string for", binding.getName()); + byte[] bytes = new byte[byteBuffer.remaining()]; + byteBuffer.get(bytes); + String name = new String(bytes); + if (name.contains("right")) { + return ControllerType.RIGHT; + } + return ControllerType.LEFT; + } + } + } + + @Override + public void poll(long var1) { + if (this.initialized) { + this.mc.getProfiler().push("events"); + //pollVREvents(); + + if (!this.dh.vrSettings.seated) { + this.mc.getProfiler().popPush("controllers"); + this.mc.getProfiler().push("gui"); + + if (this.mc.screen == null && this.dh.vrSettings.vrTouchHotbar) { + + if (this.dh.vrSettings.vrHudLockMode != VRSettings.HUDLock.HEAD && this.hudPopup) { + this.processHotbar(); + } + } + + this.mc.getProfiler().pop(); + } + this.mc.getProfiler().popPush("updatePose/Vsync"); + this.updatePose(); + this.mc.getProfiler().popPush("processInputs"); + this.processInputs(); + this.mc.getProfiler().popPush("hmdSampling"); + this.hmdSampling(); + this.mc.getProfiler().pop(); + } + } + + private void updatePose() { + RenderPassManager.setGUIRenderPass(); + + if (mc == null) { + return; + } + try (MemoryStack stack = MemoryStack.stackPush()) { + XrFrameState frameState = XrFrameState.calloc(stack).type(XR10.XR_TYPE_FRAME_STATE); + + int error = XR10.xrWaitFrame( + session, + XrFrameWaitInfo.calloc(stack).type(XR10.XR_TYPE_FRAME_WAIT_INFO), + frameState); + logError(error, "xrWaitFrame", ""); + + time = frameState.predictedDisplayTime(); + this.shouldRender = frameState.shouldRender(); + + error = XR10.xrBeginFrame( + session, + XrFrameBeginInfo.calloc(stack).type(XR10.XR_TYPE_FRAME_BEGIN_INFO)); + logError(error, "xrBeginFrame", ""); + + + XrViewState viewState = XrViewState.calloc(stack).type(XR10.XR_TYPE_VIEW_STATE); + IntBuffer intBuf = stack.callocInt(1); + + XrViewLocateInfo viewLocateInfo = XrViewLocateInfo.calloc(stack); + viewLocateInfo.set(XR10.XR_TYPE_VIEW_LOCATE_INFO, + 0, + XR10.XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, + frameState.predictedDisplayTime(), + xrAppSpace + ); + + error = XR10.xrLocateViews(session, viewLocateInfo, viewState, intBuf, viewBuffer); + logError(error, "xrLocateViews", ""); + + XrSpaceLocation space_location = XrSpaceLocation.calloc(stack).type(XR10.XR_TYPE_SPACE_LOCATION); + + //HMD pose + error = XR10.xrLocateSpace(xrViewSpace, xrAppSpace, time, space_location); + logError(error, "xrLocateSpace", "xrViewSpace"); + if (error >= 0) { + OpenXRUtil.openXRPoseToMarix(space_location.pose(), this.hmdPose); + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.hmdRotation); + + Vec3 vec3 = new Vec3(space_location.pose().position$().x(), space_location.pose().position$().y(), space_location.pose().position$().z()); + this.hmdHistory.add(vec3); + Vector3 vector3 = this.hmdRotation.transform(new Vector3(0.0F, -0.1F, 0.1F)); + this.hmdPivotHistory.add(new Vec3((double) vector3.getX() + vec3.x, (double) vector3.getY() + vec3.y, (double) vector3.getZ() + vec3.z)); + headIsTracking = true; + } else { + headIsTracking = false; + } + + //Eye positions + OpenXRUtil.openXRPoseToMarix(viewBuffer.get(0).pose(), this.hmdPoseLeftEye); + OpenXRUtil.openXRPoseToMarix(viewBuffer.get(1).pose(), this.hmdPoseRightEye); + + //reverse + if (this.dh.vrSettings.reverseHands) { + XrSpace temp = gripSpace[0]; + gripSpace[0] = gripSpace[1]; + gripSpace[1] = temp; + temp = aimSpace[0]; + aimSpace[0] = aimSpace[1]; + aimSpace[1] = temp; + } + + //Controller aim and grip poses + error = XR10.xrLocateSpace(gripSpace[0], xrAppSpace, time, space_location); + logError(error, "xrLocateSpace", "gripSpace[0]"); + if (error >= 0) { + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.handRotation[0]); + } + + error = XR10.xrLocateSpace(gripSpace[1], xrAppSpace, time, space_location); + logError(error, "xrLocateSpace", "gripSpace[1]"); + if (error >= 0) { + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.handRotation[1]); + } + + error = XR10.xrLocateSpace(aimSpace[0], xrAppSpace, time, space_location); + logError(error, "xrLocateSpace", "aimSpace[0]"); + if (error >= 0) { + OpenXRUtil.openXRPoseToMarix(space_location.pose(), this.controllerPose[0]); + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.controllerRotation[0]); + this.aimSource[0] = new Vec3(space_location.pose().position$().x(), space_location.pose().position$().y(), space_location.pose().position$().z()); + this.controllerHistory[0].add(this.getAimSource(0)); + this.controllerForwardHistory[0].add(this.getAimSource(0)); + Vec3 vec33 = this.controllerRotation[0].transform(this.up).toVector3d(); + this.controllerUpHistory[0].add(vec33); + this.controllerTracking[0] = true; + } else { + this.controllerTracking[0] = false; + } + + error = XR10.xrLocateSpace(aimSpace[1], xrAppSpace, time, space_location); + logError(error, "xrLocateSpace", "aimSpace[1]"); + if (error >= 0) { + OpenXRUtil.openXRPoseToMarix(space_location.pose(), this.controllerPose[1]); + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.controllerRotation[1]); + this.aimSource[1] = new Vec3(space_location.pose().position$().x(), space_location.pose().position$().y(), space_location.pose().position$().z()); + this.controllerHistory[1].add(this.getAimSource(1)); + this.controllerForwardHistory[1].add(this.getAimSource(1)); + Vec3 vec32 = this.controllerRotation[1].transform(this.up).toVector3d(); + this.controllerUpHistory[1].add(vec32); + this.controllerTracking[1] = true; + } else { + this.controllerTracking[1] = false; + } + + //TODO merge with updateAim so it's one method + if (this.dh.vrSettings.seated) { + this.controllerPose[0] = this.hmdPose.inverted().inverted(); + this.controllerPose[1] = this.hmdPose.inverted().inverted(); + this.handRotation[0] = hmdRotation; + this.handRotation[1] = hmdRotation; + this.controllerRotation[0] = hmdRotation; + this.controllerRotation[1] = hmdRotation; + this.aimSource[1] = this.getCenterEyePosition(); + this.aimSource[0] = this.getCenterEyePosition(); + + if (this.mc.screen == null) { + Vec3 vec31 = this.getAimVector(1); + org.vivecraft.common.utils.lwjgl.Matrix4f matrix4f = new org.vivecraft.common.utils.lwjgl.Matrix4f(); + float f = 110.0F; + float f1 = 180.0F; + double d0 = this.mc.mouseHandler.xpos() / (double) this.mc.getWindow().getScreenWidth() * (double) f - (double) (f / 2.0F); + int i = this.mc.getWindow().getScreenHeight(); + + if (i % 2 != 0) { + --i; + } + + double d1 = -this.mc.mouseHandler.ypos() / (double) i * (double) f1 + (double) (f1 / 2.0F); + double d2 = -d1; + + if (this.mc.isWindowActive()) { + float f2 = this.dh.vrSettings.keyholeX; + float f3 = 20.0F * this.dh.vrSettings.xSensitivity; + int j = (int) ((double) (-f2 + f / 2.0F) * (double) this.mc.getWindow().getScreenWidth() / (double) f) + 1; + int k = (int) ((double) (f2 + f / 2.0F) * (double) this.mc.getWindow().getScreenWidth() / (double) f) - 1; + float f4 = ((float) Math.abs(d0) - f2) / (f / 2.0F - f2); + double d3 = this.mc.mouseHandler.xpos(); + + if (d0 < (double) (-f2)) { + this.seatedRot += f3 * f4; + this.seatedRot %= 360.0F; + this.hmdForwardYaw = (float) Math.toDegrees(Math.atan2(vec31.x, vec31.z)); + d3 = j; + d0 = -f2; + } else if (d0 > (double) f2) { + this.seatedRot -= f3 * f4; + this.seatedRot %= 360.0F; + this.hmdForwardYaw = (float) Math.toDegrees(Math.atan2(vec31.x, vec31.z)); + d3 = k; + d0 = f2; + } + + double d4 = 0.5D * (double) this.dh.vrSettings.ySensitivity; + d2 = (double) this.aimPitch + d1 * d4; + d2 = Mth.clamp(d2, -89.9D, 89.9D); + InputSimulator.setMousePos(d3, i / 2); + GLFW.glfwSetCursorPos(this.mc.getWindow().getWindow(), d3, i / 2); + matrix4f.rotate((float) Math.toRadians(-d2), new Vector3f(1.0F, 0.0F, 0.0F)); + matrix4f.rotate((float) Math.toRadians(-180.0D + d0 - (double) this.hmdForwardYaw), new Vector3f(0.0F, 1.0F, 0.0F)); + } + + this.controllerRotation[0].M[0][0] = matrix4f.m00; + this.controllerRotation[0].M[0][1] = matrix4f.m01; + this.controllerRotation[0].M[0][2] = matrix4f.m02; + this.controllerRotation[0].M[1][0] = matrix4f.m10; + this.controllerRotation[0].M[1][1] = matrix4f.m11; + this.controllerRotation[0].M[1][2] = matrix4f.m12; + this.controllerRotation[0].M[2][0] = matrix4f.m20; + this.controllerRotation[0].M[2][1] = matrix4f.m21; + this.controllerRotation[0].M[2][2] = matrix4f.m22; + + this.handRotation[0].M[0][0] = matrix4f.m00; + this.handRotation[0].M[0][1] = matrix4f.m01; + this.handRotation[0].M[0][2] = matrix4f.m02; + this.handRotation[0].M[1][0] = matrix4f.m10; + this.handRotation[0].M[1][1] = matrix4f.m11; + this.handRotation[0].M[1][2] = matrix4f.m12; + this.handRotation[0].M[2][0] = matrix4f.m20; + this.handRotation[0].M[2][1] = matrix4f.m21; + this.handRotation[0].M[2][2] = matrix4f.m22; + } + } + Vec3 vec32 = this.getAimVector(0); + this.aimPitch = (float) Math.toDegrees(Math.asin(vec32.y / vec32.length())); + + if (this.inputInitialized) { + this.mc.getProfiler().push("updateActionState"); + + if (this.updateActiveActionSets()) { + XrActionsSyncInfo syncInfo = XrActionsSyncInfo.calloc(stack) + .type(XR10.XR_TYPE_ACTIONS_SYNC_INFO) + .activeActionSets(activeActionSetsBuffer); + error = XR10.xrSyncActions(session, syncInfo); + logError(error, "xrSyncActions", ""); + } + + this.inputActions.values().forEach(this::readNewData); + + //TODO Not needed it seems? Poses come from the action space + XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); + this.readPoseData(this.grip[0], actionSet); + this.readPoseData(this.grip[1], actionSet); + this.readPoseData(this.aim[0], actionSet); + this.readPoseData(this.aim[1], actionSet); + + this.mc.getProfiler().pop(); + } + } + } + + @Override + public Vec3 getEyePosition(RenderPass eye) { + org.vivecraft.common.utils.math.Matrix4f matrix4f = null; + + if (eye == RenderPass.LEFT) { + matrix4f = this.hmdPoseLeftEye; + } else if (eye == RenderPass.RIGHT) { + matrix4f = this.hmdPoseRightEye; + } + + if (matrix4f == null) { + org.vivecraft.common.utils.math.Matrix4f matrix4f2 = this.hmdPose; + Vector3 vector31 = Utils.convertMatrix4ftoTranslationVector(matrix4f2); + + if (this.dh.vrSettings.seated || this.dh.vrSettings.allowStandingOriginOffset) { + if (this.dh.vr.isHMDTracking()) { + vector31 = vector31.add(this.dh.vrSettings.originOffset); + } + } + + return vector31.toVector3d(); + } else { + Vector3 vector3 = Utils.convertMatrix4ftoTranslationVector(matrix4f); + + if (this.dh.vrSettings.seated || this.dh.vrSettings.allowStandingOriginOffset) { + if (this.dh.vr.isHMDTracking()) { + vector3 = vector3.add(this.dh.vrSettings.originOffset); + } + } + + return vector3.toVector3d(); + } + } + + @Override + public org.vivecraft.common.utils.math.Matrix4f getEyeRotation(RenderPass eye) { + org.vivecraft.common.utils.math.Matrix4f matrix4f; + + if (eye == RenderPass.LEFT) { + matrix4f = this.hmdPoseLeftEye; + } else if (eye == RenderPass.RIGHT) { + matrix4f = this.hmdPoseRightEye; + } else { + matrix4f = null; + } + + if (matrix4f != null) { + org.vivecraft.common.utils.math.Matrix4f matrix4f1 = new org.vivecraft.common.utils.math.Matrix4f(); + matrix4f1.M[0][0] = matrix4f.M[0][0]; + matrix4f1.M[0][1] = matrix4f.M[0][1]; + matrix4f1.M[0][2] = matrix4f.M[0][2]; + matrix4f1.M[0][3] = 0.0F; + matrix4f1.M[1][0] = matrix4f.M[1][0]; + matrix4f1.M[1][1] = matrix4f.M[1][1]; + matrix4f1.M[1][2] = matrix4f.M[1][2]; + matrix4f1.M[1][3] = 0.0F; + matrix4f1.M[2][0] = matrix4f.M[2][0]; + matrix4f1.M[2][1] = matrix4f.M[2][1]; + matrix4f1.M[2][2] = matrix4f.M[2][2]; + matrix4f1.M[2][3] = 0.0F; + matrix4f1.M[3][0] = 0.0F; + matrix4f1.M[3][1] = 0.0F; + matrix4f1.M[3][2] = 0.0F; + matrix4f1.M[3][3] = 1.0F; + return matrix4f1; + } else { + return this.hmdRotation; + } + } + + public void readNewData(VRInputAction action) { + String s = action.type; + + switch (s) { + case "boolean": + if (action.isHanded()) { + for (ControllerType controllertype1 : ControllerType.values()) { + this.readBoolean(action, controllertype1); + } + } else { + this.readBoolean(action, null); + } + + break; + + case "vector1": + if (action.isHanded()) { + for (ControllerType controllertype : ControllerType.values()) { + this.readFloat(action, controllertype); + } + } else { + this.readFloat(action, null); + } + break; + + case "vector2": + if (action.isHanded()) { + for (ControllerType controllertype : ControllerType.values()) { + this.readVecData(action, controllertype); + } + } else { + this.readVecData(action, null); + } + break; + + case "vector3": + + } + } + + private void readBoolean(VRInputAction action, ControllerType hand) { + int i = 0; + + if (hand != null) { + i = hand.ordinal(); + } + try (MemoryStack stack = MemoryStack.stackPush()){ + XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); + info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); + info.action(new XrAction(action.handle, new XrActionSet(actionSetHandles.get(action.actionSet), instance))); + XrActionStateBoolean state = XrActionStateBoolean.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_BOOLEAN); + int error = XR10.xrGetActionStateBoolean(session, info, state); + logError(error, "xrGetActionStateBoolean", action.name); + + action.digitalData[i].state = state.currentState(); + action.digitalData[i].isActive = state.isActive(); + action.digitalData[i].isChanged = state.changedSinceLastSync(); + action.digitalData[i].activeOrigin = getOrigins(action).get(0); + } + } + + private void readFloat(VRInputAction action, ControllerType hand) { + int i = 0; + + if (hand != null) { + i = hand.ordinal(); + } + try (MemoryStack stack = MemoryStack.stackPush()){ + XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); + info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); + info.action(new XrAction(action.handle, new XrActionSet(actionSetHandles.get(action.actionSet), instance))); + XrActionStateFloat state = XrActionStateFloat.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_FLOAT); + int error = XR10.xrGetActionStateFloat(session, info, state); + logError(error, "xrGetActionStateFloat", action.name); + + action.analogData[i].deltaX = action.analogData[i].x - state.currentState(); + action.analogData[i].x = state.currentState(); + action.analogData[i].activeOrigin = getOrigins(action).get(0); + action.analogData[i].isActive = state.isActive(); + action.analogData[i].isChanged = state.changedSinceLastSync(); + } + } + + private void readVecData(VRInputAction action, ControllerType hand) { + int i = 0; + + if (hand != null) { + i = hand.ordinal(); + } + try (MemoryStack stack = MemoryStack.stackPush()){ + XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); + info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); + info.action(new XrAction(action.handle, new XrActionSet(actionSetHandles.get(action.actionSet), instance))); + XrActionStateVector2f state = XrActionStateVector2f.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_VECTOR2F); + int error = XR10.xrGetActionStateVector2f(session, info, state); + logError(error, "xrGetActionStateVector2f", action.name); + + action.analogData[i].deltaX = action.analogData[i].x - state.currentState().x(); + action.analogData[i].deltaY = action.analogData[i].y - state.currentState().y(); + action.analogData[i].x = state.currentState().x(); + action.analogData[i].y = state.currentState().y(); + action.analogData[i].activeOrigin = getOrigins(action).get(0); + action.analogData[i].isActive = state.isActive(); + action.analogData[i].isChanged = state.changedSinceLastSync(); + } + } + + private void readPoseData(Long action, XrActionSet set) { + try (MemoryStack stack = MemoryStack.stackPush()){ + XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); + info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); + info.action(new XrAction(action, set)); + XrActionStatePose state = XrActionStatePose.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_POSE); + int error = XR10.xrGetActionStatePose(session, info, state); + logError(error, "xrGetActionStatePose", ""); + } + } + + private boolean updateActiveActionSets() { + ArrayList arraylist = new ArrayList<>(); + arraylist.add(VRInputActionSet.GLOBAL); + + // we are always modded + arraylist.add(VRInputActionSet.MOD); + + arraylist.add(VRInputActionSet.MIXED_REALITY); + arraylist.add(VRInputActionSet.TECHNICAL); + + if (this.mc.screen == null) { + arraylist.add(VRInputActionSet.INGAME); + arraylist.add(VRInputActionSet.CONTEXTUAL); + } else { + arraylist.add(VRInputActionSet.GUI); + if (ClientDataHolderVR.getInstance().vrSettings.ingameBindingsInGui) { + arraylist.add(VRInputActionSet.INGAME); + } + } + + if (KeyboardHandler.Showing || RadialHandler.isShowing()) { + arraylist.add(VRInputActionSet.KEYBOARD); + } + + if (this.activeActionSetsBuffer == null) { + activeActionSetsBuffer = XrActiveActionSet.calloc(arraylist.size()); + } else if (activeActionSetsBuffer.capacity() != arraylist.size()) { + activeActionSetsBuffer.close(); + activeActionSetsBuffer = XrActiveActionSet.calloc(arraylist.size()); + } + + for (int i = 0; i < arraylist.size(); ++i) { + VRInputActionSet vrinputactionset = arraylist.get(i); + activeActionSetsBuffer.get(i).set(new XrActionSet(this.getActionSetHandle(vrinputactionset), instance), NULL); + } + + return !arraylist.isEmpty(); + } + + private void updateControllerPose(int controller, long actionHandle) { + + } + + long getActionSetHandle(VRInputActionSet actionSet) { + return this.actionSetHandles.get(actionSet); + } + + private void pollVREvents() { + while (true) { + eventDataBuffer.clear(); + eventDataBuffer.type(XR10.XR_TYPE_EVENT_DATA_BUFFER); + int error = XR10.xrPollEvent(instance, eventDataBuffer); + logError(error, "xrPollEvent", ""); + if (error != XR10.XR_SUCCESS) { + break; + } + XrEventDataBaseHeader event = XrEventDataBaseHeader.create(eventDataBuffer.address()); + + switch (event.type()) { + case XR10.XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING -> { + XrEventDataInstanceLossPending instanceLossPending = XrEventDataInstanceLossPending.create(event.address()); + } + case XR10.XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED -> { + this.sessionChanged(XrEventDataSessionStateChanged.create(event.address())); + } + case XR10.XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED -> { + } + case XR10.XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING -> { + } + default -> { + } + } + } + } + + private void sessionChanged(XrEventDataSessionStateChanged xrEventDataSessionStateChanged) { + int state = xrEventDataSessionStateChanged.state(); + + switch (state) { + case XR10.XR_SESSION_STATE_READY: { + try (MemoryStack stack = MemoryStack.stackPush()){ + XrSessionBeginInfo sessionBeginInfo = XrSessionBeginInfo.calloc(stack); + sessionBeginInfo.type(XR10.XR_TYPE_SESSION_BEGIN_INFO); + sessionBeginInfo.next(NULL); + sessionBeginInfo.primaryViewConfigurationType(XR10.XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO); + + int error = XR10.xrBeginSession(session, sessionBeginInfo); + logError(error, "xrBeginSession", "XR_SESSION_STATE_READY"); + } + this.isActive = true; + break; + } + case XR10.XR_SESSION_STATE_STOPPING: { + this.isActive = false; + int error = XR10.xrEndSession(session); + logError(error, "xrEndSession", "XR_SESSION_STATE_STOPPING"); + } + case XR10.XR_SESSION_STATE_VISIBLE, XR10.XR_SESSION_STATE_FOCUSED: { + this.isActive = true; + break; + } + case XR10.XR_SESSION_STATE_EXITING, XR10.XR_SESSION_STATE_IDLE, XR10.XR_SESSION_STATE_SYNCHRONIZED: { + this.isActive = false; + break; + } + case XR10.XR_SESSION_STATE_LOSS_PENDING: { + break; + } + default: + break; + } + } + + @Override + public Vector2f getPlayAreaSize() { + try (MemoryStack stack = MemoryStack.stackPush()) { + XrExtent2Df vec = XrExtent2Df.calloc(stack); + int error = XR10.xrGetReferenceSpaceBoundsRect(session, XR10.XR_REFERENCE_SPACE_TYPE_STAGE, vec); + logError(error, "xrGetReferenceSpaceBoundsRect", ""); + return new Vector2f(vec.width(), vec.height()); + } + } + + @Override + public boolean init() { + if (this.initialized) { + return true; + } else if (this.tried) { + return this.initialized; + } else { + tried = true; + this.mc = Minecraft.getInstance(); + try { + this.initializeOpenXRInstance(); + this.initializeOpenXRSession(); + this.initializeOpenXRSpace(); + this.initializeOpenXRSwapChain(); + } catch (Exception e) { + e.printStackTrace(); + this.initSuccess = false; + this.initStatus = e.getLocalizedMessage(); + return false; + } + + //TODO Seated when no controllers + + System.out.println("OpenXR initialized & VR connected."); + this.deviceVelocity = new Vec3[64]; + + for (int i = 0; i < this.poseMatrices.length; ++i) { + this.poseMatrices[i] = new Matrix4f(); + this.deviceVelocity[i] = new Vec3(0.0D, 0.0D, 0.0D); + } + + this.initialized = true; + return true; + } + } + + private void initializeOpenXRInstance() { + try (MemoryStack stack = MemoryStack.stackPush()) { + + //Check extensions + IntBuffer numExtensions = stack.callocInt(1); + int error = XR10.xrEnumerateInstanceExtensionProperties((ByteBuffer) null, numExtensions, null); + logError(error, "xrEnumerateInstanceExtensionProperties", "get count"); + + XrExtensionProperties.Buffer properties = new XrExtensionProperties.Buffer( + bufferStack(numExtensions.get(0), XrExtensionProperties.SIZEOF, XR10.XR_TYPE_EXTENSION_PROPERTIES) + ); + + //Load extensions + error = XR10.xrEnumerateInstanceExtensionProperties((ByteBuffer) null, numExtensions, properties); + logError(error, "xrEnumerateInstanceExtensionProperties", "get extensions"); + + //get needed extensions + boolean missingOpenGL = true; + PointerBuffer extensions = stack.callocPointer(3); + while (properties.hasRemaining()) { + XrExtensionProperties prop = properties.get(); + String extensionName = prop.extensionNameString(); + if (extensionName.equals(KHROpenGLEnable.XR_KHR_OPENGL_ENABLE_EXTENSION_NAME)) { + missingOpenGL = false; + extensions.put(memAddress(stackUTF8(KHROpenGLEnable.XR_KHR_OPENGL_ENABLE_EXTENSION_NAME))); + } + if (extensionName.equals(EXTHPMixedRealityController.XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME)) { + extensions.put(memAddress(stackUTF8(EXTHPMixedRealityController.XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME))); + } + if (extensionName.equals(HTCViveCosmosControllerInteraction.XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME)) { + extensions.put(memAddress(stackUTF8(HTCViveCosmosControllerInteraction.XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME))); + } + } + + if (missingOpenGL) { + throw new RuntimeException("OpenXR runtime does not support OpenGL, try using SteamVR instead"); + } + + //Create APP info + XrApplicationInfo applicationInfo = XrApplicationInfo.calloc(stack); + applicationInfo.apiVersion(XR10.XR_CURRENT_API_VERSION); + applicationInfo.applicationName(stack.UTF8("Vivecraft")); + applicationInfo.applicationVersion(1); + + //Create instance info + XrInstanceCreateInfo createInfo = XrInstanceCreateInfo.calloc(stack); + createInfo.type(XR10.XR_TYPE_INSTANCE_CREATE_INFO); + createInfo.next(NULL); + createInfo.createFlags(0); + createInfo.applicationInfo(applicationInfo); + createInfo.enabledApiLayerNames(null); + createInfo.enabledExtensionNames(extensions.flip()); + + //Create XR instance + PointerBuffer instancePtr = stack.callocPointer(1); + int xrResult = XR10.xrCreateInstance(createInfo, instancePtr); + if (xrResult == XR10.XR_ERROR_RUNTIME_FAILURE) { + throw new RuntimeException("Failed to create xrInstance, are you sure your headset is plugged in?"); + } else if (xrResult == XR10.XR_ERROR_INSTANCE_LOST) { + throw new RuntimeException("Failed to create xrInstance due to runtime updating"); + } else if (xrResult < 0) { + throw new RuntimeException("XR method returned " + xrResult); + } + instance = new XrInstance(instancePtr.get(0), createInfo); + + this.poseMatrices = new Matrix4f[64]; + + for (int i = 0; i < this.poseMatrices.length; ++i) { + this.poseMatrices[i] = new Matrix4f(); + } + + this.initSuccess = true; + } + } + + public static MCOpenXR get() { + return ome; + } + + private void initializeOpenXRSession() { + try (MemoryStack stack = MemoryStack.stackPush()) { + //Create system + XrSystemGetInfo system = XrSystemGetInfo.calloc(stack); + system.type(XR10.XR_TYPE_SYSTEM_GET_INFO); + system.next(NULL); + system.formFactor(XR10.XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY); + + LongBuffer longBuffer = stack.callocLong(1); + int error = XR10.xrGetSystem(instance, system, longBuffer); + logError(error, "xrGetSystem", ""); + this.systemID = longBuffer.get(0); + + if (systemID == 0) { + throw new RuntimeException("No compatible headset detected"); + } + + //Bind graphics + Struct graphics = this.getGraphicsAPI(stack); + + //Create session + XrSessionCreateInfo info = XrSessionCreateInfo.calloc(stack); + info.type(XR10.XR_TYPE_SESSION_CREATE_INFO); + info.next(graphics.address()); + info.createFlags(0); + info.systemId(systemID); + + PointerBuffer sessionPtr = stack.callocPointer(1); + error = XR10.xrCreateSession(instance, info, sessionPtr); + logError(error, "xrCreateSession", ""); + + session = new XrSession(sessionPtr.get(0), instance); + + XrSessionBeginInfo sessionBeginInfo = XrSessionBeginInfo.calloc(stack); + sessionBeginInfo.type(XR10.XR_TYPE_SESSION_BEGIN_INFO); + sessionBeginInfo.next(NULL); + sessionBeginInfo.primaryViewConfigurationType(XR10.XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO); + + error = XR10.xrBeginSession(session, sessionBeginInfo); + logError(error, "xrBeginSession", ""); + this.isActive = true; + + } + } + + private void initializeOpenXRSpace() { + try (MemoryStack stack = MemoryStack.stackPush()){ + XrPosef identityPose = XrPosef.calloc(stack); + identityPose.set( + XrQuaternionf.calloc(stack).set(0, 0, 0, 1), + XrVector3f.calloc(stack) + ); + + XrReferenceSpaceCreateInfo referenceSpaceCreateInfo = XrReferenceSpaceCreateInfo.calloc(stack); + referenceSpaceCreateInfo.type(XR10.XR_TYPE_REFERENCE_SPACE_CREATE_INFO); + referenceSpaceCreateInfo.next(NULL); + referenceSpaceCreateInfo.referenceSpaceType(XR10.XR_REFERENCE_SPACE_TYPE_STAGE); + referenceSpaceCreateInfo.poseInReferenceSpace(identityPose); + + PointerBuffer pp = stack.callocPointer(1); + int error = XR10.xrCreateReferenceSpace(session, referenceSpaceCreateInfo, pp); + xrAppSpace = new XrSpace(pp.get(0), session); + logError(error, "xrCreateReferenceSpace", "XR_REFERENCE_SPACE_TYPE_STAGE"); + + referenceSpaceCreateInfo.referenceSpaceType(XR10.XR_REFERENCE_SPACE_TYPE_VIEW); + error = XR10.xrCreateReferenceSpace(session, referenceSpaceCreateInfo, pp); + logError(error, "xrCreateReferenceSpace", "XR_REFERENCE_SPACE_TYPE_VIEW"); + xrViewSpace = new XrSpace(pp.get(0), session); + } + } + + private void initializeOpenXRSwapChain() { + try (MemoryStack stack = stackPush()) { + //Check amount of views + IntBuffer intBuf = stack.callocInt(1); + int error = XR10.xrEnumerateViewConfigurationViews(instance, systemID, XR10.XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, intBuf, null); + logError(error, "xrEnumerateViewConfigurationViews", "get count"); + + //Get all views + ByteBuffer viewConfBuffer = bufferStack(intBuf.get(0), XrViewConfigurationView.SIZEOF, XR10.XR_TYPE_VIEW_CONFIGURATION_VIEW); + XrViewConfigurationView.Buffer views = new XrViewConfigurationView.Buffer(viewConfBuffer); + error = XR10.xrEnumerateViewConfigurationViews(instance, systemID, XR10.XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, intBuf, views); + logError(error, "xrEnumerateViewConfigurationViews", "get views"); + int viewCountNumber = intBuf.get(0); + + this.viewBuffer = new XrView.Buffer( + bufferHeap(viewCountNumber, XrView.SIZEOF, XR10.XR_TYPE_VIEW) + ); + //Check swapchain formats + error = XR10.xrEnumerateSwapchainFormats(session, intBuf, null); + logError(error, "xrEnumerateSwapchainFormats", "get count"); + + //Get swapchain formats + LongBuffer swapchainFormats = stack.callocLong(intBuf.get(0)); + error = XR10.xrEnumerateSwapchainFormats(session, intBuf, swapchainFormats); + logError(error, "xrEnumerateSwapchainFormats", "get formats"); + + long[] desiredSwapchainFormats = { + //SRGB formats + GL21.GL_SRGB8_ALPHA8, + GL21.GL_SRGB8, + //others + GL11.GL_RGB10_A2, + GL30.GL_RGBA16F, + GL30.GL_RGB16F, + + // The two below should only be used as a fallback, as they are linear color formats without enough bits for color + // depth, thus leading to banding. + GL11.GL_RGBA8, + GL31.GL_RGBA8_SNORM, + }; + + //Choose format + long chosenFormat = 0; + for (long glFormatIter : desiredSwapchainFormats) { + swapchainFormats.rewind(); + while (swapchainFormats.hasRemaining()) { + if (glFormatIter == swapchainFormats.get()) { + chosenFormat = glFormatIter; + break; + } + } + if (chosenFormat != 0) { + break; + } + } + + if (chosenFormat == 0) { + var formats = new ArrayList(); + swapchainFormats.rewind(); + while (swapchainFormats.hasRemaining()) { + formats.add(swapchainFormats.get()); + } + throw new RuntimeException("No compatible swapchain / framebuffer format available: " + formats); + } + + //Make swapchain + XrViewConfigurationView viewConfig = views.get(0); + XrSwapchainCreateInfo swapchainCreateInfo = XrSwapchainCreateInfo.calloc(stack); + swapchainCreateInfo.type(XR10.XR_TYPE_SWAPCHAIN_CREATE_INFO); + swapchainCreateInfo.next(NULL); + swapchainCreateInfo.createFlags(0); + swapchainCreateInfo.usageFlags(XR10.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT); + swapchainCreateInfo.format(chosenFormat); + swapchainCreateInfo.sampleCount(1); + swapchainCreateInfo.width(viewConfig.recommendedImageRectWidth()); + swapchainCreateInfo.height(viewConfig.recommendedImageRectHeight()); + swapchainCreateInfo.faceCount(1); + swapchainCreateInfo.arraySize(2); + swapchainCreateInfo.mipCount(1); + + PointerBuffer handlePointer = stack.callocPointer(1); + error = XR10.xrCreateSwapchain(session, swapchainCreateInfo, handlePointer); + logError(error, "xrCreateSwapchain", "format: " + chosenFormat); + swapchain = new XrSwapchain(handlePointer.get(0), session); + this.width = swapchainCreateInfo.width(); + this.height = swapchainCreateInfo.height(); + } + } + + private Struct getGraphicsAPI(MemoryStack stack) { + XrGraphicsRequirementsOpenGLKHR graphicsRequirements = XrGraphicsRequirementsOpenGLKHR.calloc(stack).type(KHROpenGLEnable.XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR); + KHROpenGLEnable.xrGetOpenGLGraphicsRequirementsKHR(instance, systemID, graphicsRequirements); + + XrSystemProperties systemProperties = XrSystemProperties.calloc(stack).type(XR10.XR_TYPE_SYSTEM_PROPERTIES); + int error = XR10.xrGetSystemProperties(instance, systemID, systemProperties); + logError(error, "xrGetSystemProperties", ""); + XrSystemTrackingProperties trackingProperties = systemProperties.trackingProperties(); + XrSystemGraphicsProperties graphicsProperties = systemProperties.graphicsProperties(); + + this.systemName = memUTF8(memAddress(systemProperties.systemName())); + int vendor = systemProperties.vendorId(); + boolean orientationTracking = trackingProperties.orientationTracking(); + boolean positionTracking = trackingProperties.positionTracking(); + int maxWidth = graphicsProperties.maxSwapchainImageWidth(); + int maxHeight = graphicsProperties.maxSwapchainImageHeight(); + int maxLayerCount = graphicsProperties.maxLayerCount(); + + VRSettings.logger.info("Found device with id: {}", systemID); + VRSettings.logger.info("Headset Name: {}, Vendor: {}", systemName, vendor); + VRSettings.logger.info("Headset Orientation Tracking: {}, Position Tracking: {}", orientationTracking, positionTracking); + VRSettings.logger.info("Headset Max Width: {}, Max Height: {}, Max Layer Count: {}", maxWidth, maxHeight, maxLayerCount); + + //Bind the OpenGL context to the OpenXR instance and create the session + Window window = mc.getWindow(); + long windowHandle = window.getWindow(); + if (Platform.get() == Platform.WINDOWS) { + return XrGraphicsBindingOpenGLWin32KHR.calloc(stack).set( + KHROpenGLEnable.XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR, + NULL, + User32.GetDC(GLFWNativeWin32.glfwGetWin32Window(windowHandle)), + GLFWNativeWGL.glfwGetWGLContext(windowHandle) + ); + } else if (Platform.get() == Platform.LINUX) { + long xDisplay = GLFWNativeX11.glfwGetX11Display(); + + long glXContext = GLFWNativeGLX.glfwGetGLXContext(windowHandle); + long glXWindowHandle = GLFWNativeGLX.glfwGetGLXWindow(windowHandle); + + int fbXID = glXQueryDrawable(xDisplay, glXWindowHandle, GLX_FBCONFIG_ID); + PointerBuffer fbConfigBuf = glXChooseFBConfig(xDisplay, X11.XDefaultScreen(xDisplay), stackInts(GLX_FBCONFIG_ID, fbXID, 0)); + if(fbConfigBuf == null) { + throw new IllegalStateException("Your framebuffer config was null, make a github issue"); + } + long fbConfig = fbConfigBuf.get(); + + return XrGraphicsBindingOpenGLXlibKHR.calloc(stack).set( + KHROpenGLEnable.XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, + NULL, + xDisplay, + (int) Objects.requireNonNull(glXGetVisualFromFBConfig(xDisplay, fbConfig)).visualid(), + fbConfig, + glXWindowHandle, + glXContext + ); + } else { + throw new IllegalStateException("Macos not supported"); + } + } + + /** + * Creates an array of XrStructs with their types pre set to @param type + */ + static ByteBuffer bufferStack(int capacity, int sizeof, int type) { + ByteBuffer b = stackCalloc(capacity * sizeof); + + for (int i = 0; i < capacity; i++) { + b.position(i * sizeof); + b.putInt(type); + } + b.rewind(); + return b; + } + + + @Override + public boolean postinit() throws RenderConfigException { + this.initInputAndApplication(); + return inputInitialized; + } + + private void initInputAndApplication() { + this.populateInputActions(); + + //this.generateActionManifest(); + //this.loadActionManifest(); + this.loadActionHandles(); + this.loadDefaultBindings(); + //this.installApplicationManifest(false); + this.inputInitialized = true; + + } + + @Override + public Matrix4f getControllerComponentTransform(int var1, String var2) { + return Utils.Matrix4fSetIdentity(new Matrix4f()); + } + + @Override + public boolean hasThirdController() { + return false; + } + + @Override + public List getOrigins(VRInputAction var1) { + try (MemoryStack stack = MemoryStack.stackPush()){ + XrBoundSourcesForActionEnumerateInfo info = XrBoundSourcesForActionEnumerateInfo.calloc(stack); + info.type(XR10.XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO); + info.next(NULL); + info.action(new XrAction(var1.handle, new XrActionSet(actionSetHandles.get(var1.actionSet), instance))); + IntBuffer buf = stack.callocInt(1); + int error = XR10.xrEnumerateBoundSourcesForAction(session, info, buf, null); + logError(error, "xrEnumerateBoundSourcesForAction", var1.name); + + int size = buf.get(); + if (size <= 0) { + return List.of(0L); + } + + buf = stack.callocInt(size); + LongBuffer longbuf = stack.callocLong(size); + error = XR10.xrEnumerateBoundSourcesForAction(session, info, buf, longbuf); + logError(error, "xrEnumerateBoundSourcesForAction", var1.name); + long[] array; + if (longbuf.hasArray()) { //TODO really? + array = longbuf.array(); + } else { + longbuf.rewind(); + array = new long[longbuf.remaining()]; + int index = 0; + while (longbuf.hasRemaining()) { + array[index++] = longbuf.get(); + } + } + return Arrays.stream(array).boxed().toList(); + } + } + + @Override + public String getOriginName(long l) { + try (MemoryStack stack = MemoryStack.stackPush()){ + XrInputSourceLocalizedNameGetInfo info = XrInputSourceLocalizedNameGetInfo.calloc(stack); + info.type(XR10.XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO); + info.next(0); + info.sourcePath(l); + info.whichComponents(XR10.XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT); + + IntBuffer buf = stack.callocInt(1); + int error = XR10.xrGetInputSourceLocalizedName(session, info, buf, null); + logError(error, "xrGetInputSourceLocalizedName", "get length"); + + int size = buf.get(); + if (size <= 0) { + return ""; + } + + buf = stack.callocInt(size); + ByteBuffer byteBuffer = stack.calloc(size); + error = XR10.xrGetInputSourceLocalizedName(session, info, buf, byteBuffer); + logError(error, "xrGetInputSourceLocalizedName", "get String"); + return new String(byteBuffer.array()); + } + } + + @Override + public VRRenderer createVRRenderer() { + return new OpenXRStereoRenderer(this); + } + + @Override + public boolean isActive() { + this.pollVREvents(); + return isActive; + } + + @Override + public ControllerType getOriginControllerType(long i) { + if (i == aim[0]) { + return ControllerType.RIGHT; + } + return ControllerType.LEFT; + } + + @Override + public float getIPD() { + return (float) (this.getEyePosition(RenderPass.RIGHT).x - this.getEyePosition(RenderPass.LEFT).x); + } + + @Override + public String getRuntimeName() { + return "OpenXR"; + } + + //TODO Collect and register all actions + private void loadActionHandles() { + for (VRInputActionSet vrinputactionset : VRInputActionSet.values()) { + long actionSet = makeActionSet(instance, vrinputactionset.name, vrinputactionset.localizedName, 0); + this.actionSetHandles.put(vrinputactionset, actionSet); + } + + for (VRInputAction vrinputaction : this.inputActions.values()) { + long action = createAction(vrinputaction.name, vrinputaction.name, vrinputaction.type, new XrActionSet(this.actionSetHandles.get(vrinputaction.actionSet), instance)); + vrinputaction.setHandle(action); + } + + setupControllers(); + + XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); + this.haptics[0] = createAction("/actions/global/out/righthaptic", "/actions/global/out/righthaptic", "haptic", actionSet); + this.haptics[1] = createAction("/actions/global/out/lefthaptic", "/actions/global/out/lefthaptic", "haptic", actionSet); + + } + + private void setupControllers() { + XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); + this.grip[0] = createAction("/actions/global/in/righthand", "/actions/global/in/righthand", "pose", actionSet); + this.grip[1] = createAction("/actions/global/in/lefthand", "/actions/global/in/lefthand", "pose", actionSet); + this.aim[0] = createAction("/actions/global/in/righthandaim", "/actions/global/in/righthandaim", "pose", actionSet); + this.aim[1] = createAction("/actions/global/in/lefthandaim", "/actions/global/in/lefthandaim", "pose", actionSet); + } + + private void loadDefaultBindings() { + try (MemoryStack stack = MemoryStack.stackPush()) { + int error; + for (String headset: XRBindings.supportedHeadsets()) { + VRSettings.logger.info("loading defaults for {}", headset); + Pair[] defaultBindings = XRBindings.getBinding(headset).toArray(new Pair[0]); + XrActionSuggestedBinding.Buffer bindings = XrActionSuggestedBinding.calloc(defaultBindings.length + 6, stack); //TODO different way of adding controller poses + + for (int i = 0; i < defaultBindings.length; i++) { + Pair pair = defaultBindings[i]; + VRInputAction binding = this.getInputActionByName(pair.getLeft()); + if (binding.handle == 0L) { + VRSettings.logger.error("Handle for '{}'/'{}' is null", pair.getLeft(), pair.getRight()); + continue; + } + bindings.get(i).set( + new XrAction(binding.handle, new XrActionSet(actionSetHandles.get(binding.actionSet), instance)), + getPath(pair.getRight()) + ); + } + + //TODO make this also changeable? + XrActionSet actionSet = new XrActionSet(actionSetHandles.get(VRInputActionSet.GLOBAL), instance); + bindings.get(defaultBindings.length).set( + new XrAction(this.grip[0], actionSet), + getPath("/user/hand/right/input/grip/pose") + ); + bindings.get(defaultBindings.length + 1).set( + new XrAction(this.grip[1], actionSet), + getPath("/user/hand/left/input/grip/pose") + ); + bindings.get(defaultBindings.length + 2).set( + new XrAction(this.aim[0], actionSet), + getPath("/user/hand/right/input/aim/pose") + ); + bindings.get(defaultBindings.length + 3).set( + new XrAction(this.aim[1], actionSet), + getPath("/user/hand/left/input/aim/pose") + ); + + bindings.get(defaultBindings.length + 4).set( + new XrAction(this.haptics[0], actionSet), + getPath("/user/hand/right/output/haptic") + ); + + bindings.get(defaultBindings.length + 5).set( + new XrAction(this.haptics[1], actionSet), + getPath("/user/hand/left/output/haptic") + ); + + XrInteractionProfileSuggestedBinding suggested_binds = XrInteractionProfileSuggestedBinding.calloc(stack); + suggested_binds.type(XR10.XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING); + suggested_binds.next(NULL); + suggested_binds.interactionProfile(getPath(headset)); + suggested_binds.suggestedBindings(bindings); + + error = XR10.xrSuggestInteractionProfileBindings(instance, suggested_binds); + logError(error, "xrSuggestInteractionProfileBindings", headset); + } + + + XrSessionActionSetsAttachInfo attach_info = XrSessionActionSetsAttachInfo.calloc(stack); + attach_info.type(XR10.XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO); + attach_info.next(NULL); + attach_info.actionSets(stackPointers(actionSetHandles.values().stream().mapToLong(value -> value).toArray())); + + error = XR10.xrAttachSessionActionSets(session, attach_info); + logError(error, "xrAttachSessionActionSets", ""); + + XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); + XrActionSpaceCreateInfo grip_left = XrActionSpaceCreateInfo.calloc(stack); + grip_left.type(XR10.XR_TYPE_ACTION_SPACE_CREATE_INFO); + grip_left.next(NULL); + grip_left.action(new XrAction(grip[0], actionSet)); + grip_left.subactionPath(getPath("/user/hand/right")); + grip_left.poseInActionSpace(POSE_IDENTITY); + PointerBuffer pp = stackCallocPointer(1); + error = XR10.xrCreateActionSpace(session, grip_left, pp); + logError(error, "xrCreateActionSpace", "grip: /user/hand/right"); + this.gripSpace[0] = new XrSpace(pp.get(0), session); + + grip_left.action(new XrAction(grip[1], actionSet)); + grip_left.subactionPath(getPath("/user/hand/left")); + error = XR10.xrCreateActionSpace(session, grip_left, pp); + logError(error, "xrCreateActionSpace", "grip: /user/hand/left"); + this.gripSpace[1] = new XrSpace(pp.get(0), session); + + grip_left.action(new XrAction(aim[0], actionSet)); + grip_left.subactionPath(getPath("/user/hand/right")); + error = XR10.xrCreateActionSpace(session, grip_left, pp); + logError(error, "xrCreateActionSpace", "aim: /user/hand/right"); + this.aimSpace[0] = new XrSpace(pp.get(0), session); + + grip_left.action(new XrAction(aim[1], actionSet)); + grip_left.subactionPath(getPath("/user/hand/left")); + error = XR10.xrCreateActionSpace(session, grip_left, pp); + logError(error, "xrCreateActionSpace", "aim: /user/hand/left"); + this.aimSpace[1] = new XrSpace(pp.get(0), session); + + } + } + + public long getPath(String pathString) { + return this.paths.computeIfAbsent(pathString, s -> { + try (MemoryStack ignored = stackPush()) { + LongBuffer buf = stackCallocLong(1); + int error = XR10.xrStringToPath(instance, pathString, buf); + logError(error, "getPath", pathString); + return buf.get(); + } + }); + } + + private long createAction(String name, String localisedName, String type, XrActionSet actionSet) { + try (MemoryStack stack = MemoryStack.stackPush()){ + String s = name.split("/")[name.split("/").length -1].toLowerCase(); + XrActionCreateInfo hands = XrActionCreateInfo.calloc(stack); + hands.type(XR10.XR_TYPE_ACTION_CREATE_INFO); + hands.next(NULL); + hands.actionName(memUTF8(s)); + switch (type) { + case "boolean" -> hands.actionType(XR10.XR_ACTION_TYPE_BOOLEAN_INPUT); + case "vector1" -> hands.actionType(XR10.XR_ACTION_TYPE_FLOAT_INPUT); + case "vector2" -> hands.actionType(XR10.XR_ACTION_TYPE_VECTOR2F_INPUT); + case "pose" -> hands.actionType(XR10.XR_ACTION_TYPE_POSE_INPUT); + case "haptic" -> hands.actionType(XR10.XR_ACTION_TYPE_VIBRATION_OUTPUT); + } + hands.countSubactionPaths(0); + hands.subactionPaths(null); + hands.localizedActionName(memUTF8(s)); + PointerBuffer buffer = stackCallocPointer(1); + + int error = XR10.xrCreateAction(actionSet, hands, buffer); + logError(error, "xrCreateAction", "name:", name, "type:", type); + return buffer.get(0); + } + } + + private long makeActionSet(XrInstance instance, String name, String localisedName, int priority) { + try (MemoryStack stack = MemoryStack.stackPush()){ + XrActionSetCreateInfo info = XrActionSetCreateInfo.calloc(stack); + info.type(XR10.XR_TYPE_ACTION_SET_CREATE_INFO); + info.next(NULL); + info.actionSetName(memUTF8(localisedName.toLowerCase())); + info.localizedActionSetName(memUTF8(localisedName.toLowerCase())); + info.priority(priority); + PointerBuffer buffer = stack.callocPointer(1); + + int error = XR10.xrCreateActionSet(instance, info, buffer); + logError(error, "makeActionSet", localisedName.toLowerCase()); + return buffer.get(0); + } + } + + static ByteBuffer bufferHeap(int capacity, int sizeof, int type) { + ByteBuffer b = memCalloc(capacity * sizeof); + + for (int i = 0; i < capacity; i++) { + b.position(i * sizeof); + b.putInt(type); + } + b.rewind(); + return b; + } + + /** + * gets the String for the given xrResult + */ + private String getResultName(int xrResult) { + String resultString = switch (xrResult) { + case 1 -> "XR_TIMEOUT_EXPIRED"; + case 3 -> "XR_SESSION_LOSS_PENDING"; + case 4 -> "XR_EVENT_UNAVAILABLE"; + case 7 -> "XR_SPACE_BOUNDS_UNAVAILABLE"; + case 8 -> "XR_SESSION_NOT_FOCUSED"; + case 9 -> "XR_FRAME_DISCARDED"; + case -1 -> "XR_ERROR_VALIDATION_FAILURE"; + case -2 -> "XR_ERROR_RUNTIME_FAILURE"; + case -3 -> "XR_ERROR_OUT_OF_MEMORY"; + case -4 -> "XR_ERROR_API_VERSION_UNSUPPORTED"; + case -6 -> "XR_ERROR_INITIALIZATION_FAILED"; + case -7 -> "XR_ERROR_FUNCTION_UNSUPPORTED"; + case -8 -> "XR_ERROR_FEATURE_UNSUPPORTED"; + case -9 -> "XR_ERROR_EXTENSION_NOT_PRESENT"; + case -10 -> "XR_ERROR_LIMIT_REACHED"; + case -11 -> "XR_ERROR_SIZE_INSUFFICIENT"; + case -12 -> "XR_ERROR_HANDLE_INVALID"; + case -13 -> "XR_ERROR_INSTANCE_LOST"; + case -14 -> "XR_ERROR_SESSION_RUNNING"; + case -16 -> "XR_ERROR_SESSION_NOT_RUNNING"; + case -17 -> "XR_ERROR_SESSION_LOST"; + case -18 -> "XR_ERROR_SYSTEM_INVALID"; + case -19 -> "XR_ERROR_PATH_INVALID"; + case -20 -> "XR_ERROR_PATH_COUNT_EXCEEDED"; + case -21 -> "XR_ERROR_PATH_FORMAT_INVALID"; + case -22 -> "XR_ERROR_PATH_UNSUPPORTED"; + case -23 -> "XR_ERROR_LAYER_INVALID"; + case -24 -> "XR_ERROR_LAYER_LIMIT_EXCEEDED"; + case -25 -> "XR_ERROR_SWAPCHAIN_RECT_INVALID"; + case -26 -> "XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED"; + case -27 -> "XR_ERROR_ACTION_TYPE_MISMATCH"; + case -28 -> "XR_ERROR_SESSION_NOT_READY"; + case -29 -> "XR_ERROR_SESSION_NOT_STOPPING"; + case -30 -> "XR_ERROR_TIME_INVALID"; + case -31 -> "XR_ERROR_REFERENCE_SPACE_UNSUPPORTED"; + case -32 -> "XR_ERROR_FILE_ACCESS_ERROR"; + case -33 -> "XR_ERROR_FILE_CONTENTS_INVALID"; + case -34 -> "XR_ERROR_FORM_FACTOR_UNSUPPORTED"; + case -35 -> "XR_ERROR_FORM_FACTOR_UNAVAILABLE"; + case -36 -> "XR_ERROR_API_LAYER_NOT_PRESENT"; + case -37 -> "XR_ERROR_CALL_ORDER_INVALID"; + case -38 -> "XR_ERROR_GRAPHICS_DEVICE_INVALID"; + case -39 -> "XR_ERROR_POSE_INVALID"; + case -40 -> "XR_ERROR_INDEX_OUT_OF_RANGE"; + case -41 -> "XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED"; + case -42 -> "XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED"; + case -44 -> "XR_ERROR_NAME_DUPLICATED"; + case -45 -> "XR_ERROR_NAME_INVALID"; + case -46 -> "XR_ERROR_ACTIONSET_NOT_ATTACHED"; + case -47 -> "XR_ERROR_ACTIONSETS_ALREADY_ATTACHED"; + case -48 -> "XR_ERROR_LOCALIZED_NAME_DUPLICATED"; + case -49 -> "XR_ERROR_LOCALIZED_NAME_INVALID"; + case -50 -> "XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING"; + case -51 -> "XR_ERROR_RUNTIME_UNAVAILABLE"; + default -> null; + }; + if (resultString == null) { + // ask the runtime for the xrResult name + try (MemoryStack stack = MemoryStack.stackPush()) { + ByteBuffer str = stack.calloc(XR10.XR_MAX_RESULT_STRING_SIZE); + + if (XR10.xrResultToString(instance, xrResult, str) == XR10.XR_SUCCESS) { + resultString = (memUTF8(memAddress(str))); + } else { + resultString = "Unknown Error: " + xrResult; + } + } + } + return resultString; + } + + /** + * logs only errors + * @param xrResult result to check + * @param caller where the xrResult came from + * @param args arguments may be helpful in locating the error + */ + protected void logError(int xrResult, String caller, String... args) { + if (xrResult < 0) { + VRSettings.logger.error("{} for {} errored: {}", caller, String.join(" ", args), getResultName(xrResult)); + } + } + + /** + * logs all results except XR_SUCCESS + * @param xrResult result to check + * @param caller where the xrResult came from + * @param args arguments may be helpful in locating the error + */ + protected void logAll(int xrResult, String caller, String... args) { + if (xrResult != XR10.XR_SUCCESS) { + VRSettings.logger.error("{} for {} errored: {}", caller, String.join(" ", args), getResultName(xrResult)); + } + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticSchedular.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticSchedular.java new file mode 100644 index 000000000..ae39e4f3a --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticSchedular.java @@ -0,0 +1,47 @@ +package org.vivecraft.client_vr.provider.openxr; + +import org.lwjgl.openxr.*; +import org.lwjgl.system.MemoryStack; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.HapticScheduler; +import org.vivecraft.client_vr.provider.control.VRInputActionSet; + +import java.util.concurrent.TimeUnit; + +import static java.sql.Types.NULL; + +public class OpenXRHapticSchedular extends HapticScheduler { + + private void triggerHapticPulse(ControllerType controller, float durationSeconds, float frequency, float amplitude) { + try (MemoryStack stack = MemoryStack.stackPush()){ + int i = controller == ControllerType.RIGHT ? 0 : 1; + if (ClientDataHolderVR.getInstance().vrSettings.reverseHands) { + i = controller == ControllerType.RIGHT ? 1 : 0; + } + XrActionSet actionSet = new XrActionSet(MCOpenXR.get().getActionSetHandle(VRInputActionSet.GLOBAL), MCOpenXR.get().instance); + XrHapticActionInfo info = XrHapticActionInfo.calloc(stack); + info.type(XR10.XR_TYPE_HAPTIC_ACTION_INFO); + info.next(NULL); + info.action(new XrAction(MCOpenXR.get().haptics[i], actionSet)); + + XrHapticVibration vibration = XrHapticVibration.calloc(stack); + vibration.type(XR10.XR_ACTION_TYPE_VIBRATION_OUTPUT); + vibration.next(NULL); + vibration.duration((long) (durationSeconds * 1_000_000_000)); + vibration.frequency(frequency); + vibration.amplitude(amplitude); + + int error = XR10.xrApplyHapticFeedback(MCOpenXR.get().session, info, XrHapticBaseHeader.create(vibration)); + MCOpenXR.get().logError(error, "xrApplyHapticFeedback", ""); + } + } + + @Override + public void queueHapticPulse(ControllerType controller, float durationSeconds, float frequency, float amplitude, float delaySeconds) { + this.executor.schedule(() -> + { + this.triggerHapticPulse(controller, durationSeconds, frequency, amplitude); + }, (long) (delaySeconds * 1000000.0F), TimeUnit.MICROSECONDS); + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java new file mode 100644 index 000000000..aa787582f --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java @@ -0,0 +1,182 @@ +package org.vivecraft.client_vr.provider.openxr; + +import com.mojang.blaze3d.pipeline.RenderTarget; +import net.minecraft.util.Tuple; +import org.joml.Matrix4f; +import org.lwjgl.PointerBuffer; +import org.lwjgl.opengl.GL31; +import org.lwjgl.openxr.*; +import org.lwjgl.system.MemoryStack; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.VRTextureTarget; +import org.vivecraft.client_vr.provider.VRRenderer; +import org.vivecraft.client_vr.render.RenderConfigException; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +import static org.lwjgl.system.MemoryUtil.memAddress; +import static org.lwjgl.system.MemoryUtil.memUTF8; + +public class OpenXRStereoRenderer extends VRRenderer { + private final MCOpenXR openxr; + private int swapIndex; + private VRTextureTarget[] leftFramebuffers; + private VRTextureTarget[] rightFramebuffers; + private boolean render; + private XrCompositionLayerProjectionView.Buffer projectionLayerViews; + private VRTextureTarget rightFramebuffer; + private VRTextureTarget leftFramebuffer; + + + public OpenXRStereoRenderer(MCOpenXR vr) { + super(vr); + this.openxr = vr; + } + + @Override + public void createRenderTexture(int width, int height) throws RenderConfigException{ + try (MemoryStack stack = MemoryStack.stackPush()) { + + //Get amount of views in the swapchain + IntBuffer intBuffer = stack.ints(0); //Set value to 0 + int error = XR10.xrEnumerateSwapchainImages(openxr.swapchain, intBuffer, null); + this.openxr.logError(error, "xrEnumerateSwapchainImages", "get count"); + + //Now we know the amount, create the image buffer + int imageCount = intBuffer.get(0); + XrSwapchainImageOpenGLKHR.Buffer swapchainImageBuffer = XrSwapchainImageOpenGLKHR.calloc(imageCount, stack); + for (XrSwapchainImageOpenGLKHR image : swapchainImageBuffer) { + image.type(KHROpenGLEnable.XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR); + } + + error = XR10.xrEnumerateSwapchainImages(openxr.swapchain, intBuffer, XrSwapchainImageBaseHeader.create(swapchainImageBuffer.address(), swapchainImageBuffer.capacity())); + this.openxr.logError(error, "xrEnumerateSwapchainImages", "get images"); + + this.leftFramebuffers = new VRTextureTarget[imageCount]; + this.rightFramebuffers = new VRTextureTarget[imageCount]; + + for (int i = 0; i < imageCount; i++) { + XrSwapchainImageOpenGLKHR openxrImage = swapchainImageBuffer.get(i); + leftFramebuffers[i] = new VRTextureTarget("L Eye " + i, width, height, openxrImage.image(), 0); + this.checkGLError("Left Eye framebuffer setup"); + rightFramebuffers[i] = new VRTextureTarget("R Eye " + i, width, height, openxrImage.image(), 1); + this.checkGLError("Right Eye framebuffer setup"); + } + + this.rightFramebuffer = new VRTextureTarget("R Eye mirror", width, height, true, false, -1, true, true, ClientDataHolderVR.getInstance().vrSettings.vrUseStencil); + this.leftFramebuffer = new VRTextureTarget("L Eye mirror", width, height, true, false, -1, true, true, ClientDataHolderVR.getInstance().vrSettings.vrUseStencil); + } + } + + @Override + public void setupRenderConfiguration(boolean render) throws Exception { + super.setupRenderConfiguration(render); + + if (!render) { + return; + } + this.projectionLayerViews = XrCompositionLayerProjectionView.calloc(2); + try (MemoryStack stack = MemoryStack.stackPush()){ + + IntBuffer intBuf2 = stack.callocInt(1); + + int error = XR10.xrAcquireSwapchainImage( + openxr.swapchain, + XrSwapchainImageAcquireInfo.calloc(stack).type(XR10.XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO), + intBuf2); + this.openxr.logError(error, "xrAcquireSwapchainImage", ""); + + error = XR10.xrWaitSwapchainImage(openxr.swapchain, + XrSwapchainImageWaitInfo.calloc(stack) + .type(XR10.XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO) + .timeout(XR10.XR_INFINITE_DURATION)); + this.openxr.logError(error, "xrWaitSwapchainImage", ""); + + this.swapIndex = intBuf2.get(0); + + // Render view to the appropriate part of the swapchain image. + for (int viewIndex = 0; viewIndex < 2; viewIndex++) { + + var subImage = projectionLayerViews.get(viewIndex) + .type(XR10.XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW) + .pose(openxr.viewBuffer.get(viewIndex).pose()) + .fov(openxr.viewBuffer.get(viewIndex).fov()) + .subImage(); + subImage.swapchain(openxr.swapchain); + subImage.imageRect().offset().set(0, 0); + subImage.imageRect().extent().set(openxr.width, openxr.height); + subImage.imageArrayIndex(viewIndex); + + } + } + } + + @Override + public Matrix4f getProjectionMatrix(int eyeType, float nearClip, float farClip) { + XrFovf fov = openxr.viewBuffer.get(eyeType).fov(); + return new Matrix4f().setPerspectiveOffCenterFov(fov.angleLeft(), fov.angleRight(), fov.angleDown(), fov.angleUp(), nearClip, farClip); + } + + @Override + public void endFrame() throws RenderConfigException { + GL31.glBindFramebuffer(GL31.GL_READ_FRAMEBUFFER, getLeftEyeTarget().frameBufferId); + GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, leftFramebuffers[swapIndex].frameBufferId); + GL31.glBlitFramebuffer(0,0, getLeftEyeTarget().viewWidth, getLeftEyeTarget().viewHeight, 0,0, leftFramebuffers[swapIndex].viewWidth, leftFramebuffers[swapIndex].viewHeight, GL31.GL_STENCIL_BUFFER_BIT | GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); + + GL31.glBindFramebuffer(GL31.GL_READ_FRAMEBUFFER, getRightEyeTarget().frameBufferId); + GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, rightFramebuffers[swapIndex].frameBufferId); + GL31.glBlitFramebuffer(0,0, getRightEyeTarget().viewWidth, getRightEyeTarget().viewHeight, 0,0, rightFramebuffers[swapIndex].viewWidth, rightFramebuffers[swapIndex].viewHeight, GL31.GL_STENCIL_BUFFER_BIT | GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); + + try (MemoryStack stack = MemoryStack.stackPush()){ + PointerBuffer layers = stack.callocPointer(1); + int error; + if (this.openxr.shouldRender) { + error = XR10.xrReleaseSwapchainImage( + openxr.swapchain, + XrSwapchainImageReleaseInfo.calloc(stack) + .type(XR10.XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO)); + this.openxr.logError(error, "xrReleaseSwapchainImage", ""); + + XrCompositionLayerProjection compositionLayerProjection = XrCompositionLayerProjection.calloc(stack) + .type(XR10.XR_TYPE_COMPOSITION_LAYER_PROJECTION) + .space(openxr.xrAppSpace) + .views(projectionLayerViews); + + layers.put(compositionLayerProjection); + } + layers.flip(); + + error = XR10.xrEndFrame( + openxr.session, + XrFrameEndInfo.calloc(stack) + .type(XR10.XR_TYPE_FRAME_END_INFO) + .displayTime(openxr.time) + .environmentBlendMode(XR10.XR_ENVIRONMENT_BLEND_MODE_OPAQUE) + .layers(layers)); + this.openxr.logAll(error, "xrEndFrame", ""); + + projectionLayerViews.close(); + } + } + + @Override + public boolean providesStencilMask() { + return false; + } + + @Override + public RenderTarget getLeftEyeTarget() { + return leftFramebuffer; + } + + @Override + public RenderTarget getRightEyeTarget() { + return rightFramebuffer; + } + + @Override + public Tuple getRenderTextureSizes() { + return new Tuple<>(openxr.width, openxr.height); + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRUtil.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRUtil.java new file mode 100644 index 000000000..7ce805b55 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRUtil.java @@ -0,0 +1,50 @@ +package org.vivecraft.client_vr.provider.openxr; + +import org.joml.Matrix3f; +import org.joml.Quaternionf; +import org.lwjgl.openxr.XrPosef; +import org.lwjgl.openxr.XrQuaternionf; +import org.vivecraft.common.utils.math.Matrix4f; + +public class OpenXRUtil { + + public static void openXRPoseToMarix(XrPosef pose, Matrix4f mat) { + Matrix3f matrix3f = new Matrix3f().set(new Quaternionf(pose.orientation().x(), pose.orientation().y(), pose.orientation().z(), pose.orientation().w())); + mat.M[0][0] = matrix3f.m00; + mat.M[0][1] = matrix3f.m10; + mat.M[0][2] = matrix3f.m20; + mat.M[0][3] = pose.position$().x(); + mat.M[1][0] = matrix3f.m01; + mat.M[1][1] = matrix3f.m11; + mat.M[1][2] = matrix3f.m21; + mat.M[1][3] = pose.position$().y(); + mat.M[2][0] = matrix3f.m02; + mat.M[2][1] = matrix3f.m12; + mat.M[2][2] = matrix3f.m22; + mat.M[2][3] = pose.position$().z(); + mat.M[3][0] = 0; + mat.M[3][1] = 0; + mat.M[3][2] = 0; + mat.M[3][3] = 1; + } + + public static void openXRPoseToMarix(XrQuaternionf quat, Matrix4f mat) { + Matrix3f matrix3f = new Matrix3f().set(new Quaternionf(quat.x(), quat.y(), quat.z(), quat.w())); + mat.M[0][0] = matrix3f.m00; + mat.M[0][1] = matrix3f.m10; + mat.M[0][2] = matrix3f.m20; + mat.M[0][3] = 0; + mat.M[1][0] = matrix3f.m01; + mat.M[1][1] = matrix3f.m11; + mat.M[1][2] = matrix3f.m21; + mat.M[1][3] = 0; + mat.M[2][0] = matrix3f.m02; + mat.M[2][1] = matrix3f.m12; + mat.M[2][2] = matrix3f.m22; + mat.M[2][3] = 0; + mat.M[3][0] = 0; + mat.M[3][1] = 0; + mat.M[3][2] = 0; + mat.M[3][3] = 1; + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java new file mode 100644 index 000000000..8a3a684a6 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java @@ -0,0 +1,137 @@ +package org.vivecraft.client_vr.provider.openxr; + +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.HashSet; + +public class XRBindings { + + public static HashSet supportedHeadsets() { + HashSet set = new HashSet<>(); + if (MCOpenXR.get().systemName.toLowerCase().contains("oculus") || MCOpenXR.get().systemName.toLowerCase().contains("meta")) { + set.add("/interaction_profiles/oculus/touch_controller"); + return set; + } + if (MCOpenXR.get().session.getCapabilities().XR_HTC_vive_cosmos_controller_interaction) { + set.add("/interaction_profiles/htc/vive_cosmos_controller"); + } + set.add("/interaction_profiles/htc/vive_controller"); + return set; + } + + private static HashSet> quest2Bindings() { + HashSet> set = new HashSet<>(); + + set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); + set.add(new MutablePair<>("/actions/global/in/vivecraft.key.toggleKeyboard", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); + + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); + + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); + set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/a/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); + set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); + set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); + + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger")); + return set; + } + + private static HashSet> viveBindings() { + HashSet> set = new HashSet<>(); + + set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click")); + set.add(new MutablePair<>("/actions/global/in/vivecraft.key.toggleKeyboard", "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/right/input/trackpad/click")); + + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/trackpad/y")); + + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click")); + set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/menu/click")); + set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/trackpad/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); + set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/trackpad/x")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/trackpad")); + set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/left/input/trackpad/y")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/trackpad")); + + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click")); + + set.add(new MutablePair<>("/actions/technical/in/vivecraft.key.trackpadTouch", "/user/hand/left/input/trackpad/click")); + set.add(new MutablePair<>("/actions/technical/in/vivecraft.key.trackpadTouch", "/user/hand/right/input/trackpad/touch")); + + return set; + } + + private static HashSet> cosmosBindings() { + HashSet> set = new HashSet<>(); + + set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); + set.add(new MutablePair<>("/actions/global/in/vivecraft.key.toggleKeyboard", "/user/hand/left/input/y/long")); + set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); + + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/grip/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/grip/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/joystick/scroll")); + + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/grip/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/grip/click")); + set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); + set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/a/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/joystick/position")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/joystick/position")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/pull")); + set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/bumper/click")); + set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/bumper/click")); + + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/grip/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click")); + return set; + } + + public static HashSet> getBinding(String Headset){ + switch (Headset) { + case "/interaction_profiles/htc/vive_cosmos_controller" -> { + return cosmosBindings(); + } + case "/interaction_profiles/htc/vive_controller" -> { + return viveBindings(); + } + case "/interaction_profiles/oculus/touch_controller" -> { + return quest2Bindings(); + } + default -> { + return viveBindings(); + } + } + } +} 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 5bb494aee..5fffb77cb 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 @@ -53,9 +53,9 @@ public static void renderSingleView(RenderPass eye, float partialTicks, long nan if (dataHolder.vrSettings.useFsaa) { RenderSystem.clearColor(RenderSystem.getShaderFogColor()[0], RenderSystem.getShaderFogColor()[1], RenderSystem.getShaderFogColor()[2], RenderSystem.getShaderFogColor()[3]); if (eye == RenderPass.LEFT) { - dataHolder.vrRenderer.framebufferEye0.bindWrite(true); + dataHolder.vrRenderer.getLeftEyeTarget().bindWrite(true); } else { - dataHolder.vrRenderer.framebufferEye1.bindWrite(true); + dataHolder.vrRenderer.getRightEyeTarget().bindWrite(true); } RenderSystem.clear(16384, Minecraft.ON_OSX); mc.getProfiler().push("fsaa"); @@ -66,9 +66,9 @@ public static void renderSingleView(RenderPass eye, float partialTicks, long nan } if (eye == RenderPass.LEFT) { - dataHolder.vrRenderer.framebufferEye0.bindWrite(true); + dataHolder.vrRenderer.getLeftEyeTarget().bindWrite(true); } else { - dataHolder.vrRenderer.framebufferEye1.bindWrite(true); + dataHolder.vrRenderer.getRightEyeTarget().bindWrite(true); } if (dataHolder.vrSettings.useFOVReduction @@ -195,7 +195,8 @@ public static void renderSingleView(RenderPass eye, float partialTicks, long nan VRShaders._Overlay_pumpkinAmplitutde.set(dataHolder.pumpkineffect); VRShaders._Overlay_eye.set(dataHolder.currentPass == RenderPass.LEFT ? 1 : -1); - ((RenderTargetExtension) rendertarget).vivecraft$blitFovReduction(VRShaders.fovReductionShader, dataHolder.vrRenderer.framebufferEye0.viewWidth, dataHolder.vrRenderer.framebufferEye0.viewHeight); + + ((RenderTargetExtension) rendertarget).vivecraft$blitFovReduction(VRShaders.fovReductionShader, dataHolder.vrRenderer.getLeftEyeTarget().viewWidth, dataHolder.vrRenderer.getLeftEyeTarget().viewHeight); ProgramManager.glUseProgram(0); checkGLError("post overlay" + eye); mc.getProfiler().pop(); 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 42e0d3eee..0b68f623e 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 @@ -144,6 +144,7 @@ public enum ShaderGUIRender implements OptionEnum { public enum VRProvider implements OptionEnum { OPENVR, + OPENXR, NULLVR } @@ -1063,7 +1064,15 @@ record ConfigEntry(Field field, VrOptions vrOptions, String configName, boolean public enum VrOptions { DUMMY(false, true), // Dummy - VR_PLUGIN(false, true), // vr plugin to use + VR_PLUGIN(false, true) { // vr plugin to use + @Override + void onOptionChange() { + if (VRState.vrRunning) { + VRState.destroyVR(false); + VRState.vrEnabled = true; + } + } + }, VR_ENABLED(false, true) { // vr or nonvr @Override @@ -1568,7 +1577,7 @@ void onOptionChange() { @Override String getDisplayString(String prefix, Object value) { if (VRState.vrEnabled) { - RenderTarget eye0 = ClientDataHolderVR.getInstance().vrRenderer.framebufferEye0; + RenderTarget eye0 = ClientDataHolderVR.getInstance().vrRenderer.getLeftEyeTarget(); return prefix + Math.round((float) value * 100) + "% (" + (int) Math.ceil(eye0.viewWidth * Math.sqrt((float) value)) + "x" + (int) Math.ceil(eye0.viewHeight * Math.sqrt((float) value)) + ")"; } else { return prefix + Math.round((float) value * 100) + "%"; @@ -1760,6 +1769,7 @@ String getDisplayString(String prefix, Object value) { } }, INGAME_BINDINGS_IN_GUI(false, true), + RADIAL_NUMBER(false, false,4, 14, 2, 0), RIGHT_CLICK_DELAY(false, false); // Right Click Repeat // ANISOTROPIC_FILTERING("options.anisotropicFiltering", true, false, 1.0F, 16.0F, 0.0F) diff --git a/common/src/main/java/org/vivecraft/mixin/client/blaze3d/RenderTargetMixin.java b/common/src/main/java/org/vivecraft/mixin/client/blaze3d/RenderTargetMixin.java index 2fe6f2e3c..a2f006803 100644 --- a/common/src/main/java/org/vivecraft/mixin/client/blaze3d/RenderTargetMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client/blaze3d/RenderTargetMixin.java @@ -56,6 +56,11 @@ public abstract class RenderTargetMixin implements RenderTargetExtension { this.vivecraft$texid = texid; } + @Override + public void vivecraft$setColorid(int colorid) { + this.colorTextureId = colorid; + } + @Override public void vivecraft$isLinearFilter(boolean linearFilter) { this.vivecraft$linearFilter = linearFilter; diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java index 96d79eeff..0e05162d6 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java @@ -16,10 +16,10 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; -import org.vivecraft.client_vr.provider.openvr_lwjgl.VRInputAction; +import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.common.utils.math.Vector2; -import static org.vivecraft.client_vr.provider.openvr_lwjgl.control.VivecraftMovementInput.getMovementAxisValue; +import static org.vivecraft.client_vr.provider.control.VivecraftMovementInput.getMovementAxisValue; @Mixin(KeyboardInput.class) public class KeyboardInputVRMixin extends Input { 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 112dafb2f..8497cb5d8 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 @@ -65,7 +65,7 @@ import org.vivecraft.client_vr.gameplay.trackers.TelescopeTracker; import org.vivecraft.client_vr.menuworlds.MenuWorldDownloader; import org.vivecraft.client_vr.menuworlds.MenuWorldExporter; -import org.vivecraft.client_vr.provider.openvr_lwjgl.VRInputAction; +import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.render.VRFirstPersonArmSwing; @@ -295,7 +295,7 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { if (!VRState.vrInitialized) { return; } - boolean vrActive = !ClientDataHolderVR.getInstance().vrSettings.vrHotswitchingEnabled || ClientDataHolderVR.getInstance().vr.isActive(); + boolean vrActive = ClientDataHolderVR.getInstance().vr.isActive() || !ClientDataHolderVR.getInstance().vrSettings.vrHotswitchingEnabled; if (VRState.vrRunning != vrActive && (ClientNetworking.serverAllowsVrSwitching || player == null)) { vivecraft$switchVRState(vrActive); } @@ -355,7 +355,7 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { this.profiler.push("setupRenderConfiguration"); try { this.vivecraft$checkGLError("pre render setup "); - ClientDataHolderVR.getInstance().vrRenderer.setupRenderConfiguration(); + ClientDataHolderVR.getInstance().vrRenderer.setupRenderConfiguration(true); this.vivecraft$checkGLError("post render setup "); } catch (RenderConfigException renderConfigException) { vivecraft$switchVRState(false); @@ -860,8 +860,8 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { this.vivecraft$notifyMirror("Shader compile failed, see log", true, 10000); } } else if (ClientDataHolderVR.getInstance().vrSettings.displayMirrorMode == VRSettings.MirrorMode.DUAL) { - RenderTarget rendertarget = ClientDataHolderVR.getInstance().vrRenderer.framebufferEye0; - RenderTarget rendertarget1 = ClientDataHolderVR.getInstance().vrRenderer.framebufferEye1; + RenderTarget rendertarget = ClientDataHolderVR.getInstance().vrRenderer.getLeftEyeTarget(); + RenderTarget rendertarget1 = ClientDataHolderVR.getInstance().vrRenderer.getRightEyeTarget(); int screenWidth = ((WindowExtension) (Object) this.window).vivecraft$getActualScreenWidth() / 2; int screenHeight = ((WindowExtension) (Object) this.window).vivecraft$getActualScreenHeight(); @@ -878,7 +878,7 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { float xcrop = 0.0F; float ycrop = 0.0F; boolean ar = false; - RenderTarget source = ClientDataHolderVR.getInstance().vrRenderer.framebufferEye0; + RenderTarget source = ClientDataHolderVR.getInstance().vrRenderer.getLeftEyeTarget(); if (ClientDataHolderVR.getInstance().vrSettings.displayMirrorMode == VRSettings.MirrorMode.FIRST_PERSON) { source = ClientDataHolderVR.getInstance().vrRenderer.framebufferUndistorted; @@ -889,11 +889,11 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { } else if (ClientDataHolderVR.getInstance().vrSettings.displayMirrorMode == VRSettings.MirrorMode.SINGLE || ClientDataHolderVR.getInstance().vrSettings.displayMirrorMode == VRSettings.MirrorMode.OFF) { if (!ClientDataHolderVR.getInstance().vrSettings.displayMirrorLeftEye) { - source = ClientDataHolderVR.getInstance().vrRenderer.framebufferEye1; + source = ClientDataHolderVR.getInstance().vrRenderer.getRightEyeTarget(); } } else if (ClientDataHolderVR.getInstance().vrSettings.displayMirrorMode == VRSettings.MirrorMode.CROPPED) { if (!ClientDataHolderVR.getInstance().vrSettings.displayMirrorLeftEye) { - source = ClientDataHolderVR.getInstance().vrRenderer.framebufferEye1; + source = ClientDataHolderVR.getInstance().vrRenderer.getRightEyeTarget(); } xcrop = ClientDataHolderVR.getInstance().vrSettings.mirrorCrop; @@ -961,10 +961,10 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { } else { if (ClientDataHolderVR.getInstance().vrSettings.displayMirrorLeftEye) { RenderSystem.setShaderTexture(2, - ClientDataHolderVR.getInstance().vrRenderer.framebufferEye0.getColorTextureId()); + ClientDataHolderVR.getInstance().vrRenderer.getLeftEyeTarget().getColorTextureId()); } else { RenderSystem.setShaderTexture(2, - ClientDataHolderVR.getInstance().vrRenderer.framebufferEye1.getColorTextureId()); + ClientDataHolderVR.getInstance().vrRenderer.getRightEyeTarget().getColorTextureId()); } } VRShaders.depthMaskShader.setSampler("firstPersonColor", RenderSystem.getShaderTexture(2)); 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 358d93e64..30880f940 100644 --- a/common/src/main/resources/assets/vivecraft/lang/en_us.json +++ b/common/src/main/resources/assets/vivecraft/lang/en_us.json @@ -190,6 +190,7 @@ "vivecraft.options.MIXED_REALITY_RENDER_CAMERA_MODEL": "Show Camera Model", "vivecraft.options.PHYSICAL_KEYBOARD_THEME": "Keyboard Theme", "vivecraft.options.KEYBOARD_PRESS_BINDS": "Keyboard Presses Bindings", + "vivecraft.options.STEREOPLUGIN": "Stereo Plugin", "_comment6": "Option tooltips", "vivecraft.options.HUD_SCALE.tooltip": "Relative size HUD takes up in field-of-view.\nThe units are just relative, not in degrees or a fraction of FOV or anything.", "vivecraft.options.HUD_DISTANCE.tooltip": "Distance the floating HUD is drawn in front of your body.\nThe relative size of the HUD is unchanged by this.\nDistance is in meters (though isn't obstructed by blocks).", @@ -358,6 +359,9 @@ "vivecraft.options.keyboardtheme.aesthetic": "§bA§de§bs§dt§bh§de§bt§di§bc", "vivecraft.options.keyboardtheme.dose": "Medicine", "vivecraft.options.keyboardtheme.custom": "Custom", + "vivecraft.options.vrprovider.openvr": "OpenVR", + "vivecraft.options.vrprovider.openxr": "OpenXR", + "vivecraft.options.vrprovider.nullvr": "NullVR", "_comment8": "Button text", "vivecraft.gui.ok": "OK", "vivecraft.gui.clear": "Clear", diff --git a/fabric/build.gradle b/fabric/build.gradle index 530e818c2..f830d1050 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -67,6 +67,10 @@ dependencies { include(implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos")) include(implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows")) + include(implementation("org.lwjgl:lwjgl-openxr:3.3.1")) + include(implementation("org.lwjgl:lwjgl-openxr:3.3.1:natives-linux")) + include(implementation("org.lwjgl:lwjgl-openxr:3.3.1:natives-windows")) + } processResources { diff --git a/forge/build.gradle b/forge/build.gradle index 0631b1176..4cc790820 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -60,11 +60,19 @@ dependencies { forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.1") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.1:natives-linux") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.1:natives-windows") + // shadow the natives bundle("org.lwjgl:lwjgl-openvr:3.3.2") { transitive = false } bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-linux") { transitive = false } bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") { transitive = false } bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") { transitive = false } + + bundle("org.lwjgl:lwjgl-openxr:3.3.1") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:3.3.1:natives-linux") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:3.3.1:natives-windows") { transitive = false } } processResources { diff --git a/neoforge/build.gradle b/neoforge/build.gradle index a477d77cc..31afcfa1c 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -35,11 +35,19 @@ dependencies { forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.1") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.1:natives-linux") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.1:natives-windows") + // shadow the natives bundle("org.lwjgl:lwjgl-openvr:3.3.2") { transitive = false } bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-linux") { transitive = false } bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") { transitive = false } bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") { transitive = false } + + bundle("org.lwjgl:lwjgl-openxr:3.3.1") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:3.3.1:natives-linux") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:3.3.1:natives-windows") { transitive = false } } processResources { From d51fea36a7c89bc4ab282c2e120b33e117a350c4 Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Fri, 1 Nov 2024 13:38:43 +0100 Subject: [PATCH 02/76] add subactionPaths and XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT Co-Authored-By: The Judge <53906078+thejudge156@users.noreply.github.com> --- .../client_vr/provider/openxr/MCOpenXR.java | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 90444000a..41d7a0852 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -38,6 +38,7 @@ import org.vivecraft.common.utils.math.Matrix4f; import org.vivecraft.common.utils.math.Vector3; +import javax.annotation.Nullable; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.LongBuffer; @@ -987,7 +988,7 @@ private void initializeOpenXRSwapChain() { XrSwapchainCreateInfo swapchainCreateInfo = XrSwapchainCreateInfo.calloc(stack); swapchainCreateInfo.type(XR10.XR_TYPE_SWAPCHAIN_CREATE_INFO); swapchainCreateInfo.next(NULL); - swapchainCreateInfo.createFlags(0); + swapchainCreateInfo.createFlags(XR10.XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT); swapchainCreateInfo.usageFlags(XR10.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT); swapchainCreateInfo.format(chosenFormat); swapchainCreateInfo.sampleCount(1); @@ -1207,24 +1208,24 @@ private void loadActionHandles() { } for (VRInputAction vrinputaction : this.inputActions.values()) { - long action = createAction(vrinputaction.name, vrinputaction.name, vrinputaction.type, new XrActionSet(this.actionSetHandles.get(vrinputaction.actionSet), instance)); + long action = createAction(vrinputaction.name, vrinputaction.name, vrinputaction.type, new XrActionSet(this.actionSetHandles.get(vrinputaction.actionSet), instance), null); vrinputaction.setHandle(action); } setupControllers(); XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); - this.haptics[0] = createAction("/actions/global/out/righthaptic", "/actions/global/out/righthaptic", "haptic", actionSet); - this.haptics[1] = createAction("/actions/global/out/lefthaptic", "/actions/global/out/lefthaptic", "haptic", actionSet); + this.haptics[0] = createAction("/actions/global/out/righthaptic", "/actions/global/out/righthaptic", "haptic", actionSet, null); + this.haptics[1] = createAction("/actions/global/out/lefthaptic", "/actions/global/out/lefthaptic", "haptic", actionSet, null); } private void setupControllers() { XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); - this.grip[0] = createAction("/actions/global/in/righthand", "/actions/global/in/righthand", "pose", actionSet); - this.grip[1] = createAction("/actions/global/in/lefthand", "/actions/global/in/lefthand", "pose", actionSet); - this.aim[0] = createAction("/actions/global/in/righthandaim", "/actions/global/in/righthandaim", "pose", actionSet); - this.aim[1] = createAction("/actions/global/in/lefthandaim", "/actions/global/in/lefthandaim", "pose", actionSet); + this.grip[0] = createAction("/actions/global/in/righthand", "/actions/global/in/righthand", "pose", actionSet, null); + this.grip[1] = createAction("/actions/global/in/lefthand", "/actions/global/in/lefthand", "pose", actionSet, null); + this.aim[0] = createAction("/actions/global/in/righthandaim", "/actions/global/in/righthandaim", "pose", actionSet, null); + this.aim[1] = createAction("/actions/global/in/lefthandaim", "/actions/global/in/lefthandaim", "pose", actionSet, null); } private void loadDefaultBindings() { @@ -1340,7 +1341,7 @@ public long getPath(String pathString) { }); } - private long createAction(String name, String localisedName, String type, XrActionSet actionSet) { + private long createAction(String name, String localisedName, String type, XrActionSet actionSet, @Nullable String[] subactionPaths) { try (MemoryStack stack = MemoryStack.stackPush()){ String s = name.split("/")[name.split("/").length -1].toLowerCase(); XrActionCreateInfo hands = XrActionCreateInfo.calloc(stack); @@ -1355,7 +1356,17 @@ private long createAction(String name, String localisedName, String type, XrActi case "haptic" -> hands.actionType(XR10.XR_ACTION_TYPE_VIBRATION_OUTPUT); } hands.countSubactionPaths(0); - hands.subactionPaths(null); + if(subactionPaths != null) { + LongBuffer buffer = stackCallocLong(subactionPaths.length); + for(String path : subactionPaths) { + buffer.put(getPath(path)); + } + hands.countSubactionPaths(subactionPaths.length); + hands.subactionPaths(buffer.rewind()); + } else { + hands.countSubactionPaths(0); + hands.subactionPaths(null); + } hands.localizedActionName(memUTF8(s)); PointerBuffer buffer = stackCallocPointer(1); From 2b97efb3e081438025b43bee4c9ceb06129082a9 Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Tue, 19 Nov 2024 19:05:59 +0100 Subject: [PATCH 03/76] test oculus openxr env --- .../client_vr/provider/openxr/MCOpenXR.java | 14 +++------ .../openxr/OpenXRHapticSchedular.java | 2 +- .../provider/openxr/OpenXRStereoRenderer.java | 30 +++++++++---------- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 41d7a0852..2cd42904a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -880,14 +880,9 @@ private void initializeOpenXRSession() { session = new XrSession(sessionPtr.get(0), instance); - XrSessionBeginInfo sessionBeginInfo = XrSessionBeginInfo.calloc(stack); - sessionBeginInfo.type(XR10.XR_TYPE_SESSION_BEGIN_INFO); - sessionBeginInfo.next(NULL); - sessionBeginInfo.primaryViewConfigurationType(XR10.XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO); - - error = XR10.xrBeginSession(session, sessionBeginInfo); - logError(error, "xrBeginSession", ""); - this.isActive = true; + while (!this.isActive) { + pollVREvents(); + } } } @@ -988,7 +983,7 @@ private void initializeOpenXRSwapChain() { XrSwapchainCreateInfo swapchainCreateInfo = XrSwapchainCreateInfo.calloc(stack); swapchainCreateInfo.type(XR10.XR_TYPE_SWAPCHAIN_CREATE_INFO); swapchainCreateInfo.next(NULL); - swapchainCreateInfo.createFlags(XR10.XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT); + swapchainCreateInfo.createFlags(0); swapchainCreateInfo.usageFlags(XR10.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT); swapchainCreateInfo.format(chosenFormat); swapchainCreateInfo.sampleCount(1); @@ -1355,7 +1350,6 @@ private long createAction(String name, String localisedName, String type, XrActi case "pose" -> hands.actionType(XR10.XR_ACTION_TYPE_POSE_INPUT); case "haptic" -> hands.actionType(XR10.XR_ACTION_TYPE_VIBRATION_OUTPUT); } - hands.countSubactionPaths(0); if(subactionPaths != null) { LongBuffer buffer = stackCallocLong(subactionPaths.length); for(String path : subactionPaths) { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticSchedular.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticSchedular.java index ae39e4f3a..819a355e8 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticSchedular.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticSchedular.java @@ -26,7 +26,7 @@ private void triggerHapticPulse(ControllerType controller, float durationSeconds info.action(new XrAction(MCOpenXR.get().haptics[i], actionSet)); XrHapticVibration vibration = XrHapticVibration.calloc(stack); - vibration.type(XR10.XR_ACTION_TYPE_VIBRATION_OUTPUT); + vibration.type(XR10.XR_TYPE_HAPTIC_VIBRATION); vibration.next(NULL); vibration.duration((long) (durationSeconds * 1_000_000_000)); vibration.frequency(frequency); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java index aa787582f..5ae95cb22 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java @@ -12,12 +12,8 @@ import org.vivecraft.client_vr.provider.VRRenderer; import org.vivecraft.client_vr.render.RenderConfigException; -import java.nio.ByteBuffer; import java.nio.IntBuffer; -import static org.lwjgl.system.MemoryUtil.memAddress; -import static org.lwjgl.system.MemoryUtil.memUTF8; - public class OpenXRStereoRenderer extends VRRenderer { private final MCOpenXR openxr; private int swapIndex; @@ -129,9 +125,10 @@ public void endFrame() throws RenderConfigException { GL31.glBlitFramebuffer(0,0, getRightEyeTarget().viewWidth, getRightEyeTarget().viewHeight, 0,0, rightFramebuffers[swapIndex].viewWidth, rightFramebuffers[swapIndex].viewHeight, GL31.GL_STENCIL_BUFFER_BIT | GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); try (MemoryStack stack = MemoryStack.stackPush()){ - PointerBuffer layers = stack.callocPointer(1); - int error; if (this.openxr.shouldRender) { + PointerBuffer layers = stack.callocPointer(1); + int error; + error = XR10.xrReleaseSwapchainImage( openxr.swapchain, XrSwapchainImageReleaseInfo.calloc(stack) @@ -144,17 +141,18 @@ public void endFrame() throws RenderConfigException { .views(projectionLayerViews); layers.put(compositionLayerProjection); + + layers.flip(); + + error = XR10.xrEndFrame( + openxr.session, + XrFrameEndInfo.calloc(stack) + .type(XR10.XR_TYPE_FRAME_END_INFO) + .displayTime(openxr.time) + .environmentBlendMode(XR10.XR_ENVIRONMENT_BLEND_MODE_OPAQUE) + .layers(layers)); + this.openxr.logAll(error, "xrEndFrame", ""); } - layers.flip(); - - error = XR10.xrEndFrame( - openxr.session, - XrFrameEndInfo.calloc(stack) - .type(XR10.XR_TYPE_FRAME_END_INFO) - .displayTime(openxr.time) - .environmentBlendMode(XR10.XR_ENVIRONMENT_BLEND_MODE_OPAQUE) - .layers(layers)); - this.openxr.logAll(error, "xrEndFrame", ""); projectionLayerViews.close(); } From 344dbb7b6fe81f51f0a4800c1fb7a69bdae5f540 Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Tue, 19 Nov 2024 19:32:37 +0100 Subject: [PATCH 04/76] now for real, not with steamVR as default... --- .../client_vr/provider/openxr/OpenXRStereoRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java index 5ae95cb22..b90501845 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java @@ -70,7 +70,7 @@ public void setupRenderConfiguration(boolean render) throws Exception { super.setupRenderConfiguration(render); if (!render) { - return; + //return; } this.projectionLayerViews = XrCompositionLayerProjectionView.calloc(2); try (MemoryStack stack = MemoryStack.stackPush()){ @@ -125,7 +125,7 @@ public void endFrame() throws RenderConfigException { GL31.glBlitFramebuffer(0,0, getRightEyeTarget().viewWidth, getRightEyeTarget().viewHeight, 0,0, rightFramebuffers[swapIndex].viewWidth, rightFramebuffers[swapIndex].viewHeight, GL31.GL_STENCIL_BUFFER_BIT | GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); try (MemoryStack stack = MemoryStack.stackPush()){ - if (this.openxr.shouldRender) { + if (true) { PointerBuffer layers = stack.callocPointer(1); int error; From 99969802915311601d7d5631d2224d75e7c963fb Mon Sep 17 00:00:00 2001 From: fayer3 Date: Thu, 21 Nov 2024 02:07:05 +0100 Subject: [PATCH 05/76] fix lwjgl openxr version --- fabric/build.gradle | 6 +++--- forge/build.gradle | 12 ++++++------ neoforge/build.gradle | 12 ++++++------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/fabric/build.gradle b/fabric/build.gradle index f830d1050..37623b624 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -67,9 +67,9 @@ dependencies { include(implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos")) include(implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows")) - include(implementation("org.lwjgl:lwjgl-openxr:3.3.1")) - include(implementation("org.lwjgl:lwjgl-openxr:3.3.1:natives-linux")) - include(implementation("org.lwjgl:lwjgl-openxr:3.3.1:natives-windows")) + include(implementation("org.lwjgl:lwjgl-openxr:3.3.2")) + include(implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux")) + include(implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows")) } diff --git a/forge/build.gradle b/forge/build.gradle index 4cc790820..787a4ecbf 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -60,9 +60,9 @@ dependencies { forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") - forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.1") - forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.1:natives-linux") - forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.1:natives-windows") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") // shadow the natives bundle("org.lwjgl:lwjgl-openvr:3.3.2") { transitive = false } @@ -70,9 +70,9 @@ dependencies { bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") { transitive = false } bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") { transitive = false } - bundle("org.lwjgl:lwjgl-openxr:3.3.1") { transitive = false } - bundle("org.lwjgl:lwjgl-openxr:3.3.1:natives-linux") { transitive = false } - bundle("org.lwjgl:lwjgl-openxr:3.3.1:natives-windows") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:3.3.2") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") { transitive = false } } processResources { diff --git a/neoforge/build.gradle b/neoforge/build.gradle index 31afcfa1c..1151f4272 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -35,9 +35,9 @@ dependencies { forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") - forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.1") - forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.1:natives-linux") - forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.1:natives-windows") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") // shadow the natives bundle("org.lwjgl:lwjgl-openvr:3.3.2") { transitive = false } @@ -45,9 +45,9 @@ dependencies { bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") { transitive = false } bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") { transitive = false } - bundle("org.lwjgl:lwjgl-openxr:3.3.1") { transitive = false } - bundle("org.lwjgl:lwjgl-openxr:3.3.1:natives-linux") { transitive = false } - bundle("org.lwjgl:lwjgl-openxr:3.3.1:natives-windows") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:3.3.2") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") { transitive = false } } processResources { From f09afdd80e2f6ec5e05630901b10b1502f3c76eb Mon Sep 17 00:00:00 2001 From: Darien Johnson <84008186+CADIndie@users.noreply.github.com> Date: Sat, 23 Nov 2024 16:02:28 -0600 Subject: [PATCH 06/76] Fix Conformance Issues (#315) Co-authored-by: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Co-authored-by: The Judge <53906078+thejudge156@users.noreply.github.com> --- .../client_vr/provider/openxr/MCOpenXR.java | 16 +++++++++------- .../provider/openxr/OpenXRStereoRenderer.java | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 2cd42904a..c3d2393cf 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -1195,6 +1195,8 @@ public String getRuntimeName() { return "OpenXR"; } + private static final String[] BOTH_HANDS = new String[] {"/user/hand/left", "/user/hand/right"}; + //TODO Collect and register all actions private void loadActionHandles() { for (VRInputActionSet vrinputactionset : VRInputActionSet.values()) { @@ -1203,24 +1205,24 @@ private void loadActionHandles() { } for (VRInputAction vrinputaction : this.inputActions.values()) { - long action = createAction(vrinputaction.name, vrinputaction.name, vrinputaction.type, new XrActionSet(this.actionSetHandles.get(vrinputaction.actionSet), instance), null); + long action = createAction(vrinputaction.name, vrinputaction.name, vrinputaction.type, new XrActionSet(this.actionSetHandles.get(vrinputaction.actionSet), instance), BOTH_HANDS); vrinputaction.setHandle(action); } setupControllers(); XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); - this.haptics[0] = createAction("/actions/global/out/righthaptic", "/actions/global/out/righthaptic", "haptic", actionSet, null); - this.haptics[1] = createAction("/actions/global/out/lefthaptic", "/actions/global/out/lefthaptic", "haptic", actionSet, null); + this.haptics[0] = createAction("/actions/global/out/righthaptic", "/actions/global/out/righthaptic", "haptic", actionSet, BOTH_HANDS); + this.haptics[1] = createAction("/actions/global/out/lefthaptic", "/actions/global/out/lefthaptic", "haptic", actionSet, BOTH_HANDS); } private void setupControllers() { XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); - this.grip[0] = createAction("/actions/global/in/righthand", "/actions/global/in/righthand", "pose", actionSet, null); - this.grip[1] = createAction("/actions/global/in/lefthand", "/actions/global/in/lefthand", "pose", actionSet, null); - this.aim[0] = createAction("/actions/global/in/righthandaim", "/actions/global/in/righthandaim", "pose", actionSet, null); - this.aim[1] = createAction("/actions/global/in/lefthandaim", "/actions/global/in/lefthandaim", "pose", actionSet, null); + this.grip[0] = createAction("/actions/global/in/righthand", "/actions/global/in/righthand", "pose", actionSet, BOTH_HANDS); + this.grip[1] = createAction("/actions/global/in/lefthand", "/actions/global/in/lefthand", "pose", actionSet, BOTH_HANDS); + this.aim[0] = createAction("/actions/global/in/righthandaim", "/actions/global/in/righthandaim", "pose", actionSet, BOTH_HANDS); + this.aim[1] = createAction("/actions/global/in/lefthandaim", "/actions/global/in/lefthandaim", "pose", actionSet, BOTH_HANDS); } private void loadDefaultBindings() { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java index b90501845..191e36397 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java @@ -70,7 +70,7 @@ public void setupRenderConfiguration(boolean render) throws Exception { super.setupRenderConfiguration(render); if (!render) { - //return; + return; } this.projectionLayerViews = XrCompositionLayerProjectionView.calloc(2); try (MemoryStack stack = MemoryStack.stackPush()){ @@ -151,7 +151,7 @@ public void endFrame() throws RenderConfigException { .displayTime(openxr.time) .environmentBlendMode(XR10.XR_ENVIRONMENT_BLEND_MODE_OPAQUE) .layers(layers)); - this.openxr.logAll(error, "xrEndFrame", ""); + this.openxr.logError(error, "xrEndFrame", ""); } projectionLayerViews.close(); From 68d7d90837e0f13d1e0ac6ac9143ee7e127a7824 Mon Sep 17 00:00:00 2001 From: Darien Johnson <84008186+CADIndie@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:19:38 -0600 Subject: [PATCH 07/76] Create DeviceCompat for QuestCraft (#317) * Fix Conformance Issues Co-Authored-By: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Co-Authored-By: The Judge <53906078+thejudge156@users.noreply.github.com> * Create DeviceCompat for QuestCraft Co-Authored-By: The Judge <53906078+thejudge156@users.noreply.github.com> * fix lwjgl openxr version * Use Custom OpenXR Library * Switch to OpenXR 1.0.40 * Log Device Platform * Remove Discord from repo list --------- Co-authored-by: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Co-authored-by: The Judge <53906078+thejudge156@users.noreply.github.com> Co-authored-by: fayer3 --- build.gradle | 15 +- common/build.gradle | 2 +- .../vivecraft/client_vr/provider/MCVR.java | 3 + .../provider/openxr/DeviceCompat.java | 160 ++++++++++++++++++ .../client_vr/provider/openxr/MCOpenXR.java | 118 ++++--------- .../provider/openxr/OpenXRStereoRenderer.java | 63 ++++--- .../main/java/org/vivecraft/util/VLoader.java | 14 ++ fabric/build.gradle | 8 +- forge/build.gradle | 7 +- neoforge/build.gradle | 7 +- 10 files changed, 256 insertions(+), 141 deletions(-) create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java create mode 100644 common/src/main/java/org/vivecraft/util/VLoader.java diff --git a/build.gradle b/build.gradle index 83ac7389a..7dfde6972 100644 --- a/build.gradle +++ b/build.gradle @@ -32,10 +32,11 @@ subprojects { implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") - implementation("org.lwjgl:lwjgl-openxr:3.3.2") + // Use custom OpenXR lib for Android and GLES bindings + implementation("QuestCraftPlusPlus:lwjgl3:3.3.2:lwjgl-openxr-3.3.2") implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") - //implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-macos") implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") + } tasks.withType(JavaCompile) { @@ -124,7 +125,6 @@ allprojects { maven { url = "https://storage.googleapis.com/devan-maven/" } maven { url = "https://maven.shedaniel.me/" } maven { url = "https://aperlambda.github.io/maven" } - maven { url = "https://maven.kotlindiscord.com/repository/terraformers/" } maven { url = "https://mvn.devos.one/releases/" } maven { url = "https://mvn.devos.one/snapshots/" } maven { url = "https://maven.terraformersmc.com/" } @@ -146,17 +146,16 @@ allprojects { exclusiveContent { forRepository { ivy { - name = "Discord" - url = "https://cdn.discordapp.com/attachments/" + name = "GitHub" + url = "https://github.com/" patternLayout { - artifact '/[organisation]/[module]/[revision].[ext]' + artifact '/[organisation]/[module]/releases/download/[revision]/[classifier].jar' } metadataSources { artifact() } } } filter { - // discords are always just numbers - includeGroupByRegex "^\\d*\$" + } } } diff --git a/common/build.gradle b/common/build.gradle index d47d4b937..36714d62f 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -45,7 +45,7 @@ dependencies { compileOnly('com.electronwill.night-config:toml:3.6.6') //LaunchPopup - implementation 'com.github.fayer3:LaunchPopup:master-SNAPSHOT' + implementation 'fayer3:LaunchPopup:1.1.1:LaunchPopup-1.1.1' } // extract the LaunchPopup classes jar { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java index 74e11f821..63b9bc57a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java @@ -30,6 +30,7 @@ import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.provider.control.VRInputActionSet; import org.vivecraft.client_vr.provider.control.VivecraftMovementInput; +import org.vivecraft.client_vr.provider.openxr.DeviceCompat; import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.settings.VRHotkeys; @@ -115,11 +116,13 @@ public abstract class MCVR { protected Map inputActionsByKeyBinding = new HashMap<>(); protected final Map trackpadSwipeSamplers = new HashMap<>(); protected boolean inputInitialized; + public final DeviceCompat device; public MCVR(Minecraft mc, ClientDataHolderVR dh, VivecraftVRMod vrMod) { this.mc = mc; this.dh = dh; mod = vrMod; + this.device = DeviceCompat.detectDevice(); me = this; for (int i = 0; i < 3; ++i) { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java new file mode 100644 index 000000000..ecb9987db --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java @@ -0,0 +1,160 @@ +package org.vivecraft.client_vr.provider.openxr; + +import com.mojang.blaze3d.platform.Window; +import com.sun.jna.Platform; +import net.minecraft.client.Minecraft; +import org.lwjgl.PointerBuffer; +import org.lwjgl.glfw.GLFWNativeGLX; +import org.lwjgl.glfw.GLFWNativeWGL; +import org.lwjgl.glfw.GLFWNativeWin32; +import org.lwjgl.glfw.GLFWNativeX11; +import org.lwjgl.openxr.*; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.Struct; +import org.lwjgl.system.linux.X11; +import org.lwjgl.system.windows.User32; +import org.vivecraft.client_vr.settings.VRSettings; +import org.vivecraft.util.VLoader; + +import java.util.Objects; + +import static org.lwjgl.opengl.GLX13.*; +import static org.lwjgl.system.MemoryStack.stackInts; +import static org.lwjgl.system.MemoryUtil.NULL; + +//TODO: VulkanMod Support +public interface DeviceCompat { + long getPlatformInfo(MemoryStack stack); + void initOpenXRLoader(MemoryStack stack); + String getGraphicsExtension(); + XrSwapchainImageOpenGLKHR.Buffer createImageBuffers(int imageCount, MemoryStack stack); + Struct checkGraphics(MemoryStack stack, XrInstance instance, long systemID); + static DeviceCompat detectDevice() { + return System.getProperty("os.version").contains("Android") ? new Mobile() : new Desktop(); + } + + class Desktop implements DeviceCompat { + @Override + public long getPlatformInfo(MemoryStack stack) { + return NULL; + } + + @Override + public void initOpenXRLoader(MemoryStack stack) { + VRSettings.logger.info("Platform: {}", System.getProperty("os.version")); + } + + @Override + public String getGraphicsExtension() { + return KHROpenGLEnable.XR_KHR_OPENGL_ENABLE_EXTENSION_NAME; + } + + @Override + public XrSwapchainImageOpenGLKHR.Buffer createImageBuffers(int imageCount, MemoryStack stack) { + XrSwapchainImageOpenGLKHR.Buffer swapchainImageBuffer = XrSwapchainImageOpenGLKHR.calloc(imageCount, stack); + for (XrSwapchainImageOpenGLKHR image : swapchainImageBuffer) { + image.type(KHROpenGLEnable.XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR); + } + + return swapchainImageBuffer; + } + + @Override + public Struct checkGraphics(MemoryStack stack, XrInstance instance, long systemID) { + XrGraphicsRequirementsOpenGLKHR graphicsRequirements = XrGraphicsRequirementsOpenGLKHR.calloc(stack).type(KHROpenGLEnable.XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR); + KHROpenGLEnable.xrGetOpenGLGraphicsRequirementsKHR(instance, systemID, graphicsRequirements); + //Bind the OpenGL context to the OpenXR instance and create the session + Window window = Minecraft.getInstance().getWindow(); + long windowHandle = window.getWindow(); + if (Platform.getOSType() == Platform.WINDOWS) { + return XrGraphicsBindingOpenGLWin32KHR.calloc(stack).set( + KHROpenGLEnable.XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR, + NULL, + User32.GetDC(GLFWNativeWin32.glfwGetWin32Window(windowHandle)), + GLFWNativeWGL.glfwGetWGLContext(windowHandle) + ); + } else if (Platform.getOSType() == Platform.LINUX) { + long xDisplay = GLFWNativeX11.glfwGetX11Display(); + + long glXContext = GLFWNativeGLX.glfwGetGLXContext(windowHandle); + long glXWindowHandle = GLFWNativeGLX.glfwGetGLXWindow(windowHandle); + + int fbXID = glXQueryDrawable(xDisplay, glXWindowHandle, GLX_FBCONFIG_ID); + PointerBuffer fbConfigBuf = glXChooseFBConfig(xDisplay, X11.XDefaultScreen(xDisplay), stackInts(GLX_FBCONFIG_ID, fbXID, 0)); + if (fbConfigBuf == null) { + throw new IllegalStateException("Your framebuffer config was null, make a github issue"); + } + long fbConfig = fbConfigBuf.get(); + + return XrGraphicsBindingOpenGLXlibKHR.calloc(stack).set( + KHROpenGLEnable.XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, + NULL, + xDisplay, + (int) Objects.requireNonNull(glXGetVisualFromFBConfig(xDisplay, fbConfig)).visualid(), + fbConfig, + glXWindowHandle, + glXContext + ); + } else { + throw new IllegalStateException("Macos not supported"); + } + } + } + + class Mobile implements DeviceCompat { + @Override + public long getPlatformInfo(MemoryStack stack) { + return XrInstanceCreateInfoAndroidKHR.calloc(stack).set( + KHRAndroidCreateInstance.XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR, + NULL, + VLoader.getDalvikVM(), + VLoader.getDalvikActivity() + ).address(); + } + + @Override + public void initOpenXRLoader(MemoryStack stack) { + VRSettings.logger.info("Platform: {}", System.getProperty("os.version")); + VLoader.setupAndroid(); + XrLoaderInitInfoAndroidKHR initInfo = XrLoaderInitInfoAndroidKHR.calloc(stack).set( + KHRLoaderInitAndroid.XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, + NULL, + VLoader.getDalvikVM(), + VLoader.getDalvikActivity() + ); + + KHRLoaderInit.xrInitializeLoaderKHR(XrLoaderInitInfoBaseHeaderKHR.create(initInfo.address())); + } + + @Override + public String getGraphicsExtension() { + return KHROpenGLESEnable.XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME; + } + + @Override + public XrSwapchainImageOpenGLKHR.Buffer createImageBuffers(int imageCount, MemoryStack stack) { + XrSwapchainImageOpenGLKHR.Buffer swapchainImageBuffer = XrSwapchainImageOpenGLKHR.calloc(imageCount, stack); + for (XrSwapchainImageOpenGLKHR image : swapchainImageBuffer) { + image.type(KHROpenGLESEnable.XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR); + } + + return swapchainImageBuffer; + } + + @Override + public Struct checkGraphics(MemoryStack stack, XrInstance instance, long systemID) { + XrGraphicsRequirementsOpenGLESKHR graphicsRequirements = XrGraphicsRequirementsOpenGLESKHR.calloc(stack).type(KHROpenGLESEnable.XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR); + KHROpenGLESEnable.xrGetOpenGLESGraphicsRequirementsKHR(instance, systemID, graphicsRequirements); + XrGraphicsBindingOpenGLESAndroidKHR graphicsBinding = XrGraphicsBindingOpenGLESAndroidKHR.calloc(stack); + graphicsBinding.set( + KHROpenGLESEnable.XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR, + NULL, + VLoader.getEGLDisplay(), + VLoader.getEGLConfig(), + VLoader.getEGLContext() + ); + + return graphicsBinding; + } + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index c3d2393cf..3340d5f57 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -1,6 +1,5 @@ package org.vivecraft.client_vr.provider.openxr; -import com.mojang.blaze3d.platform.Window; import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; import net.minecraft.util.Mth; @@ -15,10 +14,6 @@ import org.lwjgl.opengl.GL31; import org.lwjgl.openxr.*; import org.lwjgl.system.MemoryStack; -import org.lwjgl.system.Platform; -import org.lwjgl.system.Struct; -import org.lwjgl.system.linux.X11; -import org.lwjgl.system.windows.User32; import org.vivecraft.client.VivecraftVRMod; import org.vivecraft.client.utils.Utils; import org.vivecraft.client_vr.ClientDataHolderVR; @@ -44,7 +39,6 @@ import java.nio.LongBuffer; import java.util.*; -import static org.lwjgl.opengl.GLX13.*; import static org.lwjgl.system.MemoryStack.*; import static org.lwjgl.system.MemoryUtil.*; @@ -770,6 +764,7 @@ public boolean init() { private void initializeOpenXRInstance() { try (MemoryStack stack = MemoryStack.stackPush()) { + device.initOpenXRLoader(stack); //Check extensions IntBuffer numExtensions = stack.callocInt(1); @@ -785,14 +780,15 @@ private void initializeOpenXRInstance() { logError(error, "xrEnumerateInstanceExtensionProperties", "get extensions"); //get needed extensions - boolean missingOpenGL = true; + String graphicsExtension = device.getGraphicsExtension(); + boolean missingGraphics = true; PointerBuffer extensions = stack.callocPointer(3); while (properties.hasRemaining()) { XrExtensionProperties prop = properties.get(); String extensionName = prop.extensionNameString(); - if (extensionName.equals(KHROpenGLEnable.XR_KHR_OPENGL_ENABLE_EXTENSION_NAME)) { - missingOpenGL = false; - extensions.put(memAddress(stackUTF8(KHROpenGLEnable.XR_KHR_OPENGL_ENABLE_EXTENSION_NAME))); + if (extensionName.equals(graphicsExtension)) { + missingGraphics = false; + extensions.put(memAddress(stackUTF8(graphicsExtension))); } if (extensionName.equals(EXTHPMixedRealityController.XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME)) { extensions.put(memAddress(stackUTF8(EXTHPMixedRealityController.XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME))); @@ -802,20 +798,20 @@ private void initializeOpenXRInstance() { } } - if (missingOpenGL) { - throw new RuntimeException("OpenXR runtime does not support OpenGL, try using SteamVR instead"); + if (missingGraphics) { + throw new RuntimeException("OpenXR runtime is missing a supported graphics extension."); } //Create APP info XrApplicationInfo applicationInfo = XrApplicationInfo.calloc(stack); - applicationInfo.apiVersion(XR10.XR_CURRENT_API_VERSION); + applicationInfo.apiVersion(XR10.XR_MAKE_VERSION(1, 0, 40)); applicationInfo.applicationName(stack.UTF8("Vivecraft")); applicationInfo.applicationVersion(1); //Create instance info XrInstanceCreateInfo createInfo = XrInstanceCreateInfo.calloc(stack); createInfo.type(XR10.XR_TYPE_INSTANCE_CREATE_INFO); - createInfo.next(NULL); + createInfo.next(device.getPlatformInfo(stack)); createInfo.createFlags(0); createInfo.applicationInfo(applicationInfo); createInfo.enabledApiLayerNames(null); @@ -864,13 +860,29 @@ private void initializeOpenXRSession() { throw new RuntimeException("No compatible headset detected"); } - //Bind graphics - Struct graphics = this.getGraphicsAPI(stack); + XrSystemProperties systemProperties = XrSystemProperties.calloc(stack).type(XR10.XR_TYPE_SYSTEM_PROPERTIES); + error = XR10.xrGetSystemProperties(instance, systemID, systemProperties); + MCOpenXR.get().logError(error, "xrGetSystemProperties", ""); + XrSystemTrackingProperties trackingProperties = systemProperties.trackingProperties(); + XrSystemGraphicsProperties graphicsProperties = systemProperties.graphicsProperties(); + + MCOpenXR.get().systemName = memUTF8(memAddress(systemProperties.systemName())); + int vendor = systemProperties.vendorId(); + boolean orientationTracking = trackingProperties.orientationTracking(); + boolean positionTracking = trackingProperties.positionTracking(); + int maxWidth = graphicsProperties.maxSwapchainImageWidth(); + int maxHeight = graphicsProperties.maxSwapchainImageHeight(); + int maxLayerCount = graphicsProperties.maxLayerCount(); + + VRSettings.logger.info("Found device with id: {}", systemID); + VRSettings.logger.info("Headset Name: {}, Vendor: {}", MCOpenXR.get().systemName, vendor); + VRSettings.logger.info("Headset Orientation Tracking: {}, Position Tracking: {}", orientationTracking, positionTracking); + VRSettings.logger.info("Headset Max Width: {}, Max Height: {}, Max Layer Count: {}", maxWidth, maxHeight, maxLayerCount); //Create session XrSessionCreateInfo info = XrSessionCreateInfo.calloc(stack); info.type(XR10.XR_TYPE_SESSION_CREATE_INFO); - info.next(graphics.address()); + info.next(device.checkGraphics(stack, instance, systemID).address()); info.createFlags(0); info.systemId(systemID); @@ -1002,66 +1014,6 @@ private void initializeOpenXRSwapChain() { } } - private Struct getGraphicsAPI(MemoryStack stack) { - XrGraphicsRequirementsOpenGLKHR graphicsRequirements = XrGraphicsRequirementsOpenGLKHR.calloc(stack).type(KHROpenGLEnable.XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR); - KHROpenGLEnable.xrGetOpenGLGraphicsRequirementsKHR(instance, systemID, graphicsRequirements); - - XrSystemProperties systemProperties = XrSystemProperties.calloc(stack).type(XR10.XR_TYPE_SYSTEM_PROPERTIES); - int error = XR10.xrGetSystemProperties(instance, systemID, systemProperties); - logError(error, "xrGetSystemProperties", ""); - XrSystemTrackingProperties trackingProperties = systemProperties.trackingProperties(); - XrSystemGraphicsProperties graphicsProperties = systemProperties.graphicsProperties(); - - this.systemName = memUTF8(memAddress(systemProperties.systemName())); - int vendor = systemProperties.vendorId(); - boolean orientationTracking = trackingProperties.orientationTracking(); - boolean positionTracking = trackingProperties.positionTracking(); - int maxWidth = graphicsProperties.maxSwapchainImageWidth(); - int maxHeight = graphicsProperties.maxSwapchainImageHeight(); - int maxLayerCount = graphicsProperties.maxLayerCount(); - - VRSettings.logger.info("Found device with id: {}", systemID); - VRSettings.logger.info("Headset Name: {}, Vendor: {}", systemName, vendor); - VRSettings.logger.info("Headset Orientation Tracking: {}, Position Tracking: {}", orientationTracking, positionTracking); - VRSettings.logger.info("Headset Max Width: {}, Max Height: {}, Max Layer Count: {}", maxWidth, maxHeight, maxLayerCount); - - //Bind the OpenGL context to the OpenXR instance and create the session - Window window = mc.getWindow(); - long windowHandle = window.getWindow(); - if (Platform.get() == Platform.WINDOWS) { - return XrGraphicsBindingOpenGLWin32KHR.calloc(stack).set( - KHROpenGLEnable.XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR, - NULL, - User32.GetDC(GLFWNativeWin32.glfwGetWin32Window(windowHandle)), - GLFWNativeWGL.glfwGetWGLContext(windowHandle) - ); - } else if (Platform.get() == Platform.LINUX) { - long xDisplay = GLFWNativeX11.glfwGetX11Display(); - - long glXContext = GLFWNativeGLX.glfwGetGLXContext(windowHandle); - long glXWindowHandle = GLFWNativeGLX.glfwGetGLXWindow(windowHandle); - - int fbXID = glXQueryDrawable(xDisplay, glXWindowHandle, GLX_FBCONFIG_ID); - PointerBuffer fbConfigBuf = glXChooseFBConfig(xDisplay, X11.XDefaultScreen(xDisplay), stackInts(GLX_FBCONFIG_ID, fbXID, 0)); - if(fbConfigBuf == null) { - throw new IllegalStateException("Your framebuffer config was null, make a github issue"); - } - long fbConfig = fbConfigBuf.get(); - - return XrGraphicsBindingOpenGLXlibKHR.calloc(stack).set( - KHROpenGLEnable.XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, - NULL, - xDisplay, - (int) Objects.requireNonNull(glXGetVisualFromFBConfig(xDisplay, fbConfig)).visualid(), - fbConfig, - glXWindowHandle, - glXContext - ); - } else { - throw new IllegalStateException("Macos not supported"); - } - } - /** * Creates an array of XrStructs with their types pre set to @param type */ @@ -1486,16 +1438,4 @@ protected void logError(int xrResult, String caller, String... args) { VRSettings.logger.error("{} for {} errored: {}", caller, String.join(" ", args), getResultName(xrResult)); } } - - /** - * logs all results except XR_SUCCESS - * @param xrResult result to check - * @param caller where the xrResult came from - * @param args arguments may be helpful in locating the error - */ - protected void logAll(int xrResult, String caller, String... args) { - if (xrResult != XR10.XR_SUCCESS) { - VRSettings.logger.error("{} for {} errored: {}", caller, String.join(" ", args), getResultName(xrResult)); - } - } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java index 191e36397..aa8352b38 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java @@ -41,10 +41,7 @@ public void createRenderTexture(int width, int height) throws RenderConfigExcept //Now we know the amount, create the image buffer int imageCount = intBuffer.get(0); - XrSwapchainImageOpenGLKHR.Buffer swapchainImageBuffer = XrSwapchainImageOpenGLKHR.calloc(imageCount, stack); - for (XrSwapchainImageOpenGLKHR image : swapchainImageBuffer) { - image.type(KHROpenGLEnable.XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR); - } + XrSwapchainImageOpenGLKHR.Buffer swapchainImageBuffer = this.openxr.device.createImageBuffers(imageCount, stack); error = XR10.xrEnumerateSwapchainImages(openxr.swapchain, intBuffer, XrSwapchainImageBaseHeader.create(swapchainImageBuffer.address(), swapchainImageBuffer.capacity())); this.openxr.logError(error, "xrEnumerateSwapchainImages", "get images"); @@ -116,6 +113,7 @@ public Matrix4f getProjectionMatrix(int eyeType, float nearClip, float farClip) @Override public void endFrame() throws RenderConfigException { + GL31.glBindFramebuffer(GL31.GL_READ_FRAMEBUFFER, getLeftEyeTarget().frameBufferId); GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, leftFramebuffers[swapIndex].frameBufferId); GL31.glBlitFramebuffer(0,0, getLeftEyeTarget().viewWidth, getLeftEyeTarget().viewHeight, 0,0, leftFramebuffers[swapIndex].viewWidth, leftFramebuffers[swapIndex].viewHeight, GL31.GL_STENCIL_BUFFER_BIT | GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); @@ -124,35 +122,34 @@ public void endFrame() throws RenderConfigException { GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, rightFramebuffers[swapIndex].frameBufferId); GL31.glBlitFramebuffer(0,0, getRightEyeTarget().viewWidth, getRightEyeTarget().viewHeight, 0,0, rightFramebuffers[swapIndex].viewWidth, rightFramebuffers[swapIndex].viewHeight, GL31.GL_STENCIL_BUFFER_BIT | GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); + try (MemoryStack stack = MemoryStack.stackPush()){ - if (true) { - PointerBuffer layers = stack.callocPointer(1); - int error; - - error = XR10.xrReleaseSwapchainImage( - openxr.swapchain, - XrSwapchainImageReleaseInfo.calloc(stack) - .type(XR10.XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO)); - this.openxr.logError(error, "xrReleaseSwapchainImage", ""); - - XrCompositionLayerProjection compositionLayerProjection = XrCompositionLayerProjection.calloc(stack) - .type(XR10.XR_TYPE_COMPOSITION_LAYER_PROJECTION) - .space(openxr.xrAppSpace) - .views(projectionLayerViews); - - layers.put(compositionLayerProjection); - - layers.flip(); - - error = XR10.xrEndFrame( - openxr.session, - XrFrameEndInfo.calloc(stack) - .type(XR10.XR_TYPE_FRAME_END_INFO) - .displayTime(openxr.time) - .environmentBlendMode(XR10.XR_ENVIRONMENT_BLEND_MODE_OPAQUE) - .layers(layers)); - this.openxr.logError(error, "xrEndFrame", ""); - } + PointerBuffer layers = stack.callocPointer(1); + int error; + + error = XR10.xrReleaseSwapchainImage( + openxr.swapchain, + XrSwapchainImageReleaseInfo.calloc(stack) + .type(XR10.XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO)); + this.openxr.logError(error, "xrReleaseSwapchainImage", ""); + + XrCompositionLayerProjection compositionLayerProjection = XrCompositionLayerProjection.calloc(stack) + .type(XR10.XR_TYPE_COMPOSITION_LAYER_PROJECTION) + .space(openxr.xrAppSpace) + .views(projectionLayerViews); + + layers.put(compositionLayerProjection); + + layers.flip(); + + error = XR10.xrEndFrame( + openxr.session, + XrFrameEndInfo.calloc(stack) + .type(XR10.XR_TYPE_FRAME_END_INFO) + .displayTime(openxr.time) + .environmentBlendMode(XR10.XR_ENVIRONMENT_BLEND_MODE_OPAQUE) + .layers(layers)); + this.openxr.logError(error, "xrEndFrame", ""); projectionLayerViews.close(); } @@ -177,4 +174,4 @@ public RenderTarget getRightEyeTarget() { public Tuple getRenderTextureSizes() { return new Tuple<>(openxr.width, openxr.height); } -} +} \ No newline at end of file diff --git a/common/src/main/java/org/vivecraft/util/VLoader.java b/common/src/main/java/org/vivecraft/util/VLoader.java new file mode 100644 index 000000000..cecdd9a10 --- /dev/null +++ b/common/src/main/java/org/vivecraft/util/VLoader.java @@ -0,0 +1,14 @@ +package org.vivecraft.util; + +public class VLoader { + static { + System.loadLibrary("vloader"); + } + + public static native long getEGLContext(); + public static native long getEGLConfig(); + public static native long getEGLDisplay(); + public static native long getDalvikVM(); + public static native long getDalvikActivity(); + public static native void setupAndroid(); +} diff --git a/fabric/build.gradle b/fabric/build.gradle index 37623b624..36378cb5d 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -67,10 +67,10 @@ dependencies { include(implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos")) include(implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows")) - include(implementation("org.lwjgl:lwjgl-openxr:3.3.2")) - include(implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux")) + // Use custom OpenXR lib for Android and GLES bindings + include(implementation("QuestCraftPlusPlus:lwjgl3:3.3.2:lwjgl-openxr-3.3.2")) include(implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows")) - + include(implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux")) } processResources { @@ -128,4 +128,4 @@ publishing { repositories { // Add repositories to publish to here. } -} +} \ No newline at end of file diff --git a/forge/build.gradle b/forge/build.gradle index 787a4ecbf..1557fdbd5 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -60,7 +60,8 @@ dependencies { forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") - forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2") + // Use custom OpenXR lib for Android and GLES bindings + forgeRuntimeLibrary("QuestCraftPlusPlus:lwjgl3:3.3.2:lwjgl-openxr-3.3.2") forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") @@ -70,7 +71,7 @@ dependencies { bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") { transitive = false } bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") { transitive = false } - bundle("org.lwjgl:lwjgl-openxr:3.3.2") { transitive = false } + bundle("QuestCraftPlusPlus:lwjgl3:3.3.2:lwjgl-openxr-3.3.2") { transitive = false } bundle("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") { transitive = false } bundle("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") { transitive = false } } @@ -133,4 +134,4 @@ publishing { repositories { // Add repositories to publish to here. } -} +} \ No newline at end of file diff --git a/neoforge/build.gradle b/neoforge/build.gradle index 1151f4272..f88cb0e37 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -35,7 +35,8 @@ dependencies { forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") - forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2") + // Use custom OpenXR lib for Android and GLES bindings + forgeRuntimeLibrary("QuestCraftPlusPlus:lwjgl3:3.3.2:lwjgl-openxr-3.3.2") forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") @@ -45,7 +46,7 @@ dependencies { bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") { transitive = false } bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") { transitive = false } - bundle("org.lwjgl:lwjgl-openxr:3.3.2") { transitive = false } + bundle("QuestCraftPlusPlus:lwjgl3:3.3.2:lwjgl-openxr-3.3.2") { transitive = false } bundle("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") { transitive = false } bundle("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") { transitive = false } } @@ -109,4 +110,4 @@ publishing { repositories { // Add repositories to publish to here. } -} +} \ No newline at end of file From c154b9dd8bad5102d5e923745e232e505b907b8a Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Tue, 3 Dec 2024 20:19:52 +0100 Subject: [PATCH 08/76] update after cleanup --- .../provider/openxr/DeviceCompat.java | 4 +- .../client_vr/provider/openxr/MCOpenXR.java | 54 ++++++++----------- .../provider/openxr/OpenXRStereoRenderer.java | 19 ++++--- .../render/helpers/ShaderHelper.java | 14 ++--- .../client_vr/settings/VRSettings.java | 3 +- 5 files changed, 45 insertions(+), 49 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java index ecb9987db..c3cff1fc4 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java @@ -41,7 +41,7 @@ public long getPlatformInfo(MemoryStack stack) { @Override public void initOpenXRLoader(MemoryStack stack) { - VRSettings.logger.info("Platform: {}", System.getProperty("os.version")); + VRSettings.LOGGER.info("Platform: {}", System.getProperty("os.version")); } @Override @@ -114,7 +114,7 @@ public long getPlatformInfo(MemoryStack stack) { @Override public void initOpenXRLoader(MemoryStack stack) { - VRSettings.logger.info("Platform: {}", System.getProperty("os.version")); + VRSettings.LOGGER.info("Platform: {}", System.getProperty("os.version")); VLoader.setupAndroid(); XrLoaderInitInfoAndroidKHR initInfo = XrLoaderInitInfoAndroidKHR.calloc(stack).set( KHRLoaderInitAndroid.XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 3340d5f57..ee1e01e2b 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -15,7 +15,7 @@ import org.lwjgl.openxr.*; import org.lwjgl.system.MemoryStack; import org.vivecraft.client.VivecraftVRMod; -import org.vivecraft.client.utils.Utils; +import org.vivecraft.client.utils.MathUtils; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler; @@ -25,7 +25,6 @@ import org.vivecraft.client_vr.provider.VRRenderer; import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.provider.control.VRInputActionSet; -import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.client_xr.render_pass.RenderPassManager; @@ -44,7 +43,7 @@ public class MCOpenXR extends MCVR { - private static MCOpenXR ome; + private static MCOpenXR OME; public XrInstance instance; public XrSession session; public XrSpace xrAppSpace; @@ -78,7 +77,7 @@ public class MCOpenXR extends MCVR { public MCOpenXR(Minecraft mc, ClientDataHolderVR dh) { super(mc, dh, VivecraftVRMod.INSTANCE); - ome = this; + OME = this; this.hapticScheduler = new OpenXRHapticSchedular(); } @@ -88,11 +87,6 @@ public String getName() { return "OpenXR"; } - @Override - public String getID() { - return "openxr"; - } - @Override public void destroy() { int error; @@ -287,7 +281,7 @@ private void updatePose() { this.aimSource[0] = new Vec3(space_location.pose().position$().x(), space_location.pose().position$().y(), space_location.pose().position$().z()); this.controllerHistory[0].add(this.getAimSource(0)); this.controllerForwardHistory[0].add(this.getAimSource(0)); - Vec3 vec33 = this.controllerRotation[0].transform(this.up).toVector3d(); + Vec3 vec33 = this.controllerRotation[0].transform(UP).toVector3d(); this.controllerUpHistory[0].add(vec33); this.controllerTracking[0] = true; } else { @@ -302,7 +296,7 @@ private void updatePose() { this.aimSource[1] = new Vec3(space_location.pose().position$().x(), space_location.pose().position$().y(), space_location.pose().position$().z()); this.controllerHistory[1].add(this.getAimSource(1)); this.controllerForwardHistory[1].add(this.getAimSource(1)); - Vec3 vec32 = this.controllerRotation[1].transform(this.up).toVector3d(); + Vec3 vec32 = this.controllerRotation[1].transform(UP).toVector3d(); this.controllerUpHistory[1].add(vec32); this.controllerTracking[1] = true; } else { @@ -317,8 +311,8 @@ private void updatePose() { this.handRotation[1] = hmdRotation; this.controllerRotation[0] = hmdRotation; this.controllerRotation[1] = hmdRotation; - this.aimSource[1] = this.getCenterEyePosition(); - this.aimSource[0] = this.getCenterEyePosition(); + this.aimSource[1] = this.getEyePosition(RenderPass.CENTER); + this.aimSource[0] = this.getEyePosition(RenderPass.CENTER); if (this.mc.screen == null) { Vec3 vec31 = this.getAimVector(1); @@ -427,7 +421,7 @@ public Vec3 getEyePosition(RenderPass eye) { if (matrix4f == null) { org.vivecraft.common.utils.math.Matrix4f matrix4f2 = this.hmdPose; - Vector3 vector31 = Utils.convertMatrix4ftoTranslationVector(matrix4f2); + Vector3 vector31 = MathUtils.convertMatrix4ftoTranslationVector(matrix4f2); if (this.dh.vrSettings.seated || this.dh.vrSettings.allowStandingOriginOffset) { if (this.dh.vr.isHMDTracking()) { @@ -437,7 +431,7 @@ public Vec3 getEyePosition(RenderPass eye) { return vector31.toVector3d(); } else { - Vector3 vector3 = Utils.convertMatrix4ftoTranslationVector(matrix4f); + Vector3 vector3 = MathUtils.convertMatrix4ftoTranslationVector(matrix4f); if (this.dh.vrSettings.seated || this.dh.vrSettings.allowStandingOriginOffset) { if (this.dh.vr.isHMDTracking()) { @@ -623,7 +617,7 @@ private boolean updateActiveActionSets() { } } - if (KeyboardHandler.Showing || RadialHandler.isShowing()) { + if (KeyboardHandler.SHOWING || RadialHandler.isShowing()) { arraylist.add(VRInputActionSet.KEYBOARD); } @@ -740,6 +734,7 @@ public boolean init() { this.initializeOpenXRSession(); this.initializeOpenXRSpace(); this.initializeOpenXRSwapChain(); + this.initInputAndApplication(); } catch (Exception e) { e.printStackTrace(); this.initSuccess = false; @@ -840,7 +835,7 @@ private void initializeOpenXRInstance() { } public static MCOpenXR get() { - return ome; + return OME; } private void initializeOpenXRSession() { @@ -874,10 +869,10 @@ private void initializeOpenXRSession() { int maxHeight = graphicsProperties.maxSwapchainImageHeight(); int maxLayerCount = graphicsProperties.maxLayerCount(); - VRSettings.logger.info("Found device with id: {}", systemID); - VRSettings.logger.info("Headset Name: {}, Vendor: {}", MCOpenXR.get().systemName, vendor); - VRSettings.logger.info("Headset Orientation Tracking: {}, Position Tracking: {}", orientationTracking, positionTracking); - VRSettings.logger.info("Headset Max Width: {}, Max Height: {}, Max Layer Count: {}", maxWidth, maxHeight, maxLayerCount); + VRSettings.LOGGER.info("Found device with id: {}", systemID); + VRSettings.LOGGER.info("Headset Name: {}, Vendor: {}", MCOpenXR.get().systemName, vendor); + VRSettings.LOGGER.info("Headset Orientation Tracking: {}, Position Tracking: {}", orientationTracking, positionTracking); + VRSettings.LOGGER.info("Headset Max Width: {}, Max Height: {}, Max Layer Count: {}", maxWidth, maxHeight, maxLayerCount); //Create session XrSessionCreateInfo info = XrSessionCreateInfo.calloc(stack); @@ -1028,13 +1023,6 @@ static ByteBuffer bufferStack(int capacity, int sizeof, int type) { return b; } - - @Override - public boolean postinit() throws RenderConfigException { - this.initInputAndApplication(); - return inputInitialized; - } - private void initInputAndApplication() { this.populateInputActions(); @@ -1049,11 +1037,11 @@ private void initInputAndApplication() { @Override public Matrix4f getControllerComponentTransform(int var1, String var2) { - return Utils.Matrix4fSetIdentity(new Matrix4f()); + return new Matrix4f(); } @Override - public boolean hasThirdController() { + public boolean hasCameraTracker() { return false; } @@ -1181,7 +1169,7 @@ private void loadDefaultBindings() { try (MemoryStack stack = MemoryStack.stackPush()) { int error; for (String headset: XRBindings.supportedHeadsets()) { - VRSettings.logger.info("loading defaults for {}", headset); + VRSettings.LOGGER.info("loading defaults for {}", headset); Pair[] defaultBindings = XRBindings.getBinding(headset).toArray(new Pair[0]); XrActionSuggestedBinding.Buffer bindings = XrActionSuggestedBinding.calloc(defaultBindings.length + 6, stack); //TODO different way of adding controller poses @@ -1189,7 +1177,7 @@ private void loadDefaultBindings() { Pair pair = defaultBindings[i]; VRInputAction binding = this.getInputActionByName(pair.getLeft()); if (binding.handle == 0L) { - VRSettings.logger.error("Handle for '{}'/'{}' is null", pair.getLeft(), pair.getRight()); + VRSettings.LOGGER.error("Handle for '{}'/'{}' is null", pair.getLeft(), pair.getRight()); continue; } bindings.get(i).set( @@ -1435,7 +1423,7 @@ private String getResultName(int xrResult) { */ protected void logError(int xrResult, String caller, String... args) { if (xrResult < 0) { - VRSettings.logger.error("{} for {} errored: {}", caller, String.join(" ", args), getResultName(xrResult)); + VRSettings.LOGGER.error("{} for {} errored: {}", caller, String.join(" ", args), getResultName(xrResult)); } } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java index aa8352b38..3cebe96cc 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java @@ -11,7 +11,9 @@ import org.vivecraft.client_vr.VRTextureTarget; import org.vivecraft.client_vr.provider.VRRenderer; import org.vivecraft.client_vr.render.RenderConfigException; +import org.vivecraft.client_vr.render.helpers.RenderHelper; +import java.io.IOException; import java.nio.IntBuffer; public class OpenXRStereoRenderer extends VRRenderer { @@ -52,18 +54,18 @@ public void createRenderTexture(int width, int height) throws RenderConfigExcept for (int i = 0; i < imageCount; i++) { XrSwapchainImageOpenGLKHR openxrImage = swapchainImageBuffer.get(i); leftFramebuffers[i] = new VRTextureTarget("L Eye " + i, width, height, openxrImage.image(), 0); - this.checkGLError("Left Eye framebuffer setup"); + RenderHelper.checkGLError("Left Eye framebuffer setup"); rightFramebuffers[i] = new VRTextureTarget("R Eye " + i, width, height, openxrImage.image(), 1); - this.checkGLError("Right Eye framebuffer setup"); + RenderHelper.checkGLError("Right Eye framebuffer setup"); } - this.rightFramebuffer = new VRTextureTarget("R Eye mirror", width, height, true, false, -1, true, true, ClientDataHolderVR.getInstance().vrSettings.vrUseStencil); - this.leftFramebuffer = new VRTextureTarget("L Eye mirror", width, height, true, false, -1, true, true, ClientDataHolderVR.getInstance().vrSettings.vrUseStencil); + this.rightFramebuffer = new VRTextureTarget("R Eye mirror", width, height, true, -1, true, true, ClientDataHolderVR.getInstance().vrSettings.vrUseStencil); + this.leftFramebuffer = new VRTextureTarget("L Eye mirror", width, height, true, -1, true, true, ClientDataHolderVR.getInstance().vrSettings.vrUseStencil); } } @Override - public void setupRenderConfiguration(boolean render) throws Exception { + public void setupRenderConfiguration(boolean render) throws IOException, RenderConfigException { super.setupRenderConfiguration(render); if (!render) { @@ -170,8 +172,13 @@ public RenderTarget getRightEyeTarget() { return rightFramebuffer; } + @Override + public String getName() { + return "OpenXR"; + } + @Override public Tuple getRenderTextureSizes() { return new Tuple<>(openxr.width, openxr.height); } -} \ No newline at end of file +} diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java index f74b94efc..3396a2d6a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java @@ -253,8 +253,8 @@ public static void drawMirror() { )) { // show both eyes side by side - RenderTarget leftEye = DATA_HOLDER.vrRenderer.framebufferEye0; - RenderTarget rightEye = DATA_HOLDER.vrRenderer.framebufferEye1; + RenderTarget leftEye = DATA_HOLDER.vrRenderer.getLeftEyeTarget(); + RenderTarget rightEye = DATA_HOLDER.vrRenderer.getRightEyeTarget(); int screenWidth = ((WindowExtension) (Object) MC.getWindow()).vivecraft$getActualScreenWidth() / 2; int screenHeight = ((WindowExtension) (Object) MC.getWindow()).vivecraft$getActualScreenHeight(); @@ -271,7 +271,7 @@ public static void drawMirror() { float xCrop = 0.0F; float yCrop = 0.0F; boolean keepAspect = false; - RenderTarget source = DATA_HOLDER.vrRenderer.framebufferEye0; + RenderTarget source = DATA_HOLDER.vrRenderer.getLeftEyeTarget(); if (DATA_HOLDER.vrSettings.displayMirrorUseScreenshotCamera && DATA_HOLDER.cameraTracker.isVisible()) @@ -288,11 +288,11 @@ public static void drawMirror() { DATA_HOLDER.vrSettings.displayMirrorMode == VRSettings.MirrorMode.OFF) { if (!DATA_HOLDER.vrSettings.displayMirrorLeftEye) { - source = DATA_HOLDER.vrRenderer.framebufferEye1; + source = DATA_HOLDER.vrRenderer.getRightEyeTarget(); } } else if (DATA_HOLDER.vrSettings.displayMirrorMode == VRSettings.MirrorMode.CROPPED) { if (!DATA_HOLDER.vrSettings.displayMirrorLeftEye) { - source = DATA_HOLDER.vrRenderer.framebufferEye1; + source = DATA_HOLDER.vrRenderer.getRightEyeTarget(); } xCrop = DATA_HOLDER.vrSettings.mirrorCrop; @@ -363,9 +363,9 @@ public static void doMixedRealityMirror() { source = DATA_HOLDER.vrRenderer.framebufferUndistorted; } else { if (DATA_HOLDER.vrSettings.displayMirrorLeftEye) { - source = DATA_HOLDER.vrRenderer.framebufferEye0; + source = DATA_HOLDER.vrRenderer.getLeftEyeTarget(); } else { - source = DATA_HOLDER.vrRenderer.framebufferEye1; + source = DATA_HOLDER.vrRenderer.getRightEyeTarget(); } } VRShaders.MIXED_REALITY_SHADER.setSampler("firstPersonColor", source.getColorTextureId()); 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 8f3e26190..c95a477eb 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 @@ -142,6 +142,7 @@ public enum ShaderGUIRender implements OptionEnum { public enum VRProvider implements OptionEnum { OPENVR, + OPENXR, NULLVR } @@ -1724,7 +1725,7 @@ void onOptionChange() { @Override String getDisplayString(String prefix, Object value) { if (VRState.VR_ENABLED) { - RenderTarget eye0 = ClientDataHolderVR.getInstance().vrRenderer.framebufferEye0; + RenderTarget eye0 = ClientDataHolderVR.getInstance().vrRenderer.getLeftEyeTarget(); return prefix + Math.round((float) value * 100) + "% (" + (int) Math.ceil(eye0.viewWidth * Math.sqrt((float) value)) + "x" + (int) Math.ceil(eye0.viewHeight * Math.sqrt((float) value)) + ")"; From 7264eed0898a4e78e09d80f7287859ab5bcf02ae Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Thu, 5 Dec 2024 21:22:19 +0100 Subject: [PATCH 09/76] update + cleanup currently, it seems some HMD position is wrong --- .../vivecraft/client_vr/provider/MCVR.java | 13 +- .../control/TrackpadSwipeSampler.java | 1 - .../provider/control/VRInputAction.java | 2 - .../provider/openvr_lwjgl/MCOpenVR.java | 103 ----- .../client_vr/provider/openxr/MCOpenXR.java | 370 +++++------------- .../client_vr/provider/openxr/OpenXRUtil.java | 41 +- .../mixin/client_vr/KeyboardInputVRMixin.java | 3 +- 7 files changed, 103 insertions(+), 430 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java index a2468e245..1cce767f8 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java @@ -44,9 +44,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.lwjgl.openvr.VR.k_ulInvalidInputValueHandle; - public abstract class MCVR { + public static final int LEFT_CONTROLLER = 1; + public static final int RIGHT_CONTROLLER = 0; + public static final int CAMERA_TRACKER = 2; protected Minecraft mc; protected ClientDataHolderVR dh; protected static MCVR ME; @@ -1240,8 +1241,8 @@ private void processInputAction(VRInputAction action) { private void processScrollInput(KeyMapping keyMapping, Runnable upCallback, Runnable downCallback) { VRInputAction action = this.getInputAction(keyMapping); - if (action.isEnabled() && action.getLastOrigin() != k_ulInvalidInputValueHandle) { - float value = action.getAxis2D(false).getY(); + if (action.isEnabled() && action.getLastOrigin() != 0L) { /** {@link org.lwjgl.openvr.VR.k_ulInvalidInputValueHandle} and {@link org.lwjgl.system.MemoryUtil.NULL} are both 0 */ + float value = action.getAxis2D(false).y(); if (value != 0.0F) { if (value > 0.0F) { upCallback.run(); @@ -1263,7 +1264,7 @@ private void processScrollInput(KeyMapping keyMapping, Runnable upCallback, Runn private void processSwipeInput(KeyMapping keyMapping, Runnable leftCallback, Runnable rightCallback, Runnable upCallback, Runnable downCallback) { VRInputAction action = this.getInputAction(keyMapping); - if (action.isEnabled() && action.getLastOrigin() != k_ulInvalidInputValueHandle) { + if (action.isEnabled() && action.getLastOrigin() != 0L) { /** {@link org.lwjgl.openvr.VR.k_ulInvalidInputValueHandle} and {@link org.lwjgl.system.MemoryUtil.NULL} are both 0 */ ControllerType controller = this.findActiveBindingControllerType(keyMapping); if (controller != null) { @@ -1294,8 +1295,6 @@ private void processSwipeInput(KeyMapping keyMapping, Runnable leftCallback, Run this.triggerHapticPulse(controller, 0.001F, 400.0F, 0.5F); rightCallback.run(); } - - } } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java index cc2954362..5dfaa3b8f 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java @@ -6,7 +6,6 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.provider.ControllerType; import org.vivecraft.client_vr.provider.openvr_lwjgl.MCOpenVR; -import org.vivecraft.client_vr.provider.openvr_lwjgl.VRInputAction; public class TrackpadSwipeSampler { private static final int UP = 0; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java index c1e8eace9..b664d57db 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java @@ -12,8 +12,6 @@ import org.vivecraft.client_vr.provider.ControllerType; import org.vivecraft.client_vr.provider.HandedKeyBinding; import org.vivecraft.client_vr.provider.InputSimulator; -import org.vivecraft.client_vr.provider.MCVR; -import org.vivecraft.client_vr.provider.openvr_lwjgl.control.VRInputActionSet; import javax.annotation.Nullable; import java.util.ArrayList; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index 0329233d4..be3d7689c 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -63,10 +63,6 @@ * MCVR implementation to communicate with OpenVR/SteamVR */ public class MCOpenVR extends MCVR { - public static final int LEFT_CONTROLLER = 1; - public static final int RIGHT_CONTROLLER = 0; - public static final int CAMERA_TRACKER = 2; - protected static MCOpenVR OME; // action paths @@ -1076,105 +1072,6 @@ private void loadActionManifest() throws RenderConfigException { } } - /** - * updates the KeyMapping state that is linked to the given VRInputAction - * @param action VRInputAction to process - */ - private void processInputAction(VRInputAction action) { - if (action.isActive() && action.isEnabledRaw() && - // try to prevent double left clicks - (!ClientDataHolderVR.getInstance().vrSettings.ingameBindingsInGui || - !(action.actionSet == VRInputActionSet.INGAME && - action.keyBinding.key.getType() == InputConstants.Type.MOUSE && - action.keyBinding.key.getValue() == GLFW.GLFW_MOUSE_BUTTON_LEFT && this.mc.screen != null - ) - )) - { - if (action.isButtonChanged()) { - if (action.isButtonPressed() && action.isEnabled()) { - // We do this, so shit like closing a GUI by clicking a button won't - // also click in the world immediately after. - if (!this.ignorePressesNextFrame) { - action.pressBinding(); - } - } else { - action.unpressBinding(); - } - } - } else { - action.unpressBinding(); - } - } - - /** - * checks the axis input of the VRInputAction linked to {@code keyMapping} and runs the callbacks when it's non 0 - * @param keyMapping KeyMapping to check - * @param upCallback action to do when the axis input is positive - * @param downCallback action to do when the axis input is negative - */ - private void processScrollInput(KeyMapping keyMapping, Runnable upCallback, Runnable downCallback) { - VRInputAction action = this.getInputAction(keyMapping); - - if (action.isEnabled() && action.getLastOrigin() != k_ulInvalidInputValueHandle) { - float value = action.getAxis2D(false).y(); - if (value != 0.0F) { - if (value > 0.0F) { - upCallback.run(); - } else if (value < 0.0F) { - downCallback.run(); - } - } - } - } - - /** - * checks the trackpad input of the controller the {@code keyMapping} is on - * @param keyMapping KeyMapping to check - * @param leftCallback action to do when swiped to the left - * @param rightCallback action to do when swiped to the right - * @param upCallback action to do when swiped to the up - * @param downCallback action to do when swiped to the down - */ - private void processSwipeInput(KeyMapping keyMapping, Runnable leftCallback, Runnable rightCallback, Runnable upCallback, Runnable downCallback) { - VRInputAction action = this.getInputAction(keyMapping); - - if (action.isEnabled() && action.getLastOrigin() != k_ulInvalidInputValueHandle) { - ControllerType controller = this.findActiveBindingControllerType(keyMapping); - - if (controller != null) { - // if that keyMapping is not tracked yet, create a new sampler - if (!this.trackpadSwipeSamplers.containsKey(keyMapping.getName())) { - this.trackpadSwipeSamplers.put(keyMapping.getName(), new TrackpadSwipeSampler()); - } - - TrackpadSwipeSampler trackpadswipesampler = this.trackpadSwipeSamplers.get(keyMapping.getName()); - trackpadswipesampler.update(controller, action.getAxis2D(false)); - - if (trackpadswipesampler.isSwipedUp() && upCallback != null) { - this.triggerHapticPulse(controller, 0.001F, 400.0F, 0.5F); - upCallback.run(); - } - - if (trackpadswipesampler.isSwipedDown() && downCallback != null) { - this.triggerHapticPulse(controller, 0.001F, 400.0F, 0.5F); - downCallback.run(); - } - - if (trackpadswipesampler.isSwipedLeft() && leftCallback != null) { - this.triggerHapticPulse(controller, 0.001F, 400.0F, 0.5F); - leftCallback.run(); - } - - if (trackpadswipesampler.isSwipedRight() && rightCallback != null) { - this.triggerHapticPulse(controller, 0.001F, 400.0F, 0.5F); - rightCallback.run(); - } - - - } - } - } - /** * fetches all available VREvents from OpenVR */ diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index ee1e01e2b..4d2850832 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -2,12 +2,11 @@ import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; -import net.minecraft.util.Mth; -import net.minecraft.world.phys.Vec3; import org.apache.commons.lang3.tuple.Pair; +import org.joml.Matrix4f; import org.joml.Vector2f; +import org.joml.Vector3f; import org.lwjgl.PointerBuffer; -import org.lwjgl.glfw.*; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL21; import org.lwjgl.opengl.GL30; @@ -15,22 +14,16 @@ import org.lwjgl.openxr.*; import org.lwjgl.system.MemoryStack; import org.vivecraft.client.VivecraftVRMod; -import org.vivecraft.client.utils.MathUtils; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler; import org.vivecraft.client_vr.provider.ControllerType; -import org.vivecraft.client_vr.provider.InputSimulator; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.VRRenderer; import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.provider.control.VRInputActionSet; import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.settings.VRSettings; -import org.vivecraft.client_xr.render_pass.RenderPassManager; -import org.vivecraft.common.utils.lwjgl.Vector3f; -import org.vivecraft.common.utils.math.Matrix4f; -import org.vivecraft.common.utils.math.Vector3; import javax.annotation.Nullable; import java.nio.ByteBuffer; @@ -79,7 +72,6 @@ public MCOpenXR(Minecraft mc, ClientDataHolderVR dh) { super(mc, dh, VivecraftVRMod.INSTANCE); OME = this; this.hapticScheduler = new OpenXRHapticSchedular(); - } @Override @@ -121,15 +113,6 @@ public void destroy() { eventDataBuffer.close(); } - @Override - protected void triggerBindingHapticPulse(KeyMapping binding, int duration) { - ControllerType controllertype = this.findActiveBindingControllerType(binding); - - if (controllertype != null) { - this.triggerHapticPulse(controllertype, duration); - } - } - @Override protected ControllerType findActiveBindingControllerType(KeyMapping binding) { if (!this.inputInitialized) { @@ -165,7 +148,7 @@ protected ControllerType findActiveBindingControllerType(KeyMapping binding) { public void poll(long var1) { if (this.initialized) { this.mc.getProfiler().push("events"); - //pollVREvents(); + this.pollVREvents(); if (!this.dh.vrSettings.seated) { this.mc.getProfiler().popPush("controllers"); @@ -191,11 +174,10 @@ public void poll(long var1) { } private void updatePose() { - RenderPassManager.setGUIRenderPass(); - if (mc == null) { return; } + try (MemoryStack stack = MemoryStack.stackPush()) { XrFrameState frameState = XrFrameState.calloc(stack).type(XR10.XR_TYPE_FRAME_STATE); @@ -236,154 +218,17 @@ private void updatePose() { if (error >= 0) { OpenXRUtil.openXRPoseToMarix(space_location.pose(), this.hmdPose); OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.hmdRotation); - - Vec3 vec3 = new Vec3(space_location.pose().position$().x(), space_location.pose().position$().y(), space_location.pose().position$().z()); - this.hmdHistory.add(vec3); - Vector3 vector3 = this.hmdRotation.transform(new Vector3(0.0F, -0.1F, 0.1F)); - this.hmdPivotHistory.add(new Vec3((double) vector3.getX() + vec3.x, (double) vector3.getY() + vec3.y, (double) vector3.getZ() + vec3.z)); headIsTracking = true; } else { headIsTracking = false; + this.hmdPose.identity(); + this.hmdPose.m31(1.6F); } //Eye positions OpenXRUtil.openXRPoseToMarix(viewBuffer.get(0).pose(), this.hmdPoseLeftEye); OpenXRUtil.openXRPoseToMarix(viewBuffer.get(1).pose(), this.hmdPoseRightEye); - //reverse - if (this.dh.vrSettings.reverseHands) { - XrSpace temp = gripSpace[0]; - gripSpace[0] = gripSpace[1]; - gripSpace[1] = temp; - temp = aimSpace[0]; - aimSpace[0] = aimSpace[1]; - aimSpace[1] = temp; - } - - //Controller aim and grip poses - error = XR10.xrLocateSpace(gripSpace[0], xrAppSpace, time, space_location); - logError(error, "xrLocateSpace", "gripSpace[0]"); - if (error >= 0) { - OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.handRotation[0]); - } - - error = XR10.xrLocateSpace(gripSpace[1], xrAppSpace, time, space_location); - logError(error, "xrLocateSpace", "gripSpace[1]"); - if (error >= 0) { - OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.handRotation[1]); - } - - error = XR10.xrLocateSpace(aimSpace[0], xrAppSpace, time, space_location); - logError(error, "xrLocateSpace", "aimSpace[0]"); - if (error >= 0) { - OpenXRUtil.openXRPoseToMarix(space_location.pose(), this.controllerPose[0]); - OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.controllerRotation[0]); - this.aimSource[0] = new Vec3(space_location.pose().position$().x(), space_location.pose().position$().y(), space_location.pose().position$().z()); - this.controllerHistory[0].add(this.getAimSource(0)); - this.controllerForwardHistory[0].add(this.getAimSource(0)); - Vec3 vec33 = this.controllerRotation[0].transform(UP).toVector3d(); - this.controllerUpHistory[0].add(vec33); - this.controllerTracking[0] = true; - } else { - this.controllerTracking[0] = false; - } - - error = XR10.xrLocateSpace(aimSpace[1], xrAppSpace, time, space_location); - logError(error, "xrLocateSpace", "aimSpace[1]"); - if (error >= 0) { - OpenXRUtil.openXRPoseToMarix(space_location.pose(), this.controllerPose[1]); - OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.controllerRotation[1]); - this.aimSource[1] = new Vec3(space_location.pose().position$().x(), space_location.pose().position$().y(), space_location.pose().position$().z()); - this.controllerHistory[1].add(this.getAimSource(1)); - this.controllerForwardHistory[1].add(this.getAimSource(1)); - Vec3 vec32 = this.controllerRotation[1].transform(UP).toVector3d(); - this.controllerUpHistory[1].add(vec32); - this.controllerTracking[1] = true; - } else { - this.controllerTracking[1] = false; - } - - //TODO merge with updateAim so it's one method - if (this.dh.vrSettings.seated) { - this.controllerPose[0] = this.hmdPose.inverted().inverted(); - this.controllerPose[1] = this.hmdPose.inverted().inverted(); - this.handRotation[0] = hmdRotation; - this.handRotation[1] = hmdRotation; - this.controllerRotation[0] = hmdRotation; - this.controllerRotation[1] = hmdRotation; - this.aimSource[1] = this.getEyePosition(RenderPass.CENTER); - this.aimSource[0] = this.getEyePosition(RenderPass.CENTER); - - if (this.mc.screen == null) { - Vec3 vec31 = this.getAimVector(1); - org.vivecraft.common.utils.lwjgl.Matrix4f matrix4f = new org.vivecraft.common.utils.lwjgl.Matrix4f(); - float f = 110.0F; - float f1 = 180.0F; - double d0 = this.mc.mouseHandler.xpos() / (double) this.mc.getWindow().getScreenWidth() * (double) f - (double) (f / 2.0F); - int i = this.mc.getWindow().getScreenHeight(); - - if (i % 2 != 0) { - --i; - } - - double d1 = -this.mc.mouseHandler.ypos() / (double) i * (double) f1 + (double) (f1 / 2.0F); - double d2 = -d1; - - if (this.mc.isWindowActive()) { - float f2 = this.dh.vrSettings.keyholeX; - float f3 = 20.0F * this.dh.vrSettings.xSensitivity; - int j = (int) ((double) (-f2 + f / 2.0F) * (double) this.mc.getWindow().getScreenWidth() / (double) f) + 1; - int k = (int) ((double) (f2 + f / 2.0F) * (double) this.mc.getWindow().getScreenWidth() / (double) f) - 1; - float f4 = ((float) Math.abs(d0) - f2) / (f / 2.0F - f2); - double d3 = this.mc.mouseHandler.xpos(); - - if (d0 < (double) (-f2)) { - this.seatedRot += f3 * f4; - this.seatedRot %= 360.0F; - this.hmdForwardYaw = (float) Math.toDegrees(Math.atan2(vec31.x, vec31.z)); - d3 = j; - d0 = -f2; - } else if (d0 > (double) f2) { - this.seatedRot -= f3 * f4; - this.seatedRot %= 360.0F; - this.hmdForwardYaw = (float) Math.toDegrees(Math.atan2(vec31.x, vec31.z)); - d3 = k; - d0 = f2; - } - - double d4 = 0.5D * (double) this.dh.vrSettings.ySensitivity; - d2 = (double) this.aimPitch + d1 * d4; - d2 = Mth.clamp(d2, -89.9D, 89.9D); - InputSimulator.setMousePos(d3, i / 2); - GLFW.glfwSetCursorPos(this.mc.getWindow().getWindow(), d3, i / 2); - matrix4f.rotate((float) Math.toRadians(-d2), new Vector3f(1.0F, 0.0F, 0.0F)); - matrix4f.rotate((float) Math.toRadians(-180.0D + d0 - (double) this.hmdForwardYaw), new Vector3f(0.0F, 1.0F, 0.0F)); - } - - this.controllerRotation[0].M[0][0] = matrix4f.m00; - this.controllerRotation[0].M[0][1] = matrix4f.m01; - this.controllerRotation[0].M[0][2] = matrix4f.m02; - this.controllerRotation[0].M[1][0] = matrix4f.m10; - this.controllerRotation[0].M[1][1] = matrix4f.m11; - this.controllerRotation[0].M[1][2] = matrix4f.m12; - this.controllerRotation[0].M[2][0] = matrix4f.m20; - this.controllerRotation[0].M[2][1] = matrix4f.m21; - this.controllerRotation[0].M[2][2] = matrix4f.m22; - - this.handRotation[0].M[0][0] = matrix4f.m00; - this.handRotation[0].M[0][1] = matrix4f.m01; - this.handRotation[0].M[0][2] = matrix4f.m02; - this.handRotation[0].M[1][0] = matrix4f.m10; - this.handRotation[0].M[1][1] = matrix4f.m11; - this.handRotation[0].M[1][2] = matrix4f.m12; - this.handRotation[0].M[2][0] = matrix4f.m20; - this.handRotation[0].M[2][1] = matrix4f.m21; - this.handRotation[0].M[2][2] = matrix4f.m22; - } - } - Vec3 vec32 = this.getAimVector(0); - this.aimPitch = (float) Math.toDegrees(Math.asin(vec32.y / vec32.length())); - if (this.inputInitialized) { this.mc.getProfiler().push("updateActionState"); @@ -399,91 +244,64 @@ private void updatePose() { //TODO Not needed it seems? Poses come from the action space XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); - this.readPoseData(this.grip[0], actionSet); - this.readPoseData(this.grip[1], actionSet); - this.readPoseData(this.aim[0], actionSet); - this.readPoseData(this.aim[1], actionSet); + this.readPoseData(this.grip[RIGHT_CONTROLLER], actionSet); + this.readPoseData(this.grip[LEFT_CONTROLLER], actionSet); + this.readPoseData(this.aim[RIGHT_CONTROLLER], actionSet); + this.readPoseData(this.aim[LEFT_CONTROLLER], actionSet); this.mc.getProfiler().pop(); - } - } - } - @Override - public Vec3 getEyePosition(RenderPass eye) { - org.vivecraft.common.utils.math.Matrix4f matrix4f = null; - - if (eye == RenderPass.LEFT) { - matrix4f = this.hmdPoseLeftEye; - } else if (eye == RenderPass.RIGHT) { - matrix4f = this.hmdPoseRightEye; - } + //reverse + if (this.dh.vrSettings.reverseHands) { + XrSpace temp = gripSpace[RIGHT_CONTROLLER]; + gripSpace[RIGHT_CONTROLLER] = gripSpace[LEFT_CONTROLLER]; + gripSpace[LEFT_CONTROLLER] = temp; + temp = aimSpace[RIGHT_CONTROLLER]; + aimSpace[RIGHT_CONTROLLER] = aimSpace[LEFT_CONTROLLER]; + aimSpace[LEFT_CONTROLLER] = temp; + } - if (matrix4f == null) { - org.vivecraft.common.utils.math.Matrix4f matrix4f2 = this.hmdPose; - Vector3 vector31 = MathUtils.convertMatrix4ftoTranslationVector(matrix4f2); + //Controller aim and grip poses + error = XR10.xrLocateSpace(gripSpace[RIGHT_CONTROLLER], xrAppSpace, time, space_location); + logError(error, "xrLocateSpace", "gripSpace[0]"); + if (error >= 0) { + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.handRotation[RIGHT_CONTROLLER]); + } - if (this.dh.vrSettings.seated || this.dh.vrSettings.allowStandingOriginOffset) { - if (this.dh.vr.isHMDTracking()) { - vector31 = vector31.add(this.dh.vrSettings.originOffset); + error = XR10.xrLocateSpace(gripSpace[LEFT_CONTROLLER], xrAppSpace, time, space_location); + logError(error, "xrLocateSpace", "gripSpace[1]"); + if (error >= 0) { + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.handRotation[LEFT_CONTROLLER]); } - } - return vector31.toVector3d(); - } else { - Vector3 vector3 = MathUtils.convertMatrix4ftoTranslationVector(matrix4f); + error = XR10.xrLocateSpace(aimSpace[RIGHT_CONTROLLER], xrAppSpace, time, space_location); + logError(error, "xrLocateSpace", "aimSpace[0]"); + if (error >= 0) { + OpenXRUtil.openXRPoseToMarix(space_location.pose(), this.controllerPose[RIGHT_CONTROLLER]); + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.controllerRotation[RIGHT_CONTROLLER]); + this.controllerTracking[RIGHT_CONTROLLER] = true; + } else { + this.controllerTracking[RIGHT_CONTROLLER] = false; + } - if (this.dh.vrSettings.seated || this.dh.vrSettings.allowStandingOriginOffset) { - if (this.dh.vr.isHMDTracking()) { - vector3 = vector3.add(this.dh.vrSettings.originOffset); + error = XR10.xrLocateSpace(aimSpace[LEFT_CONTROLLER], xrAppSpace, time, space_location); + logError(error, "xrLocateSpace", "aimSpace[1]"); + if (error >= 0) { + OpenXRUtil.openXRPoseToMarix(space_location.pose(), this.controllerPose[LEFT_CONTROLLER]); + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.controllerRotation[LEFT_CONTROLLER]); + this.controllerTracking[LEFT_CONTROLLER] = true; + } else { + this.controllerTracking[LEFT_CONTROLLER] = false; } } - return vector3.toVector3d(); - } - } - - @Override - public org.vivecraft.common.utils.math.Matrix4f getEyeRotation(RenderPass eye) { - org.vivecraft.common.utils.math.Matrix4f matrix4f; - - if (eye == RenderPass.LEFT) { - matrix4f = this.hmdPoseLeftEye; - } else if (eye == RenderPass.RIGHT) { - matrix4f = this.hmdPoseRightEye; - } else { - matrix4f = null; - } - - if (matrix4f != null) { - org.vivecraft.common.utils.math.Matrix4f matrix4f1 = new org.vivecraft.common.utils.math.Matrix4f(); - matrix4f1.M[0][0] = matrix4f.M[0][0]; - matrix4f1.M[0][1] = matrix4f.M[0][1]; - matrix4f1.M[0][2] = matrix4f.M[0][2]; - matrix4f1.M[0][3] = 0.0F; - matrix4f1.M[1][0] = matrix4f.M[1][0]; - matrix4f1.M[1][1] = matrix4f.M[1][1]; - matrix4f1.M[1][2] = matrix4f.M[1][2]; - matrix4f1.M[1][3] = 0.0F; - matrix4f1.M[2][0] = matrix4f.M[2][0]; - matrix4f1.M[2][1] = matrix4f.M[2][1]; - matrix4f1.M[2][2] = matrix4f.M[2][2]; - matrix4f1.M[2][3] = 0.0F; - matrix4f1.M[3][0] = 0.0F; - matrix4f1.M[3][1] = 0.0F; - matrix4f1.M[3][2] = 0.0F; - matrix4f1.M[3][3] = 1.0F; - return matrix4f1; - } else { - return this.hmdRotation; + this.updateAim(); } } public void readNewData(VRInputAction action) { - String s = action.type; - - switch (s) { - case "boolean": + switch (action.type) { + case "boolean" -> { if (action.isHanded()) { for (ControllerType controllertype1 : ControllerType.values()) { this.readBoolean(action, controllertype1); @@ -491,10 +309,9 @@ public void readNewData(VRInputAction action) { } else { this.readBoolean(action, null); } + } - break; - - case "vector1": + case "vector1" -> { if (action.isHanded()) { for (ControllerType controllertype : ControllerType.values()) { this.readFloat(action, controllertype); @@ -502,9 +319,9 @@ public void readNewData(VRInputAction action) { } else { this.readFloat(action, null); } - break; + } - case "vector2": + case "vector2" -> { if (action.isHanded()) { for (ControllerType controllertype : ControllerType.values()) { this.readVecData(action, controllertype); @@ -512,9 +329,7 @@ public void readNewData(VRInputAction action) { } else { this.readVecData(action, null); } - break; - - case "vector3": + } } } @@ -636,10 +451,6 @@ private boolean updateActiveActionSets() { return !arraylist.isEmpty(); } - private void updateControllerPose(int controller, long actionHandle) { - - } - long getActionSetHandle(VRInputActionSet actionSet) { return this.actionSetHandles.get(actionSet); } @@ -745,11 +556,11 @@ public boolean init() { //TODO Seated when no controllers System.out.println("OpenXR initialized & VR connected."); - this.deviceVelocity = new Vec3[64]; + this.deviceVelocity = new Vector3f[64]; for (int i = 0; i < this.poseMatrices.length; ++i) { this.poseMatrices[i] = new Matrix4f(); - this.deviceVelocity[i] = new Vec3(0.0D, 0.0D, 0.0D); + this.deviceVelocity[i] = new Vector3f(); } this.initialized = true; @@ -888,6 +699,7 @@ private void initializeOpenXRSession() { session = new XrSession(sessionPtr.get(0), instance); while (!this.isActive) { + System.out.println("waiting"); pollVREvents(); } @@ -1119,7 +931,7 @@ public boolean isActive() { @Override public ControllerType getOriginControllerType(long i) { - if (i == aim[0]) { + if (i == aim[RIGHT_CONTROLLER]) { return ControllerType.RIGHT; } return ControllerType.LEFT; @@ -1127,7 +939,7 @@ public ControllerType getOriginControllerType(long i) { @Override public float getIPD() { - return (float) (this.getEyePosition(RenderPass.RIGHT).x - this.getEyePosition(RenderPass.LEFT).x); + return this.getEyePosition(RenderPass.RIGHT).x - this.getEyePosition(RenderPass.LEFT).x; } @Override @@ -1152,17 +964,17 @@ private void loadActionHandles() { setupControllers(); XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); - this.haptics[0] = createAction("/actions/global/out/righthaptic", "/actions/global/out/righthaptic", "haptic", actionSet, BOTH_HANDS); - this.haptics[1] = createAction("/actions/global/out/lefthaptic", "/actions/global/out/lefthaptic", "haptic", actionSet, BOTH_HANDS); + this.haptics[RIGHT_CONTROLLER] = createAction("/actions/global/out/righthaptic", "/actions/global/out/righthaptic", "haptic", actionSet, BOTH_HANDS); + this.haptics[LEFT_CONTROLLER] = createAction("/actions/global/out/lefthaptic", "/actions/global/out/lefthaptic", "haptic", actionSet, BOTH_HANDS); } private void setupControllers() { XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); - this.grip[0] = createAction("/actions/global/in/righthand", "/actions/global/in/righthand", "pose", actionSet, BOTH_HANDS); - this.grip[1] = createAction("/actions/global/in/lefthand", "/actions/global/in/lefthand", "pose", actionSet, BOTH_HANDS); - this.aim[0] = createAction("/actions/global/in/righthandaim", "/actions/global/in/righthandaim", "pose", actionSet, BOTH_HANDS); - this.aim[1] = createAction("/actions/global/in/lefthandaim", "/actions/global/in/lefthandaim", "pose", actionSet, BOTH_HANDS); + this.grip[RIGHT_CONTROLLER] = createAction("/actions/global/in/righthand", "/actions/global/in/righthand", "pose", actionSet, BOTH_HANDS); + this.grip[LEFT_CONTROLLER] = createAction("/actions/global/in/lefthand", "/actions/global/in/lefthand", "pose", actionSet, BOTH_HANDS); + this.aim[RIGHT_CONTROLLER] = createAction("/actions/global/in/righthandaim", "/actions/global/in/righthandaim", "pose", actionSet, BOTH_HANDS); + this.aim[LEFT_CONTROLLER] = createAction("/actions/global/in/lefthandaim", "/actions/global/in/lefthandaim", "pose", actionSet, BOTH_HANDS); } private void loadDefaultBindings() { @@ -1189,29 +1001,29 @@ private void loadDefaultBindings() { //TODO make this also changeable? XrActionSet actionSet = new XrActionSet(actionSetHandles.get(VRInputActionSet.GLOBAL), instance); bindings.get(defaultBindings.length).set( - new XrAction(this.grip[0], actionSet), + new XrAction(this.grip[RIGHT_CONTROLLER], actionSet), getPath("/user/hand/right/input/grip/pose") ); bindings.get(defaultBindings.length + 1).set( - new XrAction(this.grip[1], actionSet), + new XrAction(this.grip[LEFT_CONTROLLER], actionSet), getPath("/user/hand/left/input/grip/pose") ); bindings.get(defaultBindings.length + 2).set( - new XrAction(this.aim[0], actionSet), + new XrAction(this.aim[RIGHT_CONTROLLER], actionSet), getPath("/user/hand/right/input/aim/pose") ); bindings.get(defaultBindings.length + 3).set( - new XrAction(this.aim[1], actionSet), + new XrAction(this.aim[LEFT_CONTROLLER], actionSet), getPath("/user/hand/left/input/aim/pose") ); bindings.get(defaultBindings.length + 4).set( - new XrAction(this.haptics[0], actionSet), + new XrAction(this.haptics[RIGHT_CONTROLLER], actionSet), getPath("/user/hand/right/output/haptic") ); bindings.get(defaultBindings.length + 5).set( - new XrAction(this.haptics[1], actionSet), + new XrAction(this.haptics[LEFT_CONTROLLER], actionSet), getPath("/user/hand/left/output/haptic") ); @@ -1235,34 +1047,34 @@ private void loadDefaultBindings() { logError(error, "xrAttachSessionActionSets", ""); XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); - XrActionSpaceCreateInfo grip_left = XrActionSpaceCreateInfo.calloc(stack); - grip_left.type(XR10.XR_TYPE_ACTION_SPACE_CREATE_INFO); - grip_left.next(NULL); - grip_left.action(new XrAction(grip[0], actionSet)); - grip_left.subactionPath(getPath("/user/hand/right")); - grip_left.poseInActionSpace(POSE_IDENTITY); + XrActionSpaceCreateInfo actionSpace = XrActionSpaceCreateInfo.calloc(stack); + actionSpace.type(XR10.XR_TYPE_ACTION_SPACE_CREATE_INFO); + actionSpace.next(NULL); + actionSpace.action(new XrAction(grip[RIGHT_CONTROLLER], actionSet)); + actionSpace.subactionPath(getPath("/user/hand/right")); + actionSpace.poseInActionSpace(POSE_IDENTITY); PointerBuffer pp = stackCallocPointer(1); - error = XR10.xrCreateActionSpace(session, grip_left, pp); + error = XR10.xrCreateActionSpace(session, actionSpace, pp); logError(error, "xrCreateActionSpace", "grip: /user/hand/right"); - this.gripSpace[0] = new XrSpace(pp.get(0), session); + this.gripSpace[RIGHT_CONTROLLER] = new XrSpace(pp.get(0), session); - grip_left.action(new XrAction(grip[1], actionSet)); - grip_left.subactionPath(getPath("/user/hand/left")); - error = XR10.xrCreateActionSpace(session, grip_left, pp); + actionSpace.action(new XrAction(grip[LEFT_CONTROLLER], actionSet)); + actionSpace.subactionPath(getPath("/user/hand/left")); + error = XR10.xrCreateActionSpace(session, actionSpace, pp); logError(error, "xrCreateActionSpace", "grip: /user/hand/left"); - this.gripSpace[1] = new XrSpace(pp.get(0), session); + this.gripSpace[LEFT_CONTROLLER] = new XrSpace(pp.get(0), session); - grip_left.action(new XrAction(aim[0], actionSet)); - grip_left.subactionPath(getPath("/user/hand/right")); - error = XR10.xrCreateActionSpace(session, grip_left, pp); + actionSpace.action(new XrAction(aim[RIGHT_CONTROLLER], actionSet)); + actionSpace.subactionPath(getPath("/user/hand/right")); + error = XR10.xrCreateActionSpace(session, actionSpace, pp); logError(error, "xrCreateActionSpace", "aim: /user/hand/right"); - this.aimSpace[0] = new XrSpace(pp.get(0), session); + this.aimSpace[RIGHT_CONTROLLER] = new XrSpace(pp.get(0), session); - grip_left.action(new XrAction(aim[1], actionSet)); - grip_left.subactionPath(getPath("/user/hand/left")); - error = XR10.xrCreateActionSpace(session, grip_left, pp); + actionSpace.action(new XrAction(aim[LEFT_CONTROLLER], actionSet)); + actionSpace.subactionPath(getPath("/user/hand/left")); + error = XR10.xrCreateActionSpace(session, actionSpace, pp); logError(error, "xrCreateActionSpace", "aim: /user/hand/left"); - this.aimSpace[1] = new XrSpace(pp.get(0), session); + this.aimSpace[LEFT_CONTROLLER] = new XrSpace(pp.get(0), session); } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRUtil.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRUtil.java index 7ce805b55..ebc94576f 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRUtil.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRUtil.java @@ -1,50 +1,19 @@ package org.vivecraft.client_vr.provider.openxr; -import org.joml.Matrix3f; +import org.joml.Matrix4f; import org.joml.Quaternionf; import org.lwjgl.openxr.XrPosef; import org.lwjgl.openxr.XrQuaternionf; -import org.vivecraft.common.utils.math.Matrix4f; public class OpenXRUtil { public static void openXRPoseToMarix(XrPosef pose, Matrix4f mat) { - Matrix3f matrix3f = new Matrix3f().set(new Quaternionf(pose.orientation().x(), pose.orientation().y(), pose.orientation().z(), pose.orientation().w())); - mat.M[0][0] = matrix3f.m00; - mat.M[0][1] = matrix3f.m10; - mat.M[0][2] = matrix3f.m20; - mat.M[0][3] = pose.position$().x(); - mat.M[1][0] = matrix3f.m01; - mat.M[1][1] = matrix3f.m11; - mat.M[1][2] = matrix3f.m21; - mat.M[1][3] = pose.position$().y(); - mat.M[2][0] = matrix3f.m02; - mat.M[2][1] = matrix3f.m12; - mat.M[2][2] = matrix3f.m22; - mat.M[2][3] = pose.position$().z(); - mat.M[3][0] = 0; - mat.M[3][1] = 0; - mat.M[3][2] = 0; - mat.M[3][3] = 1; + mat.set(new Quaternionf(pose.orientation().x(), pose.orientation().y(), pose.orientation().z(), pose.orientation().w())) + .setTranslation(pose.position$().x(), pose.position$().y(), pose.position$().z()) + .m33(1); } public static void openXRPoseToMarix(XrQuaternionf quat, Matrix4f mat) { - Matrix3f matrix3f = new Matrix3f().set(new Quaternionf(quat.x(), quat.y(), quat.z(), quat.w())); - mat.M[0][0] = matrix3f.m00; - mat.M[0][1] = matrix3f.m10; - mat.M[0][2] = matrix3f.m20; - mat.M[0][3] = 0; - mat.M[1][0] = matrix3f.m01; - mat.M[1][1] = matrix3f.m11; - mat.M[1][2] = matrix3f.m21; - mat.M[1][3] = 0; - mat.M[2][0] = matrix3f.m02; - mat.M[2][1] = matrix3f.m12; - mat.M[2][2] = matrix3f.m22; - mat.M[2][3] = 0; - mat.M[3][0] = 0; - mat.M[3][1] = 0; - mat.M[3][2] = 0; - mat.M[3][3] = 1; + mat.set(new Quaternionf(quat.x(), quat.y(), quat.z(), quat.w())); } } diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java index 7e6026179..0cd53437e 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java @@ -16,12 +16,11 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.vivecraft.client.VivecraftVRMod; +import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.common.utils.MathUtils; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; -import org.vivecraft.client_vr.provider.MCVR; -import org.vivecraft.client_vr.provider.openvr_lwjgl.VRInputAction; @Mixin(KeyboardInput.class) public class KeyboardInputVRMixin extends Input { From faa52633d14598d87e2714b95a92b7beed0b8a18 Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Thu, 5 Dec 2024 21:56:54 +0100 Subject: [PATCH 10/76] fix eye position --- .../client_vr/provider/openxr/MCOpenXR.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 4d2850832..9a11157f0 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -299,6 +299,30 @@ private void updatePose() { } } + /** + * @param eye LEFT, RIGHT or CENTER eye + * @return position of the given eye, in room space + */ + @Override + public Vector3f getEyePosition(RenderPass eye) { + Matrix4f pose = new Matrix4f(this.hmdPose); + switch (eye) { + case LEFT -> pose = this.hmdPoseLeftEye; //OpenXR includes total + case RIGHT -> pose = this.hmdPoseRightEye; + default -> {} + }; + + Vector3f pos = pose.getTranslation(new Vector3f()); + + if (this.dh.vrSettings.seated || this.dh.vrSettings.allowStandingOriginOffset) { + if (this.dh.vr.isHMDTracking()) { + pos = pos.add(this.dh.vrSettings.originOffset); + } + } + + return pos; + } + public void readNewData(VRInputAction action) { switch (action.type) { case "boolean" -> { From d7651229abe191dd40227b509e59adccdb3c76fc Mon Sep 17 00:00:00 2001 From: fayer3 Date: Tue, 10 Dec 2024 19:30:28 +0100 Subject: [PATCH 11/76] fix openxr head rotation --- .../java/org/vivecraft/client_vr/VRData.java | 2 +- .../gameplay/screenhandlers/GuiHandler.java | 2 +- .../vivecraft/client_vr/provider/MCVR.java | 39 +++++++++---------- .../provider/openvr_lwjgl/MCOpenVR.java | 4 ++ .../client_vr/provider/openxr/MCOpenXR.java | 25 ------------ 5 files changed, 24 insertions(+), 48 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/VRData.java b/common/src/main/java/org/vivecraft/client_vr/VRData.java index f90b37a08..bae767182 100644 --- a/common/src/main/java/org/vivecraft/client_vr/VRData.java +++ b/common/src/main/java/org/vivecraft/client_vr/VRData.java @@ -58,7 +58,7 @@ public VRData(Vec3 origin, float walkMul, float worldScale, float rotation) { Vector3f scaleOffset = new Vector3f(scaledPos.x - hmd_raw.x, 0.0F, scaledPos.z - hmd_raw.z); // headset - this.hmd = new VRDevicePose(this, mcVR.hmdRotation, scaledPos, mcVR.getHmdVector()); + this.hmd = new VRDevicePose(this, mcVR.getEyeRotation(RenderPass.CENTER), scaledPos, mcVR.getHmdVector()); this.eye0 = new VRDevicePose(this, mcVR.getEyeRotation(RenderPass.LEFT), diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/GuiHandler.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/GuiHandler.java index 040d288d6..4cecb936a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/GuiHandler.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/GuiHandler.java @@ -510,7 +510,7 @@ public static Vec3 applyGUIModelView(RenderPass currentPass, PoseStack poseStack direction = DH.vrPlayer.vrdata_world_render.getController(0).getDirection(); guirot = guirot.mul(DH.vr.getAimRotation(0), guirot); } else { - guirot = guirot.mul(DH.vr.hmdRotation, guirot); + guirot = guirot.mul(DH.vr.getEyeRotation(RenderPass.CENTER), guirot); } guipos = new Vec3( diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java index 1cce767f8..adf408564 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java @@ -55,11 +55,13 @@ public abstract class MCVR { protected HardwareType detectedHardware = HardwareType.VIVE; - // position/orientation of headset and eye offsets - protected Matrix4f hmdPose = new Matrix4f(); - public Matrix4f hmdRotation = new Matrix4f(); - protected Matrix4f hmdPoseLeftEye = new Matrix4f(); - protected Matrix4f hmdPoseRightEye = new Matrix4f(); + // position/orientation of headset and eyes + protected final Matrix4f hmdPose = new Matrix4f(); + protected final Matrix4f hmdRotation = new Matrix4f(); + protected final Matrix4f hmdPoseLeftEye = new Matrix4f(); + protected final Matrix4f hmdPoseRightEye = new Matrix4f(); + protected final Matrix4f hmdRotationLeftEye = new Matrix4f(); + protected final Matrix4f hmdRotationRightEye = new Matrix4f(); public Vector3fHistory hmdHistory = new Vector3fHistory(); public Vector3fHistory hmdPivotHistory = new Vector3fHistory(); @@ -285,11 +287,10 @@ public Vector3f getHandVector(int controller) { * @return position of the given eye, in room space */ public Vector3f getEyePosition(RenderPass eye) { - Matrix4f pose = new Matrix4f(this.hmdPose); - switch (eye) { - case LEFT -> pose.mul(this.hmdPoseLeftEye); - case RIGHT -> pose.mul(this.hmdPoseRightEye); - default -> {} + Matrix4fc pose = switch (eye) { + case LEFT -> this.hmdPoseLeftEye; + case RIGHT -> this.hmdPoseRightEye; + default -> this.hmdPose; }; Vector3f pos = pose.getTranslation(new Vector3f()); @@ -308,18 +309,11 @@ public Vector3f getEyePosition(RenderPass eye) { * @return rotation of the given eye, in room space */ public Matrix4fc getEyeRotation(RenderPass eye) { - Matrix4f hmdToEye = switch (eye) { - case LEFT -> this.hmdPoseLeftEye; - case RIGHT -> this.hmdPoseRightEye; - default -> null; + return switch (eye) { + case LEFT -> this.hmdRotationLeftEye; + case RIGHT -> this.hmdRotationRightEye; + default -> this.hmdRotation; }; - - if (hmdToEye != null) { - Matrix4f eyeRot = new Matrix4f().set3x3(hmdToEye); - return this.hmdRotation.mul(eyeRot, eyeRot); - } else { - return this.hmdRotation; - } } /** @@ -594,6 +588,9 @@ protected void updateAim() { this.hmdRotation.identity(); this.hmdRotation.set3x3(this.hmdPose); + this.hmdRotationLeftEye.set3x3(this.hmdPoseLeftEye); + this.hmdRotationRightEye.set3x3(this.hmdPoseRightEye); + Vector3fc eye = this.getEyePosition(RenderPass.CENTER); this.hmdHistory.add(eye); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index be3d7689c..bf8ee4fdc 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -1241,6 +1241,10 @@ private void updatePose() { this.hmdPose.m31(1.62F); } + // ret the complete room eye transforms + this.hmdPose.mul(this.hmdPoseLeftEye, this.hmdPoseLeftEye); + this.hmdPose.mul(this.hmdPoseRightEye, this.hmdPoseRightEye); + // Gotta do this here so we can get the poses if (this.inputInitialized) { this.mc.getProfiler().push("updateActionState"); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 9a11157f0..7df540539 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -217,7 +217,6 @@ private void updatePose() { logError(error, "xrLocateSpace", "xrViewSpace"); if (error >= 0) { OpenXRUtil.openXRPoseToMarix(space_location.pose(), this.hmdPose); - OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.hmdRotation); headIsTracking = true; } else { headIsTracking = false; @@ -299,30 +298,6 @@ private void updatePose() { } } - /** - * @param eye LEFT, RIGHT or CENTER eye - * @return position of the given eye, in room space - */ - @Override - public Vector3f getEyePosition(RenderPass eye) { - Matrix4f pose = new Matrix4f(this.hmdPose); - switch (eye) { - case LEFT -> pose = this.hmdPoseLeftEye; //OpenXR includes total - case RIGHT -> pose = this.hmdPoseRightEye; - default -> {} - }; - - Vector3f pos = pose.getTranslation(new Vector3f()); - - if (this.dh.vrSettings.seated || this.dh.vrSettings.allowStandingOriginOffset) { - if (this.dh.vr.isHMDTracking()) { - pos = pos.add(this.dh.vrSettings.originOffset); - } - } - - return pos; - } - public void readNewData(VRInputAction action) { switch (action.type) { case "boolean" -> { From c8f298bc2c0bfcde4be6008c9e063cf6e1a60204 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Wed, 11 Dec 2024 21:08:17 +0100 Subject: [PATCH 12/76] fix nullvr eye offset after last change --- .../java/org/vivecraft/client_vr/provider/nullvr/NullVR.java | 3 +++ 1 file changed, 3 insertions(+) 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 86978f652..84d2c5b9c 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 @@ -65,7 +65,10 @@ public boolean init() { this.hmdPose.m31(1.62F); // eye offset, 10cm total distance + this.hmdPoseLeftEye.set(this.hmdPose); this.hmdPoseLeftEye.m30(-IPD * 0.5F); + + this.hmdPoseRightEye.set(this.hmdPose); this.hmdPoseRightEye.m30(IPD * 0.5F); this.populateInputActions(); From 8c95d0561150466fdf548d70466413041cbcdc23 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 16 Dec 2024 13:53:53 +0100 Subject: [PATCH 13/76] fix lwjgl dependency declaration, parchment mappings and mixin extras somehow those got lost on the merge --- build.gradle | 23 ++++++++++++----------- forge/build.gradle | 25 ++++++++++++++----------- neoforge/build.gradle | 25 ++++++++++++++----------- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/build.gradle b/build.gradle index b5c77db1c..9ff0573f2 100644 --- a/build.gradle +++ b/build.gradle @@ -21,19 +21,20 @@ subprojects { dependencies { minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" - // The following line declares the mojmap mappings, you may use other mappings as well - mappings loom.officialMojangMappings() - // The following line declares the yarn mappings you may select this one as well. - // mappings "net.fabricmc:yarn:1.18.2+build.4:v2" - implementation("org.lwjgl:lwjgl-openvr:3.3.2") - implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-linux") - implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") - implementation("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") + mappings loom.layered() { + officialMojangMappings() + // parchment mappings as backup + parchment("org.parchmentmc.data:parchment-${rootProject.minecraft_version}:${rootProject.parchment_version}@zip") + } + implementation("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}") + implementation("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-linux") + implementation("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-macos") + implementation("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-windows") // Use custom OpenXR lib for Android and GLES bindings - implementation("QuestCraftPlusPlus:lwjgl3:3.3.2:lwjgl-openxr-3.3.2") - implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") - implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") + implementation("QuestCraftPlusPlus:lwjgl3:${rootProject.lwjgl_version}:lwjgl-openxr-${rootProject.lwjgl_version}") + implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-linux") + implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-windows") } tasks.withType(JavaCompile).configureEach { diff --git a/forge/build.gradle b/forge/build.gradle index 5644be879..d5c4a7303 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -60,19 +60,22 @@ dependencies { forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-windows") // Use custom OpenXR lib for Android and GLES bindings - forgeRuntimeLibrary("QuestCraftPlusPlus:lwjgl3:3.3.2:lwjgl-openxr-3.3.2") - forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") - forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") + forgeRuntimeLibrary("QuestCraftPlusPlus:lwjgl3:${rootProject.lwjgl_version}:lwjgl-openxr-${rootProject.lwjgl_version}") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-linux") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-windows") // shadow the natives - bundle("org.lwjgl:lwjgl-openvr:3.3.2") { transitive = false } - bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-linux") { transitive = false } - bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") { transitive = false } - bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") { transitive = false } - - bundle("QuestCraftPlusPlus:lwjgl3:3.3.2:lwjgl-openxr-3.3.2") { transitive = false } - bundle("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") { transitive = false } - bundle("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") { transitive = false } + bundle("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}") { transitive = false } + bundle("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-linux") { transitive = false } + bundle("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-macos") { transitive = false } + bundle("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-windows") { transitive = false } + + bundle("QuestCraftPlusPlus:lwjgl3:${rootProject.lwjgl_version}:lwjgl-openxr-${rootProject.lwjgl_version}") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-linux") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-windows") { transitive = false } + + compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:${rootProject.mixin_extras_version}")) + implementation(include("io.github.llamalad7:mixinextras-forge:${rootProject.mixin_extras_version}")) } processResources { diff --git a/neoforge/build.gradle b/neoforge/build.gradle index 55ab34124..3fec03e29 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -36,19 +36,22 @@ dependencies { forgeRuntimeLibrary("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-windows") // Use custom OpenXR lib for Android and GLES bindings - forgeRuntimeLibrary("QuestCraftPlusPlus:lwjgl3:3.3.2:lwjgl-openxr-3.3.2") - forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") - forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") + forgeRuntimeLibrary("QuestCraftPlusPlus:lwjgl3:${rootProject.lwjgl_version}:lwjgl-openxr-${rootProject.lwjgl_version}") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-linux") + forgeRuntimeLibrary("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-windows") // shadow the natives - bundle("org.lwjgl:lwjgl-openvr:3.3.2") { transitive = false } - bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-linux") { transitive = false } - bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-macos") { transitive = false } - bundle("org.lwjgl:lwjgl-openvr:3.3.2:natives-windows") { transitive = false } - - bundle("QuestCraftPlusPlus:lwjgl3:3.3.2:lwjgl-openxr-3.3.2") { transitive = false } - bundle("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux") { transitive = false } - bundle("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows") { transitive = false } + bundle("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}") { transitive = false } + bundle("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-linux") { transitive = false } + bundle("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-macos") { transitive = false } + bundle("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-windows") { transitive = false } + + bundle("QuestCraftPlusPlus:lwjgl3:${rootProject.lwjgl_version}:lwjgl-openxr-${rootProject.lwjgl_version}") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-linux") { transitive = false } + bundle("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-windows") { transitive = false } + + compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:${rootProject.mixin_extras_version}")) + implementation(include("io.github.llamalad7:mixinextras-neoforge:${rootProject.mixin_extras_version}")) } processResources { From 1ede10d5f2ea149a477c6a94044dffa51ca3b9c2 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 23 Dec 2024 04:12:15 +0100 Subject: [PATCH 14/76] fix fabric build gradle --- fabric/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fabric/build.gradle b/fabric/build.gradle index 82f5e8837..7e08316ee 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -69,9 +69,9 @@ dependencies { include(implementation("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-windows")) // Use custom OpenXR lib for Android and GLES bindings - include(implementation("QuestCraftPlusPlus:lwjgl3:3.3.2:lwjgl-openxr-3.3.2")) - include(implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-windows")) - include(implementation("org.lwjgl:lwjgl-openxr:3.3.2:natives-linux")) + include(implementation("QuestCraftPlusPlus:lwjgl3:${rootProject.lwjgl_version}:lwjgl-openxr-${rootProject.lwjgl_version}")) + include(implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-windows")) + include(implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-linux")) } processResources { @@ -129,4 +129,4 @@ publishing { repositories { // Add repositories to publish to here. } -} \ No newline at end of file +} From c93483780d205a528daf7c0db8bd5a1c8abcfe8b Mon Sep 17 00:00:00 2001 From: Darien Johnson <84008186+CADIndie@users.noreply.github.com> Date: Tue, 7 Jan 2025 19:16:45 -0500 Subject: [PATCH 15/76] Fixes and temp changes --- build.gradle | 4 +- .../vivecraft/client_vr/VRTextureTarget.java | 4 +- .../client_vr/provider/VRRenderer.java | 21 ------ .../provider/openvr_lwjgl/MCOpenVR.java | 10 +-- .../provider/openxr/DeviceCompat.java | 74 ++++++++++--------- .../client_vr/provider/openxr/MCOpenXR.java | 21 +++--- .../mixin/client_vr/KeyboardInputVRMixin.java | 1 - fabric/build.gradle | 4 +- 8 files changed, 63 insertions(+), 76 deletions(-) diff --git a/build.gradle b/build.gradle index c291e2fc1..5816b61e0 100644 --- a/build.gradle +++ b/build.gradle @@ -35,7 +35,9 @@ subprojects { implementation("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-windows") // Use custom OpenXR lib for Android and GLES bindings - implementation("QuestCraftPlusPlus:lwjgl3:${rootProject.lwjgl_version}:lwjgl-openxr-${rootProject.lwjgl_version}") + //implementation("QuestCraftPlusPlus:lwjgl3:${rootProject.lwjgl_version}:lwjgl-openxr-${rootProject.lwjgl_version}") + + implementation("org.lwjgl:lwjgl-openxr:3.3.3") implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-linux") implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-windows") diff --git a/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java b/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java index e2185f34d..3cb8fe5f3 100644 --- a/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java +++ b/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java @@ -42,8 +42,8 @@ public VRTextureTarget( public VRTextureTarget(String name, int width, int height, int colorid, int index) { super(true); this.name = name; - RenderSystem.assertOnGameThreadOrInit(); - this.resize(width, height, Minecraft.ON_OSX); + RenderSystem.assertOnRenderThreadOrInit(); + this.resize(width, height); ((RenderTargetExtension) this).vivecraft$setColorid(colorid); GlStateManager._glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferId); GL30.glFramebufferTextureLayer(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, colorid, 0, index); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java index c7331a0d0..515bd0a64 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java @@ -659,33 +659,12 @@ public void setupRenderConfiguration(boolean render) throws RenderConfigExceptio this.createRenderTexture(eyew, eyeh); - if (this.LeftEyeTextureId == -1) { - throw new RenderConfigException( - Component.translatable("vivecraft.messages.renderiniterror", this.getName()), - Component.literal(this.getLastError())); - } - VRSettings.LOGGER.info("Vivecraft: VR Provider supplied render texture IDs: {}, {}", this.LeftEyeTextureId, this.RightEyeTextureId); VRSettings.LOGGER.info("Vivecraft: VR Provider supplied texture resolution: {} x {}", eyew, eyeh); - } RenderHelper.checkGLError("Render Texture setup"); - if (this.framebufferEye0 == null) { - this.framebufferEye0 = new VRTextureTarget("L Eye", eyew, eyeh, false, this.LeftEyeTextureId, true, - false, false); - VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEye0); - RenderHelper.checkGLError("Left Eye framebuffer setup"); - } - - if (this.framebufferEye1 == null) { - this.framebufferEye1 = new VRTextureTarget("R Eye", eyew, eyeh, false, this.RightEyeTextureId, true, - false, false); - VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEye1); - RenderHelper.checkGLError("Right Eye framebuffer setup"); - } - float resolutionScale = ResolutionControlHelper.isLoaded() ? ResolutionControlHelper.getCurrentScaleFactor() : 1.0F; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index 9773d559e..728d32b81 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -231,7 +231,7 @@ public MCOpenVR(Minecraft mc, ClientDataHolderVR dh) throws RenderConfigExceptio this.digital = InputDigitalActionData.calloc(); this.analog = InputAnalogActionData.calloc(); - this.trackedDevicePoses = TrackedDevicePose.calloc(k_unMaxTrackedDeviceCount); + this.hmdTrackedDevicePoses = TrackedDevicePose.calloc(k_unMaxTrackedDeviceCount); } @Override @@ -255,7 +255,7 @@ public void destroy() { } // free memory - this.trackedDevicePoses.free(); + this.hmdTrackedDevicePoses.free(); this.poseData.free(); this.originInfo.free(); @@ -1440,7 +1440,7 @@ private void updateTrackerPose(int controller, boolean fetchDeviceIndex) { */ private void updatePose() { // gets poses for all tracked devices from OpenVR - int error = VRCompositor_WaitGetPoses(this.trackedDevicePoses, null); + int error = VRCompositor_WaitGetPoses(this.hmdTrackedDevicePoses, null); if (error > EVRCompositorError_VRCompositorError_None) { VRSettings.LOGGER.error("Vivecraft: Compositor Error: GetPoseError {}", @@ -1477,7 +1477,7 @@ private void updatePose() { // copy device poses for (int device = 0; device < k_unMaxTrackedDeviceCount; device++) { - TrackedDevicePose pose = this.trackedDevicePoses.get(device); + TrackedDevicePose pose = this.hmdTrackedDevicePoses.get(device); if (pose.bPoseIsValid()) { OpenVRUtil.convertSteamVRMatrix3ToMatrix4f(pose.mDeviceToAbsoluteTracking(), this.poseMatrices[device]); HmdVector3 velocity = pose.vVelocity(); @@ -1489,7 +1489,7 @@ private void updatePose() { } // check headset tracking state - if (this.trackedDevicePoses.get(k_unTrackedDeviceIndex_Hmd).bPoseIsValid()) { + if (this.hmdTrackedDevicePoses.get(k_unTrackedDeviceIndex_Hmd).bPoseIsValid()) { this.hmdPose.set(this.poseMatrices[k_unTrackedDeviceIndex_Hmd]); this.headIsTracking = true; } else { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java index c3cff1fc4..65b22f96a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java @@ -104,57 +104,61 @@ public Struct checkGraphics(MemoryStack stack, XrInstance instance, long systemI class Mobile implements DeviceCompat { @Override public long getPlatformInfo(MemoryStack stack) { - return XrInstanceCreateInfoAndroidKHR.calloc(stack).set( - KHRAndroidCreateInstance.XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR, - NULL, - VLoader.getDalvikVM(), - VLoader.getDalvikActivity() - ).address(); +// return XrInstanceCreateInfoAndroidKHR.calloc(stack).set( +// KHRAndroidCreateInstance.XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR, +// NULL, +// VLoader.getDalvikVM(), +// VLoader.getDalvikActivity() +// ).address(); + return NULL; } @Override public void initOpenXRLoader(MemoryStack stack) { - VRSettings.LOGGER.info("Platform: {}", System.getProperty("os.version")); - VLoader.setupAndroid(); - XrLoaderInitInfoAndroidKHR initInfo = XrLoaderInitInfoAndroidKHR.calloc(stack).set( - KHRLoaderInitAndroid.XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, - NULL, - VLoader.getDalvikVM(), - VLoader.getDalvikActivity() - ); - - KHRLoaderInit.xrInitializeLoaderKHR(XrLoaderInitInfoBaseHeaderKHR.create(initInfo.address())); +// VRSettings.LOGGER.info("Platform: {}", System.getProperty("os.version")); +// VLoader.setupAndroid(); +// XrLoaderInitInfoAndroidKHR initInfo = XrLoaderInitInfoAndroidKHR.calloc(stack).set( +// KHRLoaderInitAndroid.XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, +// NULL, +// VLoader.getDalvikVM(), +// VLoader.getDalvikActivity() +// ); +// +// KHRLoaderInit.xrInitializeLoaderKHR(XrLoaderInitInfoBaseHeaderKHR.create(initInfo.address())); } @Override public String getGraphicsExtension() { - return KHROpenGLESEnable.XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME; + //return KHROpenGLESEnable.XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME; + return null; } @Override public XrSwapchainImageOpenGLKHR.Buffer createImageBuffers(int imageCount, MemoryStack stack) { - XrSwapchainImageOpenGLKHR.Buffer swapchainImageBuffer = XrSwapchainImageOpenGLKHR.calloc(imageCount, stack); - for (XrSwapchainImageOpenGLKHR image : swapchainImageBuffer) { - image.type(KHROpenGLESEnable.XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR); - } - - return swapchainImageBuffer; +// XrSwapchainImageOpenGLKHR.Buffer swapchainImageBuffer = XrSwapchainImageOpenGLKHR.calloc(imageCount, stack); +// for (XrSwapchainImageOpenGLKHR image : swapchainImageBuffer) { +// image.type(KHROpenGLESEnable.XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR); +// } +// +// return swapchainImageBuffer; + return null; } @Override public Struct checkGraphics(MemoryStack stack, XrInstance instance, long systemID) { - XrGraphicsRequirementsOpenGLESKHR graphicsRequirements = XrGraphicsRequirementsOpenGLESKHR.calloc(stack).type(KHROpenGLESEnable.XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR); - KHROpenGLESEnable.xrGetOpenGLESGraphicsRequirementsKHR(instance, systemID, graphicsRequirements); - XrGraphicsBindingOpenGLESAndroidKHR graphicsBinding = XrGraphicsBindingOpenGLESAndroidKHR.calloc(stack); - graphicsBinding.set( - KHROpenGLESEnable.XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR, - NULL, - VLoader.getEGLDisplay(), - VLoader.getEGLConfig(), - VLoader.getEGLContext() - ); - - return graphicsBinding; +// XrGraphicsRequirementsOpenGLESKHR graphicsRequirements = XrGraphicsRequirementsOpenGLESKHR.calloc(stack).type(KHROpenGLESEnable.XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR); +// KHROpenGLESEnable.xrGetOpenGLESGraphicsRequirementsKHR(instance, systemID, graphicsRequirements); +// XrGraphicsBindingOpenGLESAndroidKHR graphicsBinding = XrGraphicsBindingOpenGLESAndroidKHR.calloc(stack); +// graphicsBinding.set( +// KHROpenGLESEnable.XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR, +// NULL, +// VLoader.getEGLDisplay(), +// VLoader.getEGLConfig(), +// VLoader.getEGLContext() +// ); +// +// return graphicsBinding; + return null; } } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 7df540539..b43e0641d 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -2,6 +2,7 @@ import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; +import net.minecraft.util.profiling.Profiler; import org.apache.commons.lang3.tuple.Pair; import org.joml.Matrix4f; import org.joml.Vector2f; @@ -147,12 +148,12 @@ protected ControllerType findActiveBindingControllerType(KeyMapping binding) { @Override public void poll(long var1) { if (this.initialized) { - this.mc.getProfiler().push("events"); + Profiler.get().push("events"); this.pollVREvents(); if (!this.dh.vrSettings.seated) { - this.mc.getProfiler().popPush("controllers"); - this.mc.getProfiler().push("gui"); + Profiler.get().popPush("controllers"); + Profiler.get().push("gui"); if (this.mc.screen == null && this.dh.vrSettings.vrTouchHotbar) { @@ -161,15 +162,15 @@ public void poll(long var1) { } } - this.mc.getProfiler().pop(); + Profiler.get().pop(); } - this.mc.getProfiler().popPush("updatePose/Vsync"); + Profiler.get().popPush("updatePose/Vsync"); this.updatePose(); - this.mc.getProfiler().popPush("processInputs"); + Profiler.get().popPush("processInputs"); this.processInputs(); - this.mc.getProfiler().popPush("hmdSampling"); + Profiler.get().popPush("hmdSampling"); this.hmdSampling(); - this.mc.getProfiler().pop(); + Profiler.get().pop(); } } @@ -229,7 +230,7 @@ private void updatePose() { OpenXRUtil.openXRPoseToMarix(viewBuffer.get(1).pose(), this.hmdPoseRightEye); if (this.inputInitialized) { - this.mc.getProfiler().push("updateActionState"); + Profiler.get().push("updateActionState"); if (this.updateActiveActionSets()) { XrActionsSyncInfo syncInfo = XrActionsSyncInfo.calloc(stack) @@ -248,7 +249,7 @@ private void updatePose() { this.readPoseData(this.aim[RIGHT_CONTROLLER], actionSet); this.readPoseData(this.aim[LEFT_CONTROLLER], actionSet); - this.mc.getProfiler().pop(); + Profiler.get().pop(); //reverse if (this.dh.vrSettings.reverseHands) { diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java index 3959e6483..3f3107c7a 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java @@ -24,7 +24,6 @@ import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.provider.MCVR; -import org.vivecraft.client_vr.provider.openvr_lwjgl.VRInputAction; import org.vivecraft.common.utils.MathUtils; @Mixin(KeyboardInput.class) diff --git a/fabric/build.gradle b/fabric/build.gradle index d559b1d4f..11a5c477d 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -69,7 +69,9 @@ dependencies { include(implementation("org.lwjgl:lwjgl-openvr:${rootProject.lwjgl_version}:natives-windows")) // Use custom OpenXR lib for Android and GLES bindings - include(implementation("QuestCraftPlusPlus:lwjgl3:${rootProject.lwjgl_version}:lwjgl-openxr-${rootProject.lwjgl_version}")) + //include(implementation("QuestCraftPlusPlus:lwjgl3:${rootProject.lwjgl_version}:lwjgl-openxr-${rootProject.lwjgl_version}")) + + include(implementation("org.lwjgl:lwjgl-openxr:3.3.3")) include(implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-windows")) include(implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-linux")) From b73f89f9d4d9f4e5745422ea09c81f1dca5e897b Mon Sep 17 00:00:00 2001 From: fayer3 Date: Wed, 8 Jan 2025 02:20:18 +0100 Subject: [PATCH 16/76] some formatting, and cleanup --- build.gradle | 6 +- .../java/org/vivecraft/client_vr/VRState.java | 10 +- .../vivecraft/client_vr/provider/MCVR.java | 27 +- .../client_vr/provider/VRRenderer.java | 6 - .../provider/control/HapticMusicPlayer.java | 13 +- .../provider/control/VRInputAction.java | 3 +- .../control/VivecraftMovementInput.java | 11 - .../provider/openvr_lwjgl/MCOpenVR.java | 122 +---- .../openvr_lwjgl/OpenVRStereoRenderer.java | 30 +- .../provider/openxr/DeviceCompat.java | 11 +- .../client_vr/provider/openxr/MCOpenXR.java | 459 ++++++++++-------- .../provider/openxr/OpenXRStereoRenderer.java | 76 +-- .../client_vr/provider/openxr/OpenXRUtil.java | 7 +- fabric/build.gradle | 2 +- 14 files changed, 357 insertions(+), 426 deletions(-) delete mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/control/VivecraftMovementInput.java diff --git a/build.gradle b/build.gradle index 5816b61e0..9fe9cb17e 100644 --- a/build.gradle +++ b/build.gradle @@ -22,10 +22,8 @@ subprojects { dependencies { minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" mappings loom.layered() { - // The following line declares the mojmap mappings, you may use other mappings as well + // The following line declares the mojmap mappings officialMojangMappings() - // The following line declares the yarn mappings you may select this one as well. - // "net.fabricmc:yarn:1.18.2+build.4:v2" // parchment mappings as backup parchment("org.parchmentmc.data:parchment-${rootProject.minecraft_version}:${rootProject.parchment_version}@zip") } @@ -37,7 +35,7 @@ subprojects { // Use custom OpenXR lib for Android and GLES bindings //implementation("QuestCraftPlusPlus:lwjgl3:${rootProject.lwjgl_version}:lwjgl-openxr-${rootProject.lwjgl_version}") - implementation("org.lwjgl:lwjgl-openxr:3.3.3") + implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}") implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-linux") implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-windows") 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 354187a31..1757c06db 100644 --- a/common/src/main/java/org/vivecraft/client_vr/VRState.java +++ b/common/src/main/java/org/vivecraft/client_vr/VRState.java @@ -53,11 +53,11 @@ public static void initializeVR() { ClientDataHolderVR dh = ClientDataHolderVR.getInstance(); Minecraft instance = Minecraft.getInstance(); - switch (dh.vrSettings.stereoProviderPluginID) { - case OPENVR -> dh.vr = new MCOpenVR(instance, dh); - case OPENXR -> dh.vr = new MCOpenXR(instance, dh); - default -> dh.vr = new NullVR(instance, dh); - } + dh.vr = switch (dh.vrSettings.stereoProviderPluginID) { + case OPENVR -> new MCOpenVR(instance, dh); + case OPENXR -> new MCOpenXR(instance, dh); + default -> new NullVR(instance, dh); + }; if (!dh.vr.init()) { throw new RenderConfigException(Component.translatable("vivecraft.messages.vriniterror"), diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java index ffd505257..322e2f3bb 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java @@ -1411,6 +1411,7 @@ public void processInputs() { /** * updates the KeyMapping state that is linked to the given VRInputAction + * * @param action VRInputAction to process */ private void processInputAction(VRInputAction action) { @@ -1441,14 +1442,15 @@ private void processInputAction(VRInputAction action) { /** * checks the axis input of the VRInputAction linked to {@code keyMapping} and runs the callbacks when it's non 0 - * @param keyMapping KeyMapping to check - * @param upCallback action to do when the axis input is positive + * + * @param keyMapping KeyMapping to check + * @param upCallback action to do when the axis input is positive * @param downCallback action to do when the axis input is negative */ private void processScrollInput(KeyMapping keyMapping, Runnable upCallback, Runnable downCallback) { VRInputAction action = this.getInputAction(keyMapping); - - if (action.isEnabled() && action.getLastOrigin() != 0L) { /** {@link org.lwjgl.openvr.VR.k_ulInvalidInputValueHandle} and {@link org.lwjgl.system.MemoryUtil.NULL} are both 0 */ + /** {@link org.lwjgl.openvr.VR.k_ulInvalidInputValueHandle} and {@link org.lwjgl.system.MemoryUtil.NULL} are both 0 */ + if (action.isEnabled() && action.getLastOrigin() != 0L) { float value = action.getAxis2D(false).y(); if (value != 0.0F) { if (value > 0.0F) { @@ -1462,16 +1464,21 @@ private void processScrollInput(KeyMapping keyMapping, Runnable upCallback, Runn /** * checks the trackpad input of the controller the {@code keyMapping} is on - * @param keyMapping KeyMapping to check - * @param leftCallback action to do when swiped to the left + * + * @param keyMapping KeyMapping to check + * @param leftCallback action to do when swiped to the left * @param rightCallback action to do when swiped to the right - * @param upCallback action to do when swiped to the up - * @param downCallback action to do when swiped to the down + * @param upCallback action to do when swiped to the up + * @param downCallback action to do when swiped to the down */ - private void processSwipeInput(KeyMapping keyMapping, Runnable leftCallback, Runnable rightCallback, Runnable upCallback, Runnable downCallback) { + private void processSwipeInput( + KeyMapping keyMapping, Runnable leftCallback, Runnable rightCallback, Runnable upCallback, + Runnable downCallback) + { VRInputAction action = this.getInputAction(keyMapping); - if (action.isEnabled() && action.getLastOrigin() != 0L) { /** {@link org.lwjgl.openvr.VR.k_ulInvalidInputValueHandle} and {@link org.lwjgl.system.MemoryUtil.NULL} are both 0 */ + /** {@link org.lwjgl.openvr.VR.k_ulInvalidInputValueHandle} and {@link org.lwjgl.system.MemoryUtil.NULL} are both 0 */ + if (action.isEnabled() && action.getLastOrigin() != 0L) { ControllerType controller = this.findActiveBindingControllerType(keyMapping); if (controller != null) { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java index 515bd0a64..30c7eaa75 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java @@ -659,12 +659,6 @@ public void setupRenderConfiguration(boolean render) throws RenderConfigExceptio this.createRenderTexture(eyew, eyeh); - VRSettings.LOGGER.info("Vivecraft: VR Provider supplied render texture IDs: {}, {}", - this.LeftEyeTextureId, this.RightEyeTextureId); - VRSettings.LOGGER.info("Vivecraft: VR Provider supplied texture resolution: {} x {}", eyew, eyeh); - - RenderHelper.checkGLError("Render Texture setup"); - float resolutionScale = ResolutionControlHelper.isLoaded() ? ResolutionControlHelper.getCurrentScaleFactor() : 1.0F; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/HapticMusicPlayer.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/HapticMusicPlayer.java index 0c7b4e37c..b391ebe8a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/HapticMusicPlayer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/HapticMusicPlayer.java @@ -65,14 +65,13 @@ public void play() { for (Object object : this.data) { if (object instanceof Note note) { if (note.controller != null) { - ClientDataHolderVR.getInstance().vr - .triggerHapticPulse(note.controller, note.durationSeconds, note.frequency, note.amplitude, - delayAccum); + ClientDataHolderVR.getInstance().vr.triggerHapticPulse(note.controller, + note.durationSeconds, note.frequency, note.amplitude, delayAccum); } else { - ClientDataHolderVR.getInstance().vr.triggerHapticPulse(ControllerType.RIGHT, note.durationSeconds, note.frequency, - note.amplitude, delayAccum); - ClientDataHolderVR.getInstance().vr.triggerHapticPulse(ControllerType.LEFT, note.durationSeconds, note.frequency, - note.amplitude, delayAccum); + ClientDataHolderVR.getInstance().vr.triggerHapticPulse(ControllerType.RIGHT, + note.durationSeconds, note.frequency, note.amplitude, delayAccum); + ClientDataHolderVR.getInstance().vr.triggerHapticPulse(ControllerType.LEFT, + note.durationSeconds, note.frequency, note.amplitude, delayAccum); } } else if (object instanceof Delay delay) { delayAccum += delay.durationSeconds; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java index b977855a4..9c924a8ea 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java @@ -222,7 +222,8 @@ public boolean isEnabled() { // iterate over all actions, and check if another action has a higher priority for (VRInputAction action : ClientDataHolderVR.getInstance().vr.getInputActions()) { if (action != this && action.isEnabledRaw(hand) && action.isActive() && - action.getPriority() > this.getPriority() && ClientDataHolderVR.getInstance().vr.getOrigins(action).contains(lastOrigin)) + action.getPriority() > this.getPriority() && + ClientDataHolderVR.getInstance().vr.getOrigins(action).contains(lastOrigin)) { if (action.isHanded()) { return !((HandedKeyBinding) action.keyBinding).isPriorityOnController(hand); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/VivecraftMovementInput.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/VivecraftMovementInput.java deleted file mode 100644 index 79de67246..000000000 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/VivecraftMovementInput.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.vivecraft.client_vr.provider.control; - -import net.minecraft.client.KeyMapping; -import org.vivecraft.client_vr.ClientDataHolderVR; - -public class VivecraftMovementInput { - public static float getMovementAxisValue(KeyMapping keyBinding) { - VRInputAction vrinputaction = ClientDataHolderVR.getInstance().vr.getInputAction(keyBinding); - return Math.abs(vrinputaction.getAxis1DUseTracked()); - } -} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index 728d32b81..15c8fce67 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -3,7 +3,6 @@ import com.google.common.collect.ImmutableMap; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.mojang.blaze3d.platform.InputConstants; import com.sun.jna.NativeLibrary; import net.minecraft.Util; import net.minecraft.client.KeyMapping; @@ -17,7 +16,6 @@ import org.apache.commons.lang3.tuple.Triple; import org.joml.*; import org.lwjgl.Version; -import org.lwjgl.glfw.GLFW; import org.lwjgl.openvr.*; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; @@ -27,7 +25,6 @@ import org.vivecraft.client.utils.FileUtils; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; -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.provider.*; @@ -91,12 +88,9 @@ public class MCOpenVR extends MCVR { private final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); - private final int[] controllerDeviceIndex = new int[3]; - - private final TrackedDevicePose.Buffer hmdTrackedDevicePoses; + private final TrackedDevicePose.Buffer trackedDevicePoses; // haptic handles - private long leftControllerHandle; private long leftHapticHandle; private long rightHapticHandle; @@ -116,7 +110,6 @@ public class MCOpenVR extends MCVR { private boolean paused = false; - private final Map trackpadSwipeSamplers = new HashMap<>(); private boolean triedToInit; private final Queue vrEvents = new LinkedList<>(); @@ -231,7 +224,7 @@ public MCOpenVR(Minecraft mc, ClientDataHolderVR dh) throws RenderConfigExceptio this.digital = InputDigitalActionData.calloc(); this.analog = InputAnalogActionData.calloc(); - this.hmdTrackedDevicePoses = TrackedDevicePose.calloc(k_unMaxTrackedDeviceCount); + this.trackedDevicePoses = TrackedDevicePose.calloc(k_unMaxTrackedDeviceCount); } @Override @@ -255,7 +248,7 @@ public void destroy() { } // free memory - this.hmdTrackedDevicePoses.free(); + this.trackedDevicePoses.free(); this.poseData.free(); this.originInfo.free(); @@ -1166,109 +1159,6 @@ private void loadActionManifest() throws RenderConfigException { } } - /** - * updates the KeyMapping state that is linked to the given VRInputAction - * - * @param action VRInputAction to process - */ - private void processInputAction(VRInputAction action) { - if (action.isActive() && action.isEnabledRaw() && - // try to prevent double left clicks - (!ClientDataHolderVR.getInstance().vrSettings.ingameBindingsInGui || - !(action.actionSet == VRInputActionSet.INGAME && - action.keyBinding.key.getType() == InputConstants.Type.MOUSE && - action.keyBinding.key.getValue() == GLFW.GLFW_MOUSE_BUTTON_LEFT && this.mc.screen != null - ) - )) - { - if (action.isButtonChanged()) { - if (action.isButtonPressed() && action.isEnabled()) { - // We do this, so shit like closing a GUI by clicking a button won't - // also click in the world immediately after. - if (!this.ignorePressesNextFrame) { - action.pressBinding(); - } - } else { - action.unpressBinding(); - } - } - } else { - action.unpressBinding(); - } - } - - /** - * checks the axis input of the VRInputAction linked to {@code keyMapping} and runs the callbacks when it's non 0 - * - * @param keyMapping KeyMapping to check - * @param upCallback action to do when the axis input is positive - * @param downCallback action to do when the axis input is negative - */ - private void processScrollInput(KeyMapping keyMapping, Runnable upCallback, Runnable downCallback) { - VRInputAction action = this.getInputAction(keyMapping); - - if (action.isEnabled() && action.getLastOrigin() != k_ulInvalidInputValueHandle) { - float value = action.getAxis2D(false).y(); - if (value != 0.0F) { - if (value > 0.0F) { - upCallback.run(); - } else if (value < 0.0F) { - downCallback.run(); - } - } - } - } - - /** - * checks the trackpad input of the controller the {@code keyMapping} is on - * - * @param keyMapping KeyMapping to check - * @param leftCallback action to do when swiped to the left - * @param rightCallback action to do when swiped to the right - * @param upCallback action to do when swiped to the up - * @param downCallback action to do when swiped to the down - */ - private void processSwipeInput( - KeyMapping keyMapping, Runnable leftCallback, Runnable rightCallback, Runnable upCallback, - Runnable downCallback) - { - VRInputAction action = this.getInputAction(keyMapping); - - if (action.isEnabled() && action.getLastOrigin() != k_ulInvalidInputValueHandle) { - ControllerType controller = this.findActiveBindingControllerType(keyMapping); - - if (controller != null) { - // if that keyMapping is not tracked yet, create a new sampler - if (!this.trackpadSwipeSamplers.containsKey(keyMapping.getName())) { - this.trackpadSwipeSamplers.put(keyMapping.getName(), new TrackpadSwipeSampler()); - } - - TrackpadSwipeSampler trackpadswipesampler = this.trackpadSwipeSamplers.get(keyMapping.getName()); - trackpadswipesampler.update(controller, action.getAxis2D(false)); - - if (trackpadswipesampler.isSwipedUp() && upCallback != null) { - this.triggerHapticPulse(controller, 0.001F, 400.0F, 0.5F); - upCallback.run(); - } - - if (trackpadswipesampler.isSwipedDown() && downCallback != null) { - this.triggerHapticPulse(controller, 0.001F, 400.0F, 0.5F); - downCallback.run(); - } - - if (trackpadswipesampler.isSwipedLeft() && leftCallback != null) { - this.triggerHapticPulse(controller, 0.001F, 400.0F, 0.5F); - leftCallback.run(); - } - - if (trackpadswipesampler.isSwipedRight() && rightCallback != null) { - this.triggerHapticPulse(controller, 0.001F, 400.0F, 0.5F); - rightCallback.run(); - } - } - } - } - /** * fetches all available VREvents from OpenVR */ @@ -1440,7 +1330,7 @@ private void updateTrackerPose(int controller, boolean fetchDeviceIndex) { */ private void updatePose() { // gets poses for all tracked devices from OpenVR - int error = VRCompositor_WaitGetPoses(this.hmdTrackedDevicePoses, null); + int error = VRCompositor_WaitGetPoses(this.trackedDevicePoses, null); if (error > EVRCompositorError_VRCompositorError_None) { VRSettings.LOGGER.error("Vivecraft: Compositor Error: GetPoseError {}", @@ -1477,7 +1367,7 @@ private void updatePose() { // copy device poses for (int device = 0; device < k_unMaxTrackedDeviceCount; device++) { - TrackedDevicePose pose = this.hmdTrackedDevicePoses.get(device); + TrackedDevicePose pose = this.trackedDevicePoses.get(device); if (pose.bPoseIsValid()) { OpenVRUtil.convertSteamVRMatrix3ToMatrix4f(pose.mDeviceToAbsoluteTracking(), this.poseMatrices[device]); HmdVector3 velocity = pose.vVelocity(); @@ -1489,7 +1379,7 @@ private void updatePose() { } // check headset tracking state - if (this.hmdTrackedDevicePoses.get(k_unTrackedDeviceIndex_Hmd).bPoseIsValid()) { + if (this.trackedDevicePoses.get(k_unTrackedDeviceIndex_Hmd).bPoseIsValid()) { this.hmdPose.set(this.poseMatrices[k_unTrackedDeviceIndex_Hmd]); this.headIsTracking = true; } else { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java index 26816d8b8..a946f1f90 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java @@ -36,8 +36,9 @@ public OpenVRStereoRenderer(MCOpenVR vr) { super(vr); this.openvr = vr; - hiddenMeshes[0] = HiddenAreaMesh.calloc(); - hiddenMeshes[1] = HiddenAreaMesh.calloc(); + // allocate meshes, they are freed in destroy() + this.hiddenMeshes[0] = HiddenAreaMesh.calloc(); + this.hiddenMeshes[1] = HiddenAreaMesh.calloc(); } @Override @@ -126,19 +127,22 @@ public void createRenderTexture(int width, int height) throws RenderConfigExcept Component.literal(this.getLastError())); } - VRSettings.LOGGER.info("Vivecraft: VR Provider supplied render texture IDs: {}, {}", this.LeftEyeTextureId, this.RightEyeTextureId); + VRSettings.LOGGER.info("Vivecraft: VR Provider supplied render texture IDs: {}, {}", this.LeftEyeTextureId, + this.RightEyeTextureId); VRSettings.LOGGER.info("Vivecraft: VR Provider supplied texture resolution: {} x {}", width, height); RenderHelper.checkGLError("Render Texture setup"); if (this.framebufferEye0 == null) { - this.framebufferEye0 = new VRTextureTarget("L Eye", width, height, false, this.LeftEyeTextureId, false, true, false); + this.framebufferEye0 = new VRTextureTarget("L Eye", width, height, false, this.LeftEyeTextureId, false, + true, false); VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEye0); RenderHelper.checkGLError("Left Eye framebuffer setup"); } if (this.framebufferEye1 == null) { - this.framebufferEye1 = new VRTextureTarget("R Eye", width, height, false, this.RightEyeTextureId, false, true, false); + this.framebufferEye1 = new VRTextureTarget("R Eye", width, height, false, this.RightEyeTextureId, false, + true, false); VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEye1); RenderHelper.checkGLError("Right Eye framebuffer setup"); } @@ -214,15 +218,15 @@ public String getName() { @Override protected void destroyBuffers() { super.destroyBuffers(); - if (this.framebufferEye0 != null) { - this.framebufferEye0.destroyBuffers(); - this.framebufferEye0 = null; - } + if (this.framebufferEye0 != null) { + this.framebufferEye0.destroyBuffers(); + this.framebufferEye0 = null; + } - if (this.framebufferEye1 != null) { - this.framebufferEye1.destroyBuffers(); - this.framebufferEye1 = null; - } + if (this.framebufferEye1 != null) { + this.framebufferEye1.destroyBuffers(); + this.framebufferEye1 = null; + } if (this.LeftEyeTextureId > -1) { TextureUtil.releaseTextureId(this.LeftEyeTextureId); this.LeftEyeTextureId = -1; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java index 65b22f96a..d763519f5 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java @@ -25,10 +25,15 @@ //TODO: VulkanMod Support public interface DeviceCompat { long getPlatformInfo(MemoryStack stack); + void initOpenXRLoader(MemoryStack stack); + String getGraphicsExtension(); + XrSwapchainImageOpenGLKHR.Buffer createImageBuffers(int imageCount, MemoryStack stack); + Struct checkGraphics(MemoryStack stack, XrInstance instance, long systemID); + static DeviceCompat detectDevice() { return System.getProperty("os.version").contains("Android") ? new Mobile() : new Desktop(); } @@ -61,7 +66,8 @@ public XrSwapchainImageOpenGLKHR.Buffer createImageBuffers(int imageCount, Memor @Override public Struct checkGraphics(MemoryStack stack, XrInstance instance, long systemID) { - XrGraphicsRequirementsOpenGLKHR graphicsRequirements = XrGraphicsRequirementsOpenGLKHR.calloc(stack).type(KHROpenGLEnable.XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR); + XrGraphicsRequirementsOpenGLKHR graphicsRequirements = XrGraphicsRequirementsOpenGLKHR.calloc(stack) + .type(KHROpenGLEnable.XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR); KHROpenGLEnable.xrGetOpenGLGraphicsRequirementsKHR(instance, systemID, graphicsRequirements); //Bind the OpenGL context to the OpenXR instance and create the session Window window = Minecraft.getInstance().getWindow(); @@ -80,7 +86,8 @@ public Struct checkGraphics(MemoryStack stack, XrInstance instance, long systemI long glXWindowHandle = GLFWNativeGLX.glfwGetGLXWindow(windowHandle); int fbXID = glXQueryDrawable(xDisplay, glXWindowHandle, GLX_FBCONFIG_ID); - PointerBuffer fbConfigBuf = glXChooseFBConfig(xDisplay, X11.XDefaultScreen(xDisplay), stackInts(GLX_FBCONFIG_ID, fbXID, 0)); + PointerBuffer fbConfigBuf = glXChooseFBConfig(xDisplay, X11.XDefaultScreen(xDisplay), + stackInts(GLX_FBCONFIG_ID, fbXID, 0)); if (fbConfigBuf == null) { throw new IllegalStateException("Your framebuffer config was null, make a github issue"); } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index b43e0641d..f3d2ab1c1 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -50,10 +50,10 @@ public class MCOpenXR extends MCVR { public XrView.Buffer viewBuffer; public int width; public int height; - //TODO either move to MCVR, Or make special for OpenXR holding the instance itself. + // TODO either move to MCVR, Or make special for OpenXR holding the instance itself. private final Map actionSetHandles = new EnumMap<>(VRInputActionSet.class); - //TODO Move to MCVR - private XrActiveActionSet.Buffer activeActionSetsBuffer; + // TODO Move to MCVR + private XrActiveActionSet.Buffer activeActionSetsBuffer; private boolean isActive; private final HashMap paths = new HashMap<>(); private final long[] grip = new long[2]; @@ -83,35 +83,35 @@ public String getName() { @Override public void destroy() { int error; - //Not sure if we need the action sets one here, as we are shutting down - for (Long inputActionSet : actionSetHandles.values()){ - error = XR10.xrDestroyActionSet(new XrActionSet(inputActionSet, instance)); + // Not sure if we need the action sets one here, as we are shutting down + for (Long inputActionSet : this.actionSetHandles.values()) { + error = XR10.xrDestroyActionSet(new XrActionSet(inputActionSet, this.instance)); logError(error, "xrDestroyActionSet", ""); } - if (swapchain != null) { - error = XR10.xrDestroySwapchain(swapchain); + if (this.swapchain != null) { + error = XR10.xrDestroySwapchain(this.swapchain); logError(error, "xrDestroySwapchain", ""); } - if (viewBuffer != null) { - viewBuffer.close(); + if (this.viewBuffer != null) { + this.viewBuffer.close(); } - if (xrAppSpace != null) { - error = XR10.xrDestroySpace(xrAppSpace); + if (this.xrAppSpace != null) { + error = XR10.xrDestroySpace(this.xrAppSpace); logError(error, "xrDestroySpace", "xrAppSpace"); } - if (xrViewSpace != null) { - error = XR10.xrDestroySpace(xrViewSpace); + if (this.xrViewSpace != null) { + error = XR10.xrDestroySpace(this.xrViewSpace); logError(error, "xrDestroySpace", "xrViewSpace"); } - if (session != null){ - error = XR10.xrDestroySession(session); + if (this.session != null) { + error = XR10.xrDestroySession(this.session); logError(error, "xrDestroySession", ""); } - if (instance != null){ - error = XR10.xrDestroyInstance(instance); + if (this.instance != null) { + error = XR10.xrDestroyInstance(this.instance); logError(error, "xrDestroyInstance", ""); } - eventDataBuffer.close(); + this.eventDataBuffer.close(); } @Override @@ -122,7 +122,7 @@ protected ControllerType findActiveBindingControllerType(KeyMapping binding) { long path = this.getInputAction(binding).getLastOrigin(); try (MemoryStack stack = MemoryStack.stackPush()) { IntBuffer buf = stack.callocInt(1); - int error = XR10.xrPathToString(instance, path, buf, null); + int error = XR10.xrPathToString(this.instance, path, buf, null); logError(error, "xrPathToString", "get string length for", binding.getName()); int size = buf.get(); @@ -132,7 +132,7 @@ protected ControllerType findActiveBindingControllerType(KeyMapping binding) { buf = stack.callocInt(size); ByteBuffer byteBuffer = stack.calloc(size); - error = XR10.xrPathToString(instance, path, buf, byteBuffer); + error = XR10.xrPathToString(this.instance, path, buf, byteBuffer); logError(error, "xrPathToString", "get string for", binding.getName()); byte[] bytes = new byte[byteBuffer.remaining()]; byteBuffer.get(bytes); @@ -175,7 +175,7 @@ public void poll(long var1) { } private void updatePose() { - if (mc == null) { + if (this.mc == null) { return; } @@ -183,16 +183,16 @@ private void updatePose() { XrFrameState frameState = XrFrameState.calloc(stack).type(XR10.XR_TYPE_FRAME_STATE); int error = XR10.xrWaitFrame( - session, + this.session, XrFrameWaitInfo.calloc(stack).type(XR10.XR_TYPE_FRAME_WAIT_INFO), frameState); logError(error, "xrWaitFrame", ""); - time = frameState.predictedDisplayTime(); + this.time = frameState.predictedDisplayTime(); this.shouldRender = frameState.shouldRender(); error = XR10.xrBeginFrame( - session, + this.session, XrFrameBeginInfo.calloc(stack).type(XR10.XR_TYPE_FRAME_BEGIN_INFO)); logError(error, "xrBeginFrame", ""); @@ -205,29 +205,29 @@ private void updatePose() { 0, XR10.XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, frameState.predictedDisplayTime(), - xrAppSpace + this.xrAppSpace ); - error = XR10.xrLocateViews(session, viewLocateInfo, viewState, intBuf, viewBuffer); + error = XR10.xrLocateViews(this.session, viewLocateInfo, viewState, intBuf, this.viewBuffer); logError(error, "xrLocateViews", ""); XrSpaceLocation space_location = XrSpaceLocation.calloc(stack).type(XR10.XR_TYPE_SPACE_LOCATION); - //HMD pose - error = XR10.xrLocateSpace(xrViewSpace, xrAppSpace, time, space_location); + // HMD pose + error = XR10.xrLocateSpace(this.xrViewSpace, this.xrAppSpace, this.time, space_location); logError(error, "xrLocateSpace", "xrViewSpace"); if (error >= 0) { OpenXRUtil.openXRPoseToMarix(space_location.pose(), this.hmdPose); - headIsTracking = true; + this.headIsTracking = true; } else { - headIsTracking = false; + this.headIsTracking = false; this.hmdPose.identity(); this.hmdPose.m31(1.6F); } - //Eye positions - OpenXRUtil.openXRPoseToMarix(viewBuffer.get(0).pose(), this.hmdPoseLeftEye); - OpenXRUtil.openXRPoseToMarix(viewBuffer.get(1).pose(), this.hmdPoseRightEye); + // Eye positions + OpenXRUtil.openXRPoseToMarix(this.viewBuffer.get(0).pose(), this.hmdPoseLeftEye); + OpenXRUtil.openXRPoseToMarix(this.viewBuffer.get(1).pose(), this.hmdPoseRightEye); if (this.inputInitialized) { Profiler.get().push("updateActionState"); @@ -235,15 +235,16 @@ private void updatePose() { if (this.updateActiveActionSets()) { XrActionsSyncInfo syncInfo = XrActionsSyncInfo.calloc(stack) .type(XR10.XR_TYPE_ACTIONS_SYNC_INFO) - .activeActionSets(activeActionSetsBuffer); - error = XR10.xrSyncActions(session, syncInfo); + .activeActionSets(this.activeActionSetsBuffer); + error = XR10.xrSyncActions(this.session, syncInfo); logError(error, "xrSyncActions", ""); } this.inputActions.values().forEach(this::readNewData); //TODO Not needed it seems? Poses come from the action space - XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); + XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), + this.instance); this.readPoseData(this.grip[RIGHT_CONTROLLER], actionSet); this.readPoseData(this.grip[LEFT_CONTROLLER], actionSet); this.readPoseData(this.aim[RIGHT_CONTROLLER], actionSet); @@ -251,44 +252,49 @@ private void updatePose() { Profiler.get().pop(); - //reverse + // reverse if (this.dh.vrSettings.reverseHands) { - XrSpace temp = gripSpace[RIGHT_CONTROLLER]; - gripSpace[RIGHT_CONTROLLER] = gripSpace[LEFT_CONTROLLER]; - gripSpace[LEFT_CONTROLLER] = temp; - temp = aimSpace[RIGHT_CONTROLLER]; - aimSpace[RIGHT_CONTROLLER] = aimSpace[LEFT_CONTROLLER]; - aimSpace[LEFT_CONTROLLER] = temp; + XrSpace temp = this.gripSpace[RIGHT_CONTROLLER]; + this.gripSpace[RIGHT_CONTROLLER] = this.gripSpace[LEFT_CONTROLLER]; + this.gripSpace[LEFT_CONTROLLER] = temp; + temp = this.aimSpace[RIGHT_CONTROLLER]; + this.aimSpace[RIGHT_CONTROLLER] = this.aimSpace[LEFT_CONTROLLER]; + this.aimSpace[LEFT_CONTROLLER] = temp; } - //Controller aim and grip poses - error = XR10.xrLocateSpace(gripSpace[RIGHT_CONTROLLER], xrAppSpace, time, space_location); + // Controller aim and grip poses + error = XR10.xrLocateSpace(this.gripSpace[RIGHT_CONTROLLER], this.xrAppSpace, this.time, + space_location); logError(error, "xrLocateSpace", "gripSpace[0]"); if (error >= 0) { - OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.handRotation[RIGHT_CONTROLLER]); + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), + this.handRotation[RIGHT_CONTROLLER]); } - error = XR10.xrLocateSpace(gripSpace[LEFT_CONTROLLER], xrAppSpace, time, space_location); + error = XR10.xrLocateSpace(this.gripSpace[LEFT_CONTROLLER], this.xrAppSpace, this.time, space_location); logError(error, "xrLocateSpace", "gripSpace[1]"); if (error >= 0) { - OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.handRotation[LEFT_CONTROLLER]); + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), + this.handRotation[LEFT_CONTROLLER]); } - error = XR10.xrLocateSpace(aimSpace[RIGHT_CONTROLLER], xrAppSpace, time, space_location); + error = XR10.xrLocateSpace(this.aimSpace[RIGHT_CONTROLLER], this.xrAppSpace, this.time, space_location); logError(error, "xrLocateSpace", "aimSpace[0]"); if (error >= 0) { OpenXRUtil.openXRPoseToMarix(space_location.pose(), this.controllerPose[RIGHT_CONTROLLER]); - OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.controllerRotation[RIGHT_CONTROLLER]); + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), + this.controllerRotation[RIGHT_CONTROLLER]); this.controllerTracking[RIGHT_CONTROLLER] = true; } else { this.controllerTracking[RIGHT_CONTROLLER] = false; } - error = XR10.xrLocateSpace(aimSpace[LEFT_CONTROLLER], xrAppSpace, time, space_location); + error = XR10.xrLocateSpace(this.aimSpace[LEFT_CONTROLLER], this.xrAppSpace, this.time, space_location); logError(error, "xrLocateSpace", "aimSpace[1]"); if (error >= 0) { OpenXRUtil.openXRPoseToMarix(space_location.pose(), this.controllerPose[LEFT_CONTROLLER]); - OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), this.controllerRotation[LEFT_CONTROLLER]); + OpenXRUtil.openXRPoseToMarix(space_location.pose().orientation(), + this.controllerRotation[LEFT_CONTROLLER]); this.controllerTracking[LEFT_CONTROLLER] = true; } else { this.controllerTracking[LEFT_CONTROLLER] = false; @@ -330,7 +336,6 @@ public void readNewData(VRInputAction action) { this.readVecData(action, null); } } - } } @@ -340,13 +345,14 @@ private void readBoolean(VRInputAction action, ControllerType hand) { if (hand != null) { i = hand.ordinal(); } - try (MemoryStack stack = MemoryStack.stackPush()){ + try (MemoryStack stack = MemoryStack.stackPush()) { XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); - info.action(new XrAction(action.handle, new XrActionSet(actionSetHandles.get(action.actionSet), instance))); + info.action(new XrAction(action.handle, + new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); XrActionStateBoolean state = XrActionStateBoolean.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_BOOLEAN); - int error = XR10.xrGetActionStateBoolean(session, info, state); - logError(error, "xrGetActionStateBoolean", action.name); + int error = XR10.xrGetActionStateBoolean(this.session, info, state); + logError(error, "xrGetActionStateBoolean", action.name); action.digitalData[i].state = state.currentState(); action.digitalData[i].isActive = state.isActive(); @@ -361,13 +367,14 @@ private void readFloat(VRInputAction action, ControllerType hand) { if (hand != null) { i = hand.ordinal(); } - try (MemoryStack stack = MemoryStack.stackPush()){ + try (MemoryStack stack = MemoryStack.stackPush()) { XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); - info.action(new XrAction(action.handle, new XrActionSet(actionSetHandles.get(action.actionSet), instance))); + info.action(new XrAction(action.handle, + new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); XrActionStateFloat state = XrActionStateFloat.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_FLOAT); - int error = XR10.xrGetActionStateFloat(session, info, state); - logError(error, "xrGetActionStateFloat", action.name); + int error = XR10.xrGetActionStateFloat(this.session, info, state); + logError(error, "xrGetActionStateFloat", action.name); action.analogData[i].deltaX = action.analogData[i].x - state.currentState(); action.analogData[i].x = state.currentState(); @@ -383,13 +390,14 @@ private void readVecData(VRInputAction action, ControllerType hand) { if (hand != null) { i = hand.ordinal(); } - try (MemoryStack stack = MemoryStack.stackPush()){ + try (MemoryStack stack = MemoryStack.stackPush()) { XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); - info.action(new XrAction(action.handle, new XrActionSet(actionSetHandles.get(action.actionSet), instance))); + info.action(new XrAction(action.handle, + new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); XrActionStateVector2f state = XrActionStateVector2f.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_VECTOR2F); - int error = XR10.xrGetActionStateVector2f(session, info, state); - logError(error, "xrGetActionStateVector2f", action.name); + int error = XR10.xrGetActionStateVector2f(this.session, info, state); + logError(error, "xrGetActionStateVector2f", action.name); action.analogData[i].deltaX = action.analogData[i].x - state.currentState().x(); action.analogData[i].deltaY = action.analogData[i].y - state.currentState().y(); @@ -402,13 +410,13 @@ private void readVecData(VRInputAction action, ControllerType hand) { } private void readPoseData(Long action, XrActionSet set) { - try (MemoryStack stack = MemoryStack.stackPush()){ + try (MemoryStack stack = MemoryStack.stackPush()) { XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); info.action(new XrAction(action, set)); XrActionStatePose state = XrActionStatePose.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_POSE); - int error = XR10.xrGetActionStatePose(session, info, state); - logError(error, "xrGetActionStatePose", ""); + int error = XR10.xrGetActionStatePose(this.session, info, state); + logError(error, "xrGetActionStatePose", ""); } } @@ -437,15 +445,16 @@ private boolean updateActiveActionSets() { } if (this.activeActionSetsBuffer == null) { - activeActionSetsBuffer = XrActiveActionSet.calloc(arraylist.size()); - } else if (activeActionSetsBuffer.capacity() != arraylist.size()) { - activeActionSetsBuffer.close(); - activeActionSetsBuffer = XrActiveActionSet.calloc(arraylist.size()); + this.activeActionSetsBuffer = XrActiveActionSet.calloc(arraylist.size()); + } else if (this.activeActionSetsBuffer.capacity() != arraylist.size()) { + this.activeActionSetsBuffer.close(); + this.activeActionSetsBuffer = XrActiveActionSet.calloc(arraylist.size()); } for (int i = 0; i < arraylist.size(); ++i) { VRInputActionSet vrinputactionset = arraylist.get(i); - activeActionSetsBuffer.get(i).set(new XrActionSet(this.getActionSetHandle(vrinputactionset), instance), NULL); + this.activeActionSetsBuffer.get(i) + .set(new XrActionSet(this.getActionSetHandle(vrinputactionset), this.instance), NULL); } return !arraylist.isEmpty(); @@ -457,18 +466,19 @@ long getActionSetHandle(VRInputActionSet actionSet) { private void pollVREvents() { while (true) { - eventDataBuffer.clear(); - eventDataBuffer.type(XR10.XR_TYPE_EVENT_DATA_BUFFER); - int error = XR10.xrPollEvent(instance, eventDataBuffer); - logError(error, "xrPollEvent", ""); + this.eventDataBuffer.clear(); + this.eventDataBuffer.type(XR10.XR_TYPE_EVENT_DATA_BUFFER); + int error = XR10.xrPollEvent(this.instance, this.eventDataBuffer); + logError(error, "xrPollEvent", ""); if (error != XR10.XR_SUCCESS) { break; } - XrEventDataBaseHeader event = XrEventDataBaseHeader.create(eventDataBuffer.address()); + XrEventDataBaseHeader event = XrEventDataBaseHeader.create(this.eventDataBuffer.address()); switch (event.type()) { case XR10.XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING -> { - XrEventDataInstanceLossPending instanceLossPending = XrEventDataInstanceLossPending.create(event.address()); + XrEventDataInstanceLossPending instanceLossPending = XrEventDataInstanceLossPending.create( + event.address()); } case XR10.XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED -> { this.sessionChanged(XrEventDataSessionStateChanged.create(event.address())); @@ -488,22 +498,22 @@ private void sessionChanged(XrEventDataSessionStateChanged xrEventDataSessionSta switch (state) { case XR10.XR_SESSION_STATE_READY: { - try (MemoryStack stack = MemoryStack.stackPush()){ + try (MemoryStack stack = MemoryStack.stackPush()) { XrSessionBeginInfo sessionBeginInfo = XrSessionBeginInfo.calloc(stack); sessionBeginInfo.type(XR10.XR_TYPE_SESSION_BEGIN_INFO); sessionBeginInfo.next(NULL); sessionBeginInfo.primaryViewConfigurationType(XR10.XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO); - int error = XR10.xrBeginSession(session, sessionBeginInfo); - logError(error, "xrBeginSession", "XR_SESSION_STATE_READY"); + int error = XR10.xrBeginSession(this.session, sessionBeginInfo); + logError(error, "xrBeginSession", "XR_SESSION_STATE_READY"); } this.isActive = true; break; } case XR10.XR_SESSION_STATE_STOPPING: { this.isActive = false; - int error = XR10.xrEndSession(session); - logError(error, "xrEndSession", "XR_SESSION_STATE_STOPPING"); + int error = XR10.xrEndSession(this.session); + logError(error, "xrEndSession", "XR_SESSION_STATE_STOPPING"); } case XR10.XR_SESSION_STATE_VISIBLE, XR10.XR_SESSION_STATE_FOCUSED: { this.isActive = true; @@ -525,8 +535,8 @@ private void sessionChanged(XrEventDataSessionStateChanged xrEventDataSessionSta public Vector2f getPlayAreaSize() { try (MemoryStack stack = MemoryStack.stackPush()) { XrExtent2Df vec = XrExtent2Df.calloc(stack); - int error = XR10.xrGetReferenceSpaceBoundsRect(session, XR10.XR_REFERENCE_SPACE_TYPE_STAGE, vec); - logError(error, "xrGetReferenceSpaceBoundsRect", ""); + int error = XR10.xrGetReferenceSpaceBoundsRect(this.session, XR10.XR_REFERENCE_SPACE_TYPE_STAGE, vec); + logError(error, "xrGetReferenceSpaceBoundsRect", ""); return new Vector2f(vec.width(), vec.height()); } } @@ -538,7 +548,7 @@ public boolean init() { } else if (this.tried) { return this.initialized; } else { - tried = true; + this.tried = true; this.mc = Minecraft.getInstance(); try { this.initializeOpenXRInstance(); @@ -553,7 +563,7 @@ public boolean init() { return false; } - //TODO Seated when no controllers + // TODO Seated when no controllers System.out.println("OpenXR initialized & VR connected."); this.deviceVelocity = new Vector3f[64]; @@ -570,23 +580,23 @@ public boolean init() { private void initializeOpenXRInstance() { try (MemoryStack stack = MemoryStack.stackPush()) { - device.initOpenXRLoader(stack); + this.device.initOpenXRLoader(stack); - //Check extensions + // Check extensions IntBuffer numExtensions = stack.callocInt(1); int error = XR10.xrEnumerateInstanceExtensionProperties((ByteBuffer) null, numExtensions, null); - logError(error, "xrEnumerateInstanceExtensionProperties", "get count"); + logError(error, "xrEnumerateInstanceExtensionProperties", "get count"); XrExtensionProperties.Buffer properties = new XrExtensionProperties.Buffer( bufferStack(numExtensions.get(0), XrExtensionProperties.SIZEOF, XR10.XR_TYPE_EXTENSION_PROPERTIES) ); - //Load extensions + // Load extensions error = XR10.xrEnumerateInstanceExtensionProperties((ByteBuffer) null, numExtensions, properties); - logError(error, "xrEnumerateInstanceExtensionProperties", "get extensions"); + logError(error, "xrEnumerateInstanceExtensionProperties", "get extensions"); - //get needed extensions - String graphicsExtension = device.getGraphicsExtension(); + // get needed extensions + String graphicsExtension = this.device.getGraphicsExtension(); boolean missingGraphics = true; PointerBuffer extensions = stack.callocPointer(3); while (properties.hasRemaining()) { @@ -596,11 +606,17 @@ private void initializeOpenXRInstance() { missingGraphics = false; extensions.put(memAddress(stackUTF8(graphicsExtension))); } - if (extensionName.equals(EXTHPMixedRealityController.XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME)) { - extensions.put(memAddress(stackUTF8(EXTHPMixedRealityController.XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME))); + if (extensionName.equals( + EXTHPMixedRealityController.XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME)) + { + extensions.put(memAddress( + stackUTF8(EXTHPMixedRealityController.XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME))); } - if (extensionName.equals(HTCViveCosmosControllerInteraction.XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME)) { - extensions.put(memAddress(stackUTF8(HTCViveCosmosControllerInteraction.XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME))); + if (extensionName.equals( + HTCViveCosmosControllerInteraction.XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME)) + { + extensions.put(memAddress(stackUTF8( + HTCViveCosmosControllerInteraction.XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME))); } } @@ -608,22 +624,22 @@ private void initializeOpenXRInstance() { throw new RuntimeException("OpenXR runtime is missing a supported graphics extension."); } - //Create APP info + // Create APP info XrApplicationInfo applicationInfo = XrApplicationInfo.calloc(stack); applicationInfo.apiVersion(XR10.XR_MAKE_VERSION(1, 0, 40)); applicationInfo.applicationName(stack.UTF8("Vivecraft")); applicationInfo.applicationVersion(1); - //Create instance info + // Create instance info XrInstanceCreateInfo createInfo = XrInstanceCreateInfo.calloc(stack); createInfo.type(XR10.XR_TYPE_INSTANCE_CREATE_INFO); - createInfo.next(device.getPlatformInfo(stack)); + createInfo.next(this.device.getPlatformInfo(stack)); createInfo.createFlags(0); createInfo.applicationInfo(applicationInfo); createInfo.enabledApiLayerNames(null); createInfo.enabledExtensionNames(extensions.flip()); - //Create XR instance + // Create XR instance PointerBuffer instancePtr = stack.callocPointer(1); int xrResult = XR10.xrCreateInstance(createInfo, instancePtr); if (xrResult == XR10.XR_ERROR_RUNTIME_FAILURE) { @@ -633,7 +649,7 @@ private void initializeOpenXRInstance() { } else if (xrResult < 0) { throw new RuntimeException("XR method returned " + xrResult); } - instance = new XrInstance(instancePtr.get(0), createInfo); + this.instance = new XrInstance(instancePtr.get(0), createInfo); this.poseMatrices = new Matrix4f[64]; @@ -651,24 +667,24 @@ public static MCOpenXR get() { private void initializeOpenXRSession() { try (MemoryStack stack = MemoryStack.stackPush()) { - //Create system + // Create system XrSystemGetInfo system = XrSystemGetInfo.calloc(stack); system.type(XR10.XR_TYPE_SYSTEM_GET_INFO); system.next(NULL); system.formFactor(XR10.XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY); LongBuffer longBuffer = stack.callocLong(1); - int error = XR10.xrGetSystem(instance, system, longBuffer); - logError(error, "xrGetSystem", ""); + int error = XR10.xrGetSystem(this.instance, system, longBuffer); + logError(error, "xrGetSystem", ""); this.systemID = longBuffer.get(0); - if (systemID == 0) { + if (this.systemID == 0) { throw new RuntimeException("No compatible headset detected"); } XrSystemProperties systemProperties = XrSystemProperties.calloc(stack).type(XR10.XR_TYPE_SYSTEM_PROPERTIES); - error = XR10.xrGetSystemProperties(instance, systemID, systemProperties); - MCOpenXR.get().logError(error, "xrGetSystemProperties", ""); + error = XR10.xrGetSystemProperties(this.instance, this.systemID, systemProperties); + MCOpenXR.get().logError(error, "xrGetSystemProperties", ""); XrSystemTrackingProperties trackingProperties = systemProperties.trackingProperties(); XrSystemGraphicsProperties graphicsProperties = systemProperties.graphicsProperties(); @@ -680,34 +696,35 @@ private void initializeOpenXRSession() { int maxHeight = graphicsProperties.maxSwapchainImageHeight(); int maxLayerCount = graphicsProperties.maxLayerCount(); - VRSettings.LOGGER.info("Found device with id: {}", systemID); + VRSettings.LOGGER.info("Found device with id: {}", this.systemID); VRSettings.LOGGER.info("Headset Name: {}, Vendor: {}", MCOpenXR.get().systemName, vendor); - VRSettings.LOGGER.info("Headset Orientation Tracking: {}, Position Tracking: {}", orientationTracking, positionTracking); - VRSettings.LOGGER.info("Headset Max Width: {}, Max Height: {}, Max Layer Count: {}", maxWidth, maxHeight, maxLayerCount); + VRSettings.LOGGER.info("Headset Orientation Tracking: {}, Position Tracking: {}", orientationTracking, + positionTracking); + VRSettings.LOGGER.info("Headset Max Width: {}, Max Height: {}, Max Layer Count: {}", maxWidth, maxHeight, + maxLayerCount); - //Create session + // Create session XrSessionCreateInfo info = XrSessionCreateInfo.calloc(stack); info.type(XR10.XR_TYPE_SESSION_CREATE_INFO); - info.next(device.checkGraphics(stack, instance, systemID).address()); + info.next(this.device.checkGraphics(stack, this.instance, this.systemID).address()); info.createFlags(0); - info.systemId(systemID); + info.systemId(this.systemID); PointerBuffer sessionPtr = stack.callocPointer(1); - error = XR10.xrCreateSession(instance, info, sessionPtr); - logError(error, "xrCreateSession", ""); + error = XR10.xrCreateSession(this.instance, info, sessionPtr); + logError(error, "xrCreateSession", ""); - session = new XrSession(sessionPtr.get(0), instance); + this.session = new XrSession(sessionPtr.get(0), this.instance); while (!this.isActive) { System.out.println("waiting"); pollVREvents(); } - } } private void initializeOpenXRSpace() { - try (MemoryStack stack = MemoryStack.stackPush()){ + try (MemoryStack stack = MemoryStack.stackPush()) { XrPosef identityPose = XrPosef.calloc(stack); identityPose.set( XrQuaternionf.calloc(stack).set(0, 0, 0, 1), @@ -721,48 +738,51 @@ private void initializeOpenXRSpace() { referenceSpaceCreateInfo.poseInReferenceSpace(identityPose); PointerBuffer pp = stack.callocPointer(1); - int error = XR10.xrCreateReferenceSpace(session, referenceSpaceCreateInfo, pp); - xrAppSpace = new XrSpace(pp.get(0), session); - logError(error, "xrCreateReferenceSpace", "XR_REFERENCE_SPACE_TYPE_STAGE"); + int error = XR10.xrCreateReferenceSpace(this.session, referenceSpaceCreateInfo, pp); + this.xrAppSpace = new XrSpace(pp.get(0), this.session); + logError(error, "xrCreateReferenceSpace", "XR_REFERENCE_SPACE_TYPE_STAGE"); referenceSpaceCreateInfo.referenceSpaceType(XR10.XR_REFERENCE_SPACE_TYPE_VIEW); - error = XR10.xrCreateReferenceSpace(session, referenceSpaceCreateInfo, pp); - logError(error, "xrCreateReferenceSpace", "XR_REFERENCE_SPACE_TYPE_VIEW"); - xrViewSpace = new XrSpace(pp.get(0), session); + error = XR10.xrCreateReferenceSpace(this.session, referenceSpaceCreateInfo, pp); + logError(error, "xrCreateReferenceSpace", "XR_REFERENCE_SPACE_TYPE_VIEW"); + this.xrViewSpace = new XrSpace(pp.get(0), this.session); } } private void initializeOpenXRSwapChain() { try (MemoryStack stack = stackPush()) { - //Check amount of views + // Check amount of views IntBuffer intBuf = stack.callocInt(1); - int error = XR10.xrEnumerateViewConfigurationViews(instance, systemID, XR10.XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, intBuf, null); - logError(error, "xrEnumerateViewConfigurationViews", "get count"); + int error = XR10.xrEnumerateViewConfigurationViews(this.instance, this.systemID, + XR10.XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, intBuf, null); + logError(error, "xrEnumerateViewConfigurationViews", "get count"); - //Get all views - ByteBuffer viewConfBuffer = bufferStack(intBuf.get(0), XrViewConfigurationView.SIZEOF, XR10.XR_TYPE_VIEW_CONFIGURATION_VIEW); + // Get all views + ByteBuffer viewConfBuffer = bufferStack(intBuf.get(0), XrViewConfigurationView.SIZEOF, + XR10.XR_TYPE_VIEW_CONFIGURATION_VIEW); XrViewConfigurationView.Buffer views = new XrViewConfigurationView.Buffer(viewConfBuffer); - error = XR10.xrEnumerateViewConfigurationViews(instance, systemID, XR10.XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, intBuf, views); - logError(error, "xrEnumerateViewConfigurationViews", "get views"); + error = XR10.xrEnumerateViewConfigurationViews(this.instance, this.systemID, + XR10.XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, intBuf, views); + logError(error, "xrEnumerateViewConfigurationViews", "get views"); int viewCountNumber = intBuf.get(0); this.viewBuffer = new XrView.Buffer( bufferHeap(viewCountNumber, XrView.SIZEOF, XR10.XR_TYPE_VIEW) ); - //Check swapchain formats - error = XR10.xrEnumerateSwapchainFormats(session, intBuf, null); - logError(error, "xrEnumerateSwapchainFormats", "get count"); + // Check swapchain formats + error = XR10.xrEnumerateSwapchainFormats(this.session, intBuf, null); + logError(error, "xrEnumerateSwapchainFormats", "get count"); - //Get swapchain formats + // Get swapchain formats LongBuffer swapchainFormats = stack.callocLong(intBuf.get(0)); - error = XR10.xrEnumerateSwapchainFormats(session, intBuf, swapchainFormats); - logError(error, "xrEnumerateSwapchainFormats", "get formats"); + error = XR10.xrEnumerateSwapchainFormats(this.session, intBuf, swapchainFormats); + logError(error, "xrEnumerateSwapchainFormats", "get formats"); long[] desiredSwapchainFormats = { - //SRGB formats + // SRGB formats GL21.GL_SRGB8_ALPHA8, GL21.GL_SRGB8, - //others + // others GL11.GL_RGB10_A2, GL30.GL_RGBA16F, GL30.GL_RGB16F, @@ -773,7 +793,7 @@ private void initializeOpenXRSwapChain() { GL31.GL_RGBA8_SNORM, }; - //Choose format + // Choose format long chosenFormat = 0; for (long glFormatIter : desiredSwapchainFormats) { swapchainFormats.rewind(); @@ -797,7 +817,7 @@ private void initializeOpenXRSwapChain() { throw new RuntimeException("No compatible swapchain / framebuffer format available: " + formats); } - //Make swapchain + // Make swapchain XrViewConfigurationView viewConfig = views.get(0); XrSwapchainCreateInfo swapchainCreateInfo = XrSwapchainCreateInfo.calloc(stack); swapchainCreateInfo.type(XR10.XR_TYPE_SWAPCHAIN_CREATE_INFO); @@ -813,9 +833,9 @@ private void initializeOpenXRSwapChain() { swapchainCreateInfo.mipCount(1); PointerBuffer handlePointer = stack.callocPointer(1); - error = XR10.xrCreateSwapchain(session, swapchainCreateInfo, handlePointer); - logError(error, "xrCreateSwapchain", "format: " + chosenFormat); - swapchain = new XrSwapchain(handlePointer.get(0), session); + error = XR10.xrCreateSwapchain(this.session, swapchainCreateInfo, handlePointer); + logError(error, "xrCreateSwapchain", "format: " + chosenFormat); + this.swapchain = new XrSwapchain(handlePointer.get(0), this.session); this.width = swapchainCreateInfo.width(); this.height = swapchainCreateInfo.height(); } @@ -844,7 +864,6 @@ private void initInputAndApplication() { this.loadDefaultBindings(); //this.installApplicationManifest(false); this.inputInitialized = true; - } @Override @@ -859,14 +878,15 @@ public boolean hasCameraTracker() { @Override public List getOrigins(VRInputAction var1) { - try (MemoryStack stack = MemoryStack.stackPush()){ + try (MemoryStack stack = MemoryStack.stackPush()) { XrBoundSourcesForActionEnumerateInfo info = XrBoundSourcesForActionEnumerateInfo.calloc(stack); info.type(XR10.XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO); info.next(NULL); - info.action(new XrAction(var1.handle, new XrActionSet(actionSetHandles.get(var1.actionSet), instance))); + info.action( + new XrAction(var1.handle, new XrActionSet(this.actionSetHandles.get(var1.actionSet), this.instance))); IntBuffer buf = stack.callocInt(1); - int error = XR10.xrEnumerateBoundSourcesForAction(session, info, buf, null); - logError(error, "xrEnumerateBoundSourcesForAction", var1.name); + int error = XR10.xrEnumerateBoundSourcesForAction(this.session, info, buf, null); + logError(error, "xrEnumerateBoundSourcesForAction", var1.name); int size = buf.get(); if (size <= 0) { @@ -875,8 +895,8 @@ public List getOrigins(VRInputAction var1) { buf = stack.callocInt(size); LongBuffer longbuf = stack.callocLong(size); - error = XR10.xrEnumerateBoundSourcesForAction(session, info, buf, longbuf); - logError(error, "xrEnumerateBoundSourcesForAction", var1.name); + error = XR10.xrEnumerateBoundSourcesForAction(this.session, info, buf, longbuf); + logError(error, "xrEnumerateBoundSourcesForAction", var1.name); long[] array; if (longbuf.hasArray()) { //TODO really? array = longbuf.array(); @@ -894,7 +914,7 @@ public List getOrigins(VRInputAction var1) { @Override public String getOriginName(long l) { - try (MemoryStack stack = MemoryStack.stackPush()){ + try (MemoryStack stack = MemoryStack.stackPush()) { XrInputSourceLocalizedNameGetInfo info = XrInputSourceLocalizedNameGetInfo.calloc(stack); info.type(XR10.XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO); info.next(0); @@ -902,8 +922,8 @@ public String getOriginName(long l) { info.whichComponents(XR10.XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT); IntBuffer buf = stack.callocInt(1); - int error = XR10.xrGetInputSourceLocalizedName(session, info, buf, null); - logError(error, "xrGetInputSourceLocalizedName", "get length"); + int error = XR10.xrGetInputSourceLocalizedName(this.session, info, buf, null); + logError(error, "xrGetInputSourceLocalizedName", "get length"); int size = buf.get(); if (size <= 0) { @@ -912,8 +932,8 @@ public String getOriginName(long l) { buf = stack.callocInt(size); ByteBuffer byteBuffer = stack.calloc(size); - error = XR10.xrGetInputSourceLocalizedName(session, info, buf, byteBuffer); - logError(error, "xrGetInputSourceLocalizedName", "get String"); + error = XR10.xrGetInputSourceLocalizedName(this.session, info, buf, byteBuffer); + logError(error, "xrGetInputSourceLocalizedName", "get String"); return new String(byteBuffer.array()); } } @@ -926,12 +946,12 @@ public VRRenderer createVRRenderer() { @Override public boolean isActive() { this.pollVREvents(); - return isActive; + return this.isActive; } @Override public ControllerType getOriginControllerType(long i) { - if (i == aim[RIGHT_CONTROLLER]) { + if (i == this.aim[RIGHT_CONTROLLER]) { return ControllerType.RIGHT; } return ControllerType.LEFT; @@ -947,43 +967,50 @@ public String getRuntimeName() { return "OpenXR"; } - private static final String[] BOTH_HANDS = new String[] {"/user/hand/left", "/user/hand/right"}; + private static final String[] BOTH_HANDS = new String[]{"/user/hand/left", "/user/hand/right"}; //TODO Collect and register all actions private void loadActionHandles() { for (VRInputActionSet vrinputactionset : VRInputActionSet.values()) { - long actionSet = makeActionSet(instance, vrinputactionset.name, vrinputactionset.localizedName, 0); + long actionSet = makeActionSet(this.instance, vrinputactionset.name, vrinputactionset.localizedName, 0); this.actionSetHandles.put(vrinputactionset, actionSet); } for (VRInputAction vrinputaction : this.inputActions.values()) { - long action = createAction(vrinputaction.name, vrinputaction.name, vrinputaction.type, new XrActionSet(this.actionSetHandles.get(vrinputaction.actionSet), instance), BOTH_HANDS); + long action = createAction(vrinputaction.name, vrinputaction.name, vrinputaction.type, + new XrActionSet(this.actionSetHandles.get(vrinputaction.actionSet), this.instance), BOTH_HANDS); vrinputaction.setHandle(action); } setupControllers(); - XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); - this.haptics[RIGHT_CONTROLLER] = createAction("/actions/global/out/righthaptic", "/actions/global/out/righthaptic", "haptic", actionSet, BOTH_HANDS); - this.haptics[LEFT_CONTROLLER] = createAction("/actions/global/out/lefthaptic", "/actions/global/out/lefthaptic", "haptic", actionSet, BOTH_HANDS); - + XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), this.instance); + this.haptics[RIGHT_CONTROLLER] = createAction("/actions/global/out/righthaptic", + "/actions/global/out/righthaptic", "haptic", actionSet, BOTH_HANDS); + this.haptics[LEFT_CONTROLLER] = createAction("/actions/global/out/lefthaptic", "/actions/global/out/lefthaptic", + "haptic", actionSet, BOTH_HANDS); } private void setupControllers() { - XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); - this.grip[RIGHT_CONTROLLER] = createAction("/actions/global/in/righthand", "/actions/global/in/righthand", "pose", actionSet, BOTH_HANDS); - this.grip[LEFT_CONTROLLER] = createAction("/actions/global/in/lefthand", "/actions/global/in/lefthand", "pose", actionSet, BOTH_HANDS); - this.aim[RIGHT_CONTROLLER] = createAction("/actions/global/in/righthandaim", "/actions/global/in/righthandaim", "pose", actionSet, BOTH_HANDS); - this.aim[LEFT_CONTROLLER] = createAction("/actions/global/in/lefthandaim", "/actions/global/in/lefthandaim", "pose", actionSet, BOTH_HANDS); + XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), this.instance); + this.grip[RIGHT_CONTROLLER] = createAction("/actions/global/in/righthand", "/actions/global/in/righthand", + "pose", actionSet, BOTH_HANDS); + this.grip[LEFT_CONTROLLER] = createAction("/actions/global/in/lefthand", "/actions/global/in/lefthand", "pose", + actionSet, BOTH_HANDS); + this.aim[RIGHT_CONTROLLER] = createAction("/actions/global/in/righthandaim", "/actions/global/in/righthandaim", + "pose", actionSet, BOTH_HANDS); + this.aim[LEFT_CONTROLLER] = createAction("/actions/global/in/lefthandaim", "/actions/global/in/lefthandaim", + "pose", actionSet, BOTH_HANDS); } private void loadDefaultBindings() { try (MemoryStack stack = MemoryStack.stackPush()) { int error; - for (String headset: XRBindings.supportedHeadsets()) { + for (String headset : XRBindings.supportedHeadsets()) { VRSettings.LOGGER.info("loading defaults for {}", headset); Pair[] defaultBindings = XRBindings.getBinding(headset).toArray(new Pair[0]); - XrActionSuggestedBinding.Buffer bindings = XrActionSuggestedBinding.calloc(defaultBindings.length + 6, stack); //TODO different way of adding controller poses + XrActionSuggestedBinding.Buffer bindings = XrActionSuggestedBinding.calloc(defaultBindings.length + 6, + stack); //TODO different way of adding controller poses for (int i = 0; i < defaultBindings.length; i++) { Pair pair = defaultBindings[i]; @@ -993,13 +1020,15 @@ private void loadDefaultBindings() { continue; } bindings.get(i).set( - new XrAction(binding.handle, new XrActionSet(actionSetHandles.get(binding.actionSet), instance)), + new XrAction(binding.handle, + new XrActionSet(this.actionSetHandles.get(binding.actionSet), this.instance)), getPath(pair.getRight()) ); } //TODO make this also changeable? - XrActionSet actionSet = new XrActionSet(actionSetHandles.get(VRInputActionSet.GLOBAL), instance); + XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), + this.instance); bindings.get(defaultBindings.length).set( new XrAction(this.grip[RIGHT_CONTROLLER], actionSet), getPath("/user/hand/right/input/grip/pose") @@ -1027,55 +1056,56 @@ private void loadDefaultBindings() { getPath("/user/hand/left/output/haptic") ); - XrInteractionProfileSuggestedBinding suggested_binds = XrInteractionProfileSuggestedBinding.calloc(stack); + XrInteractionProfileSuggestedBinding suggested_binds = XrInteractionProfileSuggestedBinding.calloc( + stack); suggested_binds.type(XR10.XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING); suggested_binds.next(NULL); suggested_binds.interactionProfile(getPath(headset)); suggested_binds.suggestedBindings(bindings); - error = XR10.xrSuggestInteractionProfileBindings(instance, suggested_binds); - logError(error, "xrSuggestInteractionProfileBindings", headset); + error = XR10.xrSuggestInteractionProfileBindings(this.instance, suggested_binds); + logError(error, "xrSuggestInteractionProfileBindings", headset); } XrSessionActionSetsAttachInfo attach_info = XrSessionActionSetsAttachInfo.calloc(stack); attach_info.type(XR10.XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO); attach_info.next(NULL); - attach_info.actionSets(stackPointers(actionSetHandles.values().stream().mapToLong(value -> value).toArray())); + attach_info.actionSets( + stackPointers(this.actionSetHandles.values().stream().mapToLong(value -> value).toArray())); - error = XR10.xrAttachSessionActionSets(session, attach_info); - logError(error, "xrAttachSessionActionSets", ""); + error = XR10.xrAttachSessionActionSets(this.session, attach_info); + logError(error, "xrAttachSessionActionSets", ""); - XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), instance); + XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), this.instance); XrActionSpaceCreateInfo actionSpace = XrActionSpaceCreateInfo.calloc(stack); actionSpace.type(XR10.XR_TYPE_ACTION_SPACE_CREATE_INFO); actionSpace.next(NULL); - actionSpace.action(new XrAction(grip[RIGHT_CONTROLLER], actionSet)); + actionSpace.action(new XrAction(this.grip[RIGHT_CONTROLLER], actionSet)); actionSpace.subactionPath(getPath("/user/hand/right")); actionSpace.poseInActionSpace(POSE_IDENTITY); PointerBuffer pp = stackCallocPointer(1); - error = XR10.xrCreateActionSpace(session, actionSpace, pp); - logError(error, "xrCreateActionSpace", "grip: /user/hand/right"); - this.gripSpace[RIGHT_CONTROLLER] = new XrSpace(pp.get(0), session); + error = XR10.xrCreateActionSpace(this.session, actionSpace, pp); + logError(error, "xrCreateActionSpace", "grip: /user/hand/right"); + this.gripSpace[RIGHT_CONTROLLER] = new XrSpace(pp.get(0), this.session); - actionSpace.action(new XrAction(grip[LEFT_CONTROLLER], actionSet)); + actionSpace.action(new XrAction(this.grip[LEFT_CONTROLLER], actionSet)); actionSpace.subactionPath(getPath("/user/hand/left")); - error = XR10.xrCreateActionSpace(session, actionSpace, pp); - logError(error, "xrCreateActionSpace", "grip: /user/hand/left"); - this.gripSpace[LEFT_CONTROLLER] = new XrSpace(pp.get(0), session); + error = XR10.xrCreateActionSpace(this.session, actionSpace, pp); + logError(error, "xrCreateActionSpace", "grip: /user/hand/left"); + this.gripSpace[LEFT_CONTROLLER] = new XrSpace(pp.get(0), this.session); - actionSpace.action(new XrAction(aim[RIGHT_CONTROLLER], actionSet)); + actionSpace.action(new XrAction(this.aim[RIGHT_CONTROLLER], actionSet)); actionSpace.subactionPath(getPath("/user/hand/right")); error = XR10.xrCreateActionSpace(session, actionSpace, pp); - logError(error, "xrCreateActionSpace", "aim: /user/hand/right"); - this.aimSpace[RIGHT_CONTROLLER] = new XrSpace(pp.get(0), session); + logError(error, "xrCreateActionSpace", "aim: /user/hand/right"); + this.aimSpace[RIGHT_CONTROLLER] = new XrSpace(pp.get(0), this.session); - actionSpace.action(new XrAction(aim[LEFT_CONTROLLER], actionSet)); + actionSpace.action(new XrAction(this.aim[LEFT_CONTROLLER], actionSet)); actionSpace.subactionPath(getPath("/user/hand/left")); - error = XR10.xrCreateActionSpace(session, actionSpace, pp); - logError(error, "xrCreateActionSpace", "aim: /user/hand/left"); - this.aimSpace[LEFT_CONTROLLER] = new XrSpace(pp.get(0), session); - + error = XR10.xrCreateActionSpace(this.session, actionSpace, pp); + logError(error, "xrCreateActionSpace", "aim: /user/hand/left"); + this.aimSpace[LEFT_CONTROLLER] = new XrSpace(pp.get(0), this.session); } } @@ -1083,16 +1113,18 @@ public long getPath(String pathString) { return this.paths.computeIfAbsent(pathString, s -> { try (MemoryStack ignored = stackPush()) { LongBuffer buf = stackCallocLong(1); - int error = XR10.xrStringToPath(instance, pathString, buf); - logError(error, "getPath", pathString); + int error = XR10.xrStringToPath(this.instance, pathString, buf); + logError(error, "getPath", pathString); return buf.get(); } }); } - private long createAction(String name, String localisedName, String type, XrActionSet actionSet, @Nullable String[] subactionPaths) { - try (MemoryStack stack = MemoryStack.stackPush()){ - String s = name.split("/")[name.split("/").length -1].toLowerCase(); + private long createAction( + String name, String localisedName, String type, XrActionSet actionSet, @Nullable String[] subactionPaths) + { + try (MemoryStack stack = MemoryStack.stackPush()) { + String s = name.split("/")[name.split("/").length - 1].toLowerCase(); XrActionCreateInfo hands = XrActionCreateInfo.calloc(stack); hands.type(XR10.XR_TYPE_ACTION_CREATE_INFO); hands.next(NULL); @@ -1104,9 +1136,9 @@ private long createAction(String name, String localisedName, String type, XrActi case "pose" -> hands.actionType(XR10.XR_ACTION_TYPE_POSE_INPUT); case "haptic" -> hands.actionType(XR10.XR_ACTION_TYPE_VIBRATION_OUTPUT); } - if(subactionPaths != null) { + if (subactionPaths != null) { LongBuffer buffer = stackCallocLong(subactionPaths.length); - for(String path : subactionPaths) { + for (String path : subactionPaths) { buffer.put(getPath(path)); } hands.countSubactionPaths(subactionPaths.length); @@ -1119,13 +1151,13 @@ private long createAction(String name, String localisedName, String type, XrActi PointerBuffer buffer = stackCallocPointer(1); int error = XR10.xrCreateAction(actionSet, hands, buffer); - logError(error, "xrCreateAction", "name:", name, "type:", type); + logError(error, "xrCreateAction", "name:", name, "type:", type); return buffer.get(0); } } private long makeActionSet(XrInstance instance, String name, String localisedName, int priority) { - try (MemoryStack stack = MemoryStack.stackPush()){ + try (MemoryStack stack = MemoryStack.stackPush()) { XrActionSetCreateInfo info = XrActionSetCreateInfo.calloc(stack); info.type(XR10.XR_TYPE_ACTION_SET_CREATE_INFO); info.next(NULL); @@ -1217,7 +1249,7 @@ private String getResultName(int xrResult) { try (MemoryStack stack = MemoryStack.stackPush()) { ByteBuffer str = stack.calloc(XR10.XR_MAX_RESULT_STRING_SIZE); - if (XR10.xrResultToString(instance, xrResult, str) == XR10.XR_SUCCESS) { + if (XR10.xrResultToString(this.instance, xrResult, str) == XR10.XR_SUCCESS) { resultString = (memUTF8(memAddress(str))); } else { resultString = "Unknown Error: " + xrResult; @@ -1229,9 +1261,10 @@ private String getResultName(int xrResult) { /** * logs only errors + * * @param xrResult result to check - * @param caller where the xrResult came from - * @param args arguments may be helpful in locating the error + * @param caller where the xrResult came from + * @param args arguments may be helpful in locating the error */ protected void logError(int xrResult, String caller, String... args) { if (xrResult < 0) { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java index 3cebe96cc..a11e9201b 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java @@ -33,19 +33,21 @@ public OpenXRStereoRenderer(MCOpenXR vr) { } @Override - public void createRenderTexture(int width, int height) throws RenderConfigException{ + public void createRenderTexture(int width, int height) throws RenderConfigException { try (MemoryStack stack = MemoryStack.stackPush()) { //Get amount of views in the swapchain IntBuffer intBuffer = stack.ints(0); //Set value to 0 - int error = XR10.xrEnumerateSwapchainImages(openxr.swapchain, intBuffer, null); + int error = XR10.xrEnumerateSwapchainImages(this.openxr.swapchain, intBuffer, null); this.openxr.logError(error, "xrEnumerateSwapchainImages", "get count"); //Now we know the amount, create the image buffer int imageCount = intBuffer.get(0); - XrSwapchainImageOpenGLKHR.Buffer swapchainImageBuffer = this.openxr.device.createImageBuffers(imageCount, stack); + XrSwapchainImageOpenGLKHR.Buffer swapchainImageBuffer = this.openxr.device.createImageBuffers(imageCount, + stack); - error = XR10.xrEnumerateSwapchainImages(openxr.swapchain, intBuffer, XrSwapchainImageBaseHeader.create(swapchainImageBuffer.address(), swapchainImageBuffer.capacity())); + error = XR10.xrEnumerateSwapchainImages(this.openxr.swapchain, intBuffer, + XrSwapchainImageBaseHeader.create(swapchainImageBuffer.address(), swapchainImageBuffer.capacity())); this.openxr.logError(error, "xrEnumerateSwapchainImages", "get images"); this.leftFramebuffers = new VRTextureTarget[imageCount]; @@ -53,36 +55,38 @@ public void createRenderTexture(int width, int height) throws RenderConfigExcept for (int i = 0; i < imageCount; i++) { XrSwapchainImageOpenGLKHR openxrImage = swapchainImageBuffer.get(i); - leftFramebuffers[i] = new VRTextureTarget("L Eye " + i, width, height, openxrImage.image(), 0); + this.leftFramebuffers[i] = new VRTextureTarget("L Eye " + i, width, height, openxrImage.image(), 0); RenderHelper.checkGLError("Left Eye framebuffer setup"); - rightFramebuffers[i] = new VRTextureTarget("R Eye " + i, width, height, openxrImage.image(), 1); + this.rightFramebuffers[i] = new VRTextureTarget("R Eye " + i, width, height, openxrImage.image(), 1); RenderHelper.checkGLError("Right Eye framebuffer setup"); } - this.rightFramebuffer = new VRTextureTarget("R Eye mirror", width, height, true, -1, true, true, ClientDataHolderVR.getInstance().vrSettings.vrUseStencil); - this.leftFramebuffer = new VRTextureTarget("L Eye mirror", width, height, true, -1, true, true, ClientDataHolderVR.getInstance().vrSettings.vrUseStencil); + this.rightFramebuffer = new VRTextureTarget("R Eye mirror", width, height, true, -1, true, true, + ClientDataHolderVR.getInstance().vrSettings.vrUseStencil); + this.leftFramebuffer = new VRTextureTarget("L Eye mirror", width, height, true, -1, true, true, + ClientDataHolderVR.getInstance().vrSettings.vrUseStencil); } } @Override public void setupRenderConfiguration(boolean render) throws IOException, RenderConfigException { super.setupRenderConfiguration(render); - + if (!render) { return; } this.projectionLayerViews = XrCompositionLayerProjectionView.calloc(2); - try (MemoryStack stack = MemoryStack.stackPush()){ + try (MemoryStack stack = MemoryStack.stackPush()) { IntBuffer intBuf2 = stack.callocInt(1); int error = XR10.xrAcquireSwapchainImage( - openxr.swapchain, + this.openxr.swapchain, XrSwapchainImageAcquireInfo.calloc(stack).type(XR10.XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO), intBuf2); this.openxr.logError(error, "xrAcquireSwapchainImage", ""); - error = XR10.xrWaitSwapchainImage(openxr.swapchain, + error = XR10.xrWaitSwapchainImage(this.openxr.swapchain, XrSwapchainImageWaitInfo.calloc(stack) .type(XR10.XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO) .timeout(XR10.XR_INFINITE_DURATION)); @@ -93,67 +97,71 @@ public void setupRenderConfiguration(boolean render) throws IOException, RenderC // Render view to the appropriate part of the swapchain image. for (int viewIndex = 0; viewIndex < 2; viewIndex++) { - var subImage = projectionLayerViews.get(viewIndex) + var subImage = this.projectionLayerViews.get(viewIndex) .type(XR10.XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW) - .pose(openxr.viewBuffer.get(viewIndex).pose()) - .fov(openxr.viewBuffer.get(viewIndex).fov()) + .pose(this.openxr.viewBuffer.get(viewIndex).pose()) + .fov(this.openxr.viewBuffer.get(viewIndex).fov()) .subImage(); - subImage.swapchain(openxr.swapchain); + subImage.swapchain(this.openxr.swapchain); subImage.imageRect().offset().set(0, 0); - subImage.imageRect().extent().set(openxr.width, openxr.height); + subImage.imageRect().extent().set(this.openxr.width, this.openxr.height); subImage.imageArrayIndex(viewIndex); - } } } @Override public Matrix4f getProjectionMatrix(int eyeType, float nearClip, float farClip) { - XrFovf fov = openxr.viewBuffer.get(eyeType).fov(); - return new Matrix4f().setPerspectiveOffCenterFov(fov.angleLeft(), fov.angleRight(), fov.angleDown(), fov.angleUp(), nearClip, farClip); + XrFovf fov = this.openxr.viewBuffer.get(eyeType).fov(); + return new Matrix4f().setPerspectiveOffCenterFov(fov.angleLeft(), fov.angleRight(), fov.angleDown(), + fov.angleUp(), nearClip, farClip); } @Override public void endFrame() throws RenderConfigException { GL31.glBindFramebuffer(GL31.GL_READ_FRAMEBUFFER, getLeftEyeTarget().frameBufferId); - GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, leftFramebuffers[swapIndex].frameBufferId); - GL31.glBlitFramebuffer(0,0, getLeftEyeTarget().viewWidth, getLeftEyeTarget().viewHeight, 0,0, leftFramebuffers[swapIndex].viewWidth, leftFramebuffers[swapIndex].viewHeight, GL31.GL_STENCIL_BUFFER_BIT | GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); + GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, this.leftFramebuffers[this.swapIndex].frameBufferId); + GL31.glBlitFramebuffer(0, 0, getLeftEyeTarget().viewWidth, getLeftEyeTarget().viewHeight, 0, 0, + this.leftFramebuffers[this.swapIndex].viewWidth, this.leftFramebuffers[this.swapIndex].viewHeight, + GL31.GL_STENCIL_BUFFER_BIT | GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); GL31.glBindFramebuffer(GL31.GL_READ_FRAMEBUFFER, getRightEyeTarget().frameBufferId); - GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, rightFramebuffers[swapIndex].frameBufferId); - GL31.glBlitFramebuffer(0,0, getRightEyeTarget().viewWidth, getRightEyeTarget().viewHeight, 0,0, rightFramebuffers[swapIndex].viewWidth, rightFramebuffers[swapIndex].viewHeight, GL31.GL_STENCIL_BUFFER_BIT | GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); + GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, this.rightFramebuffers[this.swapIndex].frameBufferId); + GL31.glBlitFramebuffer(0, 0, getRightEyeTarget().viewWidth, getRightEyeTarget().viewHeight, 0, 0, + this.rightFramebuffers[this.swapIndex].viewWidth, this.rightFramebuffers[this.swapIndex].viewHeight, + GL31.GL_STENCIL_BUFFER_BIT | GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); - try (MemoryStack stack = MemoryStack.stackPush()){ + try (MemoryStack stack = MemoryStack.stackPush()) { PointerBuffer layers = stack.callocPointer(1); int error; error = XR10.xrReleaseSwapchainImage( - openxr.swapchain, + this.openxr.swapchain, XrSwapchainImageReleaseInfo.calloc(stack) .type(XR10.XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO)); this.openxr.logError(error, "xrReleaseSwapchainImage", ""); XrCompositionLayerProjection compositionLayerProjection = XrCompositionLayerProjection.calloc(stack) .type(XR10.XR_TYPE_COMPOSITION_LAYER_PROJECTION) - .space(openxr.xrAppSpace) - .views(projectionLayerViews); + .space(this.openxr.xrAppSpace) + .views(this.projectionLayerViews); layers.put(compositionLayerProjection); layers.flip(); error = XR10.xrEndFrame( - openxr.session, + this.openxr.session, XrFrameEndInfo.calloc(stack) .type(XR10.XR_TYPE_FRAME_END_INFO) - .displayTime(openxr.time) + .displayTime(this.openxr.time) .environmentBlendMode(XR10.XR_ENVIRONMENT_BLEND_MODE_OPAQUE) .layers(layers)); this.openxr.logError(error, "xrEndFrame", ""); - projectionLayerViews.close(); + this.projectionLayerViews.close(); } } @@ -164,12 +172,12 @@ public boolean providesStencilMask() { @Override public RenderTarget getLeftEyeTarget() { - return leftFramebuffer; + return this.leftFramebuffer; } @Override public RenderTarget getRightEyeTarget() { - return rightFramebuffer; + return this.rightFramebuffer; } @Override @@ -179,6 +187,6 @@ public String getName() { @Override public Tuple getRenderTextureSizes() { - return new Tuple<>(openxr.width, openxr.height); + return new Tuple<>(this.openxr.width, this.openxr.height); } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRUtil.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRUtil.java index ebc94576f..eaa865b2a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRUtil.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRUtil.java @@ -8,9 +8,10 @@ public class OpenXRUtil { public static void openXRPoseToMarix(XrPosef pose, Matrix4f mat) { - mat.set(new Quaternionf(pose.orientation().x(), pose.orientation().y(), pose.orientation().z(), pose.orientation().w())) - .setTranslation(pose.position$().x(), pose.position$().y(), pose.position$().z()) - .m33(1); + mat.set(new Quaternionf(pose.orientation().x(), pose.orientation().y(), pose.orientation().z(), + pose.orientation().w())) + .setTranslation(pose.position$().x(), pose.position$().y(), pose.position$().z()) + .m33(1); } public static void openXRPoseToMarix(XrQuaternionf quat, Matrix4f mat) { diff --git a/fabric/build.gradle b/fabric/build.gradle index 11a5c477d..711a531fc 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -71,7 +71,7 @@ dependencies { // Use custom OpenXR lib for Android and GLES bindings //include(implementation("QuestCraftPlusPlus:lwjgl3:${rootProject.lwjgl_version}:lwjgl-openxr-${rootProject.lwjgl_version}")) - include(implementation("org.lwjgl:lwjgl-openxr:3.3.3")) + include(implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}")) include(implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-windows")) include(implementation("org.lwjgl:lwjgl-openxr:${rootProject.lwjgl_version}:natives-linux")) From d6205e0cd4942f5360d21d0ed17679dd49d2a096 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Wed, 8 Jan 2025 02:36:05 +0100 Subject: [PATCH 17/76] fix binding origin name getting --- .../java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index f3d2ab1c1..f2eca05c9 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -14,6 +14,7 @@ import org.lwjgl.opengl.GL31; import org.lwjgl.openxr.*; import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; import org.vivecraft.client.VivecraftVRMod; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; @@ -934,7 +935,7 @@ public String getOriginName(long l) { ByteBuffer byteBuffer = stack.calloc(size); error = XR10.xrGetInputSourceLocalizedName(this.session, info, buf, byteBuffer); logError(error, "xrGetInputSourceLocalizedName", "get String"); - return new String(byteBuffer.array()); + return MemoryUtil.memUTF8(MemoryUtil.memAddress(buf)); } } From 1a8ea30ad4dfa3298ce08724a97d3171d76d5bab Mon Sep 17 00:00:00 2001 From: fayer3 Date: Wed, 8 Jan 2025 03:35:27 +0100 Subject: [PATCH 18/76] change mirror to use framebuffer blits and openvr/nullvr fixes --- .../extensions/RenderTargetExtension.java | 6 - .../vivecraft/client_vr/VRTextureTarget.java | 26 +++- .../client_vr/provider/VRRenderer.java | 23 ++-- .../provider/nullvr/NullVRStereoRenderer.java | 58 ++++++--- .../openvr_lwjgl/OpenVRStereoRenderer.java | 76 ++++++----- .../provider/openxr/OpenXRStereoRenderer.java | 74 ++++++----- .../vivecraft/client_vr/render/VRShaders.java | 5 - .../render/helpers/ShaderHelper.java | 119 +++++++++--------- .../render/helpers/VRPassHelper.java | 10 +- .../client/blaze3d/RenderTargetMixin.java | 7 -- .../mixin/client_vr/MinecraftVRMixin.java | 11 -- .../assets/vivecraft/shaders/core/blit_vr.fsh | 11 -- .../vivecraft/shaders/core/blit_vr.json | 10 -- .../shaders/core/mixedreality_vr.fsh | 5 - 14 files changed, 218 insertions(+), 223 deletions(-) delete mode 100644 common/src/main/resources/assets/vivecraft/shaders/core/blit_vr.fsh delete mode 100644 common/src/main/resources/assets/vivecraft/shaders/core/blit_vr.json diff --git a/common/src/main/java/org/vivecraft/client/extensions/RenderTargetExtension.java b/common/src/main/java/org/vivecraft/client/extensions/RenderTargetExtension.java index 7d9e0645d..5bea9454b 100644 --- a/common/src/main/java/org/vivecraft/client/extensions/RenderTargetExtension.java +++ b/common/src/main/java/org/vivecraft/client/extensions/RenderTargetExtension.java @@ -39,10 +39,4 @@ public interface RenderTargetExtension { * @return if the RenderTarget is set to use mipmaps */ boolean vivecraft$hasMipmaps(); - - /** - * Sets the color id - * @param colorid the color id to set - */ - void vivecraft$setColorid(int colorid); } diff --git a/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java b/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java index 3cb8fe5f3..5b99d1586 100644 --- a/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java +++ b/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java @@ -2,8 +2,8 @@ import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.platform.TextureUtil; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.Minecraft; import org.lwjgl.opengl.GL30; import org.vivecraft.client.Xplat; import org.vivecraft.client.extensions.RenderTargetExtension; @@ -39,14 +39,28 @@ public VRTextureTarget( this.setClearColor(0, 0, 0, 0); } - public VRTextureTarget(String name, int width, int height, int colorid, int index) { - super(true); + public VRTextureTarget(String name, int width, int height, int colorId, int index) { + super(false); this.name = name; RenderSystem.assertOnRenderThreadOrInit(); this.resize(width, height); - ((RenderTargetExtension) this).vivecraft$setColorid(colorid); - GlStateManager._glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferId); - GL30.glFramebufferTextureLayer(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, colorid, 0, index); + + // free the old one when setting a new one + if (this.colorTextureId != -1) { + TextureUtil.releaseTextureId(this.colorTextureId); + } + this.colorTextureId = colorId; + + GlStateManager._glBindFramebuffer(GL30.GL_FRAMEBUFFER, this.frameBufferId); + // unset the old GL_COLOR_ATTACHMENT0 + GlStateManager._glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL30.GL_TEXTURE_2D, 0, + 0); + GL30.glFramebufferTextureLayer(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, colorId, 0, index); + + // unbind the framebuffer + this.unbindRead(); + this.unbindWrite(); + this.setClearColor(0, 0, 0, 0); } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java index 30c7eaa75..f2e366b47 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java @@ -25,7 +25,6 @@ import org.vivecraft.client.utils.TextUtils; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRTextureTarget; -import org.vivecraft.client_vr.extensions.GameRendererExtension; import org.vivecraft.client_vr.extensions.WindowExtension; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; @@ -54,8 +53,8 @@ public abstract class VRRenderer { private float lastFarClip = 0F; // render buffers - protected int LeftEyeTextureId = -1; - protected int RightEyeTextureId = -1; + protected boolean eyeFramebuffersCreated = false; + public RenderTarget framebufferMR; public RenderTarget framebufferUndistorted; public RenderTarget framebufferVrRender; @@ -100,7 +99,7 @@ public VRRenderer(MCVR vr) { * @param width width of the texture * @param height height of the texture */ - public abstract void createRenderTexture(int width, int height) throws RenderConfigException; + public abstract void createRenderTexture(int width, int height); /** * gets the cached projection matrix if the farClip distance matches with the last, else gets a new one from the VR runtime @@ -607,10 +606,6 @@ public void setupRenderConfiguration(boolean render) throws RenderConfigExceptio this.resizeFrameBuffers = false; } - //for OPENXR, it needs to reinit - this.eyeProj[0] = this.getProjectionMatrix(0, ((GameRendererExtension) minecraft.gameRenderer).vivecraft$getMinClipDistance(), lastFarClip); - this.eyeProj[1] = this.getProjectionMatrix(1, ((GameRendererExtension) minecraft.gameRenderer).vivecraft$getMinClipDistance(), lastFarClip); - if (this.reinitFrameBuffers) { RenderHelper.checkGLError("Start Init"); @@ -657,7 +652,17 @@ public void setupRenderConfiguration(boolean render) throws RenderConfigExceptio destroyBuffers(); - this.createRenderTexture(eyew, eyeh); + if (!this.eyeFramebuffersCreated) { + VRSettings.LOGGER.info("Vivecraft: VR Provider supplied texture resolution: {} x {}", eyew, eyeh); + this.createRenderTexture(eyew, eyeh); + + if (!this.getLastError().isEmpty()) { + throw new RenderConfigException( + Component.translatable("vivecraft.messages.renderiniterror", this.getName()), + Component.literal(this.getLastError())); + } + this.eyeFramebuffersCreated = true; + } float resolutionScale = ResolutionControlHelper.isLoaded() ? ResolutionControlHelper.getCurrentScaleFactor() : 1.0F; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRStereoRenderer.java index d71ebabca..90e0107ca 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRStereoRenderer.java @@ -8,9 +8,9 @@ import net.minecraft.util.Tuple; import org.joml.Matrix4f; import org.lwjgl.opengl.GL11; +import org.vivecraft.client_vr.VRTextureTarget; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.VRRenderer; -import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.render.helpers.RenderHelper; import org.vivecraft.client_vr.settings.VRSettings; @@ -19,8 +19,8 @@ public class NullVRStereoRenderer extends VRRenderer { protected int LeftEyeTextureId = -1; protected int RightEyeTextureId = -1; - public RenderTarget framebufferEye0; - public RenderTarget framebufferEye1; + public RenderTarget framebufferEyeLeft; + public RenderTarget framebufferEyeRight; public NullVRStereoRenderer(MCVR vr) { super(vr); @@ -44,25 +44,44 @@ protected Matrix4f getProjectionMatrix(int eyeType, float nearClip, float farCli } @Override - public void createRenderTexture(int lwidth, int lheight) throws RenderConfigException { + public void createRenderTexture(int width, int height) { + int boundTextureId = GlStateManager._getInteger(GL11.GL_TEXTURE_BINDING_2D); + this.LeftEyeTextureId = GlStateManager._genTexture(); - int i = GlStateManager._getInteger(GL11.GL_TEXTURE_BINDING_2D); RenderSystem.bindTexture(this.LeftEyeTextureId); RenderSystem.texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); RenderSystem.texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); - GlStateManager._texImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, lwidth, lheight, 0, GL11.GL_RGBA, GL11.GL_INT, + GlStateManager._texImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA, GL11.GL_INT, null); - RenderSystem.bindTexture(i); this.RightEyeTextureId = GlStateManager._genTexture(); - i = GlStateManager._getInteger(GL11.GL_TEXTURE_BINDING_2D); RenderSystem.bindTexture(this.RightEyeTextureId); RenderSystem.texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); RenderSystem.texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); - GlStateManager._texImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, lwidth, lheight, 0, GL11.GL_RGBA, GL11.GL_INT, + GlStateManager._texImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA, GL11.GL_INT, null); - RenderSystem.bindTexture(i); + this.lastError = RenderHelper.checkGLError("create VR textures"); + + this.framebufferEyeLeft = new VRTextureTarget("L Eye", width, height, false, this.LeftEyeTextureId, true, false, + false); + + VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEyeLeft); + + String leftError = RenderHelper.checkGLError("Left Eye framebuffer setup"); + + this.framebufferEyeRight = new VRTextureTarget("R Eye", width, height, false, this.RightEyeTextureId, true, false, + false); + + VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEyeRight); + + String rightError = RenderHelper.checkGLError("Right Eye framebuffer setup"); + + if (this.lastError.isEmpty()) { + this.lastError = !leftError.isEmpty() ? leftError : rightError; + } + + RenderSystem.bindTexture(boundTextureId); } @Override @@ -75,12 +94,12 @@ public boolean providesStencilMask() { @Override public RenderTarget getLeftEyeTarget() { - return framebufferEye0; + return this.framebufferEyeLeft; } @Override public RenderTarget getRightEyeTarget() { - return framebufferEye1; + return this.framebufferEyeRight; } @@ -95,17 +114,18 @@ public String getName() { } @Override - protected void destroyBuffers() { + public void destroy() { super.destroyBuffers(); + super.destroy(); - if (this.framebufferEye0 != null) { - this.framebufferEye0.destroyBuffers(); - this.framebufferEye0 = null; + if (this.framebufferEyeLeft != null) { + this.framebufferEyeLeft.destroyBuffers(); + this.framebufferEyeLeft = null; } - if (this.framebufferEye1 != null) { - this.framebufferEye1.destroyBuffers(); - this.framebufferEye1 = null; + if (this.framebufferEyeRight != null) { + this.framebufferEyeRight.destroyBuffers(); + this.framebufferEyeRight = null; } if (this.LeftEyeTextureId > -1) { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java index a946f1f90..1aa30a1ba 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java @@ -29,8 +29,8 @@ public class OpenVRStereoRenderer extends VRRenderer { private final MCOpenVR openvr; protected int LeftEyeTextureId = -1; protected int RightEyeTextureId = -1; - public RenderTarget framebufferEye0; - public RenderTarget framebufferEye1; + public RenderTarget framebufferEyeLeft; + public RenderTarget framebufferEyeRight; public OpenVRStereoRenderer(MCOpenVR vr) { super(vr); @@ -97,8 +97,9 @@ protected Matrix4f getProjectionMatrix(int eyeType, float nearClip, float farCli } @Override - public void createRenderTexture(int width, int height) throws RenderConfigException { + public void createRenderTexture(int width, int height) { int boundTextureId = GlStateManager._getInteger(GL11C.GL_TEXTURE_BINDING_2D); + // generate left eye texture this.LeftEyeTextureId = GlStateManager._genTexture(); RenderSystem.bindTexture(this.LeftEyeTextureId); @@ -121,33 +122,31 @@ public void createRenderTexture(int width, int height) throws RenderConfigExcept this.openvr.texType1.eColorSpace(VR.EColorSpace_ColorSpace_Gamma); this.openvr.texType1.eType(VR.ETextureType_TextureType_OpenGL); - if (this.LeftEyeTextureId == -1) { - throw new RenderConfigException( - Component.translatable("vivecraft.messages.renderiniterror", this.getName()), - Component.literal(this.getLastError())); - } - VRSettings.LOGGER.info("Vivecraft: VR Provider supplied render texture IDs: {}, {}", this.LeftEyeTextureId, this.RightEyeTextureId); - VRSettings.LOGGER.info("Vivecraft: VR Provider supplied texture resolution: {} x {}", width, height); - RenderHelper.checkGLError("Render Texture setup"); + this.lastError = RenderHelper.checkGLError("create VR textures"); - if (this.framebufferEye0 == null) { - this.framebufferEye0 = new VRTextureTarget("L Eye", width, height, false, this.LeftEyeTextureId, false, - true, false); - VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEye0); - RenderHelper.checkGLError("Left Eye framebuffer setup"); - } + this.framebufferEyeLeft = new VRTextureTarget("L Eye", width, height, false, this.LeftEyeTextureId, true, false, + false); + + VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEyeLeft); + + String leftError = RenderHelper.checkGLError("Left Eye framebuffer setup"); - if (this.framebufferEye1 == null) { - this.framebufferEye1 = new VRTextureTarget("R Eye", width, height, false, this.RightEyeTextureId, false, - true, false); - VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEye1); - RenderHelper.checkGLError("Right Eye framebuffer setup"); + this.framebufferEyeRight = new VRTextureTarget("R Eye", width, height, false, this.RightEyeTextureId, true, + false, + false); + + VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEyeRight); + + String rightError = RenderHelper.checkGLError("Right Eye framebuffer setup"); + + if (this.lastError.isEmpty()) { + this.lastError = !leftError.isEmpty() ? leftError : rightError; } + RenderSystem.bindTexture(boundTextureId); - this.lastError = RenderHelper.checkGLError("create VR textures"); } @Override @@ -195,12 +194,12 @@ public boolean providesStencilMask() { @Override public RenderTarget getLeftEyeTarget() { - return framebufferEye0; + return this.framebufferEyeLeft; } @Override public RenderTarget getRightEyeTarget() { - return framebufferEye1; + return this.framebufferEyeRight; } public float[] getStencilMask(RenderPass eye) { @@ -216,16 +215,20 @@ public String getName() { } @Override - protected void destroyBuffers() { - super.destroyBuffers(); - if (this.framebufferEye0 != null) { - this.framebufferEye0.destroyBuffers(); - this.framebufferEye0 = null; + public void destroy() { + super.destroy(); + + this.hiddenMeshes[0].free(); + this.hiddenMeshes[1].free(); + + if (this.framebufferEyeLeft != null) { + this.framebufferEyeLeft.destroyBuffers(); + this.framebufferEyeLeft = null; } - if (this.framebufferEye1 != null) { - this.framebufferEye1.destroyBuffers(); - this.framebufferEye1 = null; + if (this.framebufferEyeRight != null) { + this.framebufferEyeRight.destroyBuffers(); + this.framebufferEyeRight = null; } if (this.LeftEyeTextureId > -1) { TextureUtil.releaseTextureId(this.LeftEyeTextureId); @@ -237,11 +240,4 @@ protected void destroyBuffers() { this.RightEyeTextureId = -1; } } - - @Override - public void destroy() { - super.destroy(); - this.hiddenMeshes[0].free(); - this.hiddenMeshes[1].free(); - } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java index a11e9201b..a263d4db5 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java @@ -7,7 +7,6 @@ import org.lwjgl.opengl.GL31; import org.lwjgl.openxr.*; import org.lwjgl.system.MemoryStack; -import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRTextureTarget; import org.vivecraft.client_vr.provider.VRRenderer; import org.vivecraft.client_vr.render.RenderConfigException; @@ -23,8 +22,6 @@ public class OpenXRStereoRenderer extends VRRenderer { private VRTextureTarget[] rightFramebuffers; private boolean render; private XrCompositionLayerProjectionView.Buffer projectionLayerViews; - private VRTextureTarget rightFramebuffer; - private VRTextureTarget leftFramebuffer; public OpenXRStereoRenderer(MCOpenXR vr) { @@ -33,15 +30,15 @@ public OpenXRStereoRenderer(MCOpenXR vr) { } @Override - public void createRenderTexture(int width, int height) throws RenderConfigException { + public void createRenderTexture(int width, int height) { try (MemoryStack stack = MemoryStack.stackPush()) { - //Get amount of views in the swapchain + // Get amount of views in the swapchain IntBuffer intBuffer = stack.ints(0); //Set value to 0 int error = XR10.xrEnumerateSwapchainImages(this.openxr.swapchain, intBuffer, null); this.openxr.logError(error, "xrEnumerateSwapchainImages", "get count"); - //Now we know the amount, create the image buffer + // Now we know the amount, create the image buffer int imageCount = intBuffer.get(0); XrSwapchainImageOpenGLKHR.Buffer swapchainImageBuffer = this.openxr.device.createImageBuffers(imageCount, stack); @@ -56,15 +53,14 @@ public void createRenderTexture(int width, int height) throws RenderConfigExcept for (int i = 0; i < imageCount; i++) { XrSwapchainImageOpenGLKHR openxrImage = swapchainImageBuffer.get(i); this.leftFramebuffers[i] = new VRTextureTarget("L Eye " + i, width, height, openxrImage.image(), 0); - RenderHelper.checkGLError("Left Eye framebuffer setup"); + String leftError = RenderHelper.checkGLError("Left Eye " + i + " framebuffer setup"); this.rightFramebuffers[i] = new VRTextureTarget("R Eye " + i, width, height, openxrImage.image(), 1); - RenderHelper.checkGLError("Right Eye framebuffer setup"); - } + String rightError = RenderHelper.checkGLError("Right Eye " + i + " framebuffer setup"); - this.rightFramebuffer = new VRTextureTarget("R Eye mirror", width, height, true, -1, true, true, - ClientDataHolderVR.getInstance().vrSettings.vrUseStencil); - this.leftFramebuffer = new VRTextureTarget("L Eye mirror", width, height, true, -1, true, true, - ClientDataHolderVR.getInstance().vrSettings.vrUseStencil); + if (this.lastError.isEmpty()) { + this.lastError = !leftError.isEmpty() ? leftError : rightError; + } + } } } @@ -72,9 +68,8 @@ public void createRenderTexture(int width, int height) throws RenderConfigExcept public void setupRenderConfiguration(boolean render) throws IOException, RenderConfigException { super.setupRenderConfiguration(render); - if (!render) { - return; - } + if (!render) return; + this.projectionLayerViews = XrCompositionLayerProjectionView.calloc(2); try (MemoryStack stack = MemoryStack.stackPush()) { @@ -96,7 +91,6 @@ public void setupRenderConfiguration(boolean render) throws IOException, RenderC // Render view to the appropriate part of the swapchain image. for (int viewIndex = 0; viewIndex < 2; viewIndex++) { - var subImage = this.projectionLayerViews.get(viewIndex) .type(XR10.XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW) .pose(this.openxr.viewBuffer.get(viewIndex).pose()) @@ -110,6 +104,15 @@ public void setupRenderConfiguration(boolean render) throws IOException, RenderC } } + /** + * no caching for openxr + */ + @Override + public Matrix4f getCachedProjectionMatrix(int eyeType, float nearClip, float farClip) { + this.eyeProj[eyeType] = this.getProjectionMatrix(eyeType, nearClip, farClip); + return this.eyeProj[eyeType]; + } + @Override public Matrix4f getProjectionMatrix(int eyeType, float nearClip, float farClip) { XrFovf fov = this.openxr.viewBuffer.get(eyeType).fov(); @@ -119,20 +122,6 @@ public Matrix4f getProjectionMatrix(int eyeType, float nearClip, float farClip) @Override public void endFrame() throws RenderConfigException { - - GL31.glBindFramebuffer(GL31.GL_READ_FRAMEBUFFER, getLeftEyeTarget().frameBufferId); - GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, this.leftFramebuffers[this.swapIndex].frameBufferId); - GL31.glBlitFramebuffer(0, 0, getLeftEyeTarget().viewWidth, getLeftEyeTarget().viewHeight, 0, 0, - this.leftFramebuffers[this.swapIndex].viewWidth, this.leftFramebuffers[this.swapIndex].viewHeight, - GL31.GL_STENCIL_BUFFER_BIT | GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); - - GL31.glBindFramebuffer(GL31.GL_READ_FRAMEBUFFER, getRightEyeTarget().frameBufferId); - GL31.glBindFramebuffer(GL31.GL_DRAW_FRAMEBUFFER, this.rightFramebuffers[this.swapIndex].frameBufferId); - GL31.glBlitFramebuffer(0, 0, getRightEyeTarget().viewWidth, getRightEyeTarget().viewHeight, 0, 0, - this.rightFramebuffers[this.swapIndex].viewWidth, this.rightFramebuffers[this.swapIndex].viewHeight, - GL31.GL_STENCIL_BUFFER_BIT | GL31.GL_COLOR_BUFFER_BIT, GL31.GL_NEAREST); - - try (MemoryStack stack = MemoryStack.stackPush()) { PointerBuffer layers = stack.callocPointer(1); int error; @@ -172,12 +161,12 @@ public boolean providesStencilMask() { @Override public RenderTarget getLeftEyeTarget() { - return this.leftFramebuffer; + return this.leftFramebuffers[this.swapIndex]; } @Override public RenderTarget getRightEyeTarget() { - return this.rightFramebuffer; + return this.rightFramebuffers[this.swapIndex]; } @Override @@ -189,4 +178,23 @@ public String getName() { public Tuple getRenderTextureSizes() { return new Tuple<>(this.openxr.width, this.openxr.height); } + + @Override + public void destroy() { + super.destroy(); + + if (this.leftFramebuffers != null) { + for (VRTextureTarget leftFramebuffer : this.leftFramebuffers) { + leftFramebuffer.destroyBuffers(); + } + this.leftFramebuffers = null; + } + + if (this.rightFramebuffers != null) { + for (VRTextureTarget rightFramebuffer : this.rightFramebuffers) { + rightFramebuffer.destroyBuffers(); + } + this.rightFramebuffers = null; + } + } } diff --git a/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java b/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java index 79cf11e3b..98c5af94f 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java @@ -44,11 +44,6 @@ public class VRShaders { public static AbstractUniform POST_PROCESSING_OVERLAY_BLACK_ALPHA_UNIFORM; public static AbstractUniform POST_PROCESSING_OVERLAY_EYE_UNIFORM; - // blit shader - public static ShaderProgram BLIT_VR_SHADER = new ShaderProgram( - ResourceLocation.fromNamespaceAndPath("vivecraft", "core/blit_vr"), - DefaultVertexFormat.POSITION_TEX, ShaderDefines.EMPTY); - // end portal shaders public static ShaderProgram RENDERTYPE_END_PORTAL_VR_SHADER = new ShaderProgram( ResourceLocation.fromNamespaceAndPath("vivecraft", "core/rendertype_end_portal_vr"), diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java index a3b05d93d..253c81978 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java @@ -1,6 +1,7 @@ package org.vivecraft.client_vr.render.helpers; import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; import net.minecraft.Util; @@ -16,6 +17,8 @@ import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; import org.joml.Vector3f; +import org.lwjgl.opengl.GL11C; +import org.lwjgl.opengl.GL30C; import org.lwjgl.opengl.GL43; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.extensions.GameRendererExtension; @@ -88,7 +91,9 @@ private static void drawFullscreenQuad(VertexFormat format) { throw new IllegalStateException("Unexpected vertex format " + format); } + RenderSystem.disableDepthTest(); BufferUploader.draw(builder.buildOrThrow()); + RenderSystem.enableDepthTest(); } /** @@ -262,11 +267,11 @@ public static void drawMirror() { int screenHeight = MC.mainRenderTarget.height; if (leftEye != null) { - ShaderHelper.blitToScreen(leftEye, 0, screenWidth, screenHeight, 0, 0.0F, 0.0F, false); + blitFramebuffer(leftEye, 0, 0, screenWidth, screenHeight); } if (rightEye != null) { - ShaderHelper.blitToScreen(rightEye, screenWidth, screenWidth, screenHeight, 0, 0.0F, 0.0F, false); + blitFramebuffer(rightEye, screenWidth, 0, MC.mainRenderTarget.width, screenHeight); } } else { // general single buffer case @@ -305,9 +310,7 @@ public static void drawMirror() { // source = DataHolder.getInstance().vrRenderer.telescopeFramebufferR; // if (source != null) { - ShaderHelper.blitToScreen(source, - 0, MC.mainRenderTarget.width, - MC.mainRenderTarget.height, 0, + blitFramebufferCrop(source, 0, 0, MC.mainRenderTarget.width, MC.mainRenderTarget.height, xCrop, yCrop, keepAspect); } } @@ -362,6 +365,12 @@ public static void doMixedRealityMirror() { mixedRealityShader.bindSampler("thirdPersonDepth", DATA_HOLDER.vrRenderer.framebufferMR.getDepthTextureId()); + mixedRealityShader.apply(); + + drawFullscreenQuad(VRShaders.MIXED_REALITY_SHADER.vertexFormat()); + + mixedRealityShader.clear(); + if (DATA_HOLDER.vrSettings.mixedRealityUnityLike) { RenderTarget source; if (DATA_HOLDER.vrSettings.displayMirrorUseScreenshotCamera && DATA_HOLDER.cameraTracker.isVisible()) { @@ -375,14 +384,9 @@ public static void doMixedRealityMirror() { source = DATA_HOLDER.vrRenderer.getRightEyeTarget(); } } - mixedRealityShader.bindSampler("firstPersonColor", source.getColorTextureId()); + blitFramebuffer(source, MC.mainRenderTarget.width / 2, 0, + MC.mainRenderTarget.width, MC.mainRenderTarget.height / 2); } - - mixedRealityShader.apply(); - - drawFullscreenQuad(VRShaders.MIXED_REALITY_SHADER.vertexFormat()); - - mixedRealityShader.clear(); } /** @@ -436,71 +440,66 @@ public static void doFSAA(RenderTarget source, RenderTarget firstPass, RenderTar } /** - * blits the given {@code source} RenderTarget to the screen/bound buffer
+ * blits the given {@code source} RenderTarget to the bound framebuffer
* the {@code source} is drawn to the rectangle at {@code left},{@code top} with a size of {@code width},{@code height}
* if {@code xCropFactor} or {@code yCropFactor} are non 0 the {@code source} gets zoomed in - * - * @param source RenderTarget to draw to the screen - * @param left left edge of the target area - * @param width width of the target area - * @param height height of the target area - * @param top top edge of the target area + * @param source RenderTarget to draw to the screen + * @param left left edge of the target area + * @param top top edge of the target area + * @param right right edge width of the target area + * @param bottom bottom edge of the target area * @param xCropFactor vertical crop factor for the {@code source} * @param yCropFactor horizontal crop factor for the {@code source} - * @param keepAspect keeps the aspect ratio in takt when cropping the buffer + * @param keepAspect keeps the aspect ratio in takt when cropping the buffer */ - public static void blitToScreen( - RenderTarget source, int left, int width, int height, int top, float xCropFactor, float yCropFactor, - boolean keepAspect) + private static void blitFramebufferCrop( + RenderTarget source, int left, int top, int right, int bottom, + float xCropFactor, float yCropFactor, boolean keepAspect) { - RenderSystem.assertOnRenderThread(); - RenderSystem.colorMask(true, true, true, false); - RenderSystem.disableDepthTest(); - RenderSystem.depthMask(false); - RenderSystem.viewport(left, top, width, height); - RenderSystem.disableBlend(); - - float drawAspect = (float) width / (float) height; - float bufferAspect = (float) source.viewWidth / (float) source.viewHeight; - - float xMin = xCropFactor; - float yMin = yCropFactor; - float xMax = 1.0F - xCropFactor; - float yMax = 1.0F - yCropFactor; - if (keepAspect) { + float drawAspect = (float) MC.mainRenderTarget.width / (float) MC.mainRenderTarget.height; + float bufferAspect = (float) source.viewWidth / (float) source.viewHeight; if (drawAspect > bufferAspect) { // destination is wider than the buffer float heightAspect = (bufferAspect / drawAspect) * (0.5F - yCropFactor); - yMin = 0.5F - heightAspect; - yMax = 0.5F + heightAspect; + yCropFactor = 0.5F - heightAspect; } else { // destination is taller than the buffer float widthAspect = (drawAspect / bufferAspect) * (0.5F - xCropFactor); - xMin = 0.5F - widthAspect; - xMax = 0.5F + widthAspect; + xCropFactor = 0.5F - widthAspect; } } - CompiledShaderProgram blitShader = Objects.requireNonNull( - RenderSystem.setShader(VRShaders.BLIT_VR_SHADER), "Vivecraft blit shader not loaded"); - blitShader.bindSampler("DiffuseSampler", source.getColorTextureId()); - - blitShader.apply(); - - BufferBuilder bufferbuilder = RenderSystem.renderThreadTesselator() - .begin(VertexFormat.Mode.QUADS, VRShaders.BLIT_VR_SHADER.vertexFormat()); - - bufferbuilder.addVertex(-1.0F, -1.0F, 0.0F).setUv(xMin, yMin); - bufferbuilder.addVertex(1.0F, -1.0F, 0.0F).setUv(xMax, yMin); - bufferbuilder.addVertex(1.0F, 1.0F, 0.0F).setUv(xMax, yMax); - bufferbuilder.addVertex(-1.0F, 1.0F, 0.0F).setUv(xMin, yMax); - BufferUploader.draw(bufferbuilder.buildOrThrow()); - blitShader.clear(); - - RenderSystem.depthMask(true); - RenderSystem.colorMask(true, true, true, true); + int xMin = (int) (xCropFactor * source.width); + int yMin = (int) (yCropFactor * source.height); + int xMax = source.width - xMin; + int yMax = source.height - yMin; + + GlStateManager._glBindFramebuffer(GL30C.GL_READ_FRAMEBUFFER, source.frameBufferId); + GlStateManager._glBlitFrameBuffer( + xMin, yMin, xMax, yMax, + left, top, right, bottom, + GL11C.GL_COLOR_BUFFER_BIT, GL11C.GL_LINEAR); + GlStateManager._glBindFramebuffer(GL30C.GL_READ_FRAMEBUFFER, 0); + } + /** + * blits the given {@code source} RenderTarget to the bound framebuffer + * @param source RenderTarget to draw to the screen + * @param left left edge of the target area + * @param top top edge of the target area + * @param right right edge width of the target area + * @param bottom bottom edge of the target area + */ + private static void blitFramebuffer( + RenderTarget source, int left, int top, int right, int bottom) + { + GlStateManager._glBindFramebuffer(GL30C.GL_READ_FRAMEBUFFER, source.frameBufferId); + GlStateManager._glBlitFrameBuffer( + 0, 0, source.width, source.height, + left, top, right, bottom, + GL11C.GL_COLOR_BUFFER_BIT, GL11C.GL_LINEAR); + GlStateManager._glBindFramebuffer(GL30C.GL_READ_FRAMEBUFFER, 0); } } 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 0497a164c..95bbc90a2 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 @@ -248,7 +248,15 @@ public static void renderAndSubmit(boolean renderLevel, DeltaTracker.Timer delta Profiler.get().pop(); DATA_HOLDER.vrPlayer.postRender(deltaTracker.getGameTimeDeltaPartialTick(true)); - Profiler.get().push("Display/Reproject"); + + Profiler.get().push("vrMirror"); + // use the vanilla target for the mirror + RenderPassManager.setMirrorRenderPass(); + MC.mainRenderTarget.bindWrite(true); + ShaderHelper.drawMirror(); + RenderHelper.checkGLError("post-mirror"); + + Profiler.get().popPush("Display/Reproject"); try { DATA_HOLDER.vrRenderer.endFrame(); diff --git a/common/src/main/java/org/vivecraft/mixin/client/blaze3d/RenderTargetMixin.java b/common/src/main/java/org/vivecraft/mixin/client/blaze3d/RenderTargetMixin.java index 576fed1fe..1952f065e 100644 --- a/common/src/main/java/org/vivecraft/mixin/client/blaze3d/RenderTargetMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client/blaze3d/RenderTargetMixin.java @@ -23,8 +23,6 @@ public abstract class RenderTargetMixin implements RenderTargetExtension { public int width; @Shadow public int height; - @Shadow - protected int colorTextureId; @Unique private int vivecraft$texId = -1; @Unique @@ -54,11 +52,6 @@ public abstract class RenderTargetMixin implements RenderTargetExtension { this.vivecraft$texId = texId; } - @Override - public void vivecraft$setColorid(int colorid) { - this.colorTextureId = colorid; - } - @Unique public void vivecraft$setLinearFilter(boolean linearFilter) { this.vivecraft$linearFilter = linearFilter; 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 1a7eec76d..da7ffd95a 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 @@ -352,17 +352,6 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { } } - @Inject(method = "runTick", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/pipeline/RenderTarget;unbindWrite()V")) - private void vivecraft$blitMirror(CallbackInfo ci) { - if (VRState.VR_RUNNING) { - Profiler.get().popPush("vrMirror"); - RenderPassManager.setMirrorRenderPass(); - this.mainRenderTarget.bindWrite(true); - ShaderHelper.drawMirror(); - RenderHelper.checkGLError("post-mirror"); - } - } - @Inject(method = "setCameraEntity", at = @At("HEAD")) private void vivecraft$rideEntity(Entity entity, CallbackInfo ci) { if (VRState.VR_INITIALIZED) { diff --git a/common/src/main/resources/assets/vivecraft/shaders/core/blit_vr.fsh b/common/src/main/resources/assets/vivecraft/shaders/core/blit_vr.fsh deleted file mode 100644 index d961ccfc5..000000000 --- a/common/src/main/resources/assets/vivecraft/shaders/core/blit_vr.fsh +++ /dev/null @@ -1,11 +0,0 @@ -#version 150 core - -uniform sampler2D DiffuseSampler; - -in vec2 texCoordinates; - -out vec4 fragColor; - -void main(){ - fragColor = texture(DiffuseSampler, texCoordinates.st); -} diff --git a/common/src/main/resources/assets/vivecraft/shaders/core/blit_vr.json b/common/src/main/resources/assets/vivecraft/shaders/core/blit_vr.json deleted file mode 100644 index 0f3041b2a..000000000 --- a/common/src/main/resources/assets/vivecraft/shaders/core/blit_vr.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "vertex": "vivecraft:core/passthrough_vr", - "fragment": "vivecraft:core/blit_vr", - "samplers": [ - { - "name": "DiffuseSampler" - } - ], - "uniforms": [] -} diff --git a/common/src/main/resources/assets/vivecraft/shaders/core/mixedreality_vr.fsh b/common/src/main/resources/assets/vivecraft/shaders/core/mixedreality_vr.fsh index 346fab2b2..44d5465b1 100644 --- a/common/src/main/resources/assets/vivecraft/shaders/core/mixedreality_vr.fsh +++ b/common/src/main/resources/assets/vivecraft/shaders/core/mixedreality_vr.fsh @@ -1,7 +1,5 @@ #version 330 core -uniform sampler2D firstPersonColor; - uniform sampler2D thirdPersonColor; uniform sampler2D thirdPersonDepth; @@ -63,9 +61,6 @@ void main(void) { out_Color.rgb = vec3(1.0); } } - } else if (texCoordinates.x >= 0.5 && texCoordinates.y < 0.5){ - // first person - out_Color.rgb = texture(firstPersonColor, sampleTexcCoord).rgb; } } else { // side by side From 054fb744b5a0cabb187741c0ffe21c68cdb46a07 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Wed, 8 Jan 2025 16:45:16 +0100 Subject: [PATCH 19/76] handle VR events regardless of active state fix openxr not shutting down when the runtime closes fix some naming/formatting things --- .../vivecraft/client_vr/provider/MCVR.java | 7 ++- .../client_vr/provider/nullvr/NullVR.java | 3 + .../provider/openvr_lwjgl/MCOpenVR.java | 16 +++-- .../client_vr/provider/openxr/MCOpenXR.java | 63 ++++++++++++------- ...edular.java => OpenXRHapticScheduler.java} | 6 +- .../provider/openxr/OpenXRStereoRenderer.java | 1 - .../mixin/client_vr/MinecraftVRMixin.java | 5 +- 7 files changed, 67 insertions(+), 34 deletions(-) rename common/src/main/java/org/vivecraft/client_vr/provider/openxr/{OpenXRHapticSchedular.java => OpenXRHapticScheduler.java} (90%) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java index 322e2f3bb..a2803c9db 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java @@ -1520,7 +1520,12 @@ private void processSwipeInput( protected abstract ControllerType findActiveBindingControllerType(KeyMapping keyMapping); /** - * polls VR events, and fetches new device poses and inputs + * polls and processes VR events + */ + public abstract void handleEvents(); + + /** + * fetches new device poses and inputs * * @param frameIndex index of the current VR frame. Some VR runtimes need that */ 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 309fb34cc..572e9ca38 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 @@ -123,6 +123,9 @@ public boolean init() { return this.initialized; } + @Override + public void handleEvents() {} + @Override public void poll(long frameIndex) { if (this.initialized) { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index 15c8fce67..af2679bbc 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -421,15 +421,21 @@ private void initializeOpenVR() throws RuntimeException { } @Override - public void poll(long frameIndex) { - if (!this.initialized) return; - - this.paused = VRSystem_ShouldApplicationPause(); + public void handleEvents() { Profiler.get().push("pollEvents"); this.pollVREvents(); Profiler.get().popPush("processEvents"); this.processVREvents(); - Profiler.get().popPush("updatePose/Vsync"); + Profiler.get().pop(); + } + + @Override + public void poll(long frameIndex) { + if (!this.initialized) return; + + this.paused = VRSystem_ShouldApplicationPause(); + + Profiler.get().push("updatePose/Vsync"); this.updatePose(); if (!this.dh.vrSettings.seated) { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index f2eca05c9..c0bdaf2f0 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -17,6 +17,7 @@ import org.lwjgl.system.MemoryUtil; import org.vivecraft.client.VivecraftVRMod; import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler; import org.vivecraft.client_vr.provider.ControllerType; @@ -73,7 +74,7 @@ public class MCOpenXR extends MCVR { public MCOpenXR(Minecraft mc, ClientDataHolderVR dh) { super(mc, dh, VivecraftVRMod.INSTANCE); OME = this; - this.hapticScheduler = new OpenXRHapticSchedular(); + this.hapticScheduler = new OpenXRHapticScheduler(); } @Override @@ -116,15 +117,15 @@ public void destroy() { } @Override - protected ControllerType findActiveBindingControllerType(KeyMapping binding) { + protected ControllerType findActiveBindingControllerType(KeyMapping keyMapping) { if (!this.inputInitialized) { return null; } else { - long path = this.getInputAction(binding).getLastOrigin(); + long path = this.getInputAction(keyMapping).getLastOrigin(); try (MemoryStack stack = MemoryStack.stackPush()) { IntBuffer buf = stack.callocInt(1); int error = XR10.xrPathToString(this.instance, path, buf, null); - logError(error, "xrPathToString", "get string length for", binding.getName()); + logError(error, "xrPathToString", "get string length for", keyMapping.getName()); int size = buf.get(); if (size <= 0) { @@ -134,7 +135,7 @@ protected ControllerType findActiveBindingControllerType(KeyMapping binding) { buf = stack.callocInt(size); ByteBuffer byteBuffer = stack.calloc(size); error = XR10.xrPathToString(this.instance, path, buf, byteBuffer); - logError(error, "xrPathToString", "get string for", binding.getName()); + logError(error, "xrPathToString", "get string for", keyMapping.getName()); byte[] bytes = new byte[byteBuffer.remaining()]; byteBuffer.get(bytes); String name = new String(bytes); @@ -147,13 +148,18 @@ protected ControllerType findActiveBindingControllerType(KeyMapping binding) { } @Override - public void poll(long var1) { + public void handleEvents() { + Profiler.get().push("events"); + this.pollVREvents(); + Profiler.get().pop(); + } + + @Override + public void poll(long frameIndex) { if (this.initialized) { - Profiler.get().push("events"); - this.pollVREvents(); if (!this.dh.vrSettings.seated) { - Profiler.get().popPush("controllers"); + Profiler.get().push("controllers"); Profiler.get().push("gui"); if (this.mc.screen == null && this.dh.vrSettings.vrTouchHotbar) { @@ -515,6 +521,16 @@ private void sessionChanged(XrEventDataSessionStateChanged xrEventDataSessionSta this.isActive = false; int error = XR10.xrEndSession(this.session); logError(error, "xrEndSession", "XR_SESSION_STATE_STOPPING"); + + if (ClientDataHolderVR.getInstance().vrSettings.closeWithRuntime) { + VRSettings.LOGGER.info("Vivecraft: OpenXR stopped, closing the game with it"); + this.mc.stop(); + } else { + VRSettings.LOGGER.info("Vivecraft: OpenXR stopped, disabling VR"); + VRState.VR_ENABLED = !VRState.VR_ENABLED; + ClientDataHolderVR.getInstance().vrSettings.vrEnabled = VRState.VR_ENABLED; + ClientDataHolderVR.getInstance().vrSettings.saveOptions(); + } } case XR10.XR_SESSION_STATE_VISIBLE, XR10.XR_SESSION_STATE_FOCUSED: { this.isActive = true; @@ -558,7 +574,7 @@ public boolean init() { this.initializeOpenXRSwapChain(); this.initInputAndApplication(); } catch (Exception e) { - e.printStackTrace(); + VRSettings.LOGGER.error("Vivecraft: OpenXR init failed", e); this.initSuccess = false; this.initStatus = e.getLocalizedMessage(); return false; @@ -566,7 +582,7 @@ public boolean init() { // TODO Seated when no controllers - System.out.println("OpenXR initialized & VR connected."); + VRSettings.LOGGER.info("Vivecraft: OpenXR initialized & VR connected."); this.deviceVelocity = new Vector3f[64]; for (int i = 0; i < this.poseMatrices.length; ++i) { @@ -718,7 +734,7 @@ private void initializeOpenXRSession() { this.session = new XrSession(sessionPtr.get(0), this.instance); while (!this.isActive) { - System.out.println("waiting"); + VRSettings.LOGGER.info("Vivecraft: waiting for OpenXR session to start"); pollVREvents(); } } @@ -843,7 +859,7 @@ private void initializeOpenXRSwapChain() { } /** - * Creates an array of XrStructs with their types pre set to @param type + * Creates an array of XrStructs with their types preset to {@code type} */ static ByteBuffer bufferStack(int capacity, int sizeof, int type) { ByteBuffer b = stackCalloc(capacity * sizeof); @@ -868,7 +884,7 @@ private void initInputAndApplication() { } @Override - public Matrix4f getControllerComponentTransform(int var1, String var2) { + public Matrix4f getControllerComponentTransform(int controllerIndex, String componentName) { return new Matrix4f(); } @@ -878,16 +894,16 @@ public boolean hasCameraTracker() { } @Override - public List getOrigins(VRInputAction var1) { + public List getOrigins(VRInputAction action) { try (MemoryStack stack = MemoryStack.stackPush()) { XrBoundSourcesForActionEnumerateInfo info = XrBoundSourcesForActionEnumerateInfo.calloc(stack); info.type(XR10.XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO); info.next(NULL); - info.action( - new XrAction(var1.handle, new XrActionSet(this.actionSetHandles.get(var1.actionSet), this.instance))); + info.action(new XrAction(action.handle, + new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); IntBuffer buf = stack.callocInt(1); int error = XR10.xrEnumerateBoundSourcesForAction(this.session, info, buf, null); - logError(error, "xrEnumerateBoundSourcesForAction", var1.name); + logError(error, "xrEnumerateBoundSourcesForAction", action.name); int size = buf.get(); if (size <= 0) { @@ -897,7 +913,7 @@ public List getOrigins(VRInputAction var1) { buf = stack.callocInt(size); LongBuffer longbuf = stack.callocLong(size); error = XR10.xrEnumerateBoundSourcesForAction(this.session, info, buf, longbuf); - logError(error, "xrEnumerateBoundSourcesForAction", var1.name); + logError(error, "xrEnumerateBoundSourcesForAction", action.name); long[] array; if (longbuf.hasArray()) { //TODO really? array = longbuf.array(); @@ -914,12 +930,12 @@ public List getOrigins(VRInputAction var1) { } @Override - public String getOriginName(long l) { + public String getOriginName(long origin) { try (MemoryStack stack = MemoryStack.stackPush()) { XrInputSourceLocalizedNameGetInfo info = XrInputSourceLocalizedNameGetInfo.calloc(stack); info.type(XR10.XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO); info.next(0); - info.sourcePath(l); + info.sourcePath(origin); info.whichComponents(XR10.XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT); IntBuffer buf = stack.callocInt(1); @@ -946,13 +962,12 @@ public VRRenderer createVRRenderer() { @Override public boolean isActive() { - this.pollVREvents(); return this.isActive; } @Override - public ControllerType getOriginControllerType(long i) { - if (i == this.aim[RIGHT_CONTROLLER]) { + public ControllerType getOriginControllerType(long inputValueHandle) { + if (inputValueHandle == this.aim[RIGHT_CONTROLLER]) { return ControllerType.RIGHT; } return ControllerType.LEFT; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticSchedular.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticScheduler.java similarity index 90% rename from common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticSchedular.java rename to common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticScheduler.java index 819a355e8..a0022a671 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticSchedular.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticScheduler.java @@ -11,9 +11,11 @@ import static java.sql.Types.NULL; -public class OpenXRHapticSchedular extends HapticScheduler { +public class OpenXRHapticScheduler extends HapticScheduler { - private void triggerHapticPulse(ControllerType controller, float durationSeconds, float frequency, float amplitude) { + private void triggerHapticPulse( + ControllerType controller, float durationSeconds, float frequency, float amplitude) + { try (MemoryStack stack = MemoryStack.stackPush()){ int i = controller == ControllerType.RIGHT ? 0 : 1; if (ClientDataHolderVR.getInstance().vrSettings.reverseHands) { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java index a263d4db5..4d8aecca6 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java @@ -4,7 +4,6 @@ import net.minecraft.util.Tuple; import org.joml.Matrix4f; import org.lwjgl.PointerBuffer; -import org.lwjgl.opengl.GL31; import org.lwjgl.openxr.*; import org.lwjgl.system.MemoryStack; import org.vivecraft.client_vr.VRTextureTarget; 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 da7ffd95a..f5b3c5ad4 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 @@ -74,7 +74,6 @@ import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.render.VRFirstPersonArmSwing; import org.vivecraft.client_vr.render.helpers.RenderHelper; -import org.vivecraft.client_vr.render.helpers.ShaderHelper; import org.vivecraft.client_vr.settings.VRHotkeys; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.client_xr.render_pass.RenderPassManager; @@ -246,6 +245,10 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { if (!VRState.VR_INITIALIZED) { return; } + + // handle vr events, regardless of VR active state + ClientDataHolderVR.getInstance().vr.handleEvents(); + boolean vrActive = !ClientDataHolderVR.getInstance().vrSettings.vrHotswitchingEnabled || ClientDataHolderVR.getInstance().vr.isActive(); if (VRState.VR_RUNNING != vrActive && (ClientNetworking.SERVER_ALLOWS_VR_SWITCHING || this.player == null)) { From b54e705de95293629c1a8a50b359b8f10e522465 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Wed, 8 Jan 2025 18:19:46 +0100 Subject: [PATCH 20/76] fix inputs with openvr --- .../org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java | 1 - 1 file changed, 1 deletion(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index af2679bbc..fdca4b509 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -102,7 +102,6 @@ public class MCOpenVR extends MCVR { // holds the handle to the devices other than the headset private final long[] deviceHandle = new long[MCVR.TRACKABLE_DEVICE_COUNT]; - private boolean inputInitialized; private final InputOriginInfo originInfo; private final InputPoseActionData poseData; private final InputDigitalActionData digital; From ab612fc72c53567cc16b9bf95e308027eafa79bb Mon Sep 17 00:00:00 2001 From: fayer3 Date: Wed, 8 Jan 2025 19:36:23 +0100 Subject: [PATCH 21/76] projection matrix only once per frame --- .../provider/openxr/OpenXRStereoRenderer.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java index 4d8aecca6..13b89a698 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java @@ -21,6 +21,7 @@ public class OpenXRStereoRenderer extends VRRenderer { private VRTextureTarget[] rightFramebuffers; private boolean render; private XrCompositionLayerProjectionView.Buffer projectionLayerViews; + private boolean recalculateProjectionMatrix = true; public OpenXRStereoRenderer(MCOpenXR vr) { @@ -90,7 +91,7 @@ public void setupRenderConfiguration(boolean render) throws IOException, RenderC // Render view to the appropriate part of the swapchain image. for (int viewIndex = 0; viewIndex < 2; viewIndex++) { - var subImage = this.projectionLayerViews.get(viewIndex) + XrSwapchainSubImage subImage = this.projectionLayerViews.get(viewIndex) .type(XR10.XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW) .pose(this.openxr.viewBuffer.get(viewIndex).pose()) .fov(this.openxr.viewBuffer.get(viewIndex).fov()) @@ -100,15 +101,21 @@ public void setupRenderConfiguration(boolean render) throws IOException, RenderC subImage.imageRect().extent().set(this.openxr.width, this.openxr.height); subImage.imageArrayIndex(viewIndex); } + this.recalculateProjectionMatrix = true; } } /** * no caching for openxr + * the projection matrix may change every frame, so recalculate it once per frame for up to date info */ @Override public Matrix4f getCachedProjectionMatrix(int eyeType, float nearClip, float farClip) { - this.eyeProj[eyeType] = this.getProjectionMatrix(eyeType, nearClip, farClip); + if (this.recalculateProjectionMatrix) { + this.eyeProj[0] = this.getProjectionMatrix(0, nearClip, farClip); + this.eyeProj[1] = this.getProjectionMatrix(1, nearClip, farClip); + this.recalculateProjectionMatrix = false; + } return this.eyeProj[eyeType]; } From 3a71a9e1ccaa458b43a8ca26fb451f437a1f7af0 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Wed, 8 Jan 2025 23:56:24 +0100 Subject: [PATCH 22/76] fix analog button input --- .../org/vivecraft/client_vr/provider/openxr/MCOpenXR.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index c0bdaf2f0..0cf12d801 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -383,7 +383,7 @@ private void readFloat(VRInputAction action, ControllerType hand) { int error = XR10.xrGetActionStateFloat(this.session, info, state); logError(error, "xrGetActionStateFloat", action.name); - action.analogData[i].deltaX = action.analogData[i].x - state.currentState(); + action.analogData[i].deltaX = state.currentState() - action.analogData[i].x; action.analogData[i].x = state.currentState(); action.analogData[i].activeOrigin = getOrigins(action).get(0); action.analogData[i].isActive = state.isActive(); @@ -406,8 +406,8 @@ private void readVecData(VRInputAction action, ControllerType hand) { int error = XR10.xrGetActionStateVector2f(this.session, info, state); logError(error, "xrGetActionStateVector2f", action.name); - action.analogData[i].deltaX = action.analogData[i].x - state.currentState().x(); - action.analogData[i].deltaY = action.analogData[i].y - state.currentState().y(); + action.analogData[i].deltaX = state.currentState().x() - action.analogData[i].x; + action.analogData[i].deltaY = state.currentState().y() - action.analogData[i].y; action.analogData[i].x = state.currentState().x(); action.analogData[i].y = state.currentState().y(); action.analogData[i].activeOrigin = getOrigins(action).get(0); From 48023e9fb004da98cee79b1cf1de21cec58e939c Mon Sep 17 00:00:00 2001 From: fayer3 Date: Thu, 9 Jan 2025 00:46:56 +0100 Subject: [PATCH 23/76] add interact/climbey bindings, fix cosoms bindings --- .../client_vr/provider/openxr/XRBindings.java | 54 ++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java index 8a3a684a6..987f3d8d9 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java @@ -49,6 +49,16 @@ private static HashSet> quest2Bindings() { set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze")); set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger")); set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger")); return set; } @@ -84,6 +94,16 @@ private static HashSet> viveBindings() { set.add(new MutablePair<>("/actions/technical/in/vivecraft.key.trackpadTouch", "/user/hand/left/input/trackpad/click")); set.add(new MutablePair<>("/actions/technical/in/vivecraft.key.trackpadTouch", "/user/hand/right/input/trackpad/touch")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/click")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/click")); + return set; } @@ -91,30 +111,40 @@ private static HashSet> cosmosBindings() { HashSet> set = new HashSet<>(); set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); - set.add(new MutablePair<>("/actions/global/in/vivecraft.key.toggleKeyboard", "/user/hand/left/input/y/long")); + set.add(new MutablePair<>("/actions/global/in/vivecraft.key.toggleKeyboard", "/user/hand/left/input/y/click")); set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/grip/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/grip/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/joystick/scroll")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/grip/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/grip/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click")); set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/a/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/joystick/position")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/joystick/position")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/pull")); - set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/bumper/click")); - set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/bumper/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); + set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/shoulder/click")); + set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/shoulder/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/grip/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/click")); set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click")); set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/click")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/click")); return set; } From 6c3a95be36c3ca1c70fb118fff09f95a9c733873 Mon Sep 17 00:00:00 2001 From: Darien Johnson <84008186+CADIndie@users.noreply.github.com> Date: Mon, 27 Jan 2025 20:10:30 -0500 Subject: [PATCH 24/76] Add Default, Pico, and Index Controller Bindings --- .../client_vr/provider/openxr/XRBindings.java | 130 ++++++++++++++++-- 1 file changed, 122 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java index 987f3d8d9..76ce8a5f6 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java @@ -9,14 +9,19 @@ public class XRBindings { public static HashSet supportedHeadsets() { HashSet set = new HashSet<>(); - if (MCOpenXR.get().systemName.toLowerCase().contains("oculus") || MCOpenXR.get().systemName.toLowerCase().contains("meta")) { - set.add("/interaction_profiles/oculus/touch_controller"); - return set; - } if (MCOpenXR.get().session.getCapabilities().XR_HTC_vive_cosmos_controller_interaction) { set.add("/interaction_profiles/htc/vive_cosmos_controller"); } + + if (MCOpenXR.get().session.getCapabilities().XR_BD_controller_interaction) { + set.add("/interaction_profiles/bytedance/pico4_controller"); + set.add("/interaction_profiles/bytedance/pico_neo3_controller"); + } + + set.add("/interaction_profiles/khr/simple_controller"); + set.add("/interaction_profiles/oculus/touch_controller"); set.add("/interaction_profiles/htc/vive_controller"); + set.add("/interaction_profiles/valve/index_controller"); return set; } @@ -24,7 +29,6 @@ private static HashSet> quest2Bindings() { HashSet> set = new HashSet<>(); set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); - set.add(new MutablePair<>("/actions/global/in/vivecraft.key.toggleKeyboard", "/user/hand/left/input/squeeze")); set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze")); @@ -66,7 +70,6 @@ private static HashSet> viveBindings() { HashSet> set = new HashSet<>(); set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click")); - set.add(new MutablePair<>("/actions/global/in/vivecraft.key.toggleKeyboard", "/user/hand/left/input/squeeze/click")); set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/right/input/trackpad/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click")); @@ -111,7 +114,6 @@ private static HashSet> cosmosBindings() { HashSet> set = new HashSet<>(); set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); - set.add(new MutablePair<>("/actions/global/in/vivecraft.key.toggleKeyboard", "/user/hand/left/input/y/click")); set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click")); @@ -148,6 +150,111 @@ private static HashSet> cosmosBindings() { return set; } + private static HashSet> picoBindings() { + HashSet> set = new HashSet<>(); + + set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); + set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); + + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); + + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); + set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/a/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); + set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); + set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); + + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/click")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/click")); + return set; + } + + private static HashSet> indexBindings() { + HashSet> set = new HashSet<>(); + + set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/b/click")); + set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/a/click")); + + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/trackpad/y")); + + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); + set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/trackpad")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); + set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); + set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/a/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); + + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/click")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/click")); + return set; + } + + private static HashSet> defaultBindings() { + HashSet> set = new HashSet<>(); + + set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/select/click")); + + set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/select/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/select/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/select/click")); + + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/select/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/select/click")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/select/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/select/click")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/select/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/select/click")); + + return set; + } + public static HashSet> getBinding(String Headset){ switch (Headset) { case "/interaction_profiles/htc/vive_cosmos_controller" -> { @@ -156,11 +263,18 @@ public static HashSet> getBinding(String Headset){ case "/interaction_profiles/htc/vive_controller" -> { return viveBindings(); } + case "/interaction_profiles/valve/index_controller" -> { + return indexBindings(); + } case "/interaction_profiles/oculus/touch_controller" -> { return quest2Bindings(); } + case "/interaction_profiles/bytedance/pico4_controller", + "/interaction_profiles/bytedance/pico_neo3_controller" -> { + return picoBindings(); + } default -> { - return viveBindings(); + return defaultBindings(); } } } From a87509b2a453da999b891d2b04c06915e336ca97 Mon Sep 17 00:00:00 2001 From: Darien Johnson <84008186+CADIndie@users.noreply.github.com> Date: Mon, 27 Jan 2025 20:33:43 -0500 Subject: [PATCH 25/76] Totally didn't forget the extension --- .../org/vivecraft/client_vr/provider/openxr/MCOpenXR.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 0cf12d801..6122bb42a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -615,7 +615,7 @@ private void initializeOpenXRInstance() { // get needed extensions String graphicsExtension = this.device.getGraphicsExtension(); boolean missingGraphics = true; - PointerBuffer extensions = stack.callocPointer(3); + PointerBuffer extensions = stack.callocPointer(4); while (properties.hasRemaining()) { XrExtensionProperties prop = properties.get(); String extensionName = prop.extensionNameString(); @@ -635,6 +635,12 @@ private void initializeOpenXRInstance() { extensions.put(memAddress(stackUTF8( HTCViveCosmosControllerInteraction.XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME))); } + if (extensionName.equals( + BDControllerInteraction.XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME)) + { + extensions.put(memAddress(stackUTF8( + BDControllerInteraction.XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME))); + } } if (missingGraphics) { From db061c10bea30362de8af7f444697996091140a0 Mon Sep 17 00:00:00 2001 From: Darien Johnson <84008186+CADIndie@users.noreply.github.com> Date: Mon, 27 Jan 2025 21:25:41 -0500 Subject: [PATCH 26/76] Set Refresh Rate --- .../client_vr/provider/openxr/MCOpenXR.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 6122bb42a..532d5cef6 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -30,6 +30,7 @@ import javax.annotation.Nullable; import java.nio.ByteBuffer; +import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.LongBuffer; import java.util.*; @@ -615,7 +616,7 @@ private void initializeOpenXRInstance() { // get needed extensions String graphicsExtension = this.device.getGraphicsExtension(); boolean missingGraphics = true; - PointerBuffer extensions = stack.callocPointer(4); + PointerBuffer extensions = stack.callocPointer(5); while (properties.hasRemaining()) { XrExtensionProperties prop = properties.get(); String extensionName = prop.extensionNameString(); @@ -641,6 +642,12 @@ private void initializeOpenXRInstance() { extensions.put(memAddress(stackUTF8( BDControllerInteraction.XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME))); } + if (extensionName.equals( + FBDisplayRefreshRate.XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME)) + { + extensions.put(memAddress(stackUTF8( + FBDisplayRefreshRate.XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME))); + } } if (missingGraphics) { @@ -864,6 +871,17 @@ private void initializeOpenXRSwapChain() { } } + private void initDisplayRefreshRate() { + try (MemoryStack stack = MemoryStack.stackPush()) { + IntBuffer refreshRateCount = stack.callocInt(1); + FBDisplayRefreshRate.xrEnumerateDisplayRefreshRatesFB(session, refreshRateCount, null); + FloatBuffer refreshRateBuffer = stack.callocFloat(refreshRateCount.get(0)); + FBDisplayRefreshRate.xrEnumerateDisplayRefreshRatesFB(session, refreshRateCount, refreshRateBuffer); + refreshRateBuffer.rewind(); + FBDisplayRefreshRate.xrRequestDisplayRefreshRateFB(session, refreshRateBuffer.get(refreshRateCount.get(0) -1)); + } + } + /** * Creates an array of XrStructs with their types preset to {@code type} */ @@ -887,6 +905,7 @@ private void initInputAndApplication() { this.loadDefaultBindings(); //this.installApplicationManifest(false); this.inputInitialized = true; + this.initDisplayRefreshRate(); } @Override From 248facb75b021c23b49b510741cd8f5c64fba961 Mon Sep 17 00:00:00 2001 From: Darien Johnson <84008186+CADIndie@users.noreply.github.com> Date: Sat, 15 Feb 2025 14:20:13 -0500 Subject: [PATCH 27/76] Ensure FBRefreshRate Before Usage --- .../vivecraft/client_vr/provider/openxr/MCOpenXR.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 532d5cef6..f0ca6df34 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -872,13 +872,15 @@ private void initializeOpenXRSwapChain() { } private void initDisplayRefreshRate() { - try (MemoryStack stack = MemoryStack.stackPush()) { + if (this.session.getCapabilities().XR_FB_display_refresh_rate) { + try (MemoryStack stack = MemoryStack.stackPush()) { IntBuffer refreshRateCount = stack.callocInt(1); - FBDisplayRefreshRate.xrEnumerateDisplayRefreshRatesFB(session, refreshRateCount, null); + FBDisplayRefreshRate.xrEnumerateDisplayRefreshRatesFB(this.session, refreshRateCount, null); FloatBuffer refreshRateBuffer = stack.callocFloat(refreshRateCount.get(0)); - FBDisplayRefreshRate.xrEnumerateDisplayRefreshRatesFB(session, refreshRateCount, refreshRateBuffer); + FBDisplayRefreshRate.xrEnumerateDisplayRefreshRatesFB(this.session, refreshRateCount, refreshRateBuffer); refreshRateBuffer.rewind(); - FBDisplayRefreshRate.xrRequestDisplayRefreshRateFB(session, refreshRateBuffer.get(refreshRateCount.get(0) -1)); + FBDisplayRefreshRate.xrRequestDisplayRefreshRateFB(this.session, refreshRateBuffer.get(refreshRateCount.get(0) -1)); + } } } From 49d7a24a3515b05d7a03b13e6823c87603b4aa1e Mon Sep 17 00:00:00 2001 From: fayer3 Date: Tue, 7 Oct 2025 00:27:01 +0200 Subject: [PATCH 28/76] formatting --- .../org/vivecraft/client/VivecraftVRMod.java | 5 +++- .../gui/framework/screens/GuiListScreen.java | 3 ++- .../gui/framework/widgets/SettingsList.java | 26 +++++++++++-------- .../client/render/VRPlayerModel.java | 4 +-- .../client/render/VRPlayerModel_WithArms.java | 4 +-- .../render/helpers/RenderHelper.java | 1 - .../client_vr/render/helpers/VRArmHelper.java | 1 - .../render/helpers/VREffectsHelper.java | 2 -- .../vivecraft/common/utils/TooltipUtil.java | 4 ++- .../entity/EntityRenderDispatcherMixin.java | 3 ++- .../renderer/state/LevelRenderStateMixin.java | 2 +- .../renderer/ItemInHandRendererVRMixin.java | 12 ++++++--- .../java/org/vivecraft/forge/Vivecraft.java | 1 - 13 files changed, 37 insertions(+), 31 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client/VivecraftVRMod.java b/common/src/main/java/org/vivecraft/client/VivecraftVRMod.java index b57ff8364..d97f89aa9 100644 --- a/common/src/main/java/org/vivecraft/client/VivecraftVRMod.java +++ b/common/src/main/java/org/vivecraft/client/VivecraftVRMod.java @@ -7,7 +7,10 @@ import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; import org.vivecraft.client_vr.provider.HandedKeyBinding; -import java.util.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; public class VivecraftVRMod { diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiListScreen.java b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiListScreen.java index ce348a166..816bf9fe7 100644 --- a/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiListScreen.java +++ b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiListScreen.java @@ -110,7 +110,8 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia ((GuiGraphicsAccessor) guiGraphics).getDeferredTooltip() == null) { TooltipRenderer.renderTooltip(guiGraphics, entry.getTooltip(), - this.width / 2, this.list.getRowTop(this.list.children().indexOf(entry)) + 2, this.list.getItemHeight()); + this.width / 2, this.list.getRowTop(this.list.children().indexOf(entry)) + 2, + this.list.getItemHeight()); } } } diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/widgets/SettingsList.java b/common/src/main/java/org/vivecraft/client/gui/framework/widgets/SettingsList.java index f606db436..aad9d7c66 100644 --- a/common/src/main/java/org/vivecraft/client/gui/framework/widgets/SettingsList.java +++ b/common/src/main/java/org/vivecraft/client/gui/framework/widgets/SettingsList.java @@ -4,18 +4,19 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.ComponentPath; import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.*; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.ContainerObjectSelectionList; +import net.minecraft.client.gui.components.Tooltip; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.narration.NarratedElementType; import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.gui.navigation.FocusNavigationEvent; import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.client.resources.language.I18n; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.contents.TranslatableContents; -import net.minecraft.util.Mth; import org.apache.commons.lang3.tuple.Pair; import org.vivecraft.client.utils.StringSimilarity; import org.vivecraft.client_vr.ClientDataHolderVR; @@ -264,7 +265,7 @@ public CategoryEntry(Component name) { @Override public void renderContent( - GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) + GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { guiGraphics.drawString(Minecraft.getInstance().font, this.name, Minecraft.getInstance().screen.width / 2 - this.width / 2, @@ -313,12 +314,13 @@ public SelectableEntry(Component name, AbstractWidget optionalWidget, Runnable c @Override public void renderContent( - GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) + GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { super.renderContent(guiGraphics, mouseX, mouseY, hovering, partialTick); this.mainWidget.setX(this.getContentX()); this.mainWidget.setY(this.getContentY()); - this.mainWidget.setWidth(this.optionalWidget == null ? this.getContentWidth() : this.getContentWidth() - 10 - this.optionalWidget.getWidth()); + this.mainWidget.setWidth(this.optionalWidget == null ? this.getContentWidth() : + this.getContentWidth() - 10 - this.optionalWidget.getWidth()); this.mainWidget.render(guiGraphics, mouseX, mouseY, partialTick); if (this.optionalWidget != null) { @@ -403,7 +405,7 @@ private ResettableEntry( @Override public void renderContent( - GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) + GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { super.renderContent(guiGraphics, mouseX, mouseY, hovering, partialTick); this.resetButton.setX(this.getContentRight() - 20); @@ -473,7 +475,7 @@ public WidgetEntry(Component name, AbstractWidget valueWidget) { @Override public void renderContent( - GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) + GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { super.renderContent(guiGraphics, mouseX, mouseY, hovering, partialTick); @@ -483,7 +485,8 @@ public void renderContent( guiGraphics.drawString(Minecraft.getInstance().font, this.name, this.getContentX(), textY, this.textColor()); } else { - AbstractWidget.renderScrollingString(guiGraphics, Minecraft.getInstance().font, this.name, this.getContentX(), + AbstractWidget.renderScrollingString(guiGraphics, Minecraft.getInstance().font, this.name, + this.getContentX(), textY, this.getContentRight() - VALUE_BUTTON_WIDTH - 5, textY + Minecraft.getInstance().font.lineHeight - 1, this.textColor()); } @@ -525,12 +528,13 @@ public BaseEntry(Component name, Supplier tooltipSupplier) { @Override public void renderContent( - GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) + GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { if (this.isFocused() && Minecraft.getInstance().getLastInputType().isKeyboard() || hovering && Minecraft.getInstance().getLastInputType().isMouse()) { - guiGraphics.fill(this.getX(), this.getContentY(), this.getContentRight(), this.getContentY() + this.getHeight(), 0x80000000); + guiGraphics.fill(this.getX(), this.getContentY(), this.getContentRight(), + this.getContentY() + this.getHeight(), 0x80000000); } } diff --git a/common/src/main/java/org/vivecraft/client/render/VRPlayerModel.java b/common/src/main/java/org/vivecraft/client/render/VRPlayerModel.java index 5a2fa3a8d..6ff17d80d 100644 --- a/common/src/main/java/org/vivecraft/client/render/VRPlayerModel.java +++ b/common/src/main/java/org/vivecraft/client/render/VRPlayerModel.java @@ -2,7 +2,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; -import net.minecraft.client.Minecraft; import net.minecraft.client.model.PlayerModel; import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.model.geom.builders.CubeDeformation; @@ -17,7 +16,6 @@ import org.vivecraft.api.data.FBTMode; import org.vivecraft.client.ClientVRPlayers; import org.vivecraft.client.extensions.EntityRenderStateExtension; -import org.vivecraft.client.utils.ClientUtils; import org.vivecraft.client.utils.ModelUtils; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; @@ -356,7 +354,7 @@ public static void animateVRModel( tempV2.add(tempV); - GuiHandler.GUI_POS_PLAYER_MODEL = new Vec3(renderState.x, renderState.y, renderState.z) + GuiHandler.GUI_POS_PLAYER_MODEL = new Vec3(renderState.x, renderState.y, renderState.z) .add(tempV2.x, tempV2.y, tempV2.z); } tempM.rotateLocalX(-data.xRot()); diff --git a/common/src/main/java/org/vivecraft/client/render/VRPlayerModel_WithArms.java b/common/src/main/java/org/vivecraft/client/render/VRPlayerModel_WithArms.java index 6bd8143f9..0209b2360 100644 --- a/common/src/main/java/org/vivecraft/client/render/VRPlayerModel_WithArms.java +++ b/common/src/main/java/org/vivecraft/client/render/VRPlayerModel_WithArms.java @@ -1,7 +1,6 @@ package org.vivecraft.client.render; import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.model.geom.PartPose; import net.minecraft.client.model.geom.builders.CubeDeformation; @@ -18,7 +17,6 @@ import org.vivecraft.client.ClientVRPlayers; import org.vivecraft.client.extensions.EntityRenderStateExtension; import org.vivecraft.client.render.models.HandModel; -import org.vivecraft.client.utils.ClientUtils; import org.vivecraft.client.utils.ModelUtils; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; @@ -192,7 +190,7 @@ public void setupAnim(AvatarRenderState renderState) { ModelUtils.modelToWorld(renderState, offHand.x, offHand.y, offHand.z, rotInfo, data.bodyYaw(), true, true, this.tempV); - GuiHandler.GUI_POS_PLAYER_MODEL = new Vec3(renderState.x, renderState.y, renderState.z) + GuiHandler.GUI_POS_PLAYER_MODEL = new Vec3(renderState.x, renderState.y, renderState.z) .add(this.tempV.x, this.tempV.y, this.tempV.z); } } else { 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 b92f78ae6..c51dac3ca 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 @@ -24,7 +24,6 @@ import org.joml.Matrix3f; import org.joml.Matrix4f; import org.joml.Vector3f; -import org.joml.Vector3fc; import org.lwjgl.opengl.GL11C; import org.lwjgl.opengl.GL30C; import org.vivecraft.api.client.data.RenderPass; diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/VRArmHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/VRArmHelper.java index 34a1891cf..2c19a9654 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/VRArmHelper.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/VRArmHelper.java @@ -4,7 +4,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.Util; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.core.BlockPos; import net.minecraft.core.Vec3i; diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/VREffectsHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/VREffectsHelper.java index 1bd1baad5..294d157be 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/VREffectsHelper.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/VREffectsHelper.java @@ -25,10 +25,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.util.ARGB; import net.minecraft.util.Mth; -import net.minecraft.util.RandomSource; import net.minecraft.util.profiling.Profiler; import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.Items; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; diff --git a/common/src/main/java/org/vivecraft/common/utils/TooltipUtil.java b/common/src/main/java/org/vivecraft/common/utils/TooltipUtil.java index 0f7206a6c..68ceb392a 100644 --- a/common/src/main/java/org/vivecraft/common/utils/TooltipUtil.java +++ b/common/src/main/java/org/vivecraft/common/utils/TooltipUtil.java @@ -82,7 +82,9 @@ public static String getServerConfigTooltip(String serverConfigPath, boolean add } private static String getClientOnlyTooltip() { - if (Minecraft.getInstance() != null && Minecraft.getInstance().level != null && !Minecraft.getInstance().isLocalServer()) { + if (Minecraft.getInstance() != null && Minecraft.getInstance().level != null && + !Minecraft.getInstance().isLocalServer()) + { return "\n" + Language.getInstance().getOrDefault("vivecraft.messages.serversettingsnotavailablesingle"); } else { return ""; 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 7a071043d..99cb91152 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 @@ -72,7 +72,8 @@ public abstract class EntityRenderDispatcherMixin implements ResourceManagerRelo { if (ClientVRPlayers.getInstance().isVRPlayer(player)) { cir.setReturnValue( - vivecraft$getVRRenderer(player.getSkin().model(), ClientVRPlayers.getInstance().isVRAndSeated(player.getUUID()))); + vivecraft$getVRRenderer(player.getSkin().model(), + ClientVRPlayers.getInstance().isVRAndSeated(player.getUUID()))); } } } diff --git a/common/src/main/java/org/vivecraft/mixin/client/renderer/state/LevelRenderStateMixin.java b/common/src/main/java/org/vivecraft/mixin/client/renderer/state/LevelRenderStateMixin.java index 14c35a9d7..73524ff4a 100644 --- a/common/src/main/java/org/vivecraft/mixin/client/renderer/state/LevelRenderStateMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client/renderer/state/LevelRenderStateMixin.java @@ -13,7 +13,7 @@ public class LevelRenderStateMixin implements LevelRenderStateExtension { @Unique - private final BlockOutlineRenderState[] vivecraft$interactOutlineStates = new BlockOutlineRenderState[2]; + private final BlockOutlineRenderState[] vivecraft$interactOutlineStates = new BlockOutlineRenderState[2]; @Override @Unique diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/ItemInHandRendererVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/ItemInHandRendererVRMixin.java index 397c7ea37..e76008469 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/ItemInHandRendererVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/ItemInHandRendererVRMixin.java @@ -1,12 +1,14 @@ package org.vivecraft.mixin.client_vr.renderer; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; import net.minecraft.client.Minecraft; import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.client.player.LocalPlayer; -import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.ItemInHandRenderer; +import net.minecraft.client.renderer.MapRenderer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; import net.minecraft.client.renderer.state.MapRenderState; import net.minecraft.client.renderer.texture.OverlayTexture; @@ -98,7 +100,8 @@ protected abstract void renderMap( @Shadow protected abstract void renderPlayerArm( - PoseStack poseStack, SubmitNodeCollector collector, int combinedLight, float equippedProgress, float swingProgress, + PoseStack poseStack, SubmitNodeCollector collector, int combinedLight, float equippedProgress, + float swingProgress, HumanoidArm side); @Shadow @@ -123,7 +126,8 @@ protected abstract void renderPlayerArm( int combinedLight, CallbackInfo ci) { if (VRState.VR_RUNNING) { - this.vivecraft$vrRenderArmWithItem(player, partialTick, hand, swingProgress, itemStack, poseStack, collector, + this.vivecraft$vrRenderArmWithItem(player, partialTick, hand, swingProgress, itemStack, poseStack, + collector, combinedLight); ci.cancel(); } diff --git a/forge/src/main/java/org/vivecraft/forge/Vivecraft.java b/forge/src/main/java/org/vivecraft/forge/Vivecraft.java index 738936080..191ab264f 100644 --- a/forge/src/main/java/org/vivecraft/forge/Vivecraft.java +++ b/forge/src/main/java/org/vivecraft/forge/Vivecraft.java @@ -1,7 +1,6 @@ package org.vivecraft.forge; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.PacketUtils; import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraftforge.event.network.CustomPayloadEvent; import net.minecraftforge.fml.common.Mod; From 4695fdf376b9bf3207e6a18a2485d5f59b109b73 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Tue, 7 Oct 2025 13:49:38 +0200 Subject: [PATCH 29/76] fox sodium compat pre 0.4.9 --- .../mod_compat_vr/sodium/SodiumHelper.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/sodium/SodiumHelper.java b/common/src/main/java/org/vivecraft/mod_compat_vr/sodium/SodiumHelper.java index b243a0e92..0af876387 100644 --- a/common/src/main/java/org/vivecraft/mod_compat_vr/sodium/SodiumHelper.java +++ b/common/src/main/java/org/vivecraft/mod_compat_vr/sodium/SodiumHelper.java @@ -91,6 +91,7 @@ public static void copyModelCuboidUV(ModelPart source, ModelPart dest, int sourc if (init()) { try { if (HAS_MODELCUBOID_QUADS) { + // sodium 0.4.9-0.5.3 // ModelCuboid stores the texture info in quads per face Object sourceQuad = ((Object[]) ModelCuboid_quads.get( ((Object[]) ModelPart_sodium$cuboids.get(source))[0]) @@ -106,7 +107,8 @@ public static void copyModelCuboidUV(ModelPart source, ModelPart dest, int sourc destTextures[i].x = sourceTextures[i].x; destTextures[i].y = sourceTextures[i].y; } - } else { + } else if (HAS_MODELCUBOID_FLOATS || HAS_MODELCUBOID_LONGS) { + // sodium 0.5.4+ // ModelCuboid stores the texture info in per cube Object sourceCuboid = HAS_MODELCUBOID_CUBES ? Cube_sodium$cuboid.get(source.cubes.get(0)) : ((Object[]) ModelPart_sodium$cuboids.get(source))[0]; @@ -114,6 +116,7 @@ public static void copyModelCuboidUV(ModelPart source, ModelPart dest, int sourc ((Object[]) ModelPart_sodium$cuboids.get(dest))[0]; if (HAS_MODELCUBOID_FLOATS) { + // sodium 0.5.4-0.6.13 // uvs are stored as a bunch of floats float[][] UVs = new float[][]{{ (float) ModelCuboid_u0.get(sourceCuboid), @@ -132,7 +135,8 @@ public static void copyModelCuboidUV(ModelPart source, ModelPart dest, int sourc mapDirection(sourcePoly), UVs ); - } else if (HAS_MODELCUBOID_LONGS) { + } else { + // sodium 0.7+ // uvs are packed into longs long[] sourceUVs = (long[]) ModelCuboid_textures.get(sourceCuboid); long[] destUVs = (long[]) ModelCuboid_textures.get(destCuboid); @@ -181,7 +185,7 @@ private static boolean init() { } try { try { - // try new public api first + // try new public api first, 0.7+ Class spriteUtil = Class.forName("net.caffeinemc.mods.sodium.api.texture.SpriteUtil"); SpriteUtil_markSpriteActive = spriteUtil.getMethod("markSpriteActive", TextureAtlasSprite.class); SpriteUtil_INSTANCE = spriteUtil.getField("INSTANCE").get(null); @@ -208,10 +212,12 @@ private static boolean init() { try { // all cube cuboids are stored in the ModelPart + // sodium 0.4.9-0.5.11 ModelPart_sodium$cuboids = ModelPart.class.getDeclaredField("sodium$cuboids"); ModelPart_sodium$cuboids.setAccessible(true); } catch (NoSuchFieldException ignored) { // cuboid is stored in the Cube directly instead + // sodium 0.6+ Cube_sodium$cuboid = ModelPart.Cube.class.getDeclaredField("sodium$cuboid"); Cube_sodium$cuboid.setAccessible(true); HAS_MODELCUBOID_CUBES = true; @@ -222,12 +228,13 @@ private static boolean init() { "net.caffeinemc.mods.sodium.client.render.immediate.model.ModelCuboid$Quad" ); // texture bounds are stored in pre face quads + // sodium 0.4.9-0.5.3 ModelCuboid_quads = ModelCuboid.getDeclaredField("quads"); ModelCuboid$Quad_textures = ModelCuboid$Quad.getDeclaredField("textures"); HAS_MODELCUBOID_QUADS = true; } catch (ClassNotFoundException noQuads) { try { - // sodium 0.5.6-0.6.13 + // sodium 0.5.4-0.6.13 // texture bounds are stored in global UVs instead ModelCuboid_u0 = ModelCuboid.getDeclaredField("u0"); ModelCuboid_u1 = ModelCuboid.getDeclaredField("u1"); From 1df650ac385b1ec364994d4b59a4f2d6bd8063e1 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Tue, 7 Oct 2025 14:52:59 +0200 Subject: [PATCH 30/76] fix crash with some mods, that don't expect the hitresult to be null --- .../renderer/GameRendererVRMixin.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/GameRendererVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/GameRendererVRMixin.java index f70419be1..0aea477fd 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/GameRendererVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/GameRendererVRMixin.java @@ -22,6 +22,7 @@ import net.minecraft.client.renderer.ScreenEffectRenderer; import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.server.packs.resources.ResourceManagerReloadListener; import net.minecraft.tags.FluidTags; import net.minecraft.util.Mth; @@ -30,6 +31,7 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; import org.apache.commons.lang3.tuple.Triple; @@ -146,10 +148,21 @@ public abstract class GameRendererVRMixin @WrapMethod(method = "pick(F)V") private void vivecraft$vrPick(float partialTick, Operation original) { if (VRState.VR_RUNNING) { - // skip when data not available yet, or screen is open - if (vivecraft$DATA_HOLDER.vrPlayer.vrdata_world_render == null || - this.minecraft.getCameraEntity() == null || this.minecraft.screen != null) + // don't update the hitresult when chat is open + if (this.minecraft.screen != null && this.minecraft.hitResult != null) { + return; + } + // skip when data not available yet + else if (vivecraft$DATA_HOLDER.vrPlayer.vrdata_world_render == null || + this.minecraft.getCameraEntity() == null) { + // some mods don't like it when the hitresult is null, so set it to a miss + if (this.minecraft.player != null) { + this.minecraft.hitResult = BlockHitResult.miss(this.minecraft.player.position(), + this.minecraft.player.getDirection(), this.minecraft.player.blockPosition()); + } else { + this.minecraft.hitResult = BlockHitResult.miss(Vec3.ZERO, Direction.UP, BlockPos.ZERO); + } return; } From 2a4fbbd83ebc7c08ce2055a7c32ade3d38d5f699 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Tue, 7 Oct 2025 14:55:43 +0200 Subject: [PATCH 31/76] bump to 1.3.2 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 88adebc7d..6cbd92f4e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ minecraft_version=1.21.9 enabled_platforms=fabric,forge,neoforge archives_base_name=vivecraft -mod_version=1.3.0 +mod_version=1.3.2 maven_group=org.vivecraft lwjgl_version=3.3.3 From de05f5f1612d2fcf7a4ea446dd2bae11a06d6c4f Mon Sep 17 00:00:00 2001 From: fayer3 Date: Tue, 7 Oct 2025 16:22:20 +0200 Subject: [PATCH 32/76] allow running on 1.21.10 --- fabric/src/main/resources/fabric.mod.json | 2 +- forge/src/main/resources/META-INF/mods.toml | 2 +- gradle.properties | 4 ++-- neoforge/src/main/resources/META-INF/neoforge.mods.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index ab85e0912..4e1a9f9f0 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -51,7 +51,7 @@ ], "depends": { "fabricloader": ">=0.16.1", - "minecraft": ["1.21.9"], + "minecraft": ["1.21.9","1.21.10"], "java": ">=21" }, "breaks": { diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml index 375927cbd..8482afe72 100644 --- a/forge/src/main/resources/META-INF/mods.toml +++ b/forge/src/main/resources/META-INF/mods.toml @@ -30,6 +30,6 @@ side = "BOTH" [[dependencies.vivecraft]] modId = "minecraft" mandatory = true -versionRange = "[1.21.9]" +versionRange = "[1.21.9,1.21.10]" ordering = "NONE" side = "BOTH" diff --git a/gradle.properties b/gradle.properties index 6cbd92f4e..7858a30b8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,8 +10,8 @@ maven_group=org.vivecraft lwjgl_version=3.3.3 mixin_extras_version=0.4.1 -architectury_version=17.0.8 -parchment_version=1.21.8:2025.07.20 +architectury_version=18.0.3 +parchment_version=1.21.9:2025.10.05 fabric_loader_version=0.17.2 fabric_api_version=0.134.0+1.21.9 diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml index 5b45aec1c..84578da08 100644 --- a/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -30,7 +30,7 @@ side = "BOTH" [[dependencies.vivecraft]] modId = "minecraft" type = "required" -versionRange = "[1.21.9]" +versionRange = "[1.21.9,1.21.10]" ordering = "NONE" side = "BOTH" From 6393a66af1f866c845ed927d18f7340120d45a90 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sun, 12 Oct 2025 21:47:50 +0200 Subject: [PATCH 33/76] clarify that disabling teleporting only works on 1.3.0+ --- common/src/main/resources/assets/vivecraft/lang/en_us.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e0124028f..9672dec76 100644 --- a/common/src/main/resources/assets/vivecraft/lang/en_us.json +++ b/common/src/main/resources/assets/vivecraft/lang/en_us.json @@ -841,7 +841,7 @@ "vivecraft.serverSettings.crawling.enabled.tooltip": "Allows VR players to get into the crawl state by getting low to the ground. Disabling does not prevent vanilla crawling.", - "vivecraft.serverSettings.teleport.enabled.tooltip": "Allows VR players to use teleport movement. It is recommended to leave this enabled for players prone to VR sickness.", + "vivecraft.serverSettings.teleport.enabled.tooltip": "Allows VR players to use teleport movement. It is recommended to leave this enabled for players prone to VR sickness.\n Disabling this only works for Vivecraft 1.3.0+ clients.", "vivecraft.serverSettings.teleport.limitedSurvival.tooltip": "Enforces limited teleport range and frequency in Survival.", "vivecraft.serverSettings.teleport.upLimit.tooltip": "Maximum number of blocks players in Survival mode can teleport up. Set to 0 to disable.", "vivecraft.serverSettings.teleport.downLimit.tooltip": "Maximum number of blocks players in Survival mode can teleport down. Set to 0 to disable.", From 5ea0a386fee542cd551940990af8d023937f7b40 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 13 Oct 2025 22:54:19 +0200 Subject: [PATCH 34/76] change network version to an enum --- .../client/network/ClientNetworking.java | 19 +++---- .../gameplay/trackers/HapticTracker.java | 4 +- .../common/network/CommonNetworkHelper.java | 21 ++------ .../common/network/NetworkVersion.java | 49 +++++++++++++++++++ .../common/network/VrPlayerState.java | 20 ++++---- .../packet/c2s/ActiveBodyPartPayloadC2S.java | 4 +- .../network/packet/c2s/VersionPayloadC2S.java | 6 +-- .../network/packet/s2c/CrawlPayloadS2C.java | 10 ++-- .../packet/s2c/NetworkVersionPayloadS2C.java | 7 +-- .../packet/s2c/TeleportPayloadS2C.java | 10 ++-- .../mixin/world/entity/InventoryMixin.java | 6 +-- .../block/FenceGateBlockServerMixin.java | 4 +- .../vivecraft/server/ServerNetworking.java | 34 +++++++------ .../vivecraft/server/ServerVivePlayer.java | 4 +- 14 files changed, 119 insertions(+), 79 deletions(-) create mode 100644 common/src/main/java/org/vivecraft/common/network/NetworkVersion.java diff --git a/common/src/main/java/org/vivecraft/client/network/ClientNetworking.java b/common/src/main/java/org/vivecraft/client/network/ClientNetworking.java index 43dc84460..5066b700b 100644 --- a/common/src/main/java/org/vivecraft/client/network/ClientNetworking.java +++ b/common/src/main/java/org/vivecraft/client/network/ClientNetworking.java @@ -25,6 +25,7 @@ import org.vivecraft.common.CommonDataHolder; import org.vivecraft.common.VRServerPerms; import org.vivecraft.common.network.CommonNetworkHelper; +import org.vivecraft.common.network.NetworkVersion; import org.vivecraft.common.network.VrPlayerState; import org.vivecraft.common.network.packet.c2s.*; import org.vivecraft.common.network.packet.s2c.*; @@ -61,7 +62,7 @@ public class ClientNetworking { public static Map SERVER_VR_CHANGES_LIST; // assume a legacy server by default, to not send invalid packets - public static int USED_NETWORK_VERSION = CommonNetworkHelper.NETWORK_VERSION_LEGACY; + public static NetworkVersion USED_NETWORK_VERSION = NetworkVersion.LEGACY; private static float WORLDSCALE_LAST = 0.0F; private static float HEIGHT_LAST = 0.0F; public static float OVERRIDDEN_YAW; @@ -88,7 +89,7 @@ public static void resetServerSettings() { SERVER_ALLOWS_VR_SWITCHING = false; SERVER_ALLOWS_DUAL_WIELDING = false; SERVER_ALLOWS_ATTACKING_WHILE_BLOCKING = false; - USED_NETWORK_VERSION = CommonNetworkHelper.NETWORK_VERSION_LEGACY; + USED_NETWORK_VERSION = NetworkVersion.LEGACY; LAST_SENT_BODY_PART = VRBodyPart.MAIN_HAND; BODY_PART_CLIENT_OVERRIDE = null; IS_LAST_BODY_PART_AIM = false; @@ -125,8 +126,8 @@ public static void sendVersionInfo() { new VersionPayloadC2S( CommonDataHolder.getInstance().versionIdentifier, VRState.VR_RUNNING, - CommonNetworkHelper.MAX_SUPPORTED_NETWORK_VERSION, - CommonNetworkHelper.MIN_SUPPORTED_NETWORK_VERSION))); + CommonNetworkHelper.MAX_SUPPORTED_NETWORK_PROTOCOL, + CommonNetworkHelper.MIN_SUPPORTED_NETWORK_PROTOCOL))); } } @@ -155,7 +156,7 @@ public static void sendVRPlayerPositions(VRPlayer vrPlayer) { var vrPlayerState = VrPlayerState.create(vrPlayer); - if (USED_NETWORK_VERSION != CommonNetworkHelper.NETWORK_VERSION_LEGACY) { + if (USED_NETWORK_VERSION != NetworkVersion.LEGACY) { sendServerPacket(new VRPlayerStatePayloadC2S(vrPlayerState)); } else { sendLegacyPackets(vrPlayerState); @@ -215,7 +216,7 @@ public static boolean isLimitedSurvivalTeleport() { public static boolean supportsReversedBow() { // old plugins hardcode the hand order - return USED_NETWORK_VERSION >= CommonNetworkHelper.NETWORK_VERSION_DUAL_WIELDING || !SERVER_HAS_VIVECRAFT; + return NetworkVersion.DUAL_WIELDING.accepts(USED_NETWORK_VERSION) || !SERVER_HAS_VIVECRAFT; } public static int getTeleportUpLimit() { @@ -262,8 +263,8 @@ public static void sendActiveHand(InteractionHand hand, boolean useForAim) { */ public static void sendActiveBodyPart(VRBodyPart bodyPart, boolean useForAim) { if (SERVER_WANTS_DATA) { - if ((USED_NETWORK_VERSION < CommonNetworkHelper.NETWORK_VERSION_HEAD_AIM && bodyPart == VRBodyPart.HEAD) || - (USED_NETWORK_VERSION < CommonNetworkHelper.NETWORK_VERSION_DUAL_WIELDING && + if ((!NetworkVersion.HEAD_AIM.accepts(USED_NETWORK_VERSION) && bodyPart == VRBodyPart.HEAD) || + (!NetworkVersion.DUAL_WIELDING.accepts(USED_NETWORK_VERSION) && !bodyPart.availableInMode(FBTMode.ARMS_ONLY) )) { @@ -424,7 +425,7 @@ public static void handlePacket(VivecraftPayloadS2C s2cPayload) { case NETWORK_VERSION -> { USED_NETWORK_VERSION = ((NetworkVersionPayloadS2C) s2cPayload).version(); - if (USED_NETWORK_VERSION >= CommonNetworkHelper.NETWORK_VERSION_HEAD_AIM) { + if (NetworkVersion.HEAD_AIM.accepts(USED_NETWORK_VERSION)) { HEAD_AIM_WARNING = false; } } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/HapticTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/HapticTracker.java index 907303c1d..9a69bb7f6 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/HapticTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/HapticTracker.java @@ -18,7 +18,7 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.bodylink.Haptics; import org.vivecraft.client_vr.bodylink.RiggedBody; -import org.vivecraft.common.network.CommonNetworkHelper; +import org.vivecraft.common.network.NetworkVersion; import org.vivecraft.common.network.packet.c2s.DamageDirectionPayloadC2S; import org.vivecraft.common.utils.MathUtils; import org.vivecraft.common.utils.Utils; @@ -64,7 +64,7 @@ public void activeProcess(LocalPlayer player) { //TODO Find better place for this RiggedBody.getInstance().updatePose(this.dh.vrPlayer.getVRDataWorld()); - if (ClientNetworking.USED_NETWORK_VERSION >= CommonNetworkHelper.NETWORK_VERSION_DAMAGE_DIRECTION && + if (NetworkVersion.DAMAGE_DIRECTION.accepts(ClientNetworking.USED_NETWORK_VERSION) && !ClientNetworking.REQUESTED_DAMAGE_DIRECTION) { ClientNetworking.sendServerPacket(new DamageDirectionPayloadC2S()); diff --git a/common/src/main/java/org/vivecraft/common/network/CommonNetworkHelper.java b/common/src/main/java/org/vivecraft/common/network/CommonNetworkHelper.java index cf714eace..35ca3c651 100644 --- a/common/src/main/java/org/vivecraft/common/network/CommonNetworkHelper.java +++ b/common/src/main/java/org/vivecraft/common/network/CommonNetworkHelper.java @@ -11,26 +11,11 @@ public class CommonNetworkHelper { public static final ResourceLocation CHANNEL = ResourceLocation.parse("vivecraft:data"); - public static final int NETWORK_VERSION_LEGACY = -1; - // adds full body tracker data - public static final int NETWORK_VERSION_FBT = 1; - // adds dual wielding packet and server logic - public static final int NETWORK_VERSION_DUAL_WIELDING = 2; - // adds the head as a valid active BodyPart, and adds a useForAim flag - public static final int NETWORK_VERSION_HEAD_AIM = 3; - // allows sending haptic events to the client - public static final int NETWORK_VERSION_HAPTIC_PACKET = 4; - // adds a packet, to inform the client what vr changes are on non default values - public static final int NETWORK_VERSION_SERVER_VR_CHANGES = 5; - // adds packets to send/receive damage directions - public static final int NETWORK_VERSION_DAMAGE_DIRECTION = 6; - // adds features to toggle settings after initial connection - public static final int NETWORK_VERSION_OPTION_TOGGLE = 7; - // maximum supported network version - public static final int MAX_SUPPORTED_NETWORK_VERSION = NETWORK_VERSION_OPTION_TOGGLE; + public static final int MAX_SUPPORTED_NETWORK_PROTOCOL = NetworkVersion.values() + [NetworkVersion.values().length - 1].protocolVersion(); // minimum supported network version - public static final int MIN_SUPPORTED_NETWORK_VERSION = 0; + public static final int MIN_SUPPORTED_NETWORK_PROTOCOL = NetworkVersion.NEW_NETWORKING.protocolVersion(); public static void serializeF(FriendlyByteBuf buffer, Vector3fc vec3) { buffer.writeFloat(vec3.x()); diff --git a/common/src/main/java/org/vivecraft/common/network/NetworkVersion.java b/common/src/main/java/org/vivecraft/common/network/NetworkVersion.java new file mode 100644 index 000000000..224f775bc --- /dev/null +++ b/common/src/main/java/org/vivecraft/common/network/NetworkVersion.java @@ -0,0 +1,49 @@ +package org.vivecraft.common.network; + +public enum NetworkVersion { + // clients that used the old installer + LEGACY, + // allows the client to send the data in a single packet and switch back to NONVR + NEW_NETWORKING, + // adds full body tracker data + FBT, + // adds dual wielding packet and server logic + DUAL_WIELDING, + // adds the head as a valid active BodyPart, and adds a useForAim flag + HEAD_AIM, + // allows sending haptic events to the client + HAPTIC_PACKET, + // adds a packet, to inform the client what vr changes are on non default values + SERVER_VR_CHANGES, + // adds packets to send/receive damage directions + DAMAGE_DIRECTION, + // adds possibility to toggle settings after initial connection + OPTION_TOGGLE; + + public static NetworkVersion fromProtocolVersion(int protocolVersion) { + return values()[protocolVersion + 1]; + } + + /** + * @return The protocol version that is sent between server/client. This is different to the ordinal, + * because legacy is -1 + */ + public int protocolVersion() { + return this.ordinal() - 1; + } + + /** + * checks if {@code other} supports the features of {@code this} NetworkVersion + * + * @param other other NetworkVersion to test + * @return if the other Network version supports the features of this version + */ + public boolean accepts(NetworkVersion other) { + return this.ordinal() <= other.ordinal(); + } + + @Override + public String toString() { + return this.name() + ": " + this.protocolVersion(); + } +} diff --git a/common/src/main/java/org/vivecraft/common/network/VrPlayerState.java b/common/src/main/java/org/vivecraft/common/network/VrPlayerState.java index dd1a947a2..ab7c673a4 100644 --- a/common/src/main/java/org/vivecraft/common/network/VrPlayerState.java +++ b/common/src/main/java/org/vivecraft/common/network/VrPlayerState.java @@ -49,7 +49,7 @@ public record VrPlayerState(boolean seated, Pose hmd, boolean leftHanded, Pose m * @param other VrPlayerState to strip down * @param version version to strip the packet down to */ - public VrPlayerState(VrPlayerState other, int version) { + public VrPlayerState(VrPlayerState other, NetworkVersion version) { this( other.seated, other.hmd, @@ -57,20 +57,20 @@ public VrPlayerState(VrPlayerState other, int version) { other.mainHand, other.reverseHands1legacy, other.offHand, - version < CommonNetworkHelper.NETWORK_VERSION_FBT ? FBTMode.ARMS_ONLY : other.fbtMode, - version < CommonNetworkHelper.NETWORK_VERSION_FBT ? null : other.waist, - version < CommonNetworkHelper.NETWORK_VERSION_FBT ? null : other.rightFoot, - version < CommonNetworkHelper.NETWORK_VERSION_FBT ? null : other.leftFoot, - version < CommonNetworkHelper.NETWORK_VERSION_FBT ? null : other.rightKnee, - version < CommonNetworkHelper.NETWORK_VERSION_FBT ? null : other.leftKnee, - version < CommonNetworkHelper.NETWORK_VERSION_FBT ? null : other.rightElbow, - version < CommonNetworkHelper.NETWORK_VERSION_FBT ? null : other.leftElbow + NetworkVersion.FBT.accepts(version) ? other.fbtMode : FBTMode.ARMS_ONLY, + NetworkVersion.FBT.accepts(version) ? other.waist : null, + NetworkVersion.FBT.accepts(version) ? other.rightFoot : null, + NetworkVersion.FBT.accepts(version) ? other.leftFoot : null, + NetworkVersion.FBT.accepts(version) ? other.rightKnee : null, + NetworkVersion.FBT.accepts(version) ? other.leftKnee : null, + NetworkVersion.FBT.accepts(version) ? other.rightElbow : null, + NetworkVersion.FBT.accepts(version) ? other.leftElbow : null ); } public static VrPlayerState create(VRPlayer vrPlayer) { FBTMode fbtMode = vrPlayer.vrdata_world_post.fbtMode; - if (ClientNetworking.USED_NETWORK_VERSION < CommonNetworkHelper.NETWORK_VERSION_FBT) { + if (!NetworkVersion.FBT.accepts(ClientNetworking.USED_NETWORK_VERSION)) { // don't send fbt data to legacy servers fbtMode = FBTMode.ARMS_ONLY; } diff --git a/common/src/main/java/org/vivecraft/common/network/packet/c2s/ActiveBodyPartPayloadC2S.java b/common/src/main/java/org/vivecraft/common/network/packet/c2s/ActiveBodyPartPayloadC2S.java index de5447cdd..38512d3ee 100644 --- a/common/src/main/java/org/vivecraft/common/network/packet/c2s/ActiveBodyPartPayloadC2S.java +++ b/common/src/main/java/org/vivecraft/common/network/packet/c2s/ActiveBodyPartPayloadC2S.java @@ -3,7 +3,7 @@ import net.minecraft.network.FriendlyByteBuf; import org.vivecraft.api.data.VRBodyPart; import org.vivecraft.client.network.ClientNetworking; -import org.vivecraft.common.network.CommonNetworkHelper; +import org.vivecraft.common.network.NetworkVersion; import org.vivecraft.common.network.packet.PayloadIdentifier; /** @@ -23,7 +23,7 @@ public PayloadIdentifier payloadId() { public void write(FriendlyByteBuf buffer) { buffer.writeByte(payloadId().ordinal()); buffer.writeByte(this.bodyPart.ordinal()); - if (ClientNetworking.USED_NETWORK_VERSION >= CommonNetworkHelper.NETWORK_VERSION_HEAD_AIM) { + if (NetworkVersion.HEAD_AIM.accepts(ClientNetworking.USED_NETWORK_VERSION)) { buffer.writeBoolean(this.useForAim); } } diff --git a/common/src/main/java/org/vivecraft/common/network/packet/c2s/VersionPayloadC2S.java b/common/src/main/java/org/vivecraft/common/network/packet/c2s/VersionPayloadC2S.java index aa6ac4b5c..56ba96ed0 100644 --- a/common/src/main/java/org/vivecraft/common/network/packet/c2s/VersionPayloadC2S.java +++ b/common/src/main/java/org/vivecraft/common/network/packet/c2s/VersionPayloadC2S.java @@ -2,7 +2,7 @@ import com.google.common.base.Charsets; import net.minecraft.network.FriendlyByteBuf; -import org.vivecraft.common.network.CommonNetworkHelper; +import org.vivecraft.common.network.NetworkVersion; import org.vivecraft.common.network.packet.PayloadIdentifier; /** @@ -46,8 +46,8 @@ public static VersionPayloadC2S read(FriendlyByteBuf buffer) { if (parts.length >= 3) { return new VersionPayloadC2S(parts[0], vr, Integer.parseInt(parts[1]), Integer.parseInt(parts[2]), false); } else { - return new VersionPayloadC2S(parts[0], vr, CommonNetworkHelper.NETWORK_VERSION_LEGACY, - CommonNetworkHelper.NETWORK_VERSION_LEGACY, true); + return new VersionPayloadC2S(parts[0], vr, NetworkVersion.LEGACY.protocolVersion(), + NetworkVersion.LEGACY.protocolVersion(), true); } } } diff --git a/common/src/main/java/org/vivecraft/common/network/packet/s2c/CrawlPayloadS2C.java b/common/src/main/java/org/vivecraft/common/network/packet/s2c/CrawlPayloadS2C.java index 67d88f1a2..bf0a2248f 100644 --- a/common/src/main/java/org/vivecraft/common/network/packet/s2c/CrawlPayloadS2C.java +++ b/common/src/main/java/org/vivecraft/common/network/packet/s2c/CrawlPayloadS2C.java @@ -1,7 +1,7 @@ package org.vivecraft.common.network.packet.s2c; import net.minecraft.network.FriendlyByteBuf; -import org.vivecraft.common.network.CommonNetworkHelper; +import org.vivecraft.common.network.NetworkVersion; import org.vivecraft.common.network.packet.PayloadIdentifier; /** @@ -10,7 +10,7 @@ * @param allowed indicates if crawling is allowed * @param targetNetworkVersion network version of the target player, to not send additional data, if they don't support it */ -public record CrawlPayloadS2C(boolean allowed, int targetNetworkVersion) implements VivecraftPayloadS2C { +public record CrawlPayloadS2C(boolean allowed, NetworkVersion targetNetworkVersion) implements VivecraftPayloadS2C { @Override public PayloadIdentifier payloadId() { @@ -21,17 +21,17 @@ public PayloadIdentifier payloadId() { public void write(FriendlyByteBuf buffer) { buffer.writeByte(payloadId().ordinal()); // old clients don't expect additional data - if (this.targetNetworkVersion >= CommonNetworkHelper.NETWORK_VERSION_OPTION_TOGGLE) { + if (NetworkVersion.OPTION_TOGGLE.accepts(this.targetNetworkVersion)) { buffer.writeBoolean(this.allowed); } } public static CrawlPayloadS2C read(FriendlyByteBuf buffer) { if (buffer.readableBytes() > 0) { - return new CrawlPayloadS2C(buffer.readBoolean(), CommonNetworkHelper.NETWORK_VERSION_OPTION_TOGGLE); + return new CrawlPayloadS2C(buffer.readBoolean(), NetworkVersion.OPTION_TOGGLE); } else { // old servers always allowed it when they sent this packet - return new CrawlPayloadS2C(true, CommonNetworkHelper.NETWORK_VERSION_LEGACY); + return new CrawlPayloadS2C(true, NetworkVersion.LEGACY); } } } diff --git a/common/src/main/java/org/vivecraft/common/network/packet/s2c/NetworkVersionPayloadS2C.java b/common/src/main/java/org/vivecraft/common/network/packet/s2c/NetworkVersionPayloadS2C.java index 552d66a13..3cde5c459 100644 --- a/common/src/main/java/org/vivecraft/common/network/packet/s2c/NetworkVersionPayloadS2C.java +++ b/common/src/main/java/org/vivecraft/common/network/packet/s2c/NetworkVersionPayloadS2C.java @@ -1,6 +1,7 @@ package org.vivecraft.common.network.packet.s2c; import net.minecraft.network.FriendlyByteBuf; +import org.vivecraft.common.network.NetworkVersion; import org.vivecraft.common.network.packet.PayloadIdentifier; /** @@ -8,7 +9,7 @@ * * @param version network protocol version the server will use */ -public record NetworkVersionPayloadS2C(int version) implements VivecraftPayloadS2C { +public record NetworkVersionPayloadS2C(NetworkVersion version) implements VivecraftPayloadS2C { @Override public PayloadIdentifier payloadId() { @@ -18,10 +19,10 @@ public PayloadIdentifier payloadId() { @Override public void write(FriendlyByteBuf buffer) { buffer.writeByte(payloadId().ordinal()); - buffer.writeByte(this.version); + buffer.writeByte(this.version.protocolVersion()); } public static NetworkVersionPayloadS2C read(FriendlyByteBuf buffer) { - return new NetworkVersionPayloadS2C(buffer.readByte() & 0xFF); + return new NetworkVersionPayloadS2C(NetworkVersion.fromProtocolVersion(buffer.readByte() & 0xFF)); } } diff --git a/common/src/main/java/org/vivecraft/common/network/packet/s2c/TeleportPayloadS2C.java b/common/src/main/java/org/vivecraft/common/network/packet/s2c/TeleportPayloadS2C.java index 00954371e..41f92b798 100644 --- a/common/src/main/java/org/vivecraft/common/network/packet/s2c/TeleportPayloadS2C.java +++ b/common/src/main/java/org/vivecraft/common/network/packet/s2c/TeleportPayloadS2C.java @@ -1,7 +1,7 @@ package org.vivecraft.common.network.packet.s2c; import net.minecraft.network.FriendlyByteBuf; -import org.vivecraft.common.network.CommonNetworkHelper; +import org.vivecraft.common.network.NetworkVersion; import org.vivecraft.common.network.packet.PayloadIdentifier; /** @@ -10,7 +10,7 @@ * @param allowed indicates if teleports are allowed * @param targetNetworkVersion network version of the target player, to not send additional data, if they don't support it */ -public record TeleportPayloadS2C(boolean allowed, int targetNetworkVersion) implements VivecraftPayloadS2C { +public record TeleportPayloadS2C(boolean allowed, NetworkVersion targetNetworkVersion) implements VivecraftPayloadS2C { @Override public PayloadIdentifier payloadId() { @@ -21,17 +21,17 @@ public PayloadIdentifier payloadId() { public void write(FriendlyByteBuf buffer) { buffer.writeByte(payloadId().ordinal()); // old clients don't expect additional data - if (this.targetNetworkVersion >= CommonNetworkHelper.NETWORK_VERSION_OPTION_TOGGLE) { + if (NetworkVersion.OPTION_TOGGLE.accepts(this.targetNetworkVersion)) { buffer.writeBoolean(this.allowed); } } public static TeleportPayloadS2C read(FriendlyByteBuf buffer) { if (buffer.readableBytes() > 0) { - return new TeleportPayloadS2C(buffer.readBoolean(), CommonNetworkHelper.NETWORK_VERSION_OPTION_TOGGLE); + return new TeleportPayloadS2C(buffer.readBoolean(), NetworkVersion.OPTION_TOGGLE); } else { // old servers always allowed it when they sent this packet - return new TeleportPayloadS2C(true, CommonNetworkHelper.NETWORK_VERSION_LEGACY); + return new TeleportPayloadS2C(true, NetworkVersion.LEGACY); } } } diff --git a/common/src/main/java/org/vivecraft/mixin/world/entity/InventoryMixin.java b/common/src/main/java/org/vivecraft/mixin/world/entity/InventoryMixin.java index 8d6593aa8..e505a4094 100644 --- a/common/src/main/java/org/vivecraft/mixin/world/entity/InventoryMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/world/entity/InventoryMixin.java @@ -17,7 +17,7 @@ import org.vivecraft.api.data.VRBodyPart; import org.vivecraft.client.network.ClientNetworking; import org.vivecraft.client_vr.VRState; -import org.vivecraft.common.network.CommonNetworkHelper; +import org.vivecraft.common.network.NetworkVersion; import org.vivecraft.server.ServerVRPlayers; import org.vivecraft.server.ServerVivePlayer; import org.vivecraft.server.config.ServerConfig; @@ -43,7 +43,7 @@ public class InventoryMixin { if (ServerVRPlayers.isVRPlayer(serverPlayer)) { ServerVivePlayer vivePlayer = ServerVRPlayers.getVivePlayer(serverPlayer); // older clients don't reset the active hand - if (vivePlayer.networkVersion >= CommonNetworkHelper.NETWORK_VERSION_DUAL_WIELDING && + if (NetworkVersion.DUAL_WIELDING.accepts(vivePlayer.networkVersion) && vivePlayer.activeBodyPart == VRBodyPart.OFF_HAND) { cir.setReturnValue(this.equipment.set(EquipmentSlot.OFFHAND, stack)); @@ -60,7 +60,7 @@ public class InventoryMixin { if (ServerVRPlayers.isVRPlayer(serverPlayer)) { ServerVivePlayer vivePlayer = ServerVRPlayers.getVivePlayer(serverPlayer); // older clients don't reset the active hand - if (vivePlayer.networkVersion >= CommonNetworkHelper.NETWORK_VERSION_DUAL_WIELDING) { + if (NetworkVersion.DUAL_WIELDING.accepts(vivePlayer.networkVersion)) { bodyPart = vivePlayer.activeBodyPart; } } diff --git a/common/src/main/java/org/vivecraft/mixin/world/level/block/FenceGateBlockServerMixin.java b/common/src/main/java/org/vivecraft/mixin/world/level/block/FenceGateBlockServerMixin.java index 17eb52291..be86d618b 100644 --- a/common/src/main/java/org/vivecraft/mixin/world/level/block/FenceGateBlockServerMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/world/level/block/FenceGateBlockServerMixin.java @@ -11,7 +11,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.vivecraft.client.network.ClientNetworking; import org.vivecraft.client_vr.VRState; -import org.vivecraft.common.network.CommonNetworkHelper; +import org.vivecraft.common.network.NetworkVersion; import org.vivecraft.server.ServerVRPlayers; @Mixin(FenceGateBlock.class) @@ -25,7 +25,7 @@ public class FenceGateBlockServerMixin { // also do this on the client, but only if we can assume that the server also does this fix // since it would cause a wrong block state for a split second (player.isLocalPlayer() && VRState.VR_RUNNING && - ClientNetworking.USED_NETWORK_VERSION >= CommonNetworkHelper.NETWORK_VERSION_OPTION_TOGGLE + NetworkVersion.OPTION_TOGGLE.accepts(ClientNetworking.USED_NETWORK_VERSION) )) { return hitResult.getDirection().getOpposite(); diff --git a/common/src/main/java/org/vivecraft/server/ServerNetworking.java b/common/src/main/java/org/vivecraft/server/ServerNetworking.java index 19521d223..ff50b5b5d 100644 --- a/common/src/main/java/org/vivecraft/server/ServerNetworking.java +++ b/common/src/main/java/org/vivecraft/server/ServerNetworking.java @@ -25,6 +25,7 @@ import org.vivecraft.api.data.VRBodyPart; import org.vivecraft.common.CommonDataHolder; import org.vivecraft.common.network.CommonNetworkHelper; +import org.vivecraft.common.network.NetworkVersion; import org.vivecraft.common.network.VrPlayerState; import org.vivecraft.common.network.packet.PayloadIdentifier; import org.vivecraft.common.network.packet.c2s.*; @@ -86,11 +87,11 @@ public static void handlePacket( if (!payload.legacy()) { // check if client supports a supported version - if (CommonNetworkHelper.MIN_SUPPORTED_NETWORK_VERSION <= payload.maxVersion() && - payload.minVersion() <= CommonNetworkHelper.MAX_SUPPORTED_NETWORK_VERSION) + if (CommonNetworkHelper.MIN_SUPPORTED_NETWORK_PROTOCOL <= payload.maxVersion() && + payload.minVersion() <= CommonNetworkHelper.MAX_SUPPORTED_NETWORK_PROTOCOL) { - vivePlayer.networkVersion = Math.min(payload.maxVersion(), - CommonNetworkHelper.MAX_SUPPORTED_NETWORK_VERSION); + vivePlayer.networkVersion = NetworkVersion.fromProtocolVersion( + Math.min(payload.maxVersion(), CommonNetworkHelper.MAX_SUPPORTED_NETWORK_PROTOCOL)); if (ServerConfig.DEBUG.get()) { LOGGER.info("Vivecraft: {} networking supported, using version {}", player.getName().getString(), vivePlayer.networkVersion); @@ -105,14 +106,14 @@ public static void handlePacket( player.getScoreboardName(), payload.minVersion(), payload.maxVersion(), - CommonNetworkHelper.MIN_SUPPORTED_NETWORK_VERSION, - CommonNetworkHelper.MAX_SUPPORTED_NETWORK_VERSION); + CommonNetworkHelper.MIN_SUPPORTED_NETWORK_PROTOCOL, + CommonNetworkHelper.MAX_SUPPORTED_NETWORK_PROTOCOL); } return; } } else { // client didn't send a version, so it's a legacy client - vivePlayer.networkVersion = CommonNetworkHelper.NETWORK_VERSION_LEGACY; + vivePlayer.networkVersion = NetworkVersion.LEGACY; if (ServerConfig.DEBUG.get()) { LOGGER.info("Vivecraft: {} using legacy networking", player.getScoreboardName()); } @@ -132,7 +133,7 @@ public static void handlePacket( // always send in new versions to allow disabling of teleports if (ServerConfig.TELEPORT_ENABLED.get() || - vivePlayer.networkVersion >= CommonNetworkHelper.NETWORK_VERSION_OPTION_TOGGLE) + NetworkVersion.OPTION_TOGGLE.accepts(vivePlayer.networkVersion)) { packetConsumer.accept( new TeleportPayloadS2C(ServerConfig.TELEPORT_ENABLED.get(), vivePlayer.networkVersion)); @@ -161,12 +162,12 @@ public static void handlePacket( // send if hotswitching is allowed packetConsumer.accept(getVRSwitchingPayload()); - if (vivePlayer.networkVersion >= CommonNetworkHelper.NETWORK_VERSION_DUAL_WIELDING) { + if (NetworkVersion.DUAL_WIELDING.accepts(vivePlayer.networkVersion)) { packetConsumer.accept(new DualWieldingPayloadS2C(ServerConfig.DUAL_WIELDING.get())); } // send vr changes settings, to inform the client what is non default - if (vivePlayer.networkVersion >= CommonNetworkHelper.NETWORK_VERSION_SERVER_VR_CHANGES) { + if (NetworkVersion.SERVER_VR_CHANGES.accepts(vivePlayer.networkVersion)) { Map settings = new HashMap<>(); for (ConfigBuilder.ConfigValue config : ServerConfig.getConfigValues()) { if (config.getPath().startsWith("vrChanges") && !config.isDefault()) { @@ -214,7 +215,7 @@ public static void handlePacket( } vivePlayer.useBodyPartForAim = activeBodypart.useForAim(); if (vivePlayer.activeBodyPart != newBodyPart && ServerConfig.DUAL_WIELDING.get() && - vivePlayer.networkVersion >= CommonNetworkHelper.NETWORK_VERSION_DUAL_WIELDING) + NetworkVersion.DUAL_WIELDING.accepts(vivePlayer.networkVersion)) { // handle equipment changes ItemStack oldItem = player.getItemBySlot(EquipmentSlot.MAINHAND); @@ -387,7 +388,7 @@ public static void sendUpdatePacketToAll(MinecraftServer server, ConfigBuilder.C for (ServerVivePlayer vivePlayer : ServerVRPlayers.getPlayersWithVivecraft(server).values()) { VivecraftPayloadS2C payload = function.apply(vivePlayer); // old clients cannot clear server overrides, crawl or tp - if (vivePlayer.networkVersion < CommonNetworkHelper.NETWORK_VERSION_OPTION_TOGGLE && + if (!NetworkVersion.OPTION_TOGGLE.accepts(vivePlayer.networkVersion) && ((payload instanceof SettingOverridePayloadS2C override && override.clear()) || (payload instanceof CrawlPayloadS2C crawl && !crawl.allowed()) || (payload instanceof TeleportPayloadS2C tp && !tp.allowed()) @@ -442,7 +443,7 @@ public static void sendHapticToClient( { ServerVivePlayer vivePlayer = ServerVRPlayers.getVivePlayer(player); if (vivePlayer != null && vivePlayer.isVR() && - vivePlayer.networkVersion >= CommonNetworkHelper.NETWORK_VERSION_HAPTIC_PACKET) + NetworkVersion.HAPTIC_PACKET.accepts(vivePlayer.networkVersion)) { vivePlayer.player.connection.send( Xplat.getS2CPacket(new HapticPayloadS2C(bodyPart, duration, frequency, amplitude, delay))); @@ -457,13 +458,14 @@ public static void sendHapticToClient( public static void sendVrPlayerStateToClients(ServerVivePlayer vivePlayer) { // create the packets here, to try to avoid unnecessary memory copies when creating multiple packets Packet legacyPacket = Xplat.getS2CPacket( - new UberPacketPayloadS2C(vivePlayer.player.getUUID(), new VrPlayerState(vivePlayer.vrPlayerState(), 0), + new UberPacketPayloadS2C(vivePlayer.player.getUUID(), new VrPlayerState(vivePlayer.vrPlayerState(), NetworkVersion.LEGACY), vivePlayer.worldScale, vivePlayer.heightScale)); Packet newPacket = Xplat.getS2CPacket( new UberPacketPayloadS2C(vivePlayer.player.getUUID(), vivePlayer.vrPlayerState(), vivePlayer.worldScale, vivePlayer.heightScale)); - sendPacketToTrackingPlayers(vivePlayer, (version) -> version < 1 ? legacyPacket : newPacket); + sendPacketToTrackingPlayers(vivePlayer, + (version) -> version == NetworkVersion.LEGACY ? legacyPacket : newPacket); } /** @@ -497,7 +499,7 @@ private static void sendPacketToTrackingPlayers(ServerVivePlayer vivePlayer, Viv * @param packetProvider provider for network packets, based on client network version */ private static void sendPacketToTrackingPlayers( - ServerVivePlayer vivePlayer, Function> packetProvider) + ServerVivePlayer vivePlayer, Function> packetProvider) { Map vivePlayers = ServerVRPlayers.getPlayersWithVivecraft( vivePlayer.player.level().getServer()); diff --git a/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java b/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java index 9d0250ca8..dfe3be5e5 100644 --- a/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java +++ b/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java @@ -10,6 +10,7 @@ import org.vivecraft.api.data.VRPose; import org.vivecraft.common.api_impl.VRAPIImpl; import org.vivecraft.common.network.CommonNetworkHelper; +import org.vivecraft.common.network.NetworkVersion; import org.vivecraft.common.network.VrPlayerState; import org.vivecraft.common.utils.MathUtils; @@ -38,7 +39,8 @@ public class ServerVivePlayer { // player this data belongs to public ServerPlayer player; // network protocol this player is communicating with - public int networkVersion = CommonNetworkHelper.MAX_SUPPORTED_NETWORK_VERSION; + public NetworkVersion networkVersion = NetworkVersion.fromProtocolVersion( + CommonNetworkHelper.MAX_SUPPORTED_NETWORK_PROTOCOL); // if the client requested damage direction data public boolean wantsDamageDirection = false; From 24f98d4c59cc0f0b9f1bf40fb4becc01c718b0b2 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 13 Oct 2025 23:56:29 +0200 Subject: [PATCH 35/76] add option to disable mirror off text, and make it translateable --- .../gui/settings/GuiRenderOpticsSettings.java | 4 ++++ .../client_vr/render/helpers/ShaderHelper.java | 13 +++++++++---- .../vivecraft/client_vr/settings/VRSettings.java | 3 +++ .../vivecraft/mixin/client_vr/MinecraftVRMixin.java | 5 +++++ .../main/resources/assets/vivecraft/lang/de_de.json | 7 +++++-- .../main/resources/assets/vivecraft/lang/en_us.json | 3 +++ 6 files changed, 29 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiRenderOpticsSettings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiRenderOpticsSettings.java index 8aaf4d1a4..7dee59c0c 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiRenderOpticsSettings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiRenderOpticsSettings.java @@ -38,6 +38,9 @@ public class GuiRenderOpticsSettings extends GuiVROptionsBase { private static final VRSettings.VrOptions[] SINGLE_OPTIONS = new VRSettings.VrOptions[]{ VRSettings.VrOptions.MIRROR_EYE }; + private static final VRSettings.VrOptions[] OFF_OPTIONS = new VRSettings.VrOptions[]{ + VRSettings.VrOptions.MIRROR_OFF_TEXT + }; private final VROptionEntry[] MROptions = new VROptionEntry[]{new VROptionEntry( "vivecraft.options.screen.mixedreality.button", (button, mousePos) -> { Minecraft.getInstance().setScreen(new GuiMixedRealitySettings(this)); @@ -91,6 +94,7 @@ public void init() { case THIRD_PERSON -> super.init(THIRD_OPTIONS, false); case CROPPED -> super.init(CROP_OPTIONS, false); case SINGLE -> super.init(SINGLE_OPTIONS, false); + case OFF -> super.init(OFF_OPTIONS, false); } super.addDefaultButtons(); diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java index 33ab244ad..d7cc00f11 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java @@ -8,6 +8,7 @@ import com.mojang.blaze3d.vertex.*; import net.minecraft.Util; import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.language.I18n; import net.minecraft.core.component.DataComponents; import net.minecraft.util.Mth; import net.minecraft.world.entity.EquipmentSlot; @@ -252,11 +253,15 @@ public static void doVrPostProcess(RenderPass eye, RenderTarget source, RenderTa * draws the desktop mirror to the bound buffer */ public static void drawMirror() { - if (DATA_HOLDER.vrSettings.displayMirrorMode == VRSettings.MirrorMode.OFF && - DATA_HOLDER.vr.isHMDTracking()) - { + if (DATA_HOLDER.vrSettings.displayMirrorMode == VRSettings.MirrorMode.OFF && DATA_HOLDER.vr.isHMDTracking()) { // no mirror, only show when headset is not tracking, to be able to see the menu with the headset off - MirrorNotification.notify("Mirror is OFF", true, 1000); + if (DATA_HOLDER.vrSettings.showMirrorOffText) { + MirrorNotification.notify(I18n.get("vivecraft.messages.mirroroff"), true, 1000); + } else { + // just clear it + RenderSystem.getDevice().createCommandEncoder() + .clearColorTexture(MC.mainRenderTarget.getColorTexture(), 0xFF000000); + } } else if (DATA_HOLDER.vrSettings.displayMirrorMode == VRSettings.MirrorMode.MIXED_REALITY) { ShaderHelper.doMixedRealityMirror(); } else if (DATA_HOLDER.vrSettings.displayMirrorMode == VRSettings.MirrorMode.DUAL && 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 1dd22257b..58a4dba94 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 @@ -428,6 +428,8 @@ public enum AimDevice implements OptionEnum { public float displayMirrorCenterSmooth = 0.0F; @SettingField(VrOptions.MIRROR_SCREENSHOT_CAMERA) public boolean displayMirrorUseScreenshotCamera = false; + @SettingField(VrOptions.MIRROR_OFF_TEXT) + public boolean showMirrorOffText = true; @SettingField(VrOptions.SHOW_PLAYER_MODEL) public boolean shouldRenderSelf = false; @SettingField(VrOptions.MAIN_PLAYER_DATA) @@ -1709,6 +1711,7 @@ String getDisplayString(String prefix, Object value) { } } }, + MIRROR_OFF_TEXT(false, true), // if text should be shown when the mirror is off MIRROR_SCREENSHOT_CAMERA(false, true), MIXED_REALITY_KEY_COLOR(false, false) { // Key Color private static final List> COLORS; 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 bc69989ba..412a061ca 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 @@ -23,6 +23,7 @@ import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.client.resources.language.I18n; import net.minecraft.client.server.IntegratedServer; import net.minecraft.client.sounds.SoundManager; import net.minecraft.core.BlockPos; @@ -818,6 +819,10 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { this.mouseHandler.onMove(this.window.handle(), this.mouseHandler.xpos(), this.mouseHandler.ypos()); } + if (ClientDataHolderVR.getInstance().vrSettings.displayMirrorMode == VRSettings.MirrorMode.OFF) { + // make sure this is shown at lest once when the text is disabled + MirrorNotification.notify(I18n.get("vivecraft.messages.mirroroff"), true, 1000); + } } else { // VR got disabled RenderPassManager.setVanillaRenderPass(); 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 a31fae3b4..5bdd466c7 100644 --- a/common/src/main/resources/assets/vivecraft/lang/de_de.json +++ b/common/src/main/resources/assets/vivecraft/lang/de_de.json @@ -319,7 +319,7 @@ "vivecraft.options.weaponcollision.auto": "Automatisch", "vivecraft.options.default": "Standard", "vivecraft.options.opaque": "Undurchsichtig", - "vivecraft.options.mirrormode.off": "OFF (Schnell)", + "vivecraft.options.mirrormode.off": "AUS (Schnell)", "vivecraft.options.mirrormode.dual": "Doppel (Schnell)", "vivecraft.options.mirrormode.single": "Einzeln (Schnell)", "vivecraft.options.mirrormode.firstperson": "1. Person (Langsam)", @@ -534,6 +534,7 @@ "vivecraft.options.MENU_WORLD_FALLBACK": "Ersatz Methode", "vivecraft.options.MIRROR_CROP": "Spiegel Zuschnitt", "vivecraft.options.MIRROR_SCREENSHOT_CAMERA": "Kamera als Desktop Spiegel", + "vivecraft.options.MIRROR_OFF_TEXT": "Zeige Spiegel AUS Text", "vivecraft.options.RENDER_DEBUG_HEAD_HITBOX": "Kopf Kollisionsboxen", "vivecraft.options.RENDER_DEBUG_DEVICE_AXES": "Lokale Geräte Achsen", "vivecraft.options.RENDER_DEBUG_PLAYER_AXES": "Remote Geräte Achsen", @@ -591,6 +592,7 @@ "vivecraft.options.MENU_WORLD_FALLBACK.tooltip": "Wenn Menü Welten deaktiviert sind oder noch nicht geladen sind, wird dieser Ersatz stattdessen verwendet", "vivecraft.options.MIRROR_CROP.tooltip": "Gibt an, um wie viel das VR Bild zugeschnitten wird. Der Standardwert von 15%% versteckt die Augenschablone ganz gut. Wenn Sie ohne Augenschablone spielen, können Sie den Wert reduzieren, um ein größeres Sichtfeld im Desktop Spiegel zu bekommen.", "vivecraft.options.MIRROR_SCREENSHOT_CAMERA.tooltip": "Zeigt das Bild der Screenshot-Kamera im Desktop Spiegel. Wenn die Kamera inaktiv ist, wird stattdessen der ausgewählte Spiegelmodus angezeigt.\nIm Mixed Reality modus wird nur das Bild des 1. Person Teil im Unity-Layout ersetzt.", + "vivecraft.options.MIRROR_OFF_TEXT.tooltip": "Zeigt ein Text an, wenn der Desktop Spiegel deaktiviert ist.", "vivecraft.options.RENDER_DEBUG_HEAD_HITBOX.tooltip": "Zeigt Kopf Kollisionsboxen für alle Kreaturen, wenn die Debug Kollisionsboxen angezeigt werden.", "vivecraft.options.RENDER_DEBUG_DEVICE_AXES.tooltip": "Zeigt Debug Achsen für die VR Geräte des lokalen Spielers.", "vivecraft.options.RENDER_DEBUG_PLAYER_AXES.tooltip": "Zeigt Debug Achsen für die VR Geräte aller Spieler die vom Server empfangen wurden.", @@ -601,7 +603,7 @@ "vivecraft.options.PLAYER_MODEL_BODY_SCALE.tooltip": "Skaliert die dicke des Oberkörpers des Spielermodells, in der 1. Person ansicht.", "vivecraft.options.PLAYER_MODEL_LEGS_SCALE.tooltip": "Skaliert die dicke der Spielermodellbeine, in der 1. Person ansicht.", "vivecraft.options.PLAYER_MODEL_TYPE.tooltip": "Der Modell Typ für alle VR Spieler:\n Vanilla: Fügt keine körperteile hinzu und animiert einfach das Vanilla Spieler Modell.\n Geteilte Arme: Teilt die Arme in zwei Teile, so dass sie sich biegen/separieren können.\n Geteilte Arme/Beine: Gleich wie 'Geteilte Arme', nur auch für die Beine.", - "vivecraft.options.PLAYER_LIMBS_CONNECTED.tooltip": "Wenn dies aktiv ist, werden die geteilten Arme/Beine verbunden, um einen Ellbogen/Knie zu simulieren.", + "vivecraft.options.PLAYER_LIMBS_CONNECTED.tooltip": "Wenn dies aktiv ist, werden die geteilten Arme/Beine verbunden, um einen Ellbogen/Knie zu simulieren.", "vivecraft.options.PLAYER_LIMBS_LIMIT.tooltip": "Wenn dies aktiv ist, ist die Arm/Bein länge limitiert und sie bleiben verbunden.\nWenn dies deaktiviert ist, können sich Arme/Beine trennen, wenn die benötigte Länge länger als die Modelllänge ist.", "vivecraft.options.PLAYER_WALK_ANIM.tooltip": "Ob die Vanilla geh Animation über die Fußtracker gelegt werden soll.", "vivecraft.options.PLAYER_ARM_ANIM.tooltip": "Schwingt den Spieler Arm beim Angreifen, Gegenstand benutzen oder Interagieren.", @@ -661,6 +663,7 @@ "vivecraft.messages.nondefaultvrchanges.title": "Geänderte Gameplayeinstellungen", "vivecraft.messages.connectingtoruntime": "Verbinde mit der VR Laufzeit", "vivecraft.messages.noteleport": "Dieser Server hat das Teleportieren explizit deaktiviert. Der eingeschränkte Bewegungsmodus (Fallback auf freie Bewegung) wurde aktiviert.", + "vivecraft.messages.mirroroff": "Spiegle ist AUS", "vivecraft.messages.tracker.waist": "Taille", "vivecraft.messages.tracker.rightFoot": "Rechter Fuß", 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 9672dec76..f82ff35c3 100644 --- a/common/src/main/resources/assets/vivecraft/lang/en_us.json +++ b/common/src/main/resources/assets/vivecraft/lang/en_us.json @@ -536,6 +536,7 @@ "vivecraft.options.MENU_WORLD_FALLBACK": "Fallback Method", "vivecraft.options.MIRROR_CROP": "Mirror Cropping", "vivecraft.options.MIRROR_SCREENSHOT_CAMERA": "Camera as Desktop Mirror", + "vivecraft.options.MIRROR_OFF_TEXT": "Show Mirror OFF Text", "vivecraft.options.RENDER_DEBUG_HEAD_HITBOX": "Head Hitboxes", "vivecraft.options.RENDER_DEBUG_DEVICE_AXES": "Local Device Axes", "vivecraft.options.RENDER_DEBUG_PLAYER_AXES": "Remote Device Axes", @@ -593,6 +594,7 @@ "vivecraft.options.MENU_WORLD_FALLBACK.tooltip": "If Menuworlds are disabled or not loaded yet, this fallback will be shown instead.", "vivecraft.options.MIRROR_CROP.tooltip": "Specifies how much of the VR image gets cropped. The default 15%% hides the stencil pretty good. If you play without stencil, you can reduce this, to get a bigger FOV for the mirror.", "vivecraft.options.MIRROR_SCREENSHOT_CAMERA.tooltip": "If enabled, the screenshot camera will be displayed as the desktop mirror. When the camera is inactive, the currently selected mirror mode is used instead.\nIn mixed reality mode, only applies to the first person viewport in the Unity layout.", + "vivecraft.options.MIRROR_OFF_TEXT.tooltip": "If enabled, shows a text stating that the desktop mirror is disabled.", "vivecraft.options.RENDER_DEBUG_HEAD_HITBOX.tooltip": "If enabled, a head hitbox will be rendered for all entities when debug hitboxes are shown", "vivecraft.options.RENDER_DEBUG_DEVICE_AXES.tooltip": "If enabled, debug axes will be shown for the local players VR devices.", "vivecraft.options.RENDER_DEBUG_PLAYER_AXES.tooltip": "If enabled, debug axes will be shown for all VR players received from the server.", @@ -663,6 +665,7 @@ "vivecraft.messages.nondefaultvrchanges.title": "Non-Default Gameplay Settings", "vivecraft.messages.connectingtoruntime": "Connecting to the VR Runtime", "vivecraft.messages.noteleport": "This server has teleporting explicitly disabled. Restricted movement mode (fallback to free move) has been enabled.", + "vivecraft.messages.mirroroff": "Mirror is OFF", "vivecraft.messages.tracker.waist": "Waist", "vivecraft.messages.tracker.rightFoot": "Right Foot", From 44a9106dfd62f0f4f1d176552a4fe2514c78a127 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Tue, 14 Oct 2025 00:00:10 +0200 Subject: [PATCH 36/76] fix garbagecollector screens stacking when toggling vr on that screen --- common/src/main/java/org/vivecraft/client_vr/VRState.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 dd14306c6..bc5d6cb82 100644 --- a/common/src/main/java/org/vivecraft/client_vr/VRState.java +++ b/common/src/main/java/org/vivecraft/client_vr/VRState.java @@ -123,7 +123,9 @@ public static void initializeVR() { if (os.getTotalMemorySize() >= 1073741824L * 12L - 1048576L * 256L && Runtime.getRuntime().availableProcessors() >= 6) { - setScreenAndCache(new GarbageCollectorScreen(garbageCollector)); + if (!(Minecraft.getInstance().screen instanceof GarbageCollectorScreen)) { + setScreenAndCache(new GarbageCollectorScreen(garbageCollector)); + } } } } catch (Throwable e) { From d637722cae8b8a83a471dbaab25af9add0659a6e Mon Sep 17 00:00:00 2001 From: fayer3 Date: Fri, 17 Oct 2025 17:37:16 +0200 Subject: [PATCH 37/76] fix hand rendering with shaders --- .../org/vivecraft/client_vr/render/helpers/VRArmHelper.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/VRArmHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/VRArmHelper.java index 2c19a9654..fa5eb320f 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/VRArmHelper.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/VRArmHelper.java @@ -86,6 +86,8 @@ public static void renderVRHands( if (!menuHandMain || !menuHandOff) { // render the hands MC.gameRenderer.getFeatureRenderDispatcher().renderAllFeatures(); + // need to end the batches to have the hands/items actually render + MC.renderBuffers().bufferSource().endBatch(); } VREffectsHelper.reAddNausea(); From 1e1f671fc9b4cf5151f096354e71dd95aba83b1e Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sat, 18 Oct 2025 15:14:05 +0200 Subject: [PATCH 38/76] add waist freemove direction --- .../client_vr/gameplay/VRPlayer.java | 26 ++++++++++--------- .../gameplay/trackers/RunTracker.java | 4 ++- .../gameplay/trackers/SwingTracker.java | 4 ++- .../gameplay/trackers/VehicleTracker.java | 18 ++++++++----- .../client_vr/settings/VRSettings.java | 21 ++++++++++++++- .../client_vr/player/LocalPlayerVRMixin.java | 11 ++++---- .../client_vr/world/AbstractBoatMixin.java | 11 +++++--- .../assets/vivecraft/lang/de_de.json | 5 ++-- .../assets/vivecraft/lang/en_us.json | 5 ++-- 9 files changed, 70 insertions(+), 35 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java index 835ab86e3..a31f02f35 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java @@ -689,19 +689,21 @@ public void doPermanentLookOverride(LocalPlayer player, VRData data) { { // Server-side movement // when swimming/flying adjust player look according to the user setting - VRSettings.FreeMove freeMoveType = - player.isFallFlying() && this.dh.vrSettings.vrFreeMoveFlyMode != VRSettings.FreeMove.AUTO ? - this.dh.vrSettings.vrFreeMoveFlyMode : this.dh.vrSettings.vrFreeMoveMode; - - if (freeMoveType == VRSettings.FreeMove.CONTROLLER) { - player.setYRot(data.getController(1).getYaw()); - player.setYHeadRot(player.getYRot()); - player.setXRot(-data.getController(1).getPitch()); - } else { - player.setYRot(data.hmd.getYaw()); - player.setYHeadRot(player.getYRot()); - player.setXRot(-data.hmd.getPitch()); + switch (this.dh.vrSettings.getVrFreeMoveMode(player.isFallFlying(), data.fbtMode)) { + case CONTROLLER -> { + player.setYRot(data.getController(1).getYaw()); + player.setXRot(-data.getController(1).getPitch()); + } + case WAIST -> { + player.setYRot(data.waist.getYaw()); + player.setXRot(-data.hmd.getPitch()); // use head for up/down + } + default -> { + player.setYRot(data.hmd.getYaw()); + player.setXRot(-data.hmd.getPitch()); + } } + player.setYHeadRot(player.getYRot()); } else if (((GameRendererExtension) this.mc.gameRenderer).vivecraft$getCrossVec() != null) { // Look AT the crosshair by default, most compatible with mods. Vec3 playerToCrosshair = player.getEyePosition(1) diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/RunTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/RunTracker.java index 71fd57323..9f883c2b9 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/RunTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/RunTracker.java @@ -23,7 +23,9 @@ public RunTracker(Minecraft mc, ClientDataHolderVR dh) { public boolean isActive(LocalPlayer player) { if (!this.dh.vrPlayer.getFreeMove() || this.dh.vrSettings.seated) { return false; - } else if (this.dh.vrSettings.vrFreeMoveMode != VRSettings.FreeMove.RUN_IN_PLACE) { + } else if (this.dh.vrSettings.getVrFreeMoveMode(false, this.dh.vrPlayer.vrdata_world_pre.fbtMode) != + VRSettings.FreeMove.RUN_IN_PLACE) + { return false; } else if (player == null || !player.isAlive()) { return false; diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java index 70a781228..071d0ef3b 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java @@ -104,7 +104,9 @@ public boolean isActive(LocalPlayer player) { return false; } else if (this.dh.vrSettings.seated) { return false; - } else if (this.dh.vrSettings.vrFreeMoveMode == VRSettings.FreeMove.RUN_IN_PLACE && player.zza > 0.0F) { + } else if (this.dh.vrSettings.getVrFreeMoveMode(false, this.dh.vrPlayer.vrdata_world_pre.fbtMode) == + VRSettings.FreeMove.RUN_IN_PLACE && player.zza > 0.0F) + { return false; // don't hit things while RIPing. } else if (player.isBlocking() && !ClientNetworking.SERVER_ALLOWS_ATTACKING_WHILE_BLOCKING) { return false; // don't hit things while blocking. diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/VehicleTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/VehicleTracker.java index 5b1608580..d0ab24397 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/VehicleTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/VehicleTracker.java @@ -14,7 +14,6 @@ import org.vivecraft.api.client.Tracker; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRData; -import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.common.utils.MathUtils; import org.vivecraft.data.ViveItemTags; @@ -94,12 +93,17 @@ public static Vector3f getSteeringDirection(LocalPlayer player) { } private static Vector3f getFreeMoveDirection() { - if (ClientDataHolderVR.getInstance().vrSettings.vrFreeMoveMode == VRSettings.FreeMove.HMD) { - return ClientDataHolderVR.getInstance().vrPlayer.vrdata_world_pre.hmd.getDirection(); - } else { - // not exactly sure why we use the main hand for riding, when we use the offhand for regular walking - return ClientDataHolderVR.getInstance().vrPlayer.vrdata_world_pre.getController(0).getDirection(); - } + return switch (ClientDataHolderVR.getInstance().vrSettings.getVrFreeMoveMode(false, + ClientDataHolderVR.getInstance().vrPlayer.vrdata_world_pre.fbtMode)) { + case HMD -> ClientDataHolderVR.getInstance().vrPlayer.vrdata_world_pre.hmd.getDirection(); + case WAIST -> new Vector3f(0.0F, 0.0F, 1.0F) + // use head for up/down + .rotateX(-ClientDataHolderVR.getInstance().vrPlayer.vrdata_world_pre.hmd.getPitchRad()) + .rotateY(-ClientDataHolderVR.getInstance().vrPlayer.vrdata_world_pre.waist.getYawRad()); + default -> + // not exactly sure why we use the main hand for riding, when we use the offhand for regular walking + ClientDataHolderVR.getInstance().vrPlayer.vrdata_world_pre.getController(0).getDirection(); + }; } private static int getControllerWithFoodStick(LocalPlayer player) { 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 58a4dba94..a5875fcd6 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 @@ -23,6 +23,7 @@ import org.slf4j.LoggerFactory; import org.vivecraft.Xloader; import org.vivecraft.api.client.Tracker; +import org.vivecraft.api.data.FBTMode; import org.vivecraft.client.render.VRPlayerRenderer; import org.vivecraft.client.render.armor.VRArmorLayer; import org.vivecraft.client.utils.ClientUtils; @@ -118,6 +119,7 @@ public enum FreeMove implements OptionEnum { HMD, RUN_IN_PLACE, ROOM, + WAIST, AUTO // only for flying } @@ -1403,6 +1405,21 @@ public void setOptionFloatValue(VrOptions vrOption, float newValue) { } } + /** + * selects the right FreeMove mode (flying/regular), and adds a fallback for WAIST if no fbt is available + * + * @param flySwimming if the player is swimming/fall flying + * @param fbtMode active FBT mode + * @return the active FreeMove mode + */ + public FreeMove getVrFreeMoveMode(boolean flySwimming, FBTMode fbtMode) { + FreeMove freeMoveMode = + flySwimming && this.vrFreeMoveFlyMode != FreeMove.AUTO ? this.vrFreeMoveFlyMode : this.vrFreeMoveMode; + + // can't use waist if no fbt + return freeMoveMode == FreeMove.WAIST && fbtMode == FBTMode.ARMS_ONLY ? FreeMove.HMD : freeMoveMode; + } + record ConfigEntry(Field field, VrOptions vrOption, String configName, boolean separate, boolean fixedSize) {} public enum VrOptions { @@ -2114,7 +2131,7 @@ Object convertOption(String value) { @Override Object setOptionValue(Object value) { - if (value == FreeMove.ROOM) { + if (value == FreeMove.WAIST) { // skip Auto return FreeMove.CONTROLLER; } @@ -2126,6 +2143,8 @@ Object setOptionValue(Object value) { Object setOptionValue(Object value) { if (value == FreeMove.CONTROLLER) { return FreeMove.HMD; + } else if (value == FreeMove.HMD) { + return FreeMove.WAIST; } else if (value == FreeMove.AUTO) { return FreeMove.CONTROLLER; } else { diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/player/LocalPlayerVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/player/LocalPlayerVRMixin.java index 74cece9ec..9a5a17fee 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/player/LocalPlayerVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/player/LocalPlayerVRMixin.java @@ -29,6 +29,7 @@ import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.vivecraft.api.data.FBTMode; import org.vivecraft.client.network.ClientNetworking; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; @@ -388,15 +389,14 @@ public abstract class LocalPlayerVRMixin extends LocalPlayer_PlayerVRMixin imple direction = direction.yRot(-vrplayer.vrdata_world_pre.getController(c).getYawRad()); } else { - VRSettings.FreeMove freeMoveType = !this.isPassenger() && this.getAbilities().flying && - this.vivecraft$dataholder.vrSettings.vrFreeMoveFlyMode != VRSettings.FreeMove.AUTO ? - this.vivecraft$dataholder.vrSettings.vrFreeMoveFlyMode : - this.vivecraft$dataholder.vrSettings.vrFreeMoveMode; + VRSettings.FreeMove freeMoveType = this.vivecraft$dataholder.vrSettings.getVrFreeMoveMode( + !this.isPassenger() && this.getAbilities().flying, vrplayer.vrdata_world_pre.fbtMode); if (isFlyingOrSwimming) { direction = switch (freeMoveType) { case CONTROLLER -> direction.xRot(vrplayer.vrdata_world_pre.getController(1).getPitchRad()); - case HMD, RUN_IN_PLACE, ROOM -> direction.xRot(vrplayer.vrdata_world_pre.hmd.getPitchRad()); + case HMD, RUN_IN_PLACE, ROOM, WAIST -> + direction.xRot(vrplayer.vrdata_world_pre.hmd.getPitchRad()); default -> direction; }; } @@ -410,6 +410,7 @@ public abstract class LocalPlayerVRMixin extends LocalPlayer_PlayerVRMixin imple .scale(this.vivecraft$dataholder.runTracker.getSpeed()); case ROOM -> direction.yRot( (180.0F + this.vivecraft$dataholder.vrSettings.worldRotation) * Mth.DEG_TO_RAD); + case WAIST -> direction.yRot(-vrplayer.vrdata_world_pre.waist.getYawRad()); default -> direction; }; } diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/world/AbstractBoatMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/world/AbstractBoatMixin.java index fccaf73c1..8e2f4e855 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/world/AbstractBoatMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/world/AbstractBoatMixin.java @@ -12,7 +12,6 @@ import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; -import org.vivecraft.client_vr.settings.VRSettings; @Mixin(AbstractBoat.class) public abstract class AbstractBoatMixin extends Entity { @@ -48,9 +47,13 @@ public AbstractBoatMixin(EntityType entityType, Level level) { // only custom boat controls in standing mode if (this.inputUp) { // controller-based - float yaw = dataHolder.vrSettings.vrFreeMoveMode == VRSettings.FreeMove.HMD ? - dataHolder.vrPlayer.vrdata_world_pre.hmd.getYaw() : - dataHolder.vrPlayer.vrdata_world_pre.getController(1).getYaw(); + float yaw = switch (dataHolder.vrSettings.getVrFreeMoveMode(false, + dataHolder.vrPlayer.vrdata_world_pre.fbtMode)) { + case HMD -> dataHolder.vrPlayer.vrdata_world_pre.hmd.getYaw(); + case WAIST -> dataHolder.vrPlayer.vrdata_world_pre.waist.getYaw(); + default -> dataHolder.vrPlayer.vrdata_world_pre.getController(1).getYaw(); + }; + if (dataHolder.vrSettings.vehicleRotation) { // tank controls float end = this.getYRot() % 360F; 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 5bdd466c7..23927f196 100644 --- a/common/src/main/resources/assets/vivecraft/lang/de_de.json +++ b/common/src/main/resources/assets/vivecraft/lang/de_de.json @@ -273,7 +273,7 @@ "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.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 Seitenrichtung basiert auf dem Schwingen der Controller. Hoch/Tief basiert auf dem Headset.\n Raum: Die Seitenrichtung ist relativ zu Ihrem VR-Raum nach vorne. Hoch/Tief basiert auf dem Headset. Dieser Modus ist am besten nur für 180 Setups geeignet.\n Taille: Die Seitenrichtung basiert auf dem Taille FBT Tracker. Hoch/Tief basiert auf dem Headset. Fällt auf HMD zurück, wenn kein FBT verfügbar ist.", "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.", "vivecraft.options.RESET_ORIGIN.tooltip": "Stellen Sie die Füße des Spielers in der Welt auf 1,62 m unter die aktuelle HMD-Position zurück. Für nicht-absolute Trackingsysteme oder sitzendes Spiel.", "vivecraft.options.X_SENSITIVITY.tooltip": "Geschwindigkeit, mit der sich die Ansicht dreht, wenn sie auf den Rand des Schlüssellochs gedrückt wird.", @@ -475,6 +475,7 @@ "vivecraft.options.shaderguirender.aftertranslucent": "Transparent", "vivecraft.options.shaderguirender.beforetranslucentsolid": "Undurchsichtig", "vivecraft.options.freemove.auto": "Automatisch", + "vivecraft.options.freemove.waist": "Taille (FBT)", "vivecraft.options.chatservermessage.always": "Immer", "vivecraft.options.chatservermessage.serveronly": "Nur Server", "vivecraft.options.chatservermessage.never": "Nie", @@ -580,7 +581,7 @@ "vivecraft.options.VR_REMEMBER_ENABLED.tooltip": "Aktiviert VR beim Starten des Spiels, wenn es das letzte Mal aktiv war.", "vivecraft.options.VR_PLUGIN.tooltip": "Welches VR Plugin genutzt werden soll:\n OpenVR: Benützt SteamVR als Backend.\n NullVR: Benützt keine VR Api und lässt das Spiel im VR Modus laufen ohne Headset.", "vivecraft.options.VR_PLUGIN.disabled.tooltip": "§6Kann nicht geändert werden so lange VR eingeschalten ist.§r", - "vivecraft.options.FREEMOVE_FLY_MODE.tooltip": "Die Quelle für die Frei Bewegen-Richtung im Flugmodus.\n\n Automatisch: Verwendet die gleiche richtung wie das normale Frei Bewegen.\n Controller: Richtung des nicht dominanten Controllers.\n HMD: Blickrichtung des Headsets.", + "vivecraft.options.FREEMOVE_FLY_MODE.tooltip": "Die Quelle für die Frei Bewegen-Richtung im Flugmodus.\n\n Automatisch: Verwendet die gleiche Richtung wie das normale Frei Bewegen.\n Controller: Richtung des nicht dominanten Controllers.\n HMD: Blickrichtung des Headsets.\n Taille: Die Seitenrichtung basiert auf dem Taille FBT Tracker. Hoch/Tief basiert auf dem Headset. Fällt auf HMD zurück, wenn kein FBT verfügbar ist.", "vivecraft.options.SHOW_UPDATES.tooltip": "Wie oft eine Update Nachricht im Chat gezeigt werden soll.\n Immer: zeigt die Nachricht immer, wenn eine Welt geladen wird.\n Einmal: Zeigt die Nachricht einmal, wenn ein neues Update verfügbar ist.", "vivecraft.options.SHOW_PLUGIN.tooltip": "Wann die \"Server Mod erkannt\" Nachricht im Chat gezeigt werden soll.\n Immer: Zeigt die Nachricht in Einzel/Mehrspieler.\n Nur Server: Zeigt die Nachricht nur im Mehrspieler.\n Nie: Zeigt die Nachricht niemals.", "vivecraft.options.UPDATE_TYPE.tooltip": "Gibt an, welche Updates eine Benachrichtigung verursachen.", 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 f82ff35c3..728992ab1 100644 --- a/common/src/main/resources/assets/vivecraft/lang/en_us.json +++ b/common/src/main/resources/assets/vivecraft/lang/en_us.json @@ -272,7 +272,7 @@ "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.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.\n Waist: Yaw is based on the waist FBT tracker. Pitch is your Headset. If FBT is not available this falls back to HMD.", "vivecraft.options.VEHICLE_ROTATION.tooltip": "Riding in a vehicle will rotate the world as the vehicle rotates. May be disorienting.", "vivecraft.options.RESET_ORIGIN.tooltip": "Recenter the player's feet in the world to 1.62m below the current HMD position. For non-absolute tracking systems or seated play.", "vivecraft.options.X_SENSITIVITY.tooltip": "Speed the view will rotate when pushed on the edge of the keyhole.", @@ -474,6 +474,7 @@ "vivecraft.options.shaderguirender.aftertranslucent": "Translucent", "vivecraft.options.shaderguirender.beforetranslucentsolid": "Opaque", "vivecraft.options.freemove.auto": "Auto", + "vivecraft.options.freemove.waist": "Waist (FBT)", "vivecraft.options.chatservermessage.always": "Always", "vivecraft.options.chatservermessage.serveronly": "Server Only", "vivecraft.options.chatservermessage.never": "Never", @@ -582,7 +583,7 @@ "vivecraft.options.VR_REMEMBER_ENABLED.tooltip": "Activates VR on startup, if it was enabled the last time.", "vivecraft.options.VR_PLUGIN.tooltip": "Which VR plugin to use:\n OpenVR: uses SteamVR as a backend.\n NullVR: Uses no VR Api and runs the game in VR mode without a headset.", "vivecraft.options.VR_PLUGIN.disabled.tooltip": "§6Cannot be changed while VR is enabled.§r", - "vivecraft.options.FREEMOVE_FLY_MODE.tooltip": "The source for freemove direction when flying.\n\n Auto: uses the same direction as regular Freemove.\n Controller: Offhand controller pointing direction.\n HMD: Headset look direction.", + "vivecraft.options.FREEMOVE_FLY_MODE.tooltip": "The source for freemove direction when flying.\n\n Auto: uses the same direction as regular Freemove.\n Controller: Offhand controller pointing direction.\n HMD: Headset look direction.\n Waist: Yaw is based on the waist FBT tracker. Pitch is your Headset. If FBT is not available this falls back to HMD.", "vivecraft.options.SHOW_UPDATES.tooltip": "How often an update message should show up in chat.\n Always: Shows the update message each time a world is loaded.\n Once: Shows the update message only on the first world load after a new update is out.", "vivecraft.options.UPDATE_TYPE.tooltip": "Specifies what updates should trigger a notification.", "vivecraft.options.SHOW_PLUGIN.tooltip": "When the \"server mod detected\" message should show up in chat.\n Always: Shows the message on single/multiplayer.\n Server Only: Only shows the message in multiplayer.\n Never: Never shows the message.", From 71ea12caccea7c21b692b133f54e392c51585d1a Mon Sep 17 00:00:00 2001 From: hammy275 Date: Sat, 18 Oct 2025 19:13:30 -0400 Subject: [PATCH 39/76] Player-Relative Pose History and Index Out of Bounds Fix (#405) * Relative to Player Position Pose History and Fix Off-By-One in averageSpeed() and averageVelocity() * World space and version bump javadoc updates --- .../org/vivecraft/api/data/VRPoseHistory.java | 116 ++++++++++++++++-- .../org/vivecraft/client/ClientVRPlayers.java | 2 +- .../client/api_impl/VRClientAPIImpl.java | 5 +- .../client_vr/gameplay/VRPlayer.java | 2 +- .../vivecraft/common/api_impl/VRAPIImpl.java | 5 +- .../api_impl/data/VRPoseHistoryImpl.java | 77 +++++++----- .../common/api_impl/data/VRPoseImpl.java | 19 +++ .../vivecraft/server/ServerVivePlayer.java | 2 +- 8 files changed, 179 insertions(+), 49 deletions(-) diff --git a/common/src/main/java/org/vivecraft/api/data/VRPoseHistory.java b/common/src/main/java/org/vivecraft/api/data/VRPoseHistory.java index 432e52b52..ddaf93a8b 100644 --- a/common/src/main/java/org/vivecraft/api/data/VRPoseHistory.java +++ b/common/src/main/java/org/vivecraft/api/data/VRPoseHistory.java @@ -11,6 +11,12 @@ *
* Vivecraft will store data for players going up to 200 ticks into the past. Attempting to retrieve history before * this far back will throw an {@link IllegalArgumentException}. + *
+ * Many methods in this class accept the parameter {@code playerPositionRelative}. When this is {@code true}, all + * calculations are done relative to the player, while if {@code false}, calculations are done in world space. For + * example, the net movement of a player who moved from (0, 0, 0) to (3, 0, 0) but did NOT move their head, hands, etc. + * would be (3, 0, 0) if {@code playerPositionRelative} is {@code false} and would be (0, 0, 0) if + * {@code playerPositionRelative} is {@code true}. * * @since 1.3.0 */ @@ -35,18 +41,31 @@ public interface VRPoseHistory { List getAllHistoricalData(); /** - * Gets the pose from {@code ticksBack} ticks back, or {@code null} if such data isn't available. + * Gets the pose from {@code ticksBack} ticks back in world space, or {@code null} if such data isn't available. * * @param ticksBack Ticks back to retrieve data from. * @return A {@link VRPose} instance from {@code ticksBack} ticks ago, or {@code null} if that data isn't available. * @throws IllegalArgumentException Thrown when {@code ticksBack} is outside the range [0,200]. * @since 1.3.0 */ - VRPose getHistoricalData(int ticksBack) throws IllegalArgumentException; + default VRPose getHistoricalData(int ticksBack) throws IllegalArgumentException { + return getHistoricalData(ticksBack, false); + } /** - * Gets the net movement between the most recent VRPose in this instance and the oldest VRPose that can be - * retrieved, going no farther back than {@code maxTicksBack}. + * Gets the pose from {@code ticksBack} ticks back, or {@code null} if such data isn't available. + * + * @param ticksBack Ticks back to retrieve data from. + * @param playerPositionRelative Whether to get the historical data with position relative to the player's position. + * @return A {@link VRPose} instance from {@code ticksBack} ticks ago, or {@code null} if that data isn't available. + * @throws IllegalArgumentException Thrown when {@code ticksBack} is outside the range [0,200]. + * @since 1.3.3 + */ + VRPose getHistoricalData(int ticksBack, boolean playerPositionRelative) throws IllegalArgumentException; + + /** + * Gets the net movement in world space between the most recent VRPose in this instance and the oldest VRPose that + * can be retrieved, going no farther back than {@code maxTicksBack}. * * @param bodyPart The body part to get the net movement for. * @param maxTicksBack The maximum number of ticks back to compare the most recent data with. @@ -57,11 +76,29 @@ public interface VRPoseHistory { * @since 1.3.0 */ @Nullable - Vec3 netMovement(VRBodyPart bodyPart, int maxTicksBack) throws IllegalArgumentException; + default Vec3 netMovement(VRBodyPart bodyPart, int maxTicksBack) throws IllegalArgumentException { + return netMovement(bodyPart, maxTicksBack, false); + } /** - * Gets the average velocity in blocks/tick between the most recent VRPose in this instance and the oldest VRPose - * that can be retrieved, going no farther back than {@code maxTicksBack}. + * Gets the net movement between the most recent VRPose in this instance and the oldest VRPose that can be + * retrieved, going no farther back than {@code maxTicksBack}. + * + * @param bodyPart The body part to get the net movement for. + * @param maxTicksBack The maximum number of ticks back to compare the most recent data with. + * @param playerPositionRelative Whether net movement should be calculated relative to the player position. + * @return The aforementioned net movement. Note that this will return zero change on all axes if only zero ticks + * can be looked back. Will be {@code null} if the body part requested isn't available. + * @throws IllegalArgumentException Thrown when {@code maxTicksBack} is outside the range [0,200] or an invalid + * {@code bodyPart} is supplied. + * @since 1.3.3 + */ + @Nullable + Vec3 netMovement(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException; + + /** + * Gets the average velocity in world space in blocks/tick between the most recent VRPose in this instance and the + * oldest VRPose that can be retrieved, going no farther back than {@code maxTicksBack}. * * @param bodyPart The body part to get the average velocity for. * @param maxTicksBack The maximum number of ticks back to calculate velocity with. @@ -72,12 +109,30 @@ public interface VRPoseHistory { * @since 1.3.0 */ @Nullable - Vec3 averageVelocity(VRBodyPart bodyPart, int maxTicksBack) throws IllegalArgumentException; + default Vec3 averageVelocity(VRBodyPart bodyPart, int maxTicksBack) throws IllegalArgumentException { + return averageVelocity(bodyPart, maxTicksBack, false); + } /** - * Gets the average speed in blocks/tick between the most recent VRPose in this instance and the oldest VRPose + * Gets the average velocity in blocks/tick between the most recent VRPose in this instance and the oldest VRPose * that can be retrieved, going no farther back than {@code maxTicksBack}. * + * @param bodyPart The body part to get the average velocity for. + * @param maxTicksBack The maximum number of ticks back to calculate velocity with. + * @param playerPositionRelative Whether velocity should be calculated to the player position. + * @return The aforementioned average velocity on each axis. Note that this will return zero velocity on all axes + * if only zero ticks can be looked back. Will be {@code null} if the body part requested isn't available. + * @throws IllegalArgumentException Thrown when {@code maxTicksBack} is outside the range [0,200] or an invalid + * {@code bodyPart} is supplied. + * @since 1.3.3 + */ + @Nullable + Vec3 averageVelocity(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException; + + /** + * Gets the average speed in world space in blocks/tick between the most recent VRPose in this instance and the + * oldest VRPose that can be retrieved, going no farther back than {@code maxTicksBack}. + * * @param bodyPart The body part to get the average speed for. * @param maxTicksBack The maximum number of ticks back to calculate speed with. * @return The aforementioned average speed on each axis. Note that this will return zero speed if only zero ticks @@ -86,11 +141,28 @@ public interface VRPoseHistory { * {@code bodyPart} is supplied. * @since 1.3.0 */ - double averageSpeed(VRBodyPart bodyPart, int maxTicksBack) throws IllegalArgumentException; + default double averageSpeed(VRBodyPart bodyPart, int maxTicksBack) throws IllegalArgumentException { + return averageSpeed(bodyPart, maxTicksBack, false); + } /** - * Gets the average position between the most recent VRPose in this instance and the oldest VRPose that can be - * retrieved, going no farther back than {@code maxTicksBack}. + * Gets the average speed in blocks/tick between the most recent VRPose in this instance and the oldest VRPose + * that can be retrieved, going no farther back than {@code maxTicksBack}. + * + * @param bodyPart The body part to get the average speed for. + * @param maxTicksBack The maximum number of ticks back to calculate speed with. + * @param playerPositionRelative Whether the speed should be calculated relative to the player position. + * @return The aforementioned average speed on each axis. Note that this will return zero speed if only zero ticks + * can be looked back, or if the body part requested isn't available. + * @throws IllegalArgumentException Thrown when {@code maxTicksBack} is outside the range [0,200] or an invalid + * {@code bodyPart} is supplied. + * @since 1.3.3 + */ + double averageSpeed(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException; + + /** + * Gets the average position in world space between the most recent VRPose in this instance and the oldest VRPose + * that can be retrieved, going no farther back than {@code maxTicksBack}. * * @param bodyPart The body part to get the average position for. * @param maxTicksBack The maximum number of ticks back to calculate the position with. @@ -101,5 +173,23 @@ public interface VRPoseHistory { * @since 1.3.0 */ @Nullable - Vec3 averagePosition(VRBodyPart bodyPart, int maxTicksBack) throws IllegalArgumentException; + default Vec3 averagePosition(VRBodyPart bodyPart, int maxTicksBack) throws IllegalArgumentException { + return averagePosition(bodyPart, maxTicksBack, false); + } + + /** + * Gets the average position between the most recent VRPose in this instance and the oldest VRPose that can be + * retrieved, going no farther back than {@code maxTicksBack}. + * + * @param bodyPart The body part to get the average position for. + * @param maxTicksBack The maximum number of ticks back to calculate the position with. + * @param playerPositionRelative Whether the positions should be relative to the player's position. + * @return The aforementioned average position. Note that this will return the current position if only zero ticks + * can be looked back. Will be {@code null} if the body part requested isn't available. + * @throws IllegalArgumentException Thrown when {@code maxTicksBack} is outside the range [0,200] or an invalid + * {@code bodyPart} is supplied. + * @since 1.3.3 + */ + @Nullable + Vec3 averagePosition(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException; } diff --git a/common/src/main/java/org/vivecraft/client/ClientVRPlayers.java b/common/src/main/java/org/vivecraft/client/ClientVRPlayers.java index a15afed6d..26eaa9e9f 100644 --- a/common/src/main/java/org/vivecraft/client/ClientVRPlayers.java +++ b/common/src/main/java/org/vivecraft/client/ClientVRPlayers.java @@ -199,7 +199,7 @@ public void update( if (!localPlayer) { Player otherPlayer = this.mc.level.getPlayerByUUID(uuid); if (otherPlayer != null) { - VRAPIImpl.INSTANCE.addPoseToHistory(uuid, rotInfo.asVRPose(otherPlayer.position()), true); + VRAPIImpl.INSTANCE.addPoseToHistory(uuid, rotInfo.asVRPose(otherPlayer.position()), otherPlayer.position(), true); } } diff --git a/common/src/main/java/org/vivecraft/client/api_impl/VRClientAPIImpl.java b/common/src/main/java/org/vivecraft/client/api_impl/VRClientAPIImpl.java index 768e71463..28c5c7217 100644 --- a/common/src/main/java/org/vivecraft/client/api_impl/VRClientAPIImpl.java +++ b/common/src/main/java/org/vivecraft/client/api_impl/VRClientAPIImpl.java @@ -1,5 +1,6 @@ package org.vivecraft.client.api_impl; +import net.minecraft.world.phys.Vec3; import org.vivecraft.api.client.VRClientAPI; import org.vivecraft.api.client.data.CloseKeyboardContext; import org.vivecraft.api.client.data.OpenKeyboardContext; @@ -34,8 +35,8 @@ public void clearPoseHistory() { this.poseHistory.clear(); } - public void addPoseToHistory(VRPose pose) { - this.poseHistory.addPose(pose); + public void addPoseToHistory(VRPose pose, Vec3 playerPos) { + this.poseHistory.addPose(pose, playerPos); } public void processRegistrationEvent() { diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java index a31f02f35..58b787502 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java @@ -240,7 +240,7 @@ public void preTick() { if (this.mc.level != null && (this.mc.getSingleplayerServer() == null || !this.mc.getSingleplayerServer().isPaused())) { - VRClientAPIImpl.INSTANCE.addPoseToHistory(this.vrdata_world_pre.asVRPose()); + VRClientAPIImpl.INSTANCE.addPoseToHistory(this.vrdata_world_pre.asVRPose(), this.mc.player.position()); } } diff --git a/common/src/main/java/org/vivecraft/common/api_impl/VRAPIImpl.java b/common/src/main/java/org/vivecraft/common/api_impl/VRAPIImpl.java index 3559dac5d..afb45b3fb 100644 --- a/common/src/main/java/org/vivecraft/common/api_impl/VRAPIImpl.java +++ b/common/src/main/java/org/vivecraft/common/api_impl/VRAPIImpl.java @@ -2,6 +2,7 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; import org.vivecraft.api.VRAPI; import org.vivecraft.api.data.VRPose; import org.vivecraft.api.data.VRPoseHistory; @@ -30,14 +31,14 @@ public void clearPoseHistory(UUID player, boolean isClientSide) { this.getMap(isClientSide).remove(player); } - public void addPoseToHistory(UUID player, VRPose pose, boolean isClientSide) { + public void addPoseToHistory(UUID player, VRPose pose, Vec3 playerPos, boolean isClientSide) { Map poseHistories = this.getMap(isClientSide); VRPoseHistoryImpl poseHistory = poseHistories.get(player); if (poseHistory == null) { poseHistory = new VRPoseHistoryImpl(); poseHistories.put(player, poseHistory); } - poseHistory.addPose(pose); + poseHistory.addPose(pose, playerPos); } public void clearAllPoseHistories() { diff --git a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseHistoryImpl.java b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseHistoryImpl.java index 10e6f90d0..6b11c96f1 100644 --- a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseHistoryImpl.java +++ b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseHistoryImpl.java @@ -7,6 +7,7 @@ import org.vivecraft.api.data.VRPoseHistory; import org.vivecraft.common.api_impl.VRAPIImpl; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -15,12 +16,12 @@ public class VRPoseHistoryImpl implements VRPoseHistory { // Holds historical VRPose data. The index into here is simply the number of ticks back that data is, with index // 0 being 0 ticks back. - private final LinkedList dataQueue = new LinkedList<>(); + private final LinkedList dataQueue = new LinkedList<>(); public VRPoseHistoryImpl() {} - public void addPose(VRPose pose) { - this.dataQueue.addFirst(pose); + public void addPose(VRPose pose, Vec3 playerPos) { + this.dataQueue.addFirst(new PoseData(pose, playerPos)); // + 1 here since index 0 is 0 ticks back. if (this.dataQueue.size() > VRAPIImpl.MAX_HISTORY_TICKS + 1) { this.dataQueue.removeLast(); @@ -42,40 +43,38 @@ public int ticksOfHistory() { @Override public List getAllHistoricalData() { - return List.copyOf(this.dataQueue); + return this.dataQueue.stream().map(PoseData::pose).toList(); } @Override - public VRPose getHistoricalData(int ticksBack) throws IllegalArgumentException { + public VRPose getHistoricalData(int ticksBack, boolean playerPositionRelative) throws IllegalArgumentException { checkTicksBack(ticksBack); if (this.dataQueue.size() <= ticksBack) { return null; } - return this.dataQueue.get(ticksBack); + return this.dataQueue.get(ticksBack).getPose(playerPositionRelative); } @Override - public Vec3 netMovement(VRBodyPart bodyPart, int maxTicksBack) throws IllegalArgumentException { + public Vec3 netMovement(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException { checkPartNonNull(bodyPart); checkTicksBack(maxTicksBack); if (this.dataQueue.size() <= 1) { return Vec3.ZERO; } - VRBodyPartData currentData = this.dataQueue.getFirst().getBodyPartData(bodyPart); - if (currentData == null) { + Vec3 current = this.dataQueue.getFirst().getPos(bodyPart, playerPositionRelative); + if (current == null) { return null; } - Vec3 current = currentData.getPos(); - VRBodyPartData oldData = this.dataQueue.get(maxTicksBack).getBodyPartData(bodyPart); - if (oldData == null) { + Vec3 old = this.dataQueue.get(maxTicksBack).getPos(bodyPart, playerPositionRelative); + if (old == null) { return null; } - Vec3 old = oldData.getPos(); return current.subtract(old); } @Override - public Vec3 averageVelocity(VRBodyPart bodyPart, int maxTicksBack) throws IllegalArgumentException { + public Vec3 averageVelocity(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException { checkPartNonNull(bodyPart); checkTicksBack(maxTicksBack); if (this.dataQueue.size() <= 1) { @@ -83,18 +82,18 @@ public Vec3 averageVelocity(VRBodyPart bodyPart, int maxTicksBack) throws Illega } maxTicksBack = getNumTicksBack(maxTicksBack); List diffs = new ArrayList<>(maxTicksBack); - for (int i = 0; i <= maxTicksBack; i++) { - VRBodyPartData newer = this.dataQueue.get(i).getBodyPartData(bodyPart); - VRBodyPartData older = this.dataQueue.get(i + 1).getBodyPartData(bodyPart); + for (int i = 0; i < maxTicksBack; i++) { + Vec3 newer = this.dataQueue.get(i).getPos(bodyPart, playerPositionRelative); + Vec3 older = this.dataQueue.get(i + 1).getPos(bodyPart, playerPositionRelative); if (newer == null || older == null) { break; } - diffs.add(newer.getPos().subtract(older.getPos())); + diffs.add(newer.subtract(older)); } if (diffs.isEmpty()) { // Return no change if the body part is available but no historical data or null if body part isn't // available. - return this.dataQueue.getFirst().getBodyPartData(bodyPart) != null ? Vec3.ZERO : null; + return this.dataQueue.getFirst().pose.getBodyPartData(bodyPart) != null ? Vec3.ZERO : null; } return new Vec3( diffs.stream().mapToDouble(vec -> vec.x).average().orElse(0), @@ -104,7 +103,7 @@ public Vec3 averageVelocity(VRBodyPart bodyPart, int maxTicksBack) throws Illega } @Override - public double averageSpeed(VRBodyPart bodyPart, int maxTicksBack) throws IllegalArgumentException { + public double averageSpeed(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException { checkPartNonNull(bodyPart); checkTicksBack(maxTicksBack); if (this.dataQueue.size() <= 1) { @@ -112,19 +111,19 @@ public double averageSpeed(VRBodyPart bodyPart, int maxTicksBack) throws Illegal } maxTicksBack = getNumTicksBack(maxTicksBack); List speeds = new ArrayList<>(maxTicksBack); - for (int i = 0; i <= maxTicksBack; i++) { - VRBodyPartData newer = this.dataQueue.get(i).getBodyPartData(bodyPart); - VRBodyPartData older = this.dataQueue.get(i + 1).getBodyPartData(bodyPart); + for (int i = 0; i < maxTicksBack; i++) { + Vec3 newer = this.dataQueue.get(i).getPos(bodyPart, playerPositionRelative); + Vec3 older = this.dataQueue.get(i + 1).getPos(bodyPart, playerPositionRelative); if (newer == null || older == null) { break; } - speeds.add(newer.getPos().distanceTo(older.getPos())); + speeds.add(newer.distanceTo(older)); } return speeds.stream().mapToDouble(Double::valueOf).average().orElse(0); } @Override - public Vec3 averagePosition(VRBodyPart bodyPart, int maxTicksBack) throws IllegalArgumentException { + public Vec3 averagePosition(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException { checkPartNonNull(bodyPart); checkTicksBack(maxTicksBack); if (this.dataQueue.isEmpty()) { @@ -133,12 +132,12 @@ public Vec3 averagePosition(VRBodyPart bodyPart, int maxTicksBack) throws Illega maxTicksBack = getNumTicksBack(maxTicksBack); List positions = new ArrayList<>(maxTicksBack); int i = 0; - for (VRPose pose : this.dataQueue) { - VRBodyPartData data = pose.getBodyPartData(bodyPart); - if (data == null) { + for (PoseData poseData : this.dataQueue) { + Vec3 pos = poseData.getPos(bodyPart, playerPositionRelative); + if (pos == null) { break; } - positions.add(data.getPos()); + positions.add(pos); if (++i >= maxTicksBack) break; } if (positions.isEmpty()) { @@ -170,4 +169,24 @@ private int getNumTicksBack(int maxTicksBack) { return maxTicksBack; } } + + private record PoseData(VRPose pose, Vec3 playerPosition) { + @Nullable + public Vec3 getPos(VRBodyPart vrBodyPart, boolean playerPositionRelative) { + VRBodyPartData vrBodyPartData = pose.getBodyPartData(vrBodyPart); + if (vrBodyPartData == null) { + return null; + } else if (playerPositionRelative) { + return vrBodyPartData.getPos().subtract(playerPosition); + } + return vrBodyPartData.getPos(); + } + + public VRPose getPose(boolean playerPositionRelative) { + if (playerPositionRelative) { + return ((VRPoseImpl) pose).relativeToPosition(playerPosition); + } + return pose; + } + } } diff --git a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java index 6d3edbbb0..a7259d7c4 100644 --- a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java +++ b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java @@ -1,5 +1,6 @@ package org.vivecraft.common.api_impl.data; +import net.minecraft.world.phys.Vec3; import org.vivecraft.api.data.FBTMode; import org.vivecraft.api.data.VRBodyPart; import org.vivecraft.api.data.VRBodyPartData; @@ -40,6 +41,24 @@ public FBTMode getFBTMode() { return this.fbtMode; } + public VRPoseImpl relativeToPosition(Vec3 position) { + return new VRPoseImpl( + relativeToPosition(hmd, position), relativeToPosition(c0, position), relativeToPosition(c1, position), + relativeToPosition(rightFoot, position), relativeToPosition(leftFoot, position), + relativeToPosition(waist, position), + relativeToPosition(rightKnee, position), relativeToPosition(leftKnee, position), + relativeToPosition(rightElbow, position), relativeToPosition(leftElbow, position), + isSeated, isLeftHanded, fbtMode + ); + } + + private VRBodyPartData relativeToPosition(VRBodyPartData vrBodyPartData, Vec3 position) { + if (vrBodyPartData == null) { + return null; + } + return new VRBodyPartDataImpl(vrBodyPartData.getPos().subtract(position), vrBodyPartData.getDir(), vrBodyPartData.getRotation()); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java b/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java index dfe3be5e5..2a4142f70 100644 --- a/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java +++ b/common/src/main/java/org/vivecraft/server/ServerVivePlayer.java @@ -209,7 +209,7 @@ public void setVrPlayerState(VrPlayerState vrPlayerState) { this.vrPlayerState = vrPlayerState; this.vrPlayerStateAsPose = null; VRAPIImpl.INSTANCE.addPoseToHistory(this.player.getUUID(), vrPlayerState.asVRPose(this.player.position()), - false); + this.player.position(), false); } public VRPose asVRPose() { From 2a79b0b5cc91c8fe2277019c3a81a6e49b2814e5 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sun, 19 Oct 2025 01:26:36 +0200 Subject: [PATCH 40/76] build against 1.21.10 --- gradle.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 7858a30b8..2a1803cc9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ org.gradle.jvmargs=-Xmx4G -minecraft_version=1.21.9 +minecraft_version=1.21.10 enabled_platforms=fabric,forge,neoforge archives_base_name=vivecraft @@ -14,10 +14,10 @@ architectury_version=18.0.3 parchment_version=1.21.9:2025.10.05 fabric_loader_version=0.17.2 -fabric_api_version=0.134.0+1.21.9 +fabric_api_version=0.136.0+1.21.10 -forge_version=1.21.9-59.0.0 -neoforge_version=21.9.3-beta +forge_version=1.21.10-60.0.5 +neoforge_version=21.10.20-beta From af73732ed82637eff010fca424e5775f7c93b5d6 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sun, 19 Oct 2025 23:37:02 +0200 Subject: [PATCH 41/76] clarify some API javadoc --- common/src/main/java/org/vivecraft/api/VRAPI.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/vivecraft/api/VRAPI.java b/common/src/main/java/org/vivecraft/api/VRAPI.java index 75f728d83..ade1d5101 100644 --- a/common/src/main/java/org/vivecraft/api/VRAPI.java +++ b/common/src/main/java/org/vivecraft/api/VRAPI.java @@ -35,7 +35,8 @@ static VRAPI instance() { /** * Returns the VR pose for the given player. Will return {@code null} if the player isn't in VR, - * or if being called from the client and the client has yet to receive any data for the player. + * or if no data for the player has been received yet. The VRPose can still be {@code null} if + * {@link VRAPI#isVRPlayer(Player)} returned true, since those two properties are independent of each other. * * @param player Player to get the VR pose of. * @return The VR pose for a player, or {@code null} if the player isn't in VR or no data has been received for said player. From 3d0988a63ab592a9c25213ba5ca5db74124436ba Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 20 Oct 2025 00:16:50 +0200 Subject: [PATCH 42/76] fix file extraction on neoforge, and bump min neoforge version --- .../src/main/java/org/vivecraft/Xloader.java | 15 ++++++++++-- .../org/vivecraft/client/utils/FileUtils.java | 17 ++++++-------- .../org/vivecraft/fabric/XloaderImpl.java | 21 ++++++++++++++++- .../java/org/vivecraft/forge/XloaderImpl.java | 22 +++++++++++++++++- .../org/vivecraft/neoforge/XloaderImpl.java | 23 ++++++++++++++++--- .../resources/META-INF/neoforge.mods.toml | 4 ++-- 6 files changed, 83 insertions(+), 19 deletions(-) diff --git a/common/src/main/java/org/vivecraft/Xloader.java b/common/src/main/java/org/vivecraft/Xloader.java index 7ad7a45da..7b55a2af7 100644 --- a/common/src/main/java/org/vivecraft/Xloader.java +++ b/common/src/main/java/org/vivecraft/Xloader.java @@ -2,7 +2,10 @@ import dev.architectury.injectables.annotations.ExpectPlatform; +import java.io.IOException; +import java.io.InputStream; import java.nio.file.Path; +import java.util.List; /** * Xplat for stuff that only references modloader classes @@ -66,10 +69,18 @@ static Path getConfigPath(String file) { } /** - * @return path to access files inside the mod jar + * @return InputStream corresponding to the given filepath inside the mod jar */ @ExpectPlatform - static Path getJarPath() { + static InputStream getInJarFile(String sourcePath) throws IOException { + throw new AssertionError(); + } + + /** + * @return List of all files in the given folder inside the mod jar + */ + @ExpectPlatform + static List getInJarFolderFiles(String folder) throws IOException { throw new AssertionError(); } diff --git a/common/src/main/java/org/vivecraft/client/utils/FileUtils.java b/common/src/main/java/org/vivecraft/client/utils/FileUtils.java index acbbdb673..43eccee57 100644 --- a/common/src/main/java/org/vivecraft/client/utils/FileUtils.java +++ b/common/src/main/java/org/vivecraft/client/utils/FileUtils.java @@ -16,12 +16,9 @@ import java.nio.file.StandardCopyOption; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; import java.util.Formatter; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; public class FileUtils { private static final int CONNECT_TIMEOUT = 5000; @@ -104,17 +101,17 @@ private static void handleAssetException(Throwable e, String name, boolean requi * @param required if set and an error occurs, it will not be caught * @return if a file was unpacked */ - private static boolean unpackFile(Path sourcePath, File targetFile, boolean required) { + private static boolean unpackFile(String sourcePath, File targetFile, boolean required) { try { VRSettings.LOGGER.info("Vivecraft: Unpacking file '{}' ...", sourcePath); targetFile.getParentFile().mkdirs(); - Files.copy(sourcePath, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + Files.copy(Xloader.getInJarFile(sourcePath), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING); return true; } catch (Exception exception) { - handleAssetException(exception, sourcePath.toString(), required); + handleAssetException(exception, sourcePath, required); return false; } } @@ -128,7 +125,7 @@ private static boolean unpackFile(Path sourcePath, File targetFile, boolean requ * @return if a file was unpacked */ public static boolean unpackFile(String sourceFile, String targetFile, boolean required) { - return unpackFile(Xloader.getJarPath().resolve(sourceFile), new File(targetFile), required); + return unpackFile(sourceFile, new File(targetFile), required); } /** @@ -145,9 +142,9 @@ public static boolean unpackFolder(String source, String target) { boolean didExtractSomething = false; - try (Stream natives = Files.list(Xloader.getJarPath().resolve(source))) { - for (Path file : natives.collect(Collectors.toCollection(ArrayList::new))) { - didExtractSomething |= unpackFile(file, new File(target + "/" + file.getFileName()), false); + try { + for (Path path : Xloader.getInJarFolderFiles(source)) { + didExtractSomething |= unpackFile(path.toString(), new File(target + "/" + path.getFileName()), false); } } catch (IOException e) { handleAssetException(e, source, false); diff --git a/fabric/src/main/java/org/vivecraft/fabric/XloaderImpl.java b/fabric/src/main/java/org/vivecraft/fabric/XloaderImpl.java index 66dcdb16c..5a2d3dc3b 100644 --- a/fabric/src/main/java/org/vivecraft/fabric/XloaderImpl.java +++ b/fabric/src/main/java/org/vivecraft/fabric/XloaderImpl.java @@ -5,7 +5,13 @@ import org.vivecraft.Xloader; import org.vivecraft.common.utils.ClassUtils; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; public class XloaderImpl implements Xloader { @@ -41,10 +47,23 @@ public static Path getConfigPath(String fileName) { return FabricLoader.getInstance().getConfigDir().resolve(fileName); } - public static Path getJarPath() { + private static Path getJarPath() { return FabricLoader.getInstance().getModContainer("vivecraft").get().getRootPaths().get(0); } + public static InputStream getInJarFile(String sourcePath) throws IOException { + return Files.newInputStream(getJarPath().resolve(sourcePath)); + } + + public static List getInJarFolderFiles(String folder) throws IOException { + List paths = new ArrayList<>(); + Path root = getJarPath(); + try (Stream natives = Files.list(root.resolve(folder))) { + natives.forEach(file -> paths.add(root.relativize(file))); + } + return paths; + } + public static boolean isDedicatedServer() { return FabricLoader.getInstance().getEnvironmentType().equals(EnvType.SERVER); } diff --git a/forge/src/main/java/org/vivecraft/forge/XloaderImpl.java b/forge/src/main/java/org/vivecraft/forge/XloaderImpl.java index df9da7921..f6c3d9b7c 100644 --- a/forge/src/main/java/org/vivecraft/forge/XloaderImpl.java +++ b/forge/src/main/java/org/vivecraft/forge/XloaderImpl.java @@ -6,7 +6,13 @@ import net.minecraftforge.fml.loading.FMLPaths; import org.vivecraft.Xloader; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; public class XloaderImpl implements Xloader { @@ -29,10 +35,24 @@ public static Path getConfigPath(String fileName) { return FMLPaths.CONFIGDIR.get().resolve(fileName); } - public static Path getJarPath() { + private static Path getJarPath() { return FMLLoader.getLoadingModList().getModFileById("vivecraft").getFile().getSecureJar().getPath("/"); } + public static InputStream getInJarFile(String sourcePath) throws IOException { + return Files.newInputStream(getJarPath().resolve(sourcePath)); + } + + public static List getInJarFolderFiles(String folder) throws IOException { + List paths = new ArrayList<>(); + Path root = getJarPath(); + try (Stream natives = Files.list(root.resolve(folder))) { + natives.forEach(file -> paths.add(root.relativize(file))); + } + return paths; + } + + public static boolean isDedicatedServer() { return FMLEnvironment.dist == Dist.DEDICATED_SERVER; } diff --git a/neoforge/src/main/java/org/vivecraft/neoforge/XloaderImpl.java b/neoforge/src/main/java/org/vivecraft/neoforge/XloaderImpl.java index 045d5fdaa..cd31e1663 100644 --- a/neoforge/src/main/java/org/vivecraft/neoforge/XloaderImpl.java +++ b/neoforge/src/main/java/org/vivecraft/neoforge/XloaderImpl.java @@ -6,7 +6,11 @@ import net.neoforged.fml.loading.FMLPaths; import org.vivecraft.Xloader; +import java.io.IOException; +import java.io.InputStream; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; public class XloaderImpl implements Xloader { @@ -29,9 +33,22 @@ public static Path getConfigPath(String fileName) { return FMLPaths.CONFIGDIR.get().resolve(fileName); } - public static Path getJarPath() { - return FMLLoader.getCurrent().getLoadingModList().getModFileById("vivecraft").getFile().getSecureJar() - .getPrimaryPath(); + public static InputStream getInJarFile(String sourcePath) throws IOException { + return FMLLoader.getCurrent().getLoadingModList().getModFileById("vivecraft").getFile().getContents() + .openFile(sourcePath); + } + + public static List getInJarFolderFiles(String folder) throws IOException { + List paths = new ArrayList<>(); + Path target = Path.of(folder); + FMLLoader.getCurrent().getLoadingModList().getModFileById("vivecraft").getFile().getContents() + .visitContent(folder, (relPath, resource) -> { + Path file = Path.of(relPath); + if (target.equals(file.getParent())) { + paths.add(file); + } + }); + return paths; } public static boolean isDedicatedServer() { diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml index 84578da08..eec702bba 100644 --- a/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -23,14 +23,14 @@ updateJSONURL = "https://raw.githubusercontent.com/Vivecraft/VivecraftMod/forge- [[dependencies.vivecraft]] modId = "neoforge" type = "required" -versionRange = "[21.9.12-beta,)" +versionRange = "[21.10.9-beta,)" ordering = "NONE" side = "BOTH" [[dependencies.vivecraft]] modId = "minecraft" type = "required" -versionRange = "[1.21.9,1.21.10]" +versionRange = "[1.21.10]" ordering = "NONE" side = "BOTH" From 5b901d36d14de44e1cdfbb96d3e9d141ba31ca62 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 20 Oct 2025 00:36:07 +0200 Subject: [PATCH 43/76] formatting --- .../org/vivecraft/api/data/VRPoseHistory.java | 12 ++++++++---- .../org/vivecraft/client/ClientVRPlayers.java | 3 ++- .../common/api_impl/data/VRPoseHistoryImpl.java | 16 ++++++++++++---- .../common/api_impl/data/VRPoseImpl.java | 3 ++- .../client_vr/player/LocalPlayerVRMixin.java | 1 - .../org/vivecraft/server/ServerNetworking.java | 3 ++- 6 files changed, 26 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/org/vivecraft/api/data/VRPoseHistory.java b/common/src/main/java/org/vivecraft/api/data/VRPoseHistory.java index ddaf93a8b..eb64774a7 100644 --- a/common/src/main/java/org/vivecraft/api/data/VRPoseHistory.java +++ b/common/src/main/java/org/vivecraft/api/data/VRPoseHistory.java @@ -94,7 +94,8 @@ default Vec3 netMovement(VRBodyPart bodyPart, int maxTicksBack) throws IllegalAr * @since 1.3.3 */ @Nullable - Vec3 netMovement(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException; + Vec3 netMovement( + VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException; /** * Gets the average velocity in world space in blocks/tick between the most recent VRPose in this instance and the @@ -127,7 +128,8 @@ default Vec3 averageVelocity(VRBodyPart bodyPart, int maxTicksBack) throws Illeg * @since 1.3.3 */ @Nullable - Vec3 averageVelocity(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException; + Vec3 averageVelocity( + VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException; /** * Gets the average speed in world space in blocks/tick between the most recent VRPose in this instance and the @@ -158,7 +160,8 @@ default double averageSpeed(VRBodyPart bodyPart, int maxTicksBack) throws Illega * {@code bodyPart} is supplied. * @since 1.3.3 */ - double averageSpeed(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException; + double averageSpeed( + VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException; /** * Gets the average position in world space between the most recent VRPose in this instance and the oldest VRPose @@ -191,5 +194,6 @@ default Vec3 averagePosition(VRBodyPart bodyPart, int maxTicksBack) throws Illeg * @since 1.3.3 */ @Nullable - Vec3 averagePosition(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException; + Vec3 averagePosition( + VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException; } diff --git a/common/src/main/java/org/vivecraft/client/ClientVRPlayers.java b/common/src/main/java/org/vivecraft/client/ClientVRPlayers.java index 26eaa9e9f..0f09abcd1 100644 --- a/common/src/main/java/org/vivecraft/client/ClientVRPlayers.java +++ b/common/src/main/java/org/vivecraft/client/ClientVRPlayers.java @@ -199,7 +199,8 @@ public void update( if (!localPlayer) { Player otherPlayer = this.mc.level.getPlayerByUUID(uuid); if (otherPlayer != null) { - VRAPIImpl.INSTANCE.addPoseToHistory(uuid, rotInfo.asVRPose(otherPlayer.position()), otherPlayer.position(), true); + VRAPIImpl.INSTANCE.addPoseToHistory(uuid, rotInfo.asVRPose(otherPlayer.position()), + otherPlayer.position(), true); } } diff --git a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseHistoryImpl.java b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseHistoryImpl.java index 6b11c96f1..a6de24f44 100644 --- a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseHistoryImpl.java +++ b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseHistoryImpl.java @@ -56,7 +56,9 @@ public VRPose getHistoricalData(int ticksBack, boolean playerPositionRelative) t } @Override - public Vec3 netMovement(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException { + public Vec3 netMovement( + VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException + { checkPartNonNull(bodyPart); checkTicksBack(maxTicksBack); if (this.dataQueue.size() <= 1) { @@ -74,7 +76,9 @@ public Vec3 netMovement(VRBodyPart bodyPart, int maxTicksBack, boolean playerPos } @Override - public Vec3 averageVelocity(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException { + public Vec3 averageVelocity( + VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException + { checkPartNonNull(bodyPart); checkTicksBack(maxTicksBack); if (this.dataQueue.size() <= 1) { @@ -103,7 +107,9 @@ public Vec3 averageVelocity(VRBodyPart bodyPart, int maxTicksBack, boolean playe } @Override - public double averageSpeed(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException { + public double averageSpeed( + VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException + { checkPartNonNull(bodyPart); checkTicksBack(maxTicksBack); if (this.dataQueue.size() <= 1) { @@ -123,7 +129,9 @@ public double averageSpeed(VRBodyPart bodyPart, int maxTicksBack, boolean player } @Override - public Vec3 averagePosition(VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException { + public Vec3 averagePosition( + VRBodyPart bodyPart, int maxTicksBack, boolean playerPositionRelative) throws IllegalArgumentException + { checkPartNonNull(bodyPart); checkTicksBack(maxTicksBack); if (this.dataQueue.isEmpty()) { diff --git a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java index a7259d7c4..761b8da02 100644 --- a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java +++ b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java @@ -56,7 +56,8 @@ private VRBodyPartData relativeToPosition(VRBodyPartData vrBodyPartData, Vec3 po if (vrBodyPartData == null) { return null; } - return new VRBodyPartDataImpl(vrBodyPartData.getPos().subtract(position), vrBodyPartData.getDir(), vrBodyPartData.getRotation()); + return new VRBodyPartDataImpl(vrBodyPartData.getPos().subtract(position), vrBodyPartData.getDir(), + vrBodyPartData.getRotation()); } @Override diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/player/LocalPlayerVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/player/LocalPlayerVRMixin.java index 9a5a17fee..020332ae0 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/player/LocalPlayerVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/player/LocalPlayerVRMixin.java @@ -29,7 +29,6 @@ import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.vivecraft.api.data.FBTMode; import org.vivecraft.client.network.ClientNetworking; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; diff --git a/common/src/main/java/org/vivecraft/server/ServerNetworking.java b/common/src/main/java/org/vivecraft/server/ServerNetworking.java index ff50b5b5d..601038339 100644 --- a/common/src/main/java/org/vivecraft/server/ServerNetworking.java +++ b/common/src/main/java/org/vivecraft/server/ServerNetworking.java @@ -458,7 +458,8 @@ public static void sendHapticToClient( public static void sendVrPlayerStateToClients(ServerVivePlayer vivePlayer) { // create the packets here, to try to avoid unnecessary memory copies when creating multiple packets Packet legacyPacket = Xplat.getS2CPacket( - new UberPacketPayloadS2C(vivePlayer.player.getUUID(), new VrPlayerState(vivePlayer.vrPlayerState(), NetworkVersion.LEGACY), + new UberPacketPayloadS2C(vivePlayer.player.getUUID(), + new VrPlayerState(vivePlayer.vrPlayerState(), NetworkVersion.LEGACY), vivePlayer.worldScale, vivePlayer.heightScale)); Packet newPacket = Xplat.getS2CPacket( new UberPacketPayloadS2C(vivePlayer.player.getUUID(), vivePlayer.vrPlayerState(), vivePlayer.worldScale, From 50eb2894e0fceee892c08e5744cf0943a9847b67 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 20 Oct 2025 02:02:07 +0200 Subject: [PATCH 44/76] fix player not rendering when sleeping and instead showing up in VR --- .../mixin/client_vr/renderer/LevelRendererVRMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/LevelRendererVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/LevelRendererVRMixin.java index fcb24dfbe..555637261 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/LevelRendererVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/renderer/LevelRendererVRMixin.java @@ -139,7 +139,7 @@ protected abstract void renderHitOutline( @ModifyExpressionValue(method = "extractVisibleEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;isSleeping()Z")) private boolean vivecraft$noPlayerWhenSleeping(boolean isSleeping) { // no self render, we don't want an out-of-body experience - return isSleeping && !RenderPassType.isVanilla(); + return isSleeping && RenderPassType.isVanilla(); } // no remap needed to make the * work From d74dd245845ed4452fa1467efb53bd3bf246d61b Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 20 Oct 2025 02:06:27 +0200 Subject: [PATCH 45/76] bump to 1.3.3 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2a1803cc9..d2b508a21 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ minecraft_version=1.21.10 enabled_platforms=fabric,forge,neoforge archives_base_name=vivecraft -mod_version=1.3.2 +mod_version=1.3.3 maven_group=org.vivecraft lwjgl_version=3.3.3 From 110358b1a1b1818c1f33cbeb2aa20a70feef2cc2 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 20 Oct 2025 17:37:59 +0200 Subject: [PATCH 46/76] missing this --- .../common/api_impl/data/VRPoseHistoryImpl.java | 8 ++++---- .../vivecraft/common/api_impl/data/VRPoseImpl.java | 14 ++++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseHistoryImpl.java b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseHistoryImpl.java index a6de24f44..6eb303a1f 100644 --- a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseHistoryImpl.java +++ b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseHistoryImpl.java @@ -181,20 +181,20 @@ private int getNumTicksBack(int maxTicksBack) { private record PoseData(VRPose pose, Vec3 playerPosition) { @Nullable public Vec3 getPos(VRBodyPart vrBodyPart, boolean playerPositionRelative) { - VRBodyPartData vrBodyPartData = pose.getBodyPartData(vrBodyPart); + VRBodyPartData vrBodyPartData = this.pose.getBodyPartData(vrBodyPart); if (vrBodyPartData == null) { return null; } else if (playerPositionRelative) { - return vrBodyPartData.getPos().subtract(playerPosition); + return vrBodyPartData.getPos().subtract(this.playerPosition); } return vrBodyPartData.getPos(); } public VRPose getPose(boolean playerPositionRelative) { if (playerPositionRelative) { - return ((VRPoseImpl) pose).relativeToPosition(playerPosition); + return ((VRPoseImpl) this.pose).relativeToPosition(this.playerPosition); } - return pose; + return this.pose; } } } diff --git a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java index 761b8da02..f0b49cb2b 100644 --- a/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java +++ b/common/src/main/java/org/vivecraft/common/api_impl/data/VRPoseImpl.java @@ -43,12 +43,14 @@ public FBTMode getFBTMode() { public VRPoseImpl relativeToPosition(Vec3 position) { return new VRPoseImpl( - relativeToPosition(hmd, position), relativeToPosition(c0, position), relativeToPosition(c1, position), - relativeToPosition(rightFoot, position), relativeToPosition(leftFoot, position), - relativeToPosition(waist, position), - relativeToPosition(rightKnee, position), relativeToPosition(leftKnee, position), - relativeToPosition(rightElbow, position), relativeToPosition(leftElbow, position), - isSeated, isLeftHanded, fbtMode + relativeToPosition(this.hmd, position), + relativeToPosition(this.c0, position), + relativeToPosition(this.c1, position), + relativeToPosition(this.rightFoot, position), relativeToPosition(this.leftFoot, position), + relativeToPosition(this.waist, position), + relativeToPosition(this.rightKnee, position), relativeToPosition(this.leftKnee, position), + relativeToPosition(this.rightElbow, position), relativeToPosition(this.leftElbow, position), + this.isSeated, this.isLeftHanded, this.fbtMode ); } From 38fbc325884e380c111b436bdb0c45013edb135d Mon Sep 17 00:00:00 2001 From: fayer3 Date: Fri, 24 Oct 2025 23:10:59 +0200 Subject: [PATCH 47/76] fix crash with MCA on 1.21.1 fix MCA female breasts on fabric make compat helpers not crash the game on errors --- .../vivecraft/mod_compat_vr/iris/IrisHelper.java | 1 + .../vivecraft/mod_compat_vr/mca/MCAHelper.java | 11 ++++++++--- .../mca/mixin/PlayerEntityExtendedModelMixin.java | 15 ++++++++------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/iris/IrisHelper.java b/common/src/main/java/org/vivecraft/mod_compat_vr/iris/IrisHelper.java index d16dc307f..b65048172 100644 --- a/common/src/main/java/org/vivecraft/mod_compat_vr/iris/IrisHelper.java +++ b/common/src/main/java/org/vivecraft/mod_compat_vr/iris/IrisHelper.java @@ -313,6 +313,7 @@ private static boolean init() { } } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException | IllegalAccessException e) { INIT_FAILED = true; + VRSettings.LOGGER.error("Vivecraft: Failed to initialize Iris compat", e); } INITIALIZED = true; diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/mca/MCAHelper.java b/common/src/main/java/org/vivecraft/mod_compat_vr/mca/MCAHelper.java index ed2adb547..07473dbf7 100644 --- a/common/src/main/java/org/vivecraft/mod_compat_vr/mca/MCAHelper.java +++ b/common/src/main/java/org/vivecraft/mod_compat_vr/mca/MCAHelper.java @@ -3,6 +3,8 @@ import net.minecraft.world.entity.LivingEntity; import org.joml.Vector3f; import org.vivecraft.Xloader; +import org.vivecraft.client_vr.settings.VRSettings; +import org.vivecraft.common.utils.ClassUtils; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -58,16 +60,19 @@ private static boolean init() { return !INIT_FAILED; } else { try { - MCAClient_playerData = Class.forName(Xloader.getModloader().name + ".net.mca.MCAClient") + MCAClient_playerData = ClassUtils.getClassWithAlternative( + Xloader.getModloader().name + ".net.mca.MCAClient", "net.conczin.mca.MCAClient") .getField("playerData"); - Class VillagerLike = Class.forName(Xloader.getModloader().name + ".net.mca.entity.VillagerLike"); + Class VillagerLike = ClassUtils.getClassWithAlternative( + Xloader.getModloader().name + ".net.mca.entity.VillagerLike", + "net.conczin.mca.entity.VillagerLike"); VillagerLike_getRawScaleFactor = VillagerLike.getMethod("getRawScaleFactor"); VillagerLike_getHorizontalScaleFactor = VillagerLike.getMethod("getHorizontalScaleFactor"); } catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException e) { INIT_FAILED = true; - throw new RuntimeException(e); + VRSettings.LOGGER.error("Vivecraft: Failed to initialize MCA compat", e); } } diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/mca/mixin/PlayerEntityExtendedModelMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/mca/mixin/PlayerEntityExtendedModelMixin.java index 47f6671af..7891042c4 100644 --- a/common/src/main/java/org/vivecraft/mod_compat_vr/mca/mixin/PlayerEntityExtendedModelMixin.java +++ b/common/src/main/java/org/vivecraft/mod_compat_vr/mca/mixin/PlayerEntityExtendedModelMixin.java @@ -3,21 +3,22 @@ import com.llamalad7.mixinextras.sugar.Local; import net.minecraft.client.model.PlayerModel; import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.renderer.entity.state.AvatarRenderState; import net.minecraft.util.Mth; -import net.minecraft.world.entity.LivingEntity; import org.joml.Matrix3f; import org.joml.Vector3f; import org.spongepowered.asm.mixin.*; 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.ClientVRPlayers; +import org.vivecraft.client.extensions.EntityRenderStateExtension; /** * MCA uses a fixed offset for the breasts, this changes it to be relative to the body rotation */ @Pseudo @Mixin(targets = { + "net.conczin.mca.client.model.PlayerEntityExtendedModel", "fabric.net.mca.client.model.PlayerEntityExtendedModel", "forge.net.mca.client.model.PlayerEntityExtendedModel", "quilt.net.mca.client.model.PlayerEntityExtendedModel"}) @@ -41,9 +42,9 @@ public abstract class PlayerEntityExtendedModelMixin { @Unique private final Matrix3f vivecraft$rotMatrix = new Matrix3f(); - @Inject(method = "setupAnim(Lnet/minecraft/world/entity/LivingEntity;FFFFF)V", at = @At("TAIL")) - private void vivecraft$moveBreasts(CallbackInfo ci, @Local(argsOnly = true) LivingEntity villager) { - if (ClientVRPlayers.getInstance().isVRPlayer(villager)) { + @Inject(method = {"setupAnim", "method_62110"}, at = @At("TAIL"), remap = false) + private void vivecraft$moveBreasts(CallbackInfo ci, @Local(argsOnly = true) AvatarRenderState villager) { + if (((EntityRenderStateExtension) villager).vivecraft$getRotInfo() != null) { ModelPart body = ((PlayerModel) (Object) this).body; this.vivecraft$rotMatrix.rotationZYX(body.zRot, body.yRot, body.xRot); @@ -64,8 +65,8 @@ public abstract class PlayerEntityExtendedModelMixin { this.vivecraft$position.x + body.x / (this.breastSize * 0.2f + 1.05f), this.vivecraft$position.y + body.y / (this.breastSize * 0.75f + 0.75f), this.vivecraft$position.z + body.z / (this.breastSize * 0.75f + 0.75f)); - // TODO if they ever make an updated version, check how to do this correctly - this.breastsWear.loadPose(this.breasts.storePose()); + this.breastsWear.setPos(this.breasts.x, this.breasts.y, this.breasts.z); + this.breastsWear.setRotation(this.breasts.xRot, this.breasts.yRot, this.breasts.zRot); } } } From d7cadd9826e31eae33832d76f57dcfa75f8fd505 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Fri, 24 Oct 2025 23:12:51 +0200 Subject: [PATCH 48/76] fix ALLOW_ATTACKS_WHILE_BLOCKING server setting not working without changing it at runtime --- .../src/main/java/org/vivecraft/server/ServerNetworking.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/src/main/java/org/vivecraft/server/ServerNetworking.java b/common/src/main/java/org/vivecraft/server/ServerNetworking.java index 601038339..5cb8a7740 100644 --- a/common/src/main/java/org/vivecraft/server/ServerNetworking.java +++ b/common/src/main/java/org/vivecraft/server/ServerNetworking.java @@ -179,6 +179,11 @@ public static void handlePacket( } } + if (NetworkVersion.OPTION_TOGGLE.accepts(vivePlayer.networkVersion)) { + packetConsumer.accept( + new AttackWhileBlockingPayloadS2C(ServerConfig.ALLOW_ATTACKS_WHILE_BLOCKING.get())); + } + packetConsumer.accept(new NetworkVersionPayloadS2C(vivePlayer.networkVersion)); } case IS_VR_ACTIVE -> { From 6e7a0eb6f1ce5f2444b158227cc5d7967557031a Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sat, 25 Oct 2025 19:48:57 +0200 Subject: [PATCH 49/76] fix broken projection matrix when some mod tries to set the far plane to infinite (case with cosmic horizons) --- .../client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java index 949c4058b..b8f80caab 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java @@ -80,10 +80,10 @@ protected Matrix4f getProjectionMatrix(int eyeType, float nearClip, float farCli try (MemoryStack stack = MemoryStack.stackPush()) { if (eyeType == VR.EVREye_Eye_Left) { return OpenVRUtil.Matrix4fFromOpenVR( - VRSystem_GetProjectionMatrix(VR.EVREye_Eye_Left, nearClip, farClip, HmdMatrix44.calloc(stack))); + VRSystem_GetProjectionMatrix(VR.EVREye_Eye_Left, nearClip, Math.min(farClip, Float.MAX_VALUE), HmdMatrix44.calloc(stack))); } else { return OpenVRUtil.Matrix4fFromOpenVR( - VRSystem_GetProjectionMatrix(VR.EVREye_Eye_Right, nearClip, farClip, HmdMatrix44.calloc(stack))); + VRSystem_GetProjectionMatrix(VR.EVREye_Eye_Right, nearClip, Math.min(farClip, Float.MAX_VALUE), HmdMatrix44.calloc(stack))); } } } From b725b6e2dda5480921b822aa71d8ccc9b587b19a Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sat, 25 Oct 2025 22:31:59 +0200 Subject: [PATCH 50/76] fix attack while blocking packet not being handled at all --- .../vivecraft/common/network/packet/s2c/VivecraftPayloadS2C.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/java/org/vivecraft/common/network/packet/s2c/VivecraftPayloadS2C.java b/common/src/main/java/org/vivecraft/common/network/packet/s2c/VivecraftPayloadS2C.java index 632dc83b8..4e48c5d27 100644 --- a/common/src/main/java/org/vivecraft/common/network/packet/s2c/VivecraftPayloadS2C.java +++ b/common/src/main/java/org/vivecraft/common/network/packet/s2c/VivecraftPayloadS2C.java @@ -51,6 +51,7 @@ static VivecraftPayloadS2C readPacket(FriendlyByteBuf buffer) { case HAPTIC -> HapticPayloadS2C.read(buffer); case SERVER_VR_CHANGES -> ServerVrChangesS2CPacket.read(buffer); case DAMAGE_DIRECTION -> DamageDirectionPayloadS2C.read(buffer); + case ATTACK_WHILE_BLOCKING -> AttackWhileBlockingPayloadS2C.read(buffer); default -> { VRSettings.LOGGER.error("Vivecraft: Got unexpected payload identifier on client: {}", id); yield UnknownPayloadS2C.read(buffer); From e35e2e73547485fa4bcc24baeab05c85252f630b Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sat, 25 Oct 2025 22:35:56 +0200 Subject: [PATCH 51/76] fix copy/cut/paste keys not working on the VR keyboard --- .../java/org/vivecraft/client_vr/provider/InputSimulator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/InputSimulator.java b/common/src/main/java/org/vivecraft/client_vr/provider/InputSimulator.java index 5e8914016..c8fb1140b 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/InputSimulator.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/InputSimulator.java @@ -38,7 +38,7 @@ public static void pressKey(int key, int modifiers) { } public static void pressKey(int key) { - pressKey(key, 0); + pressKey(key, getActiveModifier()); } public static void releaseKey(int key, int modifiers) { @@ -47,7 +47,7 @@ public static void releaseKey(int key, int modifiers) { } public static void releaseKey(int key) { - releaseKey(key, 0); + releaseKey(key, getActiveModifier()); } public static void pressModifier(int key, int modifiers) { From f60523efc4a613e5d24121564831ff3c1059b322 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sun, 26 Oct 2025 15:55:05 +0100 Subject: [PATCH 52/76] fix broken menu panorama with the dirtbox menu --- .../main/java/org/vivecraft/client_vr/render/VRShaders.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java b/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java index 66ef30963..94ae9a9d1 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java @@ -100,11 +100,11 @@ public class VRShaders { public static final RenderPipeline SOLID_PANORAMA = RenderPipeline.builder( RenderPipelines.MATRICES_PROJECTION_SNIPPET) .withLocation("pipeline/panorama") - .withVertexShader("core/position_tex") - .withFragmentShader("core/position_tex") + .withVertexShader("core/panorama") + .withFragmentShader("core/panorama") .withSampler("Sampler0") .withDepthWrite(false) - .withVertexFormat(DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.QUADS).build(); + .withVertexFormat(DefaultVertexFormat.POSITION, VertexFormat.Mode.QUADS).build(); public static final RenderPipeline GUI_TEXTURED_ALWAYS = RenderPipeline.builder( RenderPipelines.GUI_TEXTURED_SNIPPET) From 2c5178d7fc1502e1d3ad251437c5e6f34bd95700 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Fri, 31 Oct 2025 16:56:19 +0100 Subject: [PATCH 53/76] fix crash when clearing the search and clicking a setting --- .../vivecraft/client/gui/framework/widgets/SettingsList.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/widgets/SettingsList.java b/common/src/main/java/org/vivecraft/client/gui/framework/widgets/SettingsList.java index aad9d7c66..c3ccbb379 100644 --- a/common/src/main/java/org/vivecraft/client/gui/framework/widgets/SettingsList.java +++ b/common/src/main/java/org/vivecraft/client/gui/framework/widgets/SettingsList.java @@ -95,10 +95,10 @@ private void exactFilter(String filter) { if (!filter.trim().equals(this.activeFilter)) { // scroll to the top, to not be in the void this.setScrollAmount(0); - this.activeFilter = filter.trim(); String lowerCase = filter.trim().toLowerCase(); this.replaceEntriesFlatten(this.allEntries.stream().filter(entry -> entry.filter(lowerCase))); } + this.activeFilter = filter.trim(); } /** @@ -112,7 +112,6 @@ private void fuzzyFilter(String filter) { } else if (!filter.trim().equals(this.activeFilter)) { // scroll to the top, to not be in the void this.setScrollAmount(0); - this.activeFilter = filter.trim(); String lowerCase = filter.trim().toLowerCase(); List entries = this.allEntries.stream() .flatMap(child -> child.getEntries().stream()) @@ -124,6 +123,7 @@ private void fuzzyFilter(String filter) { this.replaceEntries(entries); } + this.activeFilter = filter.trim(); } public boolean isEntryVisible(SettingsList.BaseEntry entry) { From 659ada9f9ddbe2fe5e61ab43818625b93a10adbf Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sat, 1 Nov 2025 00:51:00 +0100 Subject: [PATCH 54/76] another crash fix when removing entries from a list --- .../vivecraft/client/gui/framework/screens/GuiListScreen.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiListScreen.java b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiListScreen.java index 816bf9fe7..1a7bd268d 100644 --- a/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiListScreen.java +++ b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiListScreen.java @@ -61,7 +61,9 @@ protected void init() { this.searchBox = null; } - this.list.setSelected(this.lastSelected == -1 ? null : this.list.children().get(this.lastSelected)); + List children = this.list.children(); + this.list.setSelected( + this.lastSelected == -1 ? null : children.get(Math.min(children.size() - 1, this.lastSelected))); this.list.setFocused(this.list.getSelected()); this.list.setScrollAmount(scrollAmount); this.addRenderableWidget(this.list); From 3afb1260dfafa7eed01be3e6379957151eb6f58d Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sun, 2 Nov 2025 16:06:46 +0100 Subject: [PATCH 55/76] fix crash neoforge 21.10.24+, and bump min version to that --- gradle.properties | 2 +- .../main/java/org/vivecraft/neoforge/XeventsImpl.java | 10 +++++++--- .../src/main/resources/META-INF/neoforge.mods.toml | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index d2b508a21..53c756b45 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ fabric_loader_version=0.17.2 fabric_api_version=0.136.0+1.21.10 forge_version=1.21.10-60.0.5 -neoforge_version=21.10.20-beta +neoforge_version=21.10.45-beta diff --git a/neoforge/src/main/java/org/vivecraft/neoforge/XeventsImpl.java b/neoforge/src/main/java/org/vivecraft/neoforge/XeventsImpl.java index 942b52c11..00febf4f6 100644 --- a/neoforge/src/main/java/org/vivecraft/neoforge/XeventsImpl.java +++ b/neoforge/src/main/java/org/vivecraft/neoforge/XeventsImpl.java @@ -1,6 +1,7 @@ package org.vivecraft.neoforge; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.state.BlockState; @@ -14,14 +15,17 @@ public static boolean renderBlockOverlay( Player player, PoseStack poseStack, BlockState blockState, BlockPos blockPos) { return ClientHooks.renderBlockOverlay(player, poseStack, RenderBlockScreenEffectEvent.OverlayType.BLOCK, - blockState, blockPos); + blockState, blockPos, Minecraft.getInstance().getAtlasManager(), + Minecraft.getInstance().renderBuffers().bufferSource()); } public static boolean renderWaterOverlay(Player player, PoseStack poseStack) { - return ClientHooks.renderWaterOverlay(player, poseStack); + return ClientHooks.renderWaterOverlay(player, poseStack, Minecraft.getInstance().getAtlasManager(), + Minecraft.getInstance().renderBuffers().bufferSource()); } public static boolean renderFireOverlay(Player player, PoseStack poseStack) { - return ClientHooks.renderFireOverlay(player, poseStack); + return ClientHooks.renderFireOverlay(player, poseStack, Minecraft.getInstance().getAtlasManager(), + Minecraft.getInstance().renderBuffers().bufferSource()); } } diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml index eec702bba..0a21b18a4 100644 --- a/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -23,7 +23,7 @@ updateJSONURL = "https://raw.githubusercontent.com/Vivecraft/VivecraftMod/forge- [[dependencies.vivecraft]] modId = "neoforge" type = "required" -versionRange = "[21.10.9-beta,)" +versionRange = "[21.10.24-beta,)" ordering = "NONE" side = "BOTH" From 2b8b52aa185de91c4f2291907f458ba2b8bc90aa Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sun, 2 Nov 2025 23:19:08 +0100 Subject: [PATCH 56/76] fix optifine shaders --- .../optifine/mixin/OptifineCloudRendererMixin.java | 2 +- .../mod_compat_vr/optifine/mixin/ShadersRenderVRMixin.java | 3 +++ .../vivecraft/mod_compat_vr/optifine/mixin/ShadersVRMixin.java | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/OptifineCloudRendererMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/OptifineCloudRendererMixin.java index 45ebc2aeb..6b2faf5da 100644 --- a/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/OptifineCloudRendererMixin.java +++ b/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/OptifineCloudRendererMixin.java @@ -10,7 +10,7 @@ @ClassDependentMixin("net.optifine.Config") @Mixin(CloudRenderer.class) public class OptifineCloudRendererMixin { - @ModifyExpressionValue(method = "render", at = @At(value = "INVOKE", target = "Lnet/optifine/Config;isShaders()Z"), remap = false) + @ModifyExpressionValue(method = "render*", at = @At(value = "INVOKE", target = "Lnet/optifine/Config;isShaders()Z"), remap = false) private boolean vivecraft$rebuildMenuWorld(boolean isShaders) { // don't render the clouds with shaders in the menu world return isShaders && (ClientDataHolderVR.getInstance().menuWorldRenderer == null || diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/ShadersRenderVRMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/ShadersRenderVRMixin.java index cced8f86e..94f188348 100644 --- a/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/ShadersRenderVRMixin.java +++ b/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/ShadersRenderVRMixin.java @@ -1,6 +1,7 @@ package org.vivecraft.mod_compat_vr.optifine.mixin; import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; @@ -43,8 +44,10 @@ public static void updateActiveRenderInfo(Camera activeRenderInfo, Minecraft mc, if (!RenderPassType.isVanilla() && ClientDataHolderVR.getInstance().currentPass != RenderPass.LEFT && !ClientDataHolderVR.getInstance().vrSettings.disableShaderOptimization) { + RenderSystem.backupProjectionMatrix(); updateActiveRenderInfo(activeRenderInfo, Minecraft.getInstance(), partialTick); OptifineHelper.setCameraShadow(new PoseStack(), activeRenderInfo, partialTick); + RenderSystem.restoreProjectionMatrix(); ci.cancel(); } } diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/ShadersVRMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/ShadersVRMixin.java index 9a8d79f64..24e674632 100644 --- a/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/ShadersVRMixin.java +++ b/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/ShadersVRMixin.java @@ -64,7 +64,7 @@ public class ShadersVRMixin { } } - @Inject(method = "beginRender", at = @At(value = "INVOKE", target = "Ljava/nio/FloatBuffer;position(I)Ljava/nio/FloatBuffer;", ordinal = 0), remap = false) + @Inject(method = "beginRender", at = @At(value = "CONSTANT", args = "stringValue=beginRender"), remap = false) private static void vivecraft$updateVivecraftUniforms(CallbackInfo ci) { OptifineHelper.updateUniforms(); } From 4da75ab14196af868a2e53592c19140506de20c5 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 3 Nov 2025 15:22:57 +0100 Subject: [PATCH 57/76] update forge requirement, to block forge versions that break mixin extras --- forge/src/main/resources/META-INF/mods.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml index 8482afe72..9e8f2d42c 100644 --- a/forge/src/main/resources/META-INF/mods.toml +++ b/forge/src/main/resources/META-INF/mods.toml @@ -23,7 +23,7 @@ updateJSONURL = "https://raw.githubusercontent.com/Vivecraft/VivecraftMod/forge- [[dependencies.vivecraft]] modId = "forge" mandatory = true -versionRange = "[59.0.0,)" +versionRange = "[59.0.0,60.0.12],[60.0.15,)" ordering = "NONE" side = "BOTH" From 26df48f150b6577901a722182e1d9dbb65cbffc7 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 3 Nov 2025 16:08:05 +0100 Subject: [PATCH 58/76] move optifine cloud mixin to shaders mixin --- .../mixin/OptifineCloudRendererMixin.java | 20 ------------------- .../optifine/mixin/ShadersVRMixin.java | 14 +++++++++++-- .../resources/vivecraft.optifine.mixins.json | 1 - 3 files changed, 12 insertions(+), 23 deletions(-) delete mode 100644 common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/OptifineCloudRendererMixin.java diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/OptifineCloudRendererMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/OptifineCloudRendererMixin.java deleted file mode 100644 index 6b2faf5da..000000000 --- a/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/OptifineCloudRendererMixin.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.vivecraft.mod_compat_vr.optifine.mixin; - -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import net.minecraft.client.renderer.CloudRenderer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.extensions.ClassDependentMixin; - -@ClassDependentMixin("net.optifine.Config") -@Mixin(CloudRenderer.class) -public class OptifineCloudRendererMixin { - @ModifyExpressionValue(method = "render*", at = @At(value = "INVOKE", target = "Lnet/optifine/Config;isShaders()Z"), remap = false) - private boolean vivecraft$rebuildMenuWorld(boolean isShaders) { - // don't render the clouds with shaders in the menu world - return isShaders && (ClientDataHolderVR.getInstance().menuWorldRenderer == null || - !ClientDataHolderVR.getInstance().menuWorldRenderer.isRendering() - ); - } -} diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/ShadersVRMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/ShadersVRMixin.java index 24e674632..bce6a8905 100644 --- a/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/ShadersVRMixin.java +++ b/common/src/main/java/org/vivecraft/mod_compat_vr/optifine/mixin/ShadersVRMixin.java @@ -39,8 +39,8 @@ public class ShadersVRMixin { @ModifyVariable(method = "setCameraShadow", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack$Pose;pose()Lorg/joml/Matrix4f;", shift = At.Shift.AFTER, remap = true), remap = false) private static PoseStack vivecraft$offsetShadow(PoseStack shadowModelViewMat) { if (!RenderPassType.isVanilla() && !ClientDataHolderVR.getInstance().vrSettings.disableShaderOptimization) { - Vec3 offset = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition().subtract( - ClientDataHolderVR.getInstance().vrPlayer.getVRDataWorld().hmd.getPosition()); + Vec3 offset = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition() + .subtract(ClientDataHolderVR.getInstance().vrPlayer.getVRDataWorld().hmd.getPosition()); shadowModelViewMat.translate((float) offset.x, (float) offset.y, (float) offset.z); } return shadowModelViewMat; @@ -64,6 +64,16 @@ public class ShadersVRMixin { } } + @Inject(method = {"beginClouds", "endClouds"}, at = @At("HEAD"), remap = false, cancellable = true) + private static void vivecraft$noCloudsInMenu(CallbackInfo ci) { + // don't render the clouds with shaders in the menu world + if (ClientDataHolderVR.getInstance().menuWorldRenderer != null && + ClientDataHolderVR.getInstance().menuWorldRenderer.isRendering()) + { + ci.cancel(); + } + } + @Inject(method = "beginRender", at = @At(value = "CONSTANT", args = "stringValue=beginRender"), remap = false) private static void vivecraft$updateVivecraftUniforms(CallbackInfo ci) { OptifineHelper.updateUniforms(); diff --git a/common/src/main/resources/vivecraft.optifine.mixins.json b/common/src/main/resources/vivecraft.optifine.mixins.json index d762406ca..4becec4a9 100644 --- a/common/src/main/resources/vivecraft.optifine.mixins.json +++ b/common/src/main/resources/vivecraft.optifine.mixins.json @@ -4,7 +4,6 @@ "plugin": "org.vivecraft.MixinConfig", "compatibilityLevel": "JAVA_17", "client": [ - "OptifineCloudRendererMixin", "OptifineDefaultVertexFormatMixin", "OptifineLiquidBlockRendererMixin", "OptifineModelBlockRendererMixin", From 609415a5f9a95375d602f775de744416f4e67485 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 3 Nov 2025 20:38:03 +0100 Subject: [PATCH 59/76] add keyboard layout editor and theme editor, and some keyboard layout presets (#409) --- .../screens/GuiListEditorScreen.java | 105 +++++ .../screens/GuiOrderedListEditorScreen.java | 109 +++++ .../screens/GuiSelectionListScreen.java | 36 +- .../screens/GuiStringListEditorScreen.java | 93 +--- .../gui/framework/widgets/ColorPicker.java | 107 +++++ .../gui/framework/widgets/ColoredButton.java | 43 ++ .../framework/widgets/ColoredKeyButton.java | 50 ++ .../GuiActiveKeyboardLayoutSelector.java | 81 ++++ .../GuiChatNotificationSelection.java | 2 +- .../gui/settings/GuiKeyboardLayoutEditor.java | 164 +++++++ .../gui/settings/GuiKeyboardSettings.java | 29 +- .../gui/settings/GuiKeyboardThemeEditor.java | 130 ++++++ .../gui/settings/GuiRadialConfiguration.java | 2 +- .../screenhandlers/KeyboardHandler.java | 10 + .../vivecraft/client_vr/gui/GuiKeyboard.java | 185 ++------ .../client_vr/gui/PhysicalKeyboard.java | 435 +++--------------- .../gui/keyboard/CustomKeyboardTheme.java | 117 +++++ .../gui/keyboard/EasterEggTheme.java | 20 + .../client_vr/gui/keyboard/KeyboardKeys.java | 218 +++++++++ .../client_vr/gui/keyboard/KeyboardTheme.java | 110 +++++ .../openvr_lwjgl/OpenVRStereoRenderer.java | 6 +- .../client_vr/settings/VRSettings.java | 104 ++++- .../vivecraft/client_vr/utils/RGBAColor.java | 12 + .../mixin/client_vr/gui/EditBoxVRMixin.java | 3 +- .../assets/vivecraft/lang/de_de.json | 28 +- .../assets/vivecraft/lang/en_us.json | 26 ++ 26 files changed, 1575 insertions(+), 650 deletions(-) create mode 100644 common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiListEditorScreen.java create mode 100644 common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiOrderedListEditorScreen.java create mode 100644 common/src/main/java/org/vivecraft/client/gui/framework/widgets/ColorPicker.java create mode 100644 common/src/main/java/org/vivecraft/client/gui/framework/widgets/ColoredButton.java create mode 100644 common/src/main/java/org/vivecraft/client/gui/framework/widgets/ColoredKeyButton.java create mode 100644 common/src/main/java/org/vivecraft/client/gui/settings/GuiActiveKeyboardLayoutSelector.java create mode 100644 common/src/main/java/org/vivecraft/client/gui/settings/GuiKeyboardLayoutEditor.java create mode 100644 common/src/main/java/org/vivecraft/client/gui/settings/GuiKeyboardThemeEditor.java create mode 100644 common/src/main/java/org/vivecraft/client_vr/gui/keyboard/CustomKeyboardTheme.java create mode 100644 common/src/main/java/org/vivecraft/client_vr/gui/keyboard/EasterEggTheme.java create mode 100644 common/src/main/java/org/vivecraft/client_vr/gui/keyboard/KeyboardKeys.java create mode 100644 common/src/main/java/org/vivecraft/client_vr/gui/keyboard/KeyboardTheme.java diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiListEditorScreen.java b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiListEditorScreen.java new file mode 100644 index 000000000..fff9de0c0 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiListEditorScreen.java @@ -0,0 +1,105 @@ +package org.vivecraft.client.gui.framework.screens; + +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import org.vivecraft.client.gui.framework.widgets.SettingsList; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public abstract class GuiListEditorScreen extends GuiListScreen { + + private final Supplier> valuesSupplier; + private final Runnable loadDefaults; + private final Consumer> save; + + protected final boolean fixedEntryCount; + + protected List elements; + + public GuiListEditorScreen( + Component title, Screen lastScreen, boolean fixedEntryCount, Supplier> valuesSupplier, + Runnable loadDefaults, Consumer> save) + { + super(title, lastScreen); + this.fixedEntryCount = fixedEntryCount; + this.valuesSupplier = valuesSupplier; + this.loadDefaults = loadDefaults; + this.save = save; + } + + @Override + protected void addLowerButtons(int top) { + this.addRenderableWidget( + Button.builder(Component.translatable("vivecraft.gui.loaddefaults"), button -> { + this.loadDefaults.run(); + this.elements = null; + this.reinit = true; + }) + .bounds(this.width / 2 - 155, top, 150, 20) + .build()); + + this.addRenderableWidget( + Button.builder(Component.translatable("gui.back"), button -> this.onClose()) + .bounds(this.width / 2 + 5, top, 150, 20) + .build()); + } + + @Override + public void onClose() { + this.save.accept(this.elements); + super.onClose(); + } + + @SuppressWarnings("unchecked") + protected List getCurrentValues() { + return this.list.children().stream().map(entry -> { + if (entry instanceof ValueEntry valueEntry) { + return (T) valueEntry.getValue(); + } else { + return null; + } + }).filter(Objects::nonNull).collect(Collectors.toList()); + } + + @Override + protected List getEntries() { + List entries = new LinkedList<>(); + if (this.elements == null) { + this.elements = new ArrayList<>(this.valuesSupplier.get()); + } + int index = 0; + for (T item : this.elements) { + entries.add(this.toEntry(item, index++)); + } + + if (!this.fixedEntryCount) { + entries.add(new SettingsList.WidgetEntry(Component.literal(""), + Button.builder(Component.translatable("vivecraft.options.addnew"), button -> { + this.addNewValue(); + }).size(SettingsList.WidgetEntry.VALUE_BUTTON_WIDTH, 20).build())); + } + return entries; + } + + protected void addNewValue() { + this.elements = getCurrentValues(); + this.reinit = true; + } + + protected abstract ValueEntry toEntry(T value, int index); + + protected static abstract class ValueEntry extends SettingsList.BaseEntry { + public ValueEntry(Component name, Supplier tooltipSupplier) { + super(name, tooltipSupplier); + } + + public abstract T getValue(); + } +} diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiOrderedListEditorScreen.java b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiOrderedListEditorScreen.java new file mode 100644 index 000000000..b438571d2 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiOrderedListEditorScreen.java @@ -0,0 +1,109 @@ +package org.vivecraft.client.gui.framework.screens; + +import com.google.common.collect.ImmutableList; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.narration.NarratableEntry; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public abstract class GuiOrderedListEditorScreen extends GuiListEditorScreen { + + public GuiOrderedListEditorScreen( + Component title, Screen lastScreen, boolean fixedEntryCount, Supplier> valuesSupplier, + Runnable loadDefaults, Consumer> save) + { + super(title, lastScreen, fixedEntryCount, valuesSupplier, loadDefaults, save); + + // the underlying list is ordered, so can't filter it + this.searchable = false; + } + + private void moveEntry(int from, int offset, boolean remove) { + T value = this.elements.get(from); + this.elements.remove(from); + if (!remove) { + this.elements.add(Math.clamp(from + offset, 0, this.elements.size()), value); + } + this.reinit = true; + } + + protected class OrderedEntry extends ValueEntry { + + protected final T value; + + private final int index; + private final Button upButton; + private final Button downButton; + private final Button removeButton; + + public OrderedEntry(Component name, T value, int index) { + super(name, null); + this.value = value; + this.index = index; + this.upButton = Button.builder(Component.literal("\u2191"), + button -> moveEntry(index, -1, false)) + .bounds(0, 0, 20, 20).build(); + this.downButton = Button.builder(Component.literal("\u2193"), + button -> moveEntry(index, 1, false)) + .bounds(0, 0, 20, 20).build(); + this.removeButton = Button.builder(Component.literal("-"), + button -> moveEntry(index, 0, true)) + .bounds(0, 0, 20, 20).build(); + } + + @Override + public void renderContent( + GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) + { + super.renderContent(guiGraphics, mouseX, mouseY, hovering, partialTick); + + int textY = this.getY() + this.getHeight() / 2 - Minecraft.getInstance().font.lineHeight / 2 + 2; + guiGraphics.drawString(Minecraft.getInstance().font, this.name, this.getContentX(), textY, + this.textColor()); + + this.upButton.active = this.isActive() && this.index != 0; + this.downButton.active = + this.isActive() && this.index != GuiOrderedListEditorScreen.this.elements.size() - 1; + this.removeButton.active = this.isActive(); + + int i = 0; + for (GuiEventListener child : this.children()) { + Button b = (Button) child; + b.setX(this.getContentRight() - (2 - i) * 22 - 20); + b.setY(this.getContentY()); + b.render(guiGraphics, mouseX, mouseY, partialTick); + i++; + } + } + + @Override + public List narratables() { + return ImmutableList.of(this.upButton, this.downButton, this.removeButton); + } + + @Override + public List children() { + return ImmutableList.of(this.upButton, this.downButton, this.removeButton); + } + + @Override + public void setActive(boolean active) { + super.setActive(active); + this.upButton.active = active; + this.downButton.active = active; + this.removeButton.active = active; + } + + @Override + public T getValue() { + return this.value; + } + } +} diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiSelectionListScreen.java b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiSelectionListScreen.java index c1b316cba..a26dac78f 100644 --- a/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiSelectionListScreen.java +++ b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiSelectionListScreen.java @@ -19,6 +19,7 @@ public class GuiSelectionListScreen extends GuiListScreen { private final Function componentSupplier; private final Function categorySupplier; private final Consumer consumer; + private final boolean hasReset; private final boolean resettable; private final Function widgetSupplier; @@ -29,12 +30,13 @@ public class GuiSelectionListScreen extends GuiListScreen { * @param componentSupplier function that supplies a Component for the provided object to be able to show them in the list * @param categorySupplier function that supplies a translation string that is used for the category the given object is in * @param consumer called with the selected object, is called with {@code null} if it should reset + * @param hasReset determines if the reset/clear buton should show up * @param resettable when true, the left button will say 'reset', else 'clear' * @param widgetSupplier supplies an optional widget shown with the object */ public GuiSelectionListScreen( Component title, Screen lastScreen, Supplier> valuesSupplier, Function componentSupplier, - @Nullable Function categorySupplier, Consumer consumer, boolean resettable, + @Nullable Function categorySupplier, Consumer consumer, boolean hasReset, boolean resettable, @Nullable Function widgetSupplier) { super(title, lastScreen); @@ -42,25 +44,33 @@ public GuiSelectionListScreen( this.componentSupplier = componentSupplier; this.categorySupplier = categorySupplier != null ? categorySupplier : item -> ""; this.consumer = consumer; + this.hasReset = hasReset; this.resettable = resettable; this.widgetSupplier = widgetSupplier != null ? widgetSupplier : item -> null; } @Override protected void addLowerButtons(int top) { - this.addRenderableWidget( - new Button.Builder(Component.translatable(this.resettable ? "controls.reset" : "vivecraft.gui.clear"), - p -> { - this.consumer.accept(null); - this.onClose(); - }) - .bounds(this.width / 2 - 155, top, 150, 20) - .build()); + if (this.hasReset) { + this.addRenderableWidget( + new Button.Builder(Component.translatable(this.resettable ? "controls.reset" : "vivecraft.gui.clear"), + p -> { + this.consumer.accept(null); + this.onClose(); + }) + .bounds(this.width / 2 - 155, top, 150, 20) + .build()); - this.addRenderableWidget( - new Button.Builder(Component.translatable("gui.cancel"), p -> onClose()) - .bounds(this.width / 2 + 5, top, 150, 20) - .build()); + this.addRenderableWidget( + new Button.Builder(Component.translatable("gui.cancel"), p -> onClose()) + .bounds(this.width / 2 + 5, top, 150, 20) + .build()); + } else { + this.addRenderableWidget( + new Button.Builder(Component.translatable("gui.cancel"), p -> onClose()) + .bounds(this.width / 2 - 75, top, 150, 20) + .build()); + } } @Override diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiStringListEditorScreen.java b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiStringListEditorScreen.java index 17417963d..a1cb7ca87 100644 --- a/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiStringListEditorScreen.java +++ b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiStringListEditorScreen.java @@ -1,6 +1,7 @@ package org.vivecraft.client.gui.framework.screens; import com.google.common.collect.ImmutableList; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.EditBox; @@ -11,102 +12,42 @@ import net.minecraft.client.input.KeyEvent; import net.minecraft.network.chat.Component; import org.lwjgl.glfw.GLFW; -import org.vivecraft.client.gui.framework.widgets.SettingsList; -import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; import java.util.function.Consumer; import java.util.function.Supplier; -import java.util.stream.Collectors; -public class GuiStringListEditorScreen extends GuiListScreen { - - private final Supplier> valuesSupplier; - private final Runnable loadDefaults; - private final Consumer> save; - private final boolean fixedEntryCount; - - private List elements; +public class GuiStringListEditorScreen extends GuiListEditorScreen { public GuiStringListEditorScreen( Component title, Screen lastScreen, boolean fixedEntryCount, Supplier> valuesSupplier, Runnable loadDefaults, Consumer> save) { - super(title, lastScreen); - this.fixedEntryCount = fixedEntryCount; - this.valuesSupplier = valuesSupplier; - this.loadDefaults = loadDefaults; - this.save = save; + super(title, lastScreen, fixedEntryCount, valuesSupplier, loadDefaults, save); // can't search text boxes this.searchable = false; } @Override - protected void addLowerButtons(int top) { - this.addRenderableWidget( - Button.builder(Component.translatable("vivecraft.gui.loaddefaults"), button -> { - this.loadDefaults.run(); - this.elements = null; - this.reinit = true; - }) - .bounds(this.width / 2 - 155, top, 150, 20) - .build()); - - this.addRenderableWidget( - Button.builder(Component.translatable("gui.back"), button -> this.onClose()) - .bounds(this.width / 2 + 5, top, 150, 20) - .build()); - } - - @Override - public void onClose() { - this.save.accept(this.elements); - super.onClose(); - } - - private List getCurrentValues() { - return this.list.children().stream().map(entry -> { - if (entry instanceof StringValueEntry listValueEntry) { - return listValueEntry.getString(); - } else { - return ""; - } - }).filter(string -> !string.isEmpty()).collect(Collectors.toList()); + protected void addNewValue() { + super.addNewValue(); + this.elements.add(""); } @Override - protected List getEntries() { - List entries = new LinkedList<>(); - if (this.elements == null) { - this.elements = new ArrayList<>(this.valuesSupplier.get()); - } - int i = 0; - for (String item : this.elements) { - EditBox box = new EditBox(this.minecraft.font, 0, 0, 350, 20, Component.literal(item)); - box.setMaxLength(1000); - box.setValue(item); - int index = i++; - box.setResponder(s -> this.elements.set(index, s)); - entries.add(new StringValueEntry(Component.empty(), box, button -> { - this.elements.remove(index); - this.reinit = true; - }, !this.fixedEntryCount)); - } - - if (!this.fixedEntryCount) { - entries.add(new SettingsList.WidgetEntry(Component.literal(""), - Button.builder(Component.translatable("vivecraft.options.addnew"), button -> { - this.elements = getCurrentValues(); - this.elements.add(""); - this.reinit = true; - }).size(SettingsList.WidgetEntry.VALUE_BUTTON_WIDTH, 20).build())); - } - return entries; + protected ValueEntry toEntry(String value, int index) { + EditBox box = new EditBox(Minecraft.getInstance().font, 0, 0, 350, 20, Component.literal(value)); + box.setMaxLength(1000); + box.setValue(value); + box.setResponder(s -> this.elements.set(index, s)); + return new StringValueEntry(Component.empty(), box, button -> { + this.elements.remove(index); + this.reinit = true; + }, !this.fixedEntryCount); } - private static class StringValueEntry extends SettingsList.BaseEntry { + private static class StringValueEntry extends ValueEntry { private final EditBox editBox; private final Button deleteButton; @@ -162,7 +103,7 @@ public void setActive(boolean active) { this.deleteButton.active = active; } - public String getString() { + public String getValue() { return this.editBox.getValue(); } } diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/widgets/ColorPicker.java b/common/src/main/java/org/vivecraft/client/gui/framework/widgets/ColorPicker.java new file mode 100644 index 000000000..60ddd932b --- /dev/null +++ b/common/src/main/java/org/vivecraft/client/gui/framework/widgets/ColorPicker.java @@ -0,0 +1,107 @@ +package org.vivecraft.client.gui.framework.widgets; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.input.MouseButtonEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.util.ARGB; +import org.vivecraft.client_vr.utils.RGBAColor; + +public class ColorPicker extends AbstractWidget { + + private static final int HUE_WIDTH = 10; + + private float hue; + private float saturation = 0F; + private float brightness = 1F; + + private boolean clickedHue; + + public ColorPicker(int x, int y, int width, int height) { + super(x, y, width, height, Component.literal("Color Picker")); + } + + @Override + protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + // black background + guiGraphics.fill(this.getX(), this.getY(), this.getX() + this.width, this.getY() + this.height, + 0xFF000000); + + for (int i = 0; i < this.height - 2; i++) { + RGBAColor color = RGBAColor.fromHSB(i / (float) (this.height - 2), 1F, 1F); + guiGraphics.fill(this.getX() + 1, this.getY() + i + 1, this.getX() + HUE_WIDTH - 1, + this.getY() + i + 2, ARGB.colorFromFloat(1F, color.r, color.g, color.b)); + } + for (int x = HUE_WIDTH; x < this.width - 2; x++) { + for (int y = 0; y < this.height - 2; y++) { + RGBAColor color = RGBAColor.fromHSB(this.hue, (x - HUE_WIDTH) / (float) (this.width - HUE_WIDTH - 2), + 1F - y / (float) (this.height - 3)); + int xPos = this.getX() + x + 1; + int yPos = this.getY() + y + 1; + + guiGraphics.fill(xPos, yPos, xPos + 1, yPos + 1, ARGB.colorFromFloat(1F, color.r, color.g, color.b)); + } + } + + int satX = (int) (this.getX() + HUE_WIDTH + 1 + this.saturation * (this.width - HUE_WIDTH - 3)); + int satY = (int) (this.getY() + 1 + (1F - this.brightness) * (this.height - 3)); + guiGraphics.submitOutline(satX - 2, satY - 2, 5, 5, 0xFFFFFFFF); + + int hueY = (int) (this.getY() + 1 + this.hue * (this.height - 3)); + guiGraphics.submitOutline(this.getX(), hueY - 2, HUE_WIDTH, 5, 0xFFFFFFFF); + } + + @Override + public void onClick(MouseButtonEvent event, boolean isDoubleClick) { + this.clickedHue = event.x() < this.getX() + HUE_WIDTH; + this.setColor(event.x(), event.y()); + } + + @Override + protected void onDrag(MouseButtonEvent event, double mouseX, double mouseY) { + this.setColor(event.x(), event.y()); + } + + private void setColor(double mouseX, double mouseY) { + if (this.clickedHue) { + this.hue = (float) Math.clamp((mouseY - (this.getY() + 1)) / (this.height - 2), 0.0, 1.0); + } else { + this.brightness = 1F - (float) Math.clamp((mouseY - this.getY() - 1) / (this.height - 2), 0.0, 1.0); + this.saturation = (float) Math.clamp( + (mouseX - this.getX() - HUE_WIDTH - 1) / (this.getWidth() - HUE_WIDTH - 2), + 0.0, 1.0); + } + } + + @Override + protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) { + this.defaultButtonNarrationText(narrationElementOutput); + } + + public RGBAColor getColor() { + return RGBAColor.fromHSB(this.hue, this.saturation, this.brightness); + } + + public void setColor(RGBAColor color) { + float max = Math.max(color.r, Math.max(color.g, color.b)); + float min = Math.min(color.r, Math.min(color.g, color.b)); + float dif = max - min; + + this.brightness = max; + this.saturation = max == 0 ? 0 : dif / max; + if (dif == 0.0F) { + this.hue = 0; + return; + } + if (max == color.r) { + this.hue = (color.g - color.b) / dif; + } else if (max == color.g) { + this.hue = 2 + (color.b - color.r) / dif; + } else { + this.hue = 4 + (color.r - color.g) / dif; + } + this.hue *= 60F; + this.hue = ((this.hue + 360F) % 360F) / 360F; + } +} diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/widgets/ColoredButton.java b/common/src/main/java/org/vivecraft/client/gui/framework/widgets/ColoredButton.java new file mode 100644 index 000000000..4d1b852aa --- /dev/null +++ b/common/src/main/java/org/vivecraft/client/gui/framework/widgets/ColoredButton.java @@ -0,0 +1,43 @@ +package org.vivecraft.client.gui.framework.widgets; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.WidgetSprites; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.ARGB; +import org.vivecraft.client_vr.utils.RGBAColor; + +/** + * Button that has a color tint + */ +public class ColoredButton extends Button { + + // copied over from AbstractButton + private static final WidgetSprites SPRITES = new WidgetSprites( + ResourceLocation.withDefaultNamespace("widget/button"), + ResourceLocation.withDefaultNamespace("widget/button_disabled"), + ResourceLocation.withDefaultNamespace("widget/button_highlighted")); + + private final RGBAColor color = new RGBAColor(); + + public ColoredButton(Component message, int x, int y, int width, int height, OnPress onPress) { + super(x, y, width, height, message, onPress, Button.DEFAULT_NARRATION); + } + + public RGBAColor getColor() { + return this.color; + } + + @Override + protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + Minecraft minecraft = Minecraft.getInstance(); + guiGraphics.blitSprite(RenderPipelines.GUI_TEXTURED, SPRITES.get(this.active, this.isHoveredOrFocused()), + this.getX(), this.getY(), this.getWidth(), this.getHeight(), + ARGB.colorFromFloat(this.alpha, this.color.r, this.color.g, this.color.b)); + int i = ARGB.color(this.alpha, this.active ? 0xFFFFFFFF : 0xFFA0A0A0); + this.renderString(guiGraphics, minecraft.font, i); + } +} diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/widgets/ColoredKeyButton.java b/common/src/main/java/org/vivecraft/client/gui/framework/widgets/ColoredKeyButton.java new file mode 100644 index 000000000..9c5e7a2aa --- /dev/null +++ b/common/src/main/java/org/vivecraft/client/gui/framework/widgets/ColoredKeyButton.java @@ -0,0 +1,50 @@ +package org.vivecraft.client.gui.framework.widgets; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.input.InputWithModifiers; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.gui.keyboard.KeyboardKeys; +import org.vivecraft.client_vr.gui.keyboard.KeyboardTheme; + +/** + * Button that has a color tint that his linked to the keyboard key + */ +public class ColoredKeyButton extends ColoredButton { + + private final KeyboardKeys.Key key; + private final ClientDataHolderVR dh; + + private final KeyboardTheme keyboardTheme; + + public ColoredKeyButton(KeyboardKeys.Key key, int x, int y, int width, int height) { + this(key, x, y, width, height, null, null); + } + + public ColoredKeyButton( + KeyboardKeys.Key key, int x, int y, int width, int height, OnPress onPress, KeyboardTheme keyboardTheme) + { + super(key.label(), x, y, width, height, onPress); + this.key = key; + this.dh = ClientDataHolderVR.getInstance(); + this.keyboardTheme = keyboardTheme; + } + + @Override + public void onPress(InputWithModifiers input) { + if (this.onPress != null) { + super.onPress(input); + } else { + this.key.onPress().run(); + this.key.onRelease().run(); + } + } + + @Override + protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + KeyboardTheme theme = + this.keyboardTheme != null ? this.keyboardTheme : this.dh.vrSettings.physicalKeyboardTheme; + theme.theme.updateColor(this.getColor(), this.key.id(), this.key.x(), + this.key.y()); + super.renderWidget(guiGraphics, mouseX, mouseY, partialTick); + } +} diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiActiveKeyboardLayoutSelector.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiActiveKeyboardLayoutSelector.java new file mode 100644 index 000000000..dc123c7df --- /dev/null +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiActiveKeyboardLayoutSelector.java @@ -0,0 +1,81 @@ +package org.vivecraft.client.gui.settings; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.resources.language.LanguageInfo; +import net.minecraft.network.chat.Component; +import org.vivecraft.client.gui.framework.screens.GuiOrderedListEditorScreen; +import org.vivecraft.client.gui.framework.screens.GuiSelectionListScreen; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; +import org.vivecraft.client_vr.settings.VRSettings; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class GuiActiveKeyboardLayoutSelector extends GuiOrderedListEditorScreen { + public GuiActiveKeyboardLayoutSelector(Screen lastScreen) { + super(Component.translatable("vivecraft.options.screen.activekeyboardlayouts"), + lastScreen, false, + () -> Arrays.stream(ClientDataHolderVR.getInstance().vrSettings.keyboardLayoutOrder) + .map(l -> ClientDataHolderVR.getInstance().vrSettings.keyboardLayouts.get(l)).toList(), + () -> { + VRSettings vrSettings = ClientDataHolderVR.getInstance().vrSettings; + vrSettings.currentKeyboardLayout = 0; + vrSettings.keyboardLayoutOrder = new String[]{"custom", "en_us"}; + vrSettings.saveOptions(); + }, keyboardLayouts -> { + VRSettings vrSettings = ClientDataHolderVR.getInstance().vrSettings; + vrSettings.currentKeyboardLayout = 0; + vrSettings.keyboardLayoutOrder = keyboardLayouts.stream().map(VRSettings.KeyboardLayout::id) + .toArray(String[]::new); + vrSettings.saveOptions(); + }); + } + + @Override + public void onClose() { + super.onClose(); + KeyboardHandler.reinitKeyboard(); + } + + @Override + protected void addNewValue() { + this.minecraft.setScreen(getSelectionScreen(this, + layout -> this.elements.stream().noneMatch(e -> e.id().equals(layout.id())), + layout -> { + super.addNewValue(); + this.elements.add(layout); + }, false)); + } + + @Override + protected ValueEntry toEntry(VRSettings.KeyboardLayout value, int index) { + return new KeyboardEntry(value, index); + } + + public static GuiSelectionListScreen getSelectionScreen( + Screen parent, Predicate filter, Consumer consumer, + boolean hasReset) + { + return new GuiSelectionListScreen<>( + Component.translatable("vivecraft.options.screen.keyboardlayoutselection"), parent, + () -> ClientDataHolderVR.getInstance().vrSettings.keyboardLayouts.values().stream().filter(filter) + .sorted(Comparator.comparing(key -> getLangComponent(key).getString())).toList(), + GuiActiveKeyboardLayoutSelector::getLangComponent, + null, consumer, hasReset, true, null); + } + + private class KeyboardEntry extends OrderedEntry { + public KeyboardEntry(VRSettings.KeyboardLayout layout, int index) { + super(getLangComponent(layout), layout, index); + } + } + + private static Component getLangComponent(VRSettings.KeyboardLayout layout) { + LanguageInfo info = Minecraft.getInstance().getLanguageManager().getLanguages().get(layout.id()); + return info != null ? info.toComponent() : layout.fallbackName(); + } +} diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiChatNotificationSelection.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiChatNotificationSelection.java index ffeb6d002..991dd9b53 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiChatNotificationSelection.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiChatNotificationSelection.java @@ -36,7 +36,7 @@ public GuiChatNotificationSelection(Screen lastScreen) { } ClientDataHolderVR.getInstance().vrSettings.saveOptions(); }, - true, + true, true, resourceLocation -> new SilentButton(Component.literal("♫"), b -> BuiltInRegistries.SOUND_EVENT.get(resourceLocation) .ifPresent(soundEvent -> startSound(soundEvent.value(), b)), diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiKeyboardLayoutEditor.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiKeyboardLayoutEditor.java new file mode 100644 index 000000000..833401c82 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiKeyboardLayoutEditor.java @@ -0,0 +1,164 @@ +package org.vivecraft.client.gui.settings; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.input.CharacterEvent; +import net.minecraft.network.chat.Component; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; +import org.vivecraft.client_vr.gui.keyboard.KeyboardKeys; +import org.vivecraft.client_vr.settings.VRSettings; + +public class GuiKeyboardLayoutEditor extends Screen { + + private final Screen parent; + private boolean isShift = false; + private boolean reinit = false; + + protected GuiKeyboardLayoutEditor(Screen parent) { + super(Component.translatable("vivecraft.options.screen.customkeyboardeditor")); + this.parent = parent; + } + + @Override + public void init() { + ClientDataHolderVR dh = ClientDataHolderVR.getInstance(); + this.clearWidgets(); + + KeyboardKeys.Layout layout = KeyboardKeys.getRegularKeys( + dh.vrSettings.keyboardLayouts.get("custom"), this.isShift, () -> {}); + + int spacing = 2; + int buttonWidth = (int) (25 * Math.min(this.width / ((25F + spacing) * (layout.columns() + 5F)), 1F)); + + int yMargin = 32 + this.height / 2 - (int) ((layout.rows() + 3F) / 2F * (20 + spacing)); + int xMargin = this.width / 2 - ((buttonWidth + spacing) * (layout.columns() + 5)) / 2; + + for (KeyboardKeys.Key key : layout.keys()) { + int y = key.y() < 0 ? layout.rows() - key.y() : key.y(); + EditBox box = new EditBox(this.font, + xMargin + key.x() * (buttonWidth + spacing), yMargin + (y - 1) * (20 + spacing), + buttonWidth, 20, Component.empty()) + { + @Override + public boolean charTyped(CharacterEvent event) { + this.setValue(""); + return super.charTyped(event); + } + }; + box.setValue(key.label().getString()); + box.setMaxLength(1); + box.setCentered(true); + box.setResponder(s -> { + char newChar = s.isEmpty() ? '\u0000' : s.charAt(0); + if (this.isShift) { + char[] array = dh.vrSettings.keyboardKeysShift.toCharArray(); + array[key.id() - 500] = newChar; + dh.vrSettings.keyboardKeysShift = new String(array); + } else { + char[] array = dh.vrSettings.keyboardKeys.toCharArray(); + array[key.id()] = newChar; + dh.vrSettings.keyboardKeys = new String(array); + } + dh.vrSettings.saveOptions(); + KeyboardHandler.reinitKeyboard(); + }); + + this.addRenderableWidget(box); + } + + for (KeyboardKeys.Key key : KeyboardKeys.getSpecialKeys()) { + if (key.id() == KeyboardKeys.SHIFT_2.id()) { + continue; + } + int y = key.y() < 0 ? layout.rows() - key.y() : key.y(); + this.addRenderableWidget(new Button.Builder(key.label(), p -> { + if (key.isShift()) { + this.setShift(!this.isShift); + } + }) + .size(key.width() * buttonWidth + (key.width() - 1) * spacing, 20) + .pos(xMargin + key.x() * (buttonWidth + spacing), yMargin + (y - 1) * (20 + spacing)) + .build()).active = key.id() == KeyboardKeys.SHIFT_1.id(); + } + + this.addRenderableWidget(new Button.Builder(Component.literal("+"), p -> { + if (this.isShift) { + dh.vrSettings.keyboardKeysShift += "\u0000".repeat(layout.columns()); + } else { + dh.vrSettings.keyboardKeys += "\u0000".repeat(layout.columns()); + } + dh.vrSettings.saveOptions(); + this.reinit = true; + KeyboardHandler.reinitKeyboard(); + }) + .size(buttonWidth, 20) + .pos((layout.columns() + 2) * (buttonWidth + spacing) + xMargin, yMargin + 3 * (20 + spacing)) + .tooltip(Tooltip.create(Component.translatable("vivecraft.options.screen.addkeyboardrow.tooltip"))) + .build()).active = layout.rows() < KeyboardKeys.MAX_ROWS; + + this.addRenderableWidget(new Button.Builder(Component.literal("-"), p -> { + if (this.isShift) { + dh.vrSettings.keyboardKeysShift = dh.vrSettings.keyboardKeysShift.substring(0, + dh.vrSettings.keyboardKeysShift.length() - layout.columns()); + } else { + dh.vrSettings.keyboardKeys = dh.vrSettings.keyboardKeys.substring(0, + dh.vrSettings.keyboardKeys.length() - layout.columns()); + } + dh.vrSettings.saveOptions(); + this.reinit = true; + KeyboardHandler.reinitKeyboard(); + }) + .size(buttonWidth, 20) + .pos((layout.columns() + 3) * (buttonWidth + spacing) + xMargin, yMargin + 3 * (20 + spacing)) + .tooltip(Tooltip.create(Component.translatable("vivecraft.options.screen.removekeyboardrow.tooltip"))) + .build()).active = layout.rows() > KeyboardKeys.ROWS; + + this.addRenderableWidget(new Button.Builder( + Component.translatable("vivecraft.options.screen.loadkeyboardlayout.button"), button -> + this.minecraft.setScreen(GuiActiveKeyboardLayoutSelector.getSelectionScreen(this, + keyboard -> !keyboard.id().equals("custom"), + keyboard -> { + VRSettings.KeyboardLayout newLayout = + keyboard == null ? dh.vrSettings.keyboardLayouts.get("en_us") : keyboard; + dh.vrSettings.keyboardKeys = newLayout.regular().get(); + dh.vrSettings.keyboardKeysShift = newLayout.shift().get(); + dh.vrSettings.saveOptions(); + this.reinit = true; + this.isShift = false; + KeyboardHandler.reinitKeyboard(); + }, true))) + .bounds(this.width / 2 - 155, this.height - 30, 150, 20) + .build()); + + this.addRenderableWidget( + new Button.Builder(Component.translatable("gui.back"), p -> onClose()) + .bounds(this.width / 2 + 5, this.height - 30, 150, 20) + .build()); + } + + private void setShift(boolean shift) { + if (shift != this.isShift) { + this.isShift = shift; + this.reinit = true; + } + } + + @Override + public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + if (this.reinit) { + this.init(); + this.reinit = false; + } + guiGraphics.drawCenteredString(this.font, this.getTitle(), this.width / 2, 15, 0xFFFFFFFF); + super.render(guiGraphics, mouseX, mouseY, partialTick); + } + + @Override + public void onClose() { + this.minecraft.setScreen(this.parent); + } +} diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiKeyboardSettings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiKeyboardSettings.java index bde5a4573..41792de99 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiKeyboardSettings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiKeyboardSettings.java @@ -1,23 +1,34 @@ package org.vivecraft.client.gui.settings; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; -import org.vivecraft.api.client.data.CloseKeyboardContext; import org.vivecraft.client.gui.framework.VROptionEntry; import org.vivecraft.client.gui.framework.screens.GuiVROptionsBase; -import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.settings.VRSettings; public class GuiKeyboardSettings extends GuiVROptionsBase { - private static final VROptionEntry[] KEYBOARD_OPTIONS = new VROptionEntry[]{ - new VROptionEntry(VRSettings.VrOptions.PHYSICAL_KEYBOARD, (button, mousePos) -> { - KeyboardHandler.hideOverlay(CloseKeyboardContext.FORCE); - return false; - }), + private final VROptionEntry[] keyboardOptions = new VROptionEntry[]{ + new VROptionEntry(VRSettings.VrOptions.PHYSICAL_KEYBOARD), new VROptionEntry(VRSettings.VrOptions.KEYBOARD_PRESS_BINDS), new VROptionEntry(VRSettings.VrOptions.AUTO_OPEN_KEYBOARD), new VROptionEntry(VRSettings.VrOptions.AUTO_CLOSE_KEYBOARD), new VROptionEntry(VRSettings.VrOptions.PHYSICAL_KEYBOARD_SCALE), - new VROptionEntry(VRSettings.VrOptions.PHYSICAL_KEYBOARD_THEME) + new VROptionEntry(VRSettings.VrOptions.PHYSICAL_KEYBOARD_THEME), + new VROptionEntry( + "vivecraft.options.screen.customkeyboardeditor.button", (button, mousePos) -> { + Minecraft.getInstance().setScreen(new GuiKeyboardLayoutEditor(this)); + return true; + }), + new VROptionEntry( + "vivecraft.options.screen.customkeyboardthemeeditor.button", (button, mousePos) -> { + Minecraft.getInstance().setScreen(new GuiKeyboardThemeEditor(this)); + return true; + }), + new VROptionEntry( + "vivecraft.options.screen.activekeyboardlayouts.button", (button, mousePos) -> { + Minecraft.getInstance().setScreen(new GuiActiveKeyboardLayoutSelector(this)); + return true; + }) }; public GuiKeyboardSettings(Screen lastScreen) { @@ -27,7 +38,7 @@ public GuiKeyboardSettings(Screen lastScreen) { @Override public void init() { this.vrTitle = "vivecraft.options.screen.keyboard"; - super.init(KEYBOARD_OPTIONS, true); + super.init(this.keyboardOptions, true); super.addDefaultButtons(); } diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiKeyboardThemeEditor.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiKeyboardThemeEditor.java new file mode 100644 index 000000000..351ab1da1 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiKeyboardThemeEditor.java @@ -0,0 +1,130 @@ +package org.vivecraft.client.gui.settings; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.CycleButton; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import org.vivecraft.client.gui.framework.screens.GuiSelectionListScreen; +import org.vivecraft.client.gui.framework.widgets.ColorPicker; +import org.vivecraft.client.gui.framework.widgets.ColoredButton; +import org.vivecraft.client.gui.framework.widgets.ColoredKeyButton; +import org.vivecraft.client_vr.gui.keyboard.CustomKeyboardTheme; +import org.vivecraft.client_vr.gui.keyboard.KeyboardKeys; +import org.vivecraft.client_vr.gui.keyboard.KeyboardTheme; + +import java.util.Arrays; + +public class GuiKeyboardThemeEditor extends Screen { + + private final Screen parent; + private boolean isShift = false; + private boolean reinit = false; + + private final CustomKeyboardTheme customTheme = (CustomKeyboardTheme) KeyboardTheme.CUSTOM.theme; + + private final ColorPicker colorPicker; + + protected GuiKeyboardThemeEditor(Screen parent) { + super(Component.translatable("vivecraft.options.screen.customkeyboardthemeeditor")); + this.parent = parent; + this.colorPicker = new ColorPicker(0, 0, 50, 40); + } + + @Override + public void init() { + this.clearWidgets(); + + KeyboardKeys.Layout layout = KeyboardKeys.getRegularKeys(this.isShift, () -> {}); + this.customTheme.reload(); + + int spacing = 2; + int buttonWidth = (int) (25 * Math.min(this.width / ((25F + spacing) * (layout.columns() + 5F)), 1F)); + + int yMargin = 32 + this.height / 2 - (int) ((layout.rows() + 3F) / 2F * (20 + spacing)); + int xMargin = this.width / 2 - ((buttonWidth + spacing) * (layout.columns() + 5)) / 2; + + this.colorPicker.setPosition(xMargin + (buttonWidth + spacing) * 15, yMargin - 42); + this.addRenderableWidget(this.colorPicker); + + for (KeyboardKeys.Key key : layout.keys()) { + int y = key.y() < 0 ? layout.rows() - key.y() : key.y(); + this.addRenderableWidget(new ColoredKeyButton(key, + xMargin + key.x() * (buttonWidth + spacing), yMargin + (y - 1) * (20 + spacing), + buttonWidth, 20, b -> { + if (Minecraft.getInstance().hasShiftDown()) { + this.colorPicker.setColor(((ColoredButton) b).getColor()); + } else { + this.customTheme.setColor(key.id(), this.colorPicker.getColor()); + this.customTheme.save(); + } + }, KeyboardTheme.CUSTOM)); + } + + for (KeyboardKeys.Key key : KeyboardKeys.getSpecialKeys()) { + int y = key.y() < 0 ? layout.rows() - key.y() : key.y(); + this.addRenderableWidget(new ColoredKeyButton(key, + xMargin + key.x() * (buttonWidth + spacing), yMargin + (y - 1) * (20 + spacing), + key.width() * buttonWidth + (key.width() - 1) * spacing, 20, b -> { + if (Minecraft.getInstance().hasShiftDown()) { + this.colorPicker.setColor(((ColoredButton) b).getColor()); + } else { + this.customTheme.setColor(key.id(), this.colorPicker.getColor()); + this.customTheme.save(); + } + }, KeyboardTheme.CUSTOM)); + } + + this.addRenderableWidget( + CycleButton.onOffBuilder(this.isShift) + .create(xMargin + 12 * (buttonWidth + spacing), yMargin - (20 + spacing), + 3 * buttonWidth + 2 * spacing, 20, + Component.translatable("vivecraft.keyboard.key.shift"), + (p, b) -> this.setShift(!this.isShift))); + + this.addRenderableWidget( + new Button.Builder( + Component.translatable("vivecraft.options.screen.loadkeyboardtheme.button"), button -> + this.minecraft.setScreen(new GuiSelectionListScreen<>( + Component.translatable("vivecraft.options.screen.loadkeyboardtheme"), this, + () -> Arrays.stream(KeyboardTheme.values()).filter(t -> t != KeyboardTheme.CUSTOM).toList(), + theme -> Component.translatable(theme.getLangKey()), + null, + theme -> { + this.customTheme.load(theme == null ? KeyboardTheme.DEFAULT : theme); + this.customTheme.save(); + }, true, true, null))) + .bounds(this.width / 2 - 155, this.height - 30, 150, 20) + .build()); + + this.addRenderableWidget( + new Button.Builder(Component.translatable("gui.back"), p -> onClose()) + .bounds(this.width / 2 + 5, this.height - 30, 150, 20) + .build()); + } + + private void setShift(boolean shift) { + if (shift != this.isShift) { + this.isShift = shift; + this.reinit = true; + } + } + + @Override + public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + if (this.reinit) { + this.init(); + this.reinit = false; + } + guiGraphics.drawCenteredString(this.font, this.getTitle(), this.width / 2, 15, 0xFFFFFFFF); + super.render(guiGraphics, mouseX, mouseY, partialTick); + guiGraphics.drawCenteredString(this.font, Component.translatable("vivecraft.messages.shifttopickcolor"), + this.width / 2, 30, 0xFFFFFFFF); + } + + @Override + public void onClose() { + this.minecraft.setScreen(this.parent); + } +} diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiRadialConfiguration.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiRadialConfiguration.java index d1f5daad4..939f8365a 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiRadialConfiguration.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiRadialConfiguration.java @@ -96,7 +96,7 @@ public void init() { key -> { this.selectedIndex = index; this.setKey(key); - }, false, null + }, true, false, null )); }, index, centerX, centerY)); } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/KeyboardHandler.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/KeyboardHandler.java index 4f172a668..19ecc0e72 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/KeyboardHandler.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/KeyboardHandler.java @@ -87,6 +87,16 @@ public static boolean setOverlayShowing(boolean showingState) { return SHOWING; } + public static void reinitKeyboard() { + if (SHOWING) { + if (DH.vrSettings.physicalKeyboard) { + PHYSICAL_KEYBOARD.show(); + } else { + UI.init(); + } + } + } + public static void processGui() { POINTED_L = false; POINTED_R = false; diff --git a/common/src/main/java/org/vivecraft/client_vr/gui/GuiKeyboard.java b/common/src/main/java/org/vivecraft/client_vr/gui/GuiKeyboard.java index ac16dcfd6..7f1f5f9f9 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gui/GuiKeyboard.java +++ b/common/src/main/java/org/vivecraft/client_vr/gui/GuiKeyboard.java @@ -1,182 +1,51 @@ package org.vivecraft.client_vr.gui; import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.Button; -import net.minecraft.network.chat.Component; -import org.lwjgl.glfw.GLFW; import org.vivecraft.client.gui.framework.screens.TwoHandedScreen; -import org.vivecraft.client_vr.provider.InputSimulator; +import org.vivecraft.client.gui.framework.widgets.ColoredKeyButton; +import org.vivecraft.client_vr.gui.keyboard.KeyboardKeys; public class GuiKeyboard extends TwoHandedScreen { private boolean isShift = false; @Override public void init() { - String keys = this.dh.vrSettings.keyboardKeys; - String shiftKeys = this.dh.vrSettings.keyboardKeysShift; this.clearWidgets(); - if (this.isShift) { - keys = shiftKeys; - } + KeyboardKeys.Layout layout = KeyboardKeys.getRegularKeys(this.isShift, () -> {}); - int columns = 13; - int rows; int margin = 32; int spacing = 2; int buttonWidth = 25; - double rowsD = (double) keys.length() / (double) columns; - - if (Math.floor(rowsD) == rowsD) { - rows = (int) rowsD; - } else { - rows = (int) (rowsD + 1.0D); - } + int specialWidth = 30; - for (int row = 0; row < rows; row++) { - for (int column = 0; column < columns; column++) { - int index = row * columns + column; - char buttonChar = ' '; + int offset = specialWidth - (buttonWidth * 2 + spacing); - if (index < keys.length()) { - buttonChar = keys.charAt(index); - } + for (KeyboardKeys.Key key : layout.keys()) { + int y = key.y() < 0 ? layout.rows() - key.y() : key.y(); + this.addRenderableWidget(new ColoredKeyButton(key, + key.x() * (buttonWidth + spacing) + offset, + margin + (y - 1) * (20 + spacing), buttonWidth, 20)); + } - String label = String.valueOf(buttonChar); - final int code = index < this.dh.vrSettings.keyboardCodes.length ? - this.dh.vrSettings.keyboardCodes[index] : GLFW.GLFW_KEY_UNKNOWN; - this.addRenderableWidget(new Button.Builder(Component.literal(label), - (p) -> { - InputSimulator.pressKeyForBind(code); - InputSimulator.releaseKeyForBind(code); - InputSimulator.typeChars(label); - }) - .size(buttonWidth, 20) - .pos(margin + column * (buttonWidth + spacing), margin + row * (20 + spacing)) - .build()); + for (KeyboardKeys.Key key : KeyboardKeys.getSpecialKeys(() -> this.setShift(!this.isShift))) { + if (key.width() == 1) { + // the arrow keys are on a different spot in the gui keyboard + key = new KeyboardKeys.Key(key.id(), key.x() - 2, key.y() + layout.rows() - KeyboardKeys.ROWS, + key.width(), key.height(), key.label(), key.onPress(), key.onRelease()); + } + int y = key.y() < 0 ? layout.rows() - key.y() : key.y(); + int xPos = (key.x() > 0 ? offset : 0) + key.x() * (buttonWidth + spacing); + int width = key.x() == 0 ? specialWidth : key.width() * buttonWidth + (key.width() - 1) * spacing; + // don't let buttons go offscreen + if (xPos + width > this.width) { + width -= xPos + width - this.width; } + this.addRenderableWidget(new ColoredKeyButton(key, + xPos, margin + (y - 1) * (20 + spacing), + width, 20)); } - - this.addRenderableWidget(new Button.Builder(Component.literal("Shift"), - (p) -> this.setShift(!this.isShift)) - .size(30, 20) - .pos(0, margin + 3 * (20 + spacing)) - .build()); - - this.addRenderableWidget(new Button.Builder(Component.literal(" "), - (p) -> { - InputSimulator.pressKeyForBind(GLFW.GLFW_KEY_SPACE); - InputSimulator.releaseKeyForBind(GLFW.GLFW_KEY_SPACE); - InputSimulator.typeChars(" "); - }) - .size(5 * (buttonWidth + spacing), 20) - .pos(margin + 4 * (buttonWidth + spacing), margin + rows * (20 + spacing)) - .build()); - - this.addRenderableWidget(new Button.Builder(Component.literal("BKSP"), - (p) -> { - InputSimulator.pressKey(GLFW.GLFW_KEY_BACKSPACE); - InputSimulator.releaseKey(GLFW.GLFW_KEY_BACKSPACE); - }) - .size(35, 20) - .pos(columns * (buttonWidth + spacing) + margin, margin) - .build()); - - this.addRenderableWidget(new Button.Builder(Component.literal("ENTER"), - (p) -> { - InputSimulator.pressKey(GLFW.GLFW_KEY_ENTER); - InputSimulator.releaseKey(GLFW.GLFW_KEY_ENTER); - }) - .size(35, 20) - .pos(columns * (buttonWidth + spacing) + margin, margin + 2 * (20 + spacing)) - .build()); - - this.addRenderableWidget(new Button.Builder(Component.literal("TAB"), - (p) -> { - InputSimulator.pressKey(GLFW.GLFW_KEY_TAB); - InputSimulator.releaseKey(GLFW.GLFW_KEY_TAB); - }) - .size(30, 20) - .pos(0, margin + 20 + spacing) - .build()); - - this.addRenderableWidget(new Button.Builder(Component.literal("ESC"), - (p) -> { - InputSimulator.pressKey(GLFW.GLFW_KEY_ESCAPE); - InputSimulator.releaseKey(GLFW.GLFW_KEY_ESCAPE); - }) - .size(30, 20) - .pos(0, margin) - .build()); - - this.addRenderableWidget(new Button.Builder(Component.literal("\u2191"), - (p) -> { - InputSimulator.pressKey(GLFW.GLFW_KEY_UP); - InputSimulator.releaseKey(GLFW.GLFW_KEY_UP); - }) - .size(buttonWidth, 20) - .pos((columns - 1) * (buttonWidth + spacing) + margin, margin + rows * (20 + spacing)) - .build()); - - this.addRenderableWidget(new Button.Builder(Component.literal("\u2193"), - (p) -> { - InputSimulator.pressKey(GLFW.GLFW_KEY_DOWN); - InputSimulator.releaseKey(GLFW.GLFW_KEY_DOWN); - }) - .size(buttonWidth, 20) - .pos((columns - 1) * (buttonWidth + spacing) + margin, margin + (rows + 1) * (20 + spacing)) - .build()); - - this.addRenderableWidget(new Button.Builder(Component.literal("\u2190"), - (p) -> { - InputSimulator.pressKey(GLFW.GLFW_KEY_LEFT); - InputSimulator.releaseKey(GLFW.GLFW_KEY_LEFT); - }) - .size(buttonWidth, 20) - .pos((columns - 2) * (buttonWidth + spacing) + margin, margin + (rows + 1) * (20 + spacing)) - .build()); - - this.addRenderableWidget(new Button.Builder(Component.literal("\u2192"), - (p) -> { - InputSimulator.pressKey(GLFW.GLFW_KEY_RIGHT); - InputSimulator.releaseKey(GLFW.GLFW_KEY_RIGHT); - }) - .size(buttonWidth, 20) - .pos(columns * (buttonWidth + spacing) + margin, margin + (rows + 1) * (20 + spacing)) - .build()); - - this.addRenderableWidget(new Button.Builder(Component.literal("CUT"), - (p) -> { - InputSimulator.pressKey(GLFW.GLFW_KEY_LEFT_CONTROL); - InputSimulator.pressKey(GLFW.GLFW_KEY_X); - InputSimulator.releaseKey(GLFW.GLFW_KEY_X); - InputSimulator.releaseKey(GLFW.GLFW_KEY_LEFT_CONTROL); - }) - .size(35, 20) - .pos(margin, margin + -1 * (20 + spacing)) - .build()); - - this.addRenderableWidget(new Button.Builder(Component.literal("COPY"), - (p) -> { - InputSimulator.pressKey(GLFW.GLFW_KEY_LEFT_CONTROL); - InputSimulator.pressKey(GLFW.GLFW_KEY_C); - InputSimulator.releaseKey(GLFW.GLFW_KEY_C); - InputSimulator.releaseKey(GLFW.GLFW_KEY_LEFT_CONTROL); - }) - .size(35, 20) - .pos(35 + spacing + margin, margin + -1 * (20 + spacing)) - .build()); - - this.addRenderableWidget(new Button.Builder(Component.literal("PASTE"), - (p) -> { - InputSimulator.pressKey(GLFW.GLFW_KEY_LEFT_CONTROL); - InputSimulator.pressKey(GLFW.GLFW_KEY_V); - InputSimulator.releaseKey(GLFW.GLFW_KEY_V); - InputSimulator.releaseKey(GLFW.GLFW_KEY_LEFT_CONTROL); - }) - .size(35, 20) - .pos(2 * (35 + spacing) + margin, margin + -1 * (20 + spacing)) - .build()); + this.dh.vrSettings.physicalKeyboardTheme.theme.reload(); } public void setShift(boolean shift) { diff --git a/common/src/main/java/org/vivecraft/client_vr/gui/PhysicalKeyboard.java b/common/src/main/java/org/vivecraft/client_vr/gui/PhysicalKeyboard.java index c592d6232..ddf453154 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gui/PhysicalKeyboard.java +++ b/common/src/main/java/org/vivecraft/client_vr/gui/PhysicalKeyboard.java @@ -6,45 +6,35 @@ import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvents; -import net.minecraft.util.Mth; import net.minecraft.util.Tuple; import net.minecraft.world.phys.AABB; import org.joml.Matrix4f; import org.joml.Matrix4fStack; import org.joml.Vector3f; -import org.lwjgl.glfw.GLFW; import org.vivecraft.client.utils.ClientUtils; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; +import org.vivecraft.client_vr.gui.keyboard.EasterEggTheme; +import org.vivecraft.client_vr.gui.keyboard.KeyboardKeys; +import org.vivecraft.client_vr.gui.keyboard.KeyboardTheme; import org.vivecraft.client_vr.provider.ControllerType; -import org.vivecraft.client_vr.provider.InputSimulator; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.render.helpers.RenderHelper; import org.vivecraft.client_vr.render.rendertypes.VRRenderTypes; -import org.vivecraft.client_vr.settings.OptionEnum; -import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.client_vr.utils.RGBAColor; import org.vivecraft.mod_compat_vr.shaders.ShadersHelper; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Supplier; -import java.util.stream.Stream; public class PhysicalKeyboard { - private static final int ROWS = 4; - private static final int COLUMNS = 13; private static final float SPACING = 0.0064F; private static final float KEY_WIDTH = 0.04F; private static final float KEY_HEIGHT = 0.04F; @@ -90,193 +80,65 @@ public void init() { this.unpressAllKeys(); this.keys.clear(); - this.rows = ROWS; - this.columns = COLUMNS; this.spacing = SPACING * this.scale; this.keyWidth = KEY_WIDTH * this.scale; this.keyHeight = KEY_HEIGHT * this.scale; this.keyWidthSpecial = KEY_WIDTH_SPECIAL * this.scale; - String chars = this.dh.vrSettings.keyboardKeys; - if (this.shift) { - chars = this.dh.vrSettings.keyboardKeysShift; - } - - float calcRows = (float) chars.length() / (float) this.columns; - if (Math.abs(this.rows - calcRows) > 0.01F) { - this.rows = Mth.ceil(calcRows); - } - - for (int row = 0; row < this.rows; row++) { - for (int column = 0; column < this.columns; column++) { - int index = row * this.columns + column; - char ch = ' '; - - if (index < chars.length()) { - ch = chars.charAt(index); - } - - final char buttonChar = ch; - final int code = index < this.dh.vrSettings.keyboardCodes.length ? - this.dh.vrSettings.keyboardCodes[index] : GLFW.GLFW_KEY_UNKNOWN; - this.addKey(new KeyButton(index, String.valueOf(ch), - this.keyWidthSpecial + this.spacing + column * (this.keyWidth + this.spacing), - row * (this.keyHeight + this.spacing), this.keyWidth, this.keyHeight) - { - @Override - public void onPressed() { - InputSimulator.pressKeyForBind(code); - InputSimulator.typeChar(buttonChar); - - if (!PhysicalKeyboard.this.shiftSticky) { - setShift(false, false); - } + KeyboardKeys.Layout layout = KeyboardKeys.getRegularKeys(this.shift, () -> { + if (!PhysicalKeyboard.this.shiftSticky) { + setShift(false, false); + } + }); - if (buttonChar == '/' && PhysicalKeyboard.this.mc.screen == null) { - // this is dumb but whatever - InputSimulator.pressKey(GLFW.GLFW_KEY_SLASH); - InputSimulator.releaseKey(GLFW.GLFW_KEY_SLASH); - } - } + this.rows = layout.rows(); + this.columns = layout.columns(); - @Override - public void onReleased() { - InputSimulator.releaseKeyForBind(code); - } - }); - } + for (KeyboardKeys.Key key : layout.keys()) { + int y = key.y() < 0 ? this.rows - key.y() : key.y(); + this.addKey(new KeyButton( + key.x() * (this.keyWidth + this.spacing), (y - 1) * (this.keyHeight + this.spacing), + key.width() * this.keyWidth + (key.width() - 1) * this.spacing, + key.height() * this.keyHeight + (key.height() - 1) * this.spacing, key)); } - // shift keys - for (int i = 0; i < 2; i++) { - this.addKey(new KeyButton(1000 + i, "Shift", - i == 1 ? this.keyWidthSpecial + this.spacing + this.columns * (this.keyWidth + this.spacing) : 0.0F, - 3.0F * (this.keyHeight + this.spacing), this.keyWidthSpecial, this.keyHeight) + List specialKeys = KeyboardKeys.getSpecialKeys(() -> { + if (this.shift && !this.shiftSticky && ClientUtils.milliTime() - this.shiftPressTime < 400L) { + setShift(true, true); + } else { + setShift(!this.shift, false); + } + this.shiftPressTime = ClientUtils.milliTime(); + }); + for (KeyboardKeys.Key key : specialKeys) { + int y = key.y() < 0 ? this.rows - key.y() : key.y(); + this.addKey(new KeyButton( + key.x() * (this.keyWidth + this.spacing), + (y - 1) * (this.keyHeight + this.spacing), + key.width() * this.keyWidth + (key.width() - 1) * this.spacing, + key.height() * this.keyHeight, key) { - @Override - public void onPressed() { - if (PhysicalKeyboard.this.shift && !PhysicalKeyboard.this.shiftSticky && - ClientUtils.milliTime() - PhysicalKeyboard.this.shiftPressTime < 400L) - { - setShift(true, true); - } else { - setShift(!PhysicalKeyboard.this.shift, false); - } - - PhysicalKeyboard.this.shiftPressTime = ClientUtils.milliTime(); - } @Override public RGBAColor getRenderColor() { - if (PhysicalKeyboard.this.shift) { - RGBAColor color = new RGBAColor(this.pressed ? 1.0F : 0.5F, this.pressed ? 1.0F : 0.5F, 0.0F, - 0.5F); - + if (this.key.isShift() && PhysicalKeyboard.this.shift) { + RGBAColor color = new RGBAColor(this.pressed ? 1.0F : 0.5F, this.pressed ? 1.0F : 0.5F, + 0.0F, 0.5F); if (!PhysicalKeyboard.this.shiftSticky) { color.r = 0.0F; } - return color; } - return super.getRenderColor(); } }); } - this.addKey(new KeyButton(1002, " ", - this.keyWidthSpecial + this.spacing + (this.columns - 5) / 2.0F * (this.keyWidth + this.spacing), - this.rows * (this.keyHeight + this.spacing), 5.0F * (this.keyWidth + this.spacing) - this.spacing, - this.keyHeight) - { - @Override - public void onPressed() { - InputSimulator.pressKeyForBind(GLFW.GLFW_KEY_SPACE); - InputSimulator.typeChar(' '); - } - - @Override - public void onReleased() { - InputSimulator.releaseKeyForBind(GLFW.GLFW_KEY_SPACE); - } - }); - - this.addKey(new KeyPressButton(1003, "Tab", - 0.0F, - this.keyHeight + this.spacing, this.keyWidthSpecial, this.keyHeight, GLFW.GLFW_KEY_TAB)); - - this.addKey(new KeyPressButton(1004, "Esc", - 0.0F, - 0.0F, this.keyWidthSpecial, this.keyHeight, GLFW.GLFW_KEY_ESCAPE)); - - this.addKey(new KeyPressButton(1005, "Bksp", - this.keyWidthSpecial + this.spacing + this.columns * (this.keyWidth + this.spacing), - 0.0F, this.keyWidthSpecial, this.keyHeight, GLFW.GLFW_KEY_BACKSPACE)); - - this.addKey(new KeyPressButton(1006, "Enter", - this.keyWidthSpecial + this.spacing + this.columns * (this.keyWidth + this.spacing), - 2.0F * (this.keyHeight + this.spacing), this.keyWidthSpecial, this.keyHeight, GLFW.GLFW_KEY_ENTER)); - - this.addKey(new KeyPressButton(1007, "\u2191", - this.keyWidthSpecial + this.spacing + (this.columns + 1) * (this.keyWidth + this.spacing), - 4.0F * (this.keyHeight + this.spacing), this.keyWidth, this.keyHeight, GLFW.GLFW_KEY_UP)); - - this.addKey(new KeyPressButton(1008, "\u2193", - this.keyWidthSpecial + this.spacing + (this.columns + 1) * (this.keyWidth + this.spacing), - 5.0F * (this.keyHeight + this.spacing), this.keyWidth, this.keyHeight, GLFW.GLFW_KEY_DOWN)); - - this.addKey(new KeyPressButton(1009, "\u2190", - this.keyWidthSpecial + this.spacing + this.columns * (this.keyWidth + this.spacing), - 5.0F * (this.keyHeight + this.spacing), this.keyWidth, this.keyHeight, GLFW.GLFW_KEY_LEFT)); - - this.addKey(new KeyPressButton(1010, "\u2192", - this.keyWidthSpecial + this.spacing + (this.columns + 2) * (this.keyWidth + this.spacing), - 5.0F * (this.keyHeight + this.spacing), this.keyWidth, this.keyHeight, GLFW.GLFW_KEY_RIGHT)); - - this.addKey(new KeyButton(1011, "Cut", - (this.keyWidthSpecial + this.spacing), - -1.0F * (this.keyHeight + this.spacing), this.keyWidthSpecial, this.keyHeight) - { - @Override - public void onPressed() { - InputSimulator.pressKey(GLFW.GLFW_KEY_LEFT_CONTROL); - InputSimulator.pressKey(GLFW.GLFW_KEY_X); - InputSimulator.releaseKey(GLFW.GLFW_KEY_X); - InputSimulator.releaseKey(GLFW.GLFW_KEY_LEFT_CONTROL); - } - }); - - this.addKey(new KeyButton(1012, "Copy", - 2.0F * (this.keyWidthSpecial + this.spacing), - -1.0F * (this.keyHeight + this.spacing), this.keyWidthSpecial, this.keyHeight) - { - @Override - public void onPressed() { - InputSimulator.pressKey(GLFW.GLFW_KEY_LEFT_CONTROL); - InputSimulator.pressKey(GLFW.GLFW_KEY_C); - InputSimulator.releaseKey(GLFW.GLFW_KEY_C); - InputSimulator.releaseKey(GLFW.GLFW_KEY_LEFT_CONTROL); - } - }); - - this.addKey(new KeyButton(1013, "Paste", - 3.0F * (this.keyWidthSpecial + this.spacing), - -1.0F * (this.keyHeight + this.spacing), this.keyWidthSpecial, this.keyHeight) - { - @Override - public void onPressed() { - InputSimulator.pressKey(GLFW.GLFW_KEY_LEFT_CONTROL); - InputSimulator.pressKey(GLFW.GLFW_KEY_V); - InputSimulator.releaseKey(GLFW.GLFW_KEY_V); - InputSimulator.releaseKey(GLFW.GLFW_KEY_LEFT_CONTROL); - } - }); - // Set pressed keys to the new objects for (int c = 0; c < 2; c++) { if (this.pressedKey[c] != null) { for (KeyButton key : this.keys) { - if (key.id == this.pressedKey[c].id) { + if (key.key.id() == this.pressedKey[c].key.id()) { this.pressedKey[c] = key; key.pressed = true; break; @@ -285,54 +147,7 @@ public void onPressed() { } } - if (this.dh.vrSettings.physicalKeyboardTheme == KeyboardTheme.CUSTOM) { - this.customTheme.clear(); - File themeFile = new File(this.mc.gameDirectory, "keyboardtheme.txt"); - if (!themeFile.exists()) { - // Write template theme file - try (PrintWriter pw = new PrintWriter(new FileWriter(themeFile, StandardCharsets.UTF_8))) { - char[] normalChars = this.dh.vrSettings.keyboardKeys.toCharArray(); - for (int i = 0; i < normalChars.length; i++) { - pw.println("# " + normalChars[i] + " (Normal)"); - pw.println(i + "=255,255,255"); - } - char[] shiftChars = this.dh.vrSettings.keyboardKeysShift.toCharArray(); - for (int i = 0; i < shiftChars.length; i++) { - pw.println("# " + shiftChars[i] + " (Shifted)"); - pw.println((i + 500) + "=255,255,255"); - } - this.keys.forEach(button -> { - if (button.id >= 1000) { - pw.println("# " + button.label); - pw.println(button.id + "=255,255,255"); - } - }); - } catch (IOException ex) { - VRSettings.LOGGER.error("Vivecraft: error creating keyboard template: ", ex); - } - } else { - // Load theme file - try (Stream lines = Files.lines(Paths.get(themeFile.toURI()), StandardCharsets.UTF_8)) { - lines.forEach(line -> { - if (line.isEmpty() || line.charAt(0) == '#') { - return; - } - try { - String[] split = line.split("=", 2); - int id = Integer.parseInt(split[0]); - String[] colorSplit = split[1].split(","); - RGBAColor color = new RGBAColor(Integer.parseInt(colorSplit[0]), - Integer.parseInt(colorSplit[1]), Integer.parseInt(colorSplit[2]), 255); - this.customTheme.put(id, color); - } catch (Exception ex) { - VRSettings.LOGGER.error("Vivecraft: error reading keyboard theme line: {}:", line, ex); - } - }); - } catch (IOException ex) { - VRSettings.LOGGER.error("Vivecraft: error reading keyboard theme:", ex); - } - } - } + this.dh.vrSettings.physicalKeyboardTheme.theme.reload(); this.reinit = false; } @@ -502,39 +317,18 @@ public void render(Matrix4fStack poseStack) { Vector3f center = this.getCenterPos(); poseStack.translate(-center.x, -center.y, -center.z); - if (this.easterEggActive) { - // https://qimg.techjargaming.com/i/UkG1cWAh.png - for (KeyButton key : this.keys) { - RGBAColor color = RGBAColor.fromHSB( - (this.dh.tickCounter + ClientUtils.getCurrentPartialTick()) / 100.0F + - (float) (key.boundingBox.minX + (key.boundingBox.maxX - key.boundingBox.minX) / 2.0D) / 2.0F, - 1.0F, - 1.0F); - key.color.r = color.r; - key.color.g = color.g; - key.color.b = color.b; - } - } else { - this.keys.forEach(button -> { - if (this.dh.vrSettings.physicalKeyboardTheme == KeyboardTheme.CUSTOM) { - RGBAColor color = this.customTheme.get( - this.shift && button.id < 1000 ? button.id + 500 : button.id); - if (color != null) { - button.color.r = color.r; - button.color.g = color.g; - button.color.b = color.b; - } - } else { - this.dh.vrSettings.physicalKeyboardTheme.assignColor(button); - } - }); + + KeyboardTheme.Theme theme = + this.easterEggActive ? EasterEggTheme.INSTANCE : this.dh.vrSettings.physicalKeyboardTheme.theme; + for (KeyButton button : this.keys) { + theme.updateColor(button.color, button.key.id(), button.key.x(), button.key.y()); } // We need to ignore depth so we can see the back faces and text // Stuff for drawing labels Font font = this.mc.font; - ArrayList> labels = new ArrayList<>(); + ArrayList> labels = new ArrayList<>(); float textScale = 0.002F * this.scale; // Start building vertices for key boxes @@ -549,14 +343,14 @@ public void render(Matrix4fStack poseStack) { this.drawBox(buf, box, color, poseStack); // Calculate text position - float stringWidth = (float) font.width(key.label) * textScale; + float stringWidth = (float) font.width(key.key.label()) * textScale; float stringHeight = font.lineHeight * textScale; float textX = (float) box.minX + ((float) box.maxX - (float) box.minX) / 2.0F - stringWidth / 2.0F; float textY = (float) box.minY + ((float) box.maxY - (float) box.minY) / 2.0F - stringHeight / 2.0F; float textZ = (float) box.minZ + ((float) box.maxZ - (float) box.minZ) / 2.0F; // Put label in the list - labels.add(new Tuple<>(key.label, new Vector3f(textX, textY, textZ))); + labels.add(new Tuple<>(key.key.label(), new Vector3f(textX, textY, textZ))); } // Draw all the key boxes @@ -565,7 +359,7 @@ public void render(Matrix4fStack poseStack) { // Build all the text // TODO 1.21.5 no cull text - for (Tuple label : labels) { + for (Tuple label : labels) { poseStack.pushMatrix(); poseStack.translate(label.getB().x, label.getB().y, label.getB().z); poseStack.scale(textScale, textScale, 1.0F); @@ -627,37 +421,15 @@ public void setScale(float scale) { this.reinit = true; } - private class KeyPressButton extends KeyButton { - - private final int keyCode; - - public KeyPressButton(int id, String label, float x, float y, float width, float height, int keyCode) { - super(id, label, x, y, width, height); - this.keyCode = keyCode; - } - - @Override - public void onPressed() { - InputSimulator.pressKey(this.keyCode); - } - - @Override - public void onReleased() { - InputSimulator.releaseKey(this.keyCode); - } - } - - private abstract class KeyButton { - public final int id; - public final String label; + private class KeyButton { public final AABB boundingBox; + public final KeyboardKeys.Key key; public RGBAColor color = new RGBAColor(1.0F, 1.0F, 1.0F, 0.5F); public boolean pressed; - public KeyButton(int id, String label, float x, float y, float width, float height) { - this.id = id; - this.label = label; + public KeyButton(float x, float y, float width, float height, KeyboardKeys.Key key) { this.boundingBox = new AABB(x, y, 0.0D, x + width, y + height, 0.028D * PhysicalKeyboard.this.scale); + this.key = key; } public AABB getRenderBoundingBox() { @@ -689,114 +461,13 @@ public final void press(ControllerType controller, boolean isRepeat) { MCVR.get().triggerHapticPulse(controller, isRepeat ? 300 : 600); this.pressed = true; - this.onPressed(); - updateEasterEgg(this.label); + this.key.onPress().run(); + updateEasterEgg(this.key.label().getString()); } public final void unpress() { this.pressed = false; - this.onReleased(); - } - - public abstract void onPressed(); - - public void onReleased() { + this.key.onRelease().run(); } } - - public enum KeyboardTheme implements OptionEnum { - DEFAULT { - @Override - public void assignColor(KeyButton button) { - button.color.r = 1.0F; - button.color.g = 1.0F; - button.color.b = 1.0F; - } - }, - RED { - @Override - public void assignColor(KeyButton button) { - button.color.r = 1.0F; - button.color.g = 0.0F; - button.color.b = 0.0F; - } - }, - GREEN { - @Override - public void assignColor(KeyButton button) { - button.color.r = 0.0F; - button.color.g = 1.0F; - button.color.b = 0.0F; - } - }, - BLUE { - @Override - public void assignColor(KeyButton button) { - button.color.r = 0.0F; - button.color.g = 0.0F; - button.color.b = 1.0F; - } - }, - BLACK { - @Override - public void assignColor(KeyButton button) { - button.color.r = 0.0F; - button.color.g = 0.0F; - button.color.b = 0.0F; - } - }, - GRASS { - @Override - public void assignColor(KeyButton button) { - if (button.boundingBox.maxY < 0.07D) { - button.color.r = 0.321F; - button.color.g = 0.584F; - button.color.b = 0.184F; - } else { - button.color.r = 0.607F; - button.color.g = 0.462F; - button.color.b = 0.325F; - } - } - }, - BEES { - @Override - public void assignColor(KeyButton button) { - float val = button.boundingBox.maxX % 0.2D < 0.1D ? 1.0F : 0.0F; - button.color.r = val; - button.color.g = val; - button.color.b = 0.0F; - } - }, - AESTHETIC { - @Override - public void assignColor(KeyButton button) { - if (button.id >= 1000) { - button.color.r = 0.0F; - button.color.g = 1.0F; - button.color.b = 1.0F; - } else { - button.color.r = 1.0F; - button.color.g = 0.0F; - button.color.b = 1.0F; - } - } - }, - DOSE { - @Override - public void assignColor(KeyButton button) { - button.color.r = button.id % 2 == 0 ? 0.5F : 0.0F; - button.color.g = button.id % 2 == 0 ? 0.0F : 1.0F; - button.color.b = button.id % 2 == 0 ? 1.0F : 0.0F; - } - }, - CUSTOM { - @Override - public void assignColor(KeyButton button) { - // Handled elsewhere - } - }; - - public abstract void assignColor(KeyButton button); - } } diff --git a/common/src/main/java/org/vivecraft/client_vr/gui/keyboard/CustomKeyboardTheme.java b/common/src/main/java/org/vivecraft/client_vr/gui/keyboard/CustomKeyboardTheme.java new file mode 100644 index 000000000..1265191ad --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/gui/keyboard/CustomKeyboardTheme.java @@ -0,0 +1,117 @@ +package org.vivecraft.client_vr.gui.keyboard; + +import net.minecraft.client.Minecraft; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.settings.VRSettings; +import org.vivecraft.client_vr.utils.RGBAColor; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +public class CustomKeyboardTheme implements KeyboardTheme.IdTheme { + + private final Map keys = new HashMap<>(); + + private final static RGBAColor DEFAULT = new RGBAColor(1F, 1F, 1F, 1F); + + @Override + public void updateColor(RGBAColor color, int keyId) { + color.setRGB(getColor(keyId)); + } + + @Override + public void reload() { + this.keys.clear(); + File themeFile = new File(Minecraft.getInstance().gameDirectory, "keyboardtheme.txt"); + if (!themeFile.exists()) { + save(); + } else { + // Load theme file + try (Stream lines = Files.lines(Paths.get(themeFile.toURI()), StandardCharsets.UTF_8)) { + lines.forEach(line -> { + if (line.isEmpty() || line.charAt(0) == '#') { + return; + } + try { + String[] split = line.split("=", 2); + int id = Integer.parseInt(split[0]); + String[] colorSplit = split[1].split(","); + RGBAColor color = new RGBAColor(Integer.parseInt(colorSplit[0]), + Integer.parseInt(colorSplit[1]), Integer.parseInt(colorSplit[2]), 255); + this.keys.put(id, color); + } catch (Exception ex) { + VRSettings.LOGGER.error("Vivecraft: error reading keyboard theme line: {}:", line, ex); + } + }); + } catch (IOException ex) { + VRSettings.LOGGER.error("Vivecraft: error reading keyboard theme:", ex); + } + } + } + + public void load(KeyboardTheme theme) { + this.keys.clear(); + RGBAColor color = new RGBAColor(1F, 1F, 1F, 1F); + int keyCount = KeyboardKeys.COLUMNS * KeyboardKeys.MAX_ROWS; + VRSettings.KeyboardLayout dummy = new VRSettings.KeyboardLayout("", "", " ".repeat(keyCount), + " ".repeat(keyCount)); + for (KeyboardKeys.Key key : KeyboardKeys.getRegularKeys(dummy, false, () -> {}).keys()) { + theme.theme.updateColor(color, key.id(), key.x(), key.y()); + this.keys.put(key.id(), color.copy()); + } + for (KeyboardKeys.Key key : KeyboardKeys.getRegularKeys(dummy, true, () -> {}).keys()) { + theme.theme.updateColor(color, key.id(), key.x(), key.y()); + this.keys.put(key.id(), color.copy()); + } + for (KeyboardKeys.Key key : KeyboardKeys.getSpecialKeys()) { + theme.theme.updateColor(color, key.id(), key.x(), key.y()); + this.keys.put(key.id(), color.copy()); + } + } + + public void save() { + File themeFile = new File(Minecraft.getInstance().gameDirectory, "keyboardtheme.txt"); + // Write template theme file + try (PrintWriter pw = new PrintWriter(new FileWriter(themeFile, StandardCharsets.UTF_8))) { + VRSettings.KeyboardLayout current = ClientDataHolderVR.getInstance().vrSettings.getKeyboardLayout(); + char[] normalChars = current.regular().get().toCharArray(); + for (int i = 0; i < KeyboardKeys.COLUMNS * KeyboardKeys.MAX_ROWS; i++) { + RGBAColor color = getColor(i); + pw.println("# " + (i < normalChars.length ? normalChars[i] : " ") + " (Normal)"); + pw.println(i + + "=%d,%d,%d".formatted((int) (color.r * 255), (int) (color.g * 255), (int) (color.b * 255))); + } + char[] shiftChars = current.shift().get().toCharArray(); + for (int i = 0; i < KeyboardKeys.COLUMNS * KeyboardKeys.MAX_ROWS; i++) { + RGBAColor color = getColor(i + 500); + pw.println("# " + (i < shiftChars.length ? shiftChars[i] : " ") + " (Shifted)"); + pw.println((i + 500) + + "=%d,%d,%d".formatted((int) (color.r * 255), (int) (color.g * 255), (int) (color.b * 255))); + } + KeyboardKeys.getSpecialKeys().forEach(key -> { + RGBAColor color = getColor(key.id()); + pw.println("# " + key.label()); + pw.println(key.id() + + "=%d,%d,%d".formatted((int) (color.r * 255), (int) (color.g * 255), (int) (color.b * 255))); + }); + } catch (IOException ex) { + VRSettings.LOGGER.error("Vivecraft: error saving keyboard theme: ", ex); + } + } + + private RGBAColor getColor(int keyId) { + return this.keys.getOrDefault(keyId, DEFAULT); + } + + public void setColor(int keyId, RGBAColor color) { + this.keys.put(keyId, color.copy()); + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/gui/keyboard/EasterEggTheme.java b/common/src/main/java/org/vivecraft/client_vr/gui/keyboard/EasterEggTheme.java new file mode 100644 index 000000000..859c88817 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/gui/keyboard/EasterEggTheme.java @@ -0,0 +1,20 @@ +package org.vivecraft.client_vr.gui.keyboard; + +import org.vivecraft.client.utils.ClientUtils; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.utils.RGBAColor; + +public class EasterEggTheme implements KeyboardTheme.PositionTheme { + + public static final EasterEggTheme INSTANCE = new EasterEggTheme(); + + @Override + public void updateColor(RGBAColor color, int keyX, int keyY) { + // https://qimg.techjargaming.com/i/UkG1cWAh.png + color.setRGB(RGBAColor.fromHSB( + (ClientDataHolderVR.getInstance().tickCounter + ClientUtils.getCurrentPartialTick()) / 100.0F + + keyX / (KeyboardKeys.COLUMNS * 3F), + 1.0F, + 1.0F)); + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/gui/keyboard/KeyboardKeys.java b/common/src/main/java/org/vivecraft/client_vr/gui/keyboard/KeyboardKeys.java new file mode 100644 index 000000000..076fb69eb --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/gui/keyboard/KeyboardKeys.java @@ -0,0 +1,218 @@ +package org.vivecraft.client_vr.gui.keyboard; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import org.lwjgl.glfw.GLFW; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.provider.InputSimulator; +import org.vivecraft.client_vr.settings.VRSettings; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class KeyboardKeys { + + public static final int COLUMNS = 13; + public static final int ROWS = 4; + public static final int MAX_ROWS = 7; + public static final int SPECIAL_KEY_WIDTH = 2; + + private static final List SPECIAL_KEYS = new ArrayList<>(); + private static int SPECIAL_INDEX = 1000; + + public static final Key SHIFT_1; + public static final Key SHIFT_2; + + static { + SHIFT_1 = addSpecial(Key.wide(SPECIAL_INDEX++, 0, 4, "shift", () -> {})); + SHIFT_2 = addSpecial(Key.wide(SPECIAL_INDEX++, SPECIAL_KEY_WIDTH + COLUMNS, 4, "shift", () -> {})); + + addSpecial( + new Key(SPECIAL_INDEX++, SPECIAL_KEY_WIDTH + (COLUMNS - 5) / 2, -1, 5, 1, " ", GLFW.GLFW_KEY_SPACE, ' ')); + addSpecial(Key.wide(SPECIAL_INDEX++, 0, 2, "tab", GLFW.GLFW_KEY_TAB)); + addSpecial(Key.wide(SPECIAL_INDEX++, 0, 1, "esc", GLFW.GLFW_KEY_ESCAPE)); + addSpecial(Key.wide(SPECIAL_INDEX++, SPECIAL_KEY_WIDTH + COLUMNS, 1, "backspace", GLFW.GLFW_KEY_BACKSPACE)); + addSpecial(Key.wide(SPECIAL_INDEX++, SPECIAL_KEY_WIDTH + COLUMNS, 3, "enter", GLFW.GLFW_KEY_ENTER)); + + // Arrow keys + addSpecial(Key.single(SPECIAL_INDEX++, SPECIAL_KEY_WIDTH + COLUMNS + 1, 5, "↑", GLFW.GLFW_KEY_UP)); + addSpecial(Key.single(SPECIAL_INDEX++, SPECIAL_KEY_WIDTH + COLUMNS + 1, 6, "↓", GLFW.GLFW_KEY_DOWN)); + addSpecial(Key.single(SPECIAL_INDEX++, SPECIAL_KEY_WIDTH + COLUMNS, 6, "←", GLFW.GLFW_KEY_LEFT)); + addSpecial(Key.single(SPECIAL_INDEX++, SPECIAL_KEY_WIDTH + COLUMNS + 2, 6, "→", GLFW.GLFW_KEY_RIGHT)); + + addSpecial(Key.wide(SPECIAL_INDEX++, SPECIAL_KEY_WIDTH, 0, "cut", () -> { + InputSimulator.pressKey(GLFW.GLFW_KEY_LEFT_CONTROL); + InputSimulator.pressKey(GLFW.GLFW_KEY_X); + InputSimulator.releaseKey(GLFW.GLFW_KEY_X); + InputSimulator.releaseKey(GLFW.GLFW_KEY_LEFT_CONTROL); + })); + addSpecial(Key.wide(SPECIAL_INDEX++, SPECIAL_KEY_WIDTH * 2, 0, "copy", () -> { + InputSimulator.pressKey(GLFW.GLFW_KEY_LEFT_CONTROL); + InputSimulator.pressKey(GLFW.GLFW_KEY_C); + InputSimulator.releaseKey(GLFW.GLFW_KEY_C); + InputSimulator.releaseKey(GLFW.GLFW_KEY_LEFT_CONTROL); + })); + addSpecial(Key.wide(SPECIAL_INDEX++, SPECIAL_KEY_WIDTH * 3, 0, "paste", () -> { + InputSimulator.pressKey(GLFW.GLFW_KEY_LEFT_CONTROL); + InputSimulator.pressKey(GLFW.GLFW_KEY_V); + InputSimulator.releaseKey(GLFW.GLFW_KEY_V); + InputSimulator.releaseKey(GLFW.GLFW_KEY_LEFT_CONTROL); + })); + addSpecial(Key.wide(SPECIAL_INDEX++, SPECIAL_KEY_WIDTH * 4, 0, "switch", + () -> ClientDataHolderVR.getInstance().vrSettings.nextKeyboardLayout())); + } + + private static Key addSpecial(Key key) { + SPECIAL_KEYS.add(key); + return key; + } + + public static List getSpecialKeys(Runnable shiftTask) { + List keys = new ArrayList<>(SPECIAL_KEYS.size()); + for (Key key : SPECIAL_KEYS) { + if (key.isShift()) { + keys.add(new Key(key.id, key.x, key.y, key.width, key.height, key.label, shiftTask, () -> {})); + } else { + keys.add(key); + } + } + return keys; + } + + public static List getSpecialKeys() { + return Collections.unmodifiableList(SPECIAL_KEYS); + } + + /** + * returns all current regular keys of the current active keyboard layout, and the size of the key grid + * + * @param shift if shift or regular keys should be generated + * @param afterPress a task that is executed after any key is pressed + * @return Layout containing the keys, and the size + */ + public static Layout getRegularKeys(boolean shift, Runnable afterPress) { + return getRegularKeys(ClientDataHolderVR.getInstance().vrSettings.getKeyboardLayout(), shift, afterPress); + } + + /** + * returns all current regular keys for the give nKeyboard layout, and the size of the key grid + * + * @param layout KeyboardLayout to get the keys for + * @param shift if shift or regular keys should be generated + * @param afterPress a task that is executed after any key is pressed + * @return Layout containing the keys, and the size + */ + public static Layout getRegularKeys( + VRSettings.KeyboardLayout layout, boolean shift, Runnable afterPress) + { + VRSettings vrSettings = ClientDataHolderVR.getInstance().vrSettings; + String chars = shift ? layout.shift().get() : layout.regular().get(); + + int rows = ROWS; + float calcRows = (float) chars.length() / (float) COLUMNS; + if (Math.abs(ROWS - calcRows) > 0.01F) { + rows = Mth.ceil(calcRows); + } + + List keys = new ArrayList<>(rows * COLUMNS); + + for (int row = 0; row < rows; row++) { + for (int column = 0; column < COLUMNS; column++) { + int index = row * COLUMNS + column; + char ch = index < chars.length() ? chars.charAt(index) : '\u0000'; + final int code = + index < vrSettings.keyboardCodes.length ? vrSettings.keyboardCodes[index] : GLFW.GLFW_KEY_UNKNOWN; + keys.add( + Key.single(shift ? index + 500 : index, column + KeyboardKeys.SPECIAL_KEY_WIDTH, 1 + row, code, ch, + afterPress)); + } + } + return new Layout(keys, COLUMNS, rows); + } + + + /** + * @param id ID of the key, 0-499 regular keys, 500-999 shifted keys, 1000+ special keys + * @param x X position of the key + * @param y Y position of the key, if negative it is below the keyboard + * @param label label of the key + * @param onPress action to do when the key is pressed + * @param onRelease action to do when the key is released + */ + public record Key(int id, int x, int y, int width, int height, Component label, Runnable onPress, + Runnable onRelease) + { + + /** + * key that types a char, and presses a key if set in the settings + */ + private Key( + int id, int x, int y, int width, int height, String label, int keyCode, char keyChar) + { + this(id, x, y, width, height, label, keyCode, keyChar, () -> {}); + } + + /** + * key that types a char, and presses a key if set in the settings + */ + private Key( + int id, int x, int y, int width, int height, String label, int keyCode, char keyChar, Runnable afterPress) + { + this(id, x, y, width, height, Component.literal(label), () -> { + InputSimulator.pressKeyForBind(keyCode); + if (keyChar != '\u0000') { + InputSimulator.typeChar(keyChar); + } + + if (keyChar == '/' && Minecraft.getInstance().screen == null) { + // this is dumb but whatever + InputSimulator.pressKey(GLFW.GLFW_KEY_SLASH); + InputSimulator.releaseKey(GLFW.GLFW_KEY_SLASH); + } + afterPress.run(); + }, () -> InputSimulator.releaseKeyForBind(keyCode)); + } + + /** + * 1x1 key that types a char, and presses a key if set in the settings + */ + private static Key single(int id, int x, int y, int keyCode, char keyChar, Runnable afterPress) { + return new Key(id, x, y, 1, 1, keyChar != '\u0000' ? String.valueOf(keyChar) : "", keyCode, keyChar, + afterPress); + } + + /** + * 1x1 key that always presses a key + */ + private static Key single(int id, int x, int y, String label, int keyCode) { + return new Key(id, x, y, 1, 1, Component.literal(label), () -> InputSimulator.pressKey(keyCode), + () -> InputSimulator.releaseKey(keyCode)); + } + + /** + * 2x1 key that always presses a key + */ + private static Key wide(int id, int x, int y, String langKey, int keyCode) { + return new Key(id, x, y, 2, 1, Component.translatable("vivecraft.keyboard.key." + langKey), + () -> InputSimulator.pressKey(keyCode), () -> InputSimulator.releaseKey(keyCode)); + } + + /** + * 2x1 key that does an action + */ + private static Key wide(int id, int x, int y, String langKey, Runnable onPress) { + return new Key(id, x, y, 2, 1, Component.translatable("vivecraft.keyboard.key." + langKey), + onPress, () -> {}); + } + + public boolean isShift() { + return this.id == SHIFT_1.id || this.id == SHIFT_2.id; + } + } + + public record Layout(List keys, int columns, int rows) {} + + ; +} diff --git a/common/src/main/java/org/vivecraft/client_vr/gui/keyboard/KeyboardTheme.java b/common/src/main/java/org/vivecraft/client_vr/gui/keyboard/KeyboardTheme.java new file mode 100644 index 000000000..b202a92bb --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/gui/keyboard/KeyboardTheme.java @@ -0,0 +1,110 @@ +package org.vivecraft.client_vr.gui.keyboard; + +import org.vivecraft.client_vr.settings.OptionEnum; +import org.vivecraft.client_vr.utils.RGBAColor; + +public enum KeyboardTheme implements OptionEnum { + DEFAULT((SolidTheme) color -> color.setRGB(1F, 1F, 1F)), + RED((SolidTheme) color -> color.setRGB(1F, 0F, 0F)), + GREEN((SolidTheme) color -> color.setRGB(0F, 1F, 0F)), + BLUE((SolidTheme) color -> color.setRGB(0F, 0F, 1F)), + BLACK((SolidTheme) color -> color.setRGB(0F, 0F, 0F)), + GRASS((PositionTheme) (color, x, y) -> { + if (y >= 0 && y < 2) { + color.setRGB(0.321F, 0.584F, 0.184F); + } else { + color.setRGB(0.607F, 0.462F, 0.325F); + } + }), + BEES((PositionTheme) (color, x, y) -> { + if (x % 4 < 2) { + color.setRGB(1F, 1F, 0F); + } else { + color.setRGB(0F, 0F, 0F); + } + }), + AESTHETIC((IdTheme) (color, key) -> { + if (key >= 1000) { + color.setRGB(0F, 1F, 1F); + } else { + color.setRGB(1F, 0F, 1F); + } + }), + DOSE((IdTheme) (color, key) -> { + if (key % 2 == 0) { + color.setRGB(0.5F, 0F, 1F); + } else { + color.setRGB(0F, 1F, 0F); + } + }), + CUSTOM(new CustomKeyboardTheme()); + + public final Theme theme; + + KeyboardTheme(Theme theme) { + this.theme = theme; + } + + @FunctionalInterface + public interface Theme { + + /** + * gets the color for the given key + * + * @param color RGBAColor Object to update + * @param keyId id of the key, 0-499 regular keys, 500-999, shift keys, 1000+ special keys + * @param keyX x position of the key slot + * @param keyY y position of hte key slot + */ + void updateColor(RGBAColor color, int keyId, int keyX, int keyY); + + /** + * reloads the theme, if it needs to + */ + default void reload() {} + + /** + * updates the theme, if it has any kind of animation + */ + default void update() {} + } + + /** + * A Theme that has the same color for each key + */ + @FunctionalInterface + interface SolidTheme extends Theme { + @Override + default void updateColor(RGBAColor color, int keyId, int keyX, int keyY) { + updateColor(color); + } + + void updateColor(RGBAColor color); + } + + /** + * A Theme that changes color based on x/y key position + */ + @FunctionalInterface + interface PositionTheme extends Theme { + @Override + default void updateColor(RGBAColor color, int keyId, int keyX, int keyY) { + updateColor(color, keyX, keyY); + } + + void updateColor(RGBAColor color, int keyX, int keyY); + } + + /** + * A Theme that changes color based on key id + */ + @FunctionalInterface + interface IdTheme extends Theme { + @Override + default void updateColor(RGBAColor color, int keyId, int keyX, int keyY) { + updateColor(color, keyId); + } + + void updateColor(RGBAColor color, int keyIndex); + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java index b8f80caab..a68e01a21 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java @@ -80,10 +80,12 @@ protected Matrix4f getProjectionMatrix(int eyeType, float nearClip, float farCli try (MemoryStack stack = MemoryStack.stackPush()) { if (eyeType == VR.EVREye_Eye_Left) { return OpenVRUtil.Matrix4fFromOpenVR( - VRSystem_GetProjectionMatrix(VR.EVREye_Eye_Left, nearClip, Math.min(farClip, Float.MAX_VALUE), HmdMatrix44.calloc(stack))); + VRSystem_GetProjectionMatrix(VR.EVREye_Eye_Left, nearClip, Math.min(farClip, Float.MAX_VALUE), + HmdMatrix44.calloc(stack))); } else { return OpenVRUtil.Matrix4fFromOpenVR( - VRSystem_GetProjectionMatrix(VR.EVREye_Eye_Right, nearClip, Math.min(farClip, Float.MAX_VALUE), HmdMatrix44.calloc(stack))); + VRSystem_GetProjectionMatrix(VR.EVREye_Eye_Right, nearClip, Math.min(farClip, Float.MAX_VALUE), + HmdMatrix44.calloc(stack))); } } } 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 a5875fcd6..162f436e7 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 @@ -11,6 +11,7 @@ import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.client.sounds.SoundManager; import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; @@ -23,6 +24,8 @@ import org.slf4j.LoggerFactory; import org.vivecraft.Xloader; import org.vivecraft.api.client.Tracker; +import org.vivecraft.api.client.data.CloseKeyboardContext; +import org.vivecraft.api.client.data.OpenKeyboardContext; import org.vivecraft.api.data.FBTMode; import org.vivecraft.client.render.VRPlayerRenderer; import org.vivecraft.client.render.armor.VRArmorLayer; @@ -35,7 +38,7 @@ import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.gameplay.trackers.DebugRenderTracker; -import org.vivecraft.client_vr.gui.PhysicalKeyboard; +import org.vivecraft.client_vr.gui.keyboard.KeyboardTheme; import org.vivecraft.client_vr.provider.ControllerTransform; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.common.utils.math.AngleOrder; @@ -49,7 +52,9 @@ import java.util.*; import java.util.List; import java.util.function.BooleanSupplier; +import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -284,10 +289,17 @@ public enum AimDevice implements OptionEnum { public boolean alwaysSimulateKeyboard = false; @SettingField(VrOptions.BOW_MODE) public BowMode bowMode = BowMode.ON; + + public int currentKeyboardLayout = 0; + public final Map keyboardLayouts = getDefaultKeyboardLayouts(); + @SettingField(fixedSize = false) // custom is by default first to not break old settings + public String[] keyboardLayoutOrder = new String[]{"custom", "en_us"}; + @SettingField - public String keyboardKeys = "`1234567890-=qwertyuiop[]\\asdfghjkl;':\"zxcvbnm,./?<>"; + public String keyboardKeys = this.keyboardLayouts.get("en_us").regular.get(); @SettingField - public String keyboardKeysShift = "~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL;':\"ZXCVBNM,./?<>"; + public String keyboardKeysShift = this.keyboardLayouts.get("en_us").shift.get(); + @SettingField(VrOptions.HRTF_SELECTION) public int hrtfSelection = 0; @SettingField(VrOptions.RIGHT_CLICK_DELAY) @@ -568,7 +580,7 @@ public enum AimDevice implements OptionEnum { @SettingField(VrOptions.PHYSICAL_KEYBOARD_SCALE) public float physicalKeyboardScale = 1.0f; @SettingField(VrOptions.PHYSICAL_KEYBOARD_THEME) - public PhysicalKeyboard.KeyboardTheme physicalKeyboardTheme = PhysicalKeyboard.KeyboardTheme.DEFAULT; + public KeyboardTheme physicalKeyboardTheme = KeyboardTheme.DEFAULT; @SettingField(VrOptions.KEYBOARD_PRESS_BINDS) public boolean keyboardPressBinds = false; @SettingField(VrOptions.ALLOW_ADVANCED_BINDINGS) @@ -1420,6 +1432,27 @@ public FreeMove getVrFreeMoveMode(boolean flySwimming, FBTMode fbtMode) { return freeMoveMode == FreeMove.WAIST && fbtMode == FBTMode.ARMS_ONLY ? FreeMove.HMD : freeMoveMode; } + /** + * returns the currently active keyboard layout + * + * @return the active keyboard layout + */ + public KeyboardLayout getKeyboardLayout() { + if (this.keyboardLayoutOrder.length == 0 || this.currentKeyboardLayout >= this.keyboardLayoutOrder.length) { + return this.keyboardLayouts.get("en_us"); + } + return this.keyboardLayouts.get(this.keyboardLayoutOrder[this.currentKeyboardLayout]); + } + + /** + * switches to the next keyboard layout + */ + public void nextKeyboardLayout() { + this.currentKeyboardLayout++; + this.currentKeyboardLayout = this.currentKeyboardLayout % this.keyboardLayoutOrder.length; + KeyboardHandler.reinitKeyboard(); + } + record ConfigEntry(Field field, VrOptions vrOption, String configName, boolean separate, boolean fixedSize) {} public enum VrOptions { @@ -1585,7 +1618,17 @@ Object convertOption(String value) { RADIAL_MODE_HOLD(false, true, "vivecraft.options.hold", "vivecraft.options.press"), // Radial Menu Mode RADIAL_NUMBER(false, false, 4, 14, 2, 0), // number of radial buttons PHYSICAL_KEYBOARD(false, true, "vivecraft.options.keyboard.physical", - "vivecraft.options.keyboard.pointer"), // Keyboard Type + "vivecraft.options.keyboard.pointer") { // Keyboard Type + + @Override + void onOptionChange() { + boolean showing = KeyboardHandler.SHOWING; + KeyboardHandler.hideOverlay(CloseKeyboardContext.FORCE); + if (showing) { + KeyboardHandler.showOverlay(OpenKeyboardContext.FORCE); + } + } + }, PHYSICAL_KEYBOARD_SCALE(true, false, 0.75f, 1.5f, 0.01f, -1) { // Keyboard Size @Override @@ -1598,7 +1641,7 @@ void onOptionChange() { @Override void onOptionChange() { - KeyboardHandler.PHYSICAL_KEYBOARD.init(); + KeyboardHandler.reinitKeyboard(); } }, KEYBOARD_PRESS_BINDS(false, true), // Keyboard Presses Bindings @@ -2531,6 +2574,49 @@ public String[] getServerBlacklistDefault() { return new String[]{"mc.hypixel.net"}; } + public Map getDefaultKeyboardLayouts() { + List layouts = List.of( + new KeyboardLayout("custom", Component.translatable("vivecraft.keyboard.keymap.custom"), + () -> this.keyboardKeys, () -> this.keyboardKeysShift), + new KeyboardLayout("en_us", "English (US)", + "`1234567890-=qwertyuiop[]\\asdfghjkl;':\"zxcvbnm,./?<>", + "~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL;':\"ZXCVBNM,./?<>"), + new KeyboardLayout("en_gb", "English (UK)", + "`1234567890-=qwertyuiop[]#asdfghjkl;:'\\zxcvbnm,./?<>", + "¬!\"£$%^&*()_+QWERTYUIOP{}~ASDFGHJKL;:@|ZXCVBNM,./?<>"), + new KeyboardLayout("de_de", "German", + "^1234567890ß´qwertzuiopü+#asdfghjklöä~|yxcvbnm,.-{}<", + "°!\"€$%&/()=?`QWERTYUIOPÜ*'ASDFGHJKLÖÄ@\\ZXCVBNM;:_[]>"), + new KeyboardLayout("fr_fr", "French", + "²&é\"'(-è_çà)=azertyuiop^$*qsdfghjklmù@#wxcvbn,;:![]<", + "²1234567890°+AZERTYUIOP¨£µQSDFGHJKLM%¤~WXCVBN?./\\{}>"), + new KeyboardLayout("fr_be", "French (Belgium)", + "²&é\"'(\\è!çà)-azertyuiop^$µqsdfghjklmù@#wxcvbn,;:=[]<", + "³1234567890°_AZERTYUIOP¨*£QSDFGHJKLM%¤~WXCVBN?./+{}>"), + new KeyboardLayout("be_by", "Belarusian", + "ё1234567890-=йцукенгшўзх'\\фывапролджэ:\"ячсмітьбю.?<>", + "Ё!\"№;%:?*()_+ЙЦУКЕНГШЎЗХ'/ФЫВАПРОЛДЖЭ:\"ЯЧСМІТЬБЮ,?<>"), + new KeyboardLayout("uk_ua", "Ukrainian", + "'1234567890-=йцукенгшщзхїґфівапролджє/\"ячсмитьбю.?<>", + "'!\"№;%:?*()_+ЙЦУКЕНГШЩЗХЇҐФІВАПРОЛДЖЄ\\\"ЯЧСМИТЬБЮ,?<>"), + new KeyboardLayout("ru_ru", "Russian", + "ё1234567890-=йцукенгшщзхъ\\фывапролджэ:\"ячсмитьбю.?<>", + "Ё!\"№;%:?*()_+ЙЦУКЕНГШЩЗХЪ/ФЫВАПРОЛДЖЭ:\"ЯЧСМИТЬБЮ,?<>"), + new KeyboardLayout("system", Component.translatable("vivecraft.keyboard.keymap.system"), + () -> getSystemKeys(String::toLowerCase, this.keyboardLayouts.get("en_us").regular.get()), + () -> getSystemKeys(String::toUpperCase, this.keyboardLayouts.get("en_us").shift.get()))); + return layouts.stream().collect(Collectors.toMap(KeyboardLayout::id, layout -> layout)); + } + + private String getSystemKeys(Function mapper, String fallback) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < this.keyboardCodes.length; i++) { + String k = GLFW.glfwGetKeyName(this.keyboardCodes[i], -1); + sb.append(k != null ? mapper.apply(k).charAt(0) : fallback.charAt(i)); + } + return sb.toString(); + } + public int[] getKeyboardCodesDefault() { // Some keys in the in-game keyboard don't have assignable key codes int[] out = new int[]{ @@ -2607,6 +2693,12 @@ public Quaternionf[] getFbtRotationsDefault() { return out; } + public record KeyboardLayout(String id, Component fallbackName, Supplier regular, Supplier shift) { + public KeyboardLayout(String id, String fallbackName, String regular, String shift) { + this(id, Component.literal(fallbackName), () -> regular, () -> shift); + } + } + public class ServerOverrides { private final Map optionMap = new EnumMap<>(VrOptions.class); private final Map networkNameMap = new HashMap<>(); diff --git a/common/src/main/java/org/vivecraft/client_vr/utils/RGBAColor.java b/common/src/main/java/org/vivecraft/client_vr/utils/RGBAColor.java index 2417d0914..411ca2f1c 100644 --- a/common/src/main/java/org/vivecraft/client_vr/utils/RGBAColor.java +++ b/common/src/main/java/org/vivecraft/client_vr/utils/RGBAColor.java @@ -40,6 +40,18 @@ public RGBAColor copy() { return new RGBAColor(this.r, this.g, this.b, this.a); } + public void setRGB(float red, float green, float blue) { + this.r = red; + this.g = green; + this.b = blue; + } + + public void setRGB(RGBAColor other) { + this.r = other.r; + this.g = other.g; + this.b = other.b; + } + /** * HSB to RGB conversion, pinched from {@link java.awt.Color}. * diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/gui/EditBoxVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/gui/EditBoxVRMixin.java index abab35ef1..b3f5e6515 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/gui/EditBoxVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/gui/EditBoxVRMixin.java @@ -17,6 +17,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.vivecraft.api.client.data.OpenKeyboardContext; +import org.vivecraft.client.gui.settings.GuiKeyboardLayoutEditor; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; @@ -58,7 +59,7 @@ public EditBoxVRMixin(int x, int y, int width, int height, Component message) { GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick, CallbackInfo ci, @Local String content) { if (VRState.VR_RUNNING && !ClientDataHolderVR.getInstance().vrSettings.seated && !KeyboardHandler.SHOWING && - content.isEmpty()) + content.isEmpty() && !(Minecraft.getInstance().screen instanceof GuiKeyboardLayoutEditor)) { if ((this.hint == null && (this.suggestion == null || this.suggestion.isEmpty())) || this.isFocused()) { // limit text to field size 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 23927f196..e17a851ba 100644 --- a/common/src/main/resources/assets/vivecraft/lang/de_de.json +++ b/common/src/main/resources/assets/vivecraft/lang/de_de.json @@ -385,7 +385,7 @@ "vivecraft.options.keyboardtheme.black": "Leere", "vivecraft.options.keyboardtheme.grass": "Gras Block", "vivecraft.options.keyboardtheme.bees": "Bumblebee", - "vivecraft.options.keyboardtheme.aesthetic": "§bħbs§bt§bh§be§bt§bi§bs§bc§bh", + "vivecraft.options.keyboardtheme.aesthetic": "§bħds§bt§dh§be§dt§bi§ds§bc§dh", "vivecraft.options.keyboardtheme.dose": "Medizin", "vivecraft.options.keyboardtheme.custom": "Benutzerdefiniert", "vivecraft.options.aimdevice.controller": "Controller", @@ -462,6 +462,11 @@ "vivecraft.options.screen.fbtcalibration": "Full Body Tracking Kalibrierung", "vivecraft.options.screen.playermodel": "Spielermodell Einstellungen", "vivecraft.options.screen.weaponcollision": "Waffenkollision Einstellungen", + "vivecraft.options.screen.activekeyboardlayouts": "Aktive Tastaturen", + "vivecraft.options.screen.customkeyboardeditor": "Tastaturbearbeitung", + "vivecraft.options.screen.customkeyboardthemeeditor": "Tastaturaussehensbearbeitung", + "vivecraft.options.screen.keyboardlayoutselection": "Wähle Tastatur Voreinstellung", + "vivecraft.options.screen.loadkeyboardtheme": "Wähle Tastatur Aussehen", "_comment_m2": "Buttons that lead to the screen", "vivecraft.options.screen.mixedreality.button": "Mixed Reality Einstellungen...", "vivecraft.options.screen.posteffects.button": "Postprocessing Einst...", @@ -469,6 +474,13 @@ "vivecraft.options.screen.fbtcalibration.button": "FBT Kalibrieren...", "vivecraft.options.screen.playermodel.button": "Spielermodell Einstellungen...", "vivecraft.options.screen.weaponcollision.button": "Waffenkollision...", + "vivecraft.options.screen.activekeyboardlayouts.button": "Aktive Tastaturen...", + "vivecraft.options.screen.customkeyboardeditor.button": "Benutzer Tastatur bearb...", + "vivecraft.options.screen.customkeyboardthemeeditor.button": "Benutzer Aussehen bearb...", + "vivecraft.options.screen.loadkeyboardlayout.button": "Tastatur Voreinstellung laden", + "vivecraft.options.screen.loadkeyboardtheme.button": "Tastatur Aussehen laden", + "vivecraft.options.screen.addkeyboardrow.tooltip": "Reihe hinzufügen", + "vivecraft.options.screen.removekeyboardrow.tooltip": "Reihe entfernen", "vivecraft.options.screen.search": "Suche...", "_comment_m0": "Option values", "vivecraft.options.shaderguirender.aftershader": "Nach Shader", @@ -665,6 +677,7 @@ "vivecraft.messages.connectingtoruntime": "Verbinde mit der VR Laufzeit", "vivecraft.messages.noteleport": "Dieser Server hat das Teleportieren explizit deaktiviert. Der eingeschränkte Bewegungsmodus (Fallback auf freie Bewegung) wurde aktiviert.", "vivecraft.messages.mirroroff": "Spiegle ist AUS", + "vivecraft.messages.shifttopickcolor": "Halte Shift, um die Fabe eines Knopfs auszuwählen.", "vivecraft.messages.tracker.waist": "Taille", "vivecraft.messages.tracker.rightFoot": "Rechter Fuß", @@ -689,6 +702,19 @@ "vivecraft.toasts.point_controller.right": "rechten Controller", "vivecraft.toasts.teleport": "Teleportiere mit %s", + "vivecraft.keyboard.keymap.custom": "Benutzerdefiniert", + "vivecraft.keyboard.keymap.system": "System", + + "vivecraft.keyboard.key.shift": "Shift", + "vivecraft.keyboard.key.tab": "Tab", + "vivecraft.keyboard.key.esc": "Esc", + "vivecraft.keyboard.key.backspace": "Rück", + "vivecraft.keyboard.key.enter": "Enter", + "vivecraft.keyboard.key.cut": "Aussch.", + "vivecraft.keyboard.key.copy": "Kopieren", + "vivecraft.keyboard.key.paste": "Einfügen", + "vivecraft.keyboard.key.switch": "Wechsel", + "vivecraft.formatting.name_value": "%s: %s", "vivecraft.serverSettings.general": "Generelle Einstellungen", 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 728992ab1..4233a7319 100644 --- a/common/src/main/resources/assets/vivecraft/lang/en_us.json +++ b/common/src/main/resources/assets/vivecraft/lang/en_us.json @@ -461,6 +461,11 @@ "vivecraft.options.screen.fbtcalibration": "Full Body Tracking Calibration", "vivecraft.options.screen.playermodel": "Playermodel Settings", "vivecraft.options.screen.weaponcollision": "Weapon Collision Settings", + "vivecraft.options.screen.activekeyboardlayouts": "Active Keyboards", + "vivecraft.options.screen.customkeyboardeditor": "Keyboard Editor", + "vivecraft.options.screen.customkeyboardthemeeditor": "Keyboard Theme Editor", + "vivecraft.options.screen.keyboardlayoutselection": "Select Keyboard Preset", + "vivecraft.options.screen.loadkeyboardtheme": "Select Keyboard Theme", "_comment_m2": "Buttons that lead to the screen", "vivecraft.options.screen.mixedreality.button": "Mixed Reality Settings...", "vivecraft.options.screen.posteffects.button": "Postprocessing Settings...", @@ -468,6 +473,13 @@ "vivecraft.options.screen.fbtcalibration.button": "Calibrate FBT...", "vivecraft.options.screen.playermodel.button": "Playermodel Settings...", "vivecraft.options.screen.weaponcollision.button": "Weapon Collision...", + "vivecraft.options.screen.activekeyboardlayouts.button": "Active Keyboards...", + "vivecraft.options.screen.customkeyboardeditor.button": "Edit Custom Keyboard...", + "vivecraft.options.screen.customkeyboardthemeeditor.button": "Edit Custom Theme...", + "vivecraft.options.screen.loadkeyboardlayout.button": "Load Keyboard Preset", + "vivecraft.options.screen.loadkeyboardtheme.button": "Load Keyboard Theme", + "vivecraft.options.screen.addkeyboardrow.tooltip": "Add Row", + "vivecraft.options.screen.removekeyboardrow.tooltip": "Remove Row", "vivecraft.options.screen.search": "Search...", "_comment_m0": "Option values", "vivecraft.options.shaderguirender.aftershader": "After Shader", @@ -667,6 +679,7 @@ "vivecraft.messages.connectingtoruntime": "Connecting to the VR Runtime", "vivecraft.messages.noteleport": "This server has teleporting explicitly disabled. Restricted movement mode (fallback to free move) has been enabled.", "vivecraft.messages.mirroroff": "Mirror is OFF", + "vivecraft.messages.shifttopickcolor": "Hold shift when clicking a key to pick its color.", "vivecraft.messages.tracker.waist": "Waist", "vivecraft.messages.tracker.rightFoot": "Right Foot", @@ -691,6 +704,19 @@ "vivecraft.toasts.point_controller.right": "right Controller", "vivecraft.toasts.teleport": "Teleport with %s", + "vivecraft.keyboard.keymap.custom": "Custom", + "vivecraft.keyboard.keymap.system": "System", + + "vivecraft.keyboard.key.shift": "Shift", + "vivecraft.keyboard.key.tab": "Tab", + "vivecraft.keyboard.key.esc": "Esc", + "vivecraft.keyboard.key.backspace": "Bksp", + "vivecraft.keyboard.key.enter": "Enter", + "vivecraft.keyboard.key.cut": "Cut", + "vivecraft.keyboard.key.copy": "Copy", + "vivecraft.keyboard.key.paste": "Paste", + "vivecraft.keyboard.key.switch": "Switch", + "vivecraft.formatting.name_value": "%s: %s", "vivecraft.serverSettings.general": "General Settings", From 0cabbdb153a6df82d562e06012dae71f1d057502 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Tue, 4 Nov 2025 00:50:15 +0100 Subject: [PATCH 60/76] bump to 1.3.4 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 53c756b45..85baa5c5a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ minecraft_version=1.21.10 enabled_platforms=fabric,forge,neoforge archives_base_name=vivecraft -mod_version=1.3.3 +mod_version=1.3.4 maven_group=org.vivecraft lwjgl_version=3.3.3 From a5fcea8c0381fe777d010c82c8399dfa4eb4ace9 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Tue, 11 Nov 2025 23:45:53 +0100 Subject: [PATCH 61/76] add option to overlay the gui on the mirror. also stereo rendering screen not updating in nonvr on mirror change --- .../gui/settings/GuiMixedRealitySettings.java | 2 + .../gui/settings/GuiRenderOpticsSettings.java | 27 ++++++- .../vivecraft/client_vr/render/VRShaders.java | 16 ++++ .../render/helpers/ShaderHelper.java | 78 +++++++++++++++++-- .../render/ubos/MixedRealityUBO.java | 7 +- .../client_vr/settings/VRSettings.java | 19 +++++ .../assets/vivecraft/lang/de_de.json | 11 +++ .../assets/vivecraft/lang/en_us.json | 11 +++ .../shaders/core/mixedreality_vr.fsh | 72 +++++++++++------ 9 files changed, 207 insertions(+), 36 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiMixedRealitySettings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiMixedRealitySettings.java index 133bbbaad..db405b745 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiMixedRealitySettings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiMixedRealitySettings.java @@ -15,6 +15,8 @@ public class GuiMixedRealitySettings extends GuiVROptionsBase { VRSettings.VrOptions.MIXED_REALITY_KEY_COLOR, VRSettings.VrOptions.MIXED_REALITY_FOV, VRSettings.VrOptions.MIXED_REALITY_RENDER_CAMERA_MODEL, + VRSettings.VrOptions.MIRROR_GUI, + VRSettings.VrOptions.MIXED_REALITY_GUI, VRSettings.VrOptions.MIXED_REALITY_UNDISTORTED, VRSettings.VrOptions.MIRROR_EYE, VRSettings.VrOptions.MONO_FOV, diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiRenderOpticsSettings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiRenderOpticsSettings.java index 7dee59c0c..2378893d9 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiRenderOpticsSettings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiRenderOpticsSettings.java @@ -41,6 +41,9 @@ public class GuiRenderOpticsSettings extends GuiVROptionsBase { private static final VRSettings.VrOptions[] OFF_OPTIONS = new VRSettings.VrOptions[]{ VRSettings.VrOptions.MIRROR_OFF_TEXT }; + private static final VRSettings.VrOptions[] GUI_MIRROR_OPTIONS = new VRSettings.VrOptions[]{ + VRSettings.VrOptions.MIRROR_GUI + }; private final VROptionEntry[] MROptions = new VROptionEntry[]{new VROptionEntry( "vivecraft.options.screen.mixedreality.button", (button, mousePos) -> { Minecraft.getInstance().setScreen(new GuiMixedRealitySettings(this)); @@ -90,9 +93,18 @@ public void init() { switch (this.dataHolder.vrSettings.displayMirrorMode) { case MIXED_REALITY -> super.init(this.MROptions, false); - case FIRST_PERSON -> super.init(UNDISTORTED_OPTIONS, false); - case THIRD_PERSON -> super.init(THIRD_OPTIONS, false); - case CROPPED -> super.init(CROP_OPTIONS, false); + case FIRST_PERSON -> { + super.init(UNDISTORTED_OPTIONS, false); + super.init(GUI_MIRROR_OPTIONS, false); + } + case THIRD_PERSON -> { + super.init(THIRD_OPTIONS, false); + super.init(GUI_MIRROR_OPTIONS, false); + } + case CROPPED -> { + super.init(CROP_OPTIONS, false); + super.init(GUI_MIRROR_OPTIONS, false); + } case SINGLE -> super.init(SINGLE_OPTIONS, false); case OFF -> super.init(OFF_OPTIONS, false); } @@ -118,6 +130,15 @@ protected void loadDefaults() { } } + @Override + protected void actionPerformed(AbstractWidget widget) { + if (widget instanceof GuiVROption guivroption) { + if (guivroption.getId() == VRSettings.VrOptions.MIRROR_DISPLAY.ordinal()) { + this.reinit = true; + } + } + } + @Override public boolean mouseReleased(MouseButtonEvent mouseEvent) { // Hacky way of making the render scale slider only reinit on mouse release diff --git a/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java b/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java index 94ae9a9d1..7a5146e93 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java @@ -40,6 +40,10 @@ public class VRShaders { public static final String MIXED_REALITY_FIRST_COLOR_SAMPLER = "firstPersonColor"; public static final String MIXED_REALITY_THIRD_COLOR_SAMPLER = "thirdPersonColor"; public static final String MIXED_REALITY_THIRD_DEPTH_SAMPLER = "thirdPersonDepth"; + public static final String MIXED_REALITY_GUI_COLOR_SAMPLER = "guiColor"; + public static final int MIXED_REALITY_GUI_FIRST = 1; + public static final int MIXED_REALITY_GUI_THIRD = 2; + public static final int MIXED_REALITY_GUI_SEPARATE = 4; public static final RenderPipeline MIXED_REALITY_PIPELINE = RenderPipeline.builder() .withLocation("pipeline/vivecraft_mixed_reality") @@ -49,6 +53,7 @@ public class VRShaders { .withSampler(MIXED_REALITY_FIRST_COLOR_SAMPLER) .withSampler(MIXED_REALITY_THIRD_COLOR_SAMPLER) .withSampler(MIXED_REALITY_THIRD_DEPTH_SAMPLER) + .withSampler(MIXED_REALITY_GUI_COLOR_SAMPLER) .withVertexFormat(DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.QUADS) .withDepthWrite(false) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) @@ -82,6 +87,17 @@ public class VRShaders { .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) .build(); + public static final RenderPipeline BLIT_VR_BLEND_PIPELINE = RenderPipeline.builder() + .withLocation("pipeline/vivecraft_blit") + .withVertexShader(ResourceLocation.fromNamespaceAndPath("vivecraft", "core/passthrough_vr")) + .withFragmentShader(ResourceLocation.fromNamespaceAndPath("vivecraft", "core/blit_vr")) + .withSampler(BLIT_VR_COLOR_SAMPLER) + .withVertexFormat(DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.QUADS) + .withDepthWrite(false) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withBlend(BlendFunction.TRANSLUCENT) + .build(); + // end portal shaders private static final RenderPipeline.Snippet END_PORTAL_SNIPPET = RenderPipeline.builder( RenderPipelines.END_PORTAL_SNIPPET) diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java index d7cc00f11..ec6f1bfca 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java @@ -277,11 +277,12 @@ public static void drawMirror() { int screenHeight = MC.mainRenderTarget.height; if (leftEye != null) { - ShaderHelper.blitToScreen(leftEye, 0, screenWidth, screenHeight, 0, 0.0F, 0.0F, false); + ShaderHelper.blitToScreen(leftEye, 0, screenWidth, screenHeight, 0, 0.0F, 0.0F, false, false); } if (rightEye != null) { - ShaderHelper.blitToScreen(rightEye, screenWidth, screenWidth, screenHeight, 0, 0.0F, 0.0F, false); + ShaderHelper.blitToScreen(rightEye, screenWidth, screenWidth, screenHeight, 0, 0.0F, 0.0F, false, + false); } } else { // general single buffer case @@ -323,7 +324,10 @@ public static void drawMirror() { ShaderHelper.blitToScreen(source, 0, MC.mainRenderTarget.width, MC.mainRenderTarget.height, 0, - xCrop, yCrop, keepAspect); + xCrop, yCrop, keepAspect, false); + } + if (source != GuiHandler.GUI_FRAMEBUFFER) { + blitGui(); } } @@ -344,6 +348,18 @@ public static void doMixedRealityMirror() { boolean alphaMask = DATA_HOLDER.vrSettings.mixedRealityUnityLike && DATA_HOLDER.vrSettings.mixedRealityAlphaMask; + int guiMask = 0; + if (DATA_HOLDER.vrSettings.guiOnMirror == VRSettings.MirrorGui.ALWAYS || + (DATA_HOLDER.vrSettings.guiOnMirror == VRSettings.MirrorGui.HUD_ONLY && MC.screen == null)) + { + guiMask = switch (DATA_HOLDER.vrSettings.mixedRealityGui) { + case FIRST -> VRShaders.MIXED_REALITY_GUI_FIRST; + case THIRD -> VRShaders.MIXED_REALITY_GUI_THIRD; + case BOTH -> VRShaders.MIXED_REALITY_GUI_FIRST | VRShaders.MIXED_REALITY_GUI_THIRD; + case SEPARATE -> VRShaders.MIXED_REALITY_GUI_SEPARATE; + }; + } + VRShaders.MIXED_REALITY_UBO.updateBuffer( ((GameRendererExtension) MC.gameRenderer).vivecraft$getThirdPassProjectionMatrix(), viewMatrix, @@ -353,7 +369,8 @@ public static void doMixedRealityMirror() { DATA_HOLDER.vrSettings.mixedRealityKeyColor.getRed() / 255.0F, DATA_HOLDER.vrSettings.mixedRealityKeyColor.getGreen() / 255.0F, DATA_HOLDER.vrSettings.mixedRealityKeyColor.getBlue() / 255.0F), - alphaMask + alphaMask, + guiMask ); GpuTextureView black = RenderHelper.getGpuTexture(RenderHelper.BLACK_TEXTURE); @@ -368,6 +385,9 @@ public static void doMixedRealityMirror() { renderPass.bindSampler(VRShaders.MIXED_REALITY_THIRD_DEPTH_SAMPLER, DATA_HOLDER.vrRenderer.framebufferMR.getDepthTextureView()); + renderPass.bindSampler(VRShaders.MIXED_REALITY_GUI_COLOR_SAMPLER, + GuiHandler.GUI_FRAMEBUFFER.getColorTextureView()); + if (DATA_HOLDER.vrSettings.mixedRealityUnityLike) { RenderTarget source; if (DATA_HOLDER.vrSettings.displayMirrorUseScreenshotCamera && DATA_HOLDER.cameraTracker.isVisible()) { @@ -420,6 +440,47 @@ public static void doFSAA(RenderTarget source, RenderTarget firstPass, RenderTar } } + /** + * blits the gui to the mirror with alpha blending + * the gui is centered in the middle and at the bottom, scaled to completely fit + */ + public static void blitGui() { + if (DATA_HOLDER.vrSettings.guiOnMirror == VRSettings.MirrorGui.OFF || + (DATA_HOLDER.vrSettings.guiOnMirror == VRSettings.MirrorGui.HUD_ONLY && MC.screen != null)) + { + return; + } + + float mirrorAspect = (float) MC.mainRenderTarget.width / (float) MC.mainRenderTarget.height; + float guiAspect = (float) GuiHandler.GUI_FRAMEBUFFER.width / (float) GuiHandler.GUI_FRAMEBUFFER.height; + + float xMin = 0; + float yMin = 0; + float xMax = 1.0F; + float yMax = 1.0F; + + if (mirrorAspect > guiAspect) { + // mirror is wider than the gui + // limit the width, so the complete height is filled + float aspect = (guiAspect / mirrorAspect) * 0.5F; + + xMin = 0.5F - aspect; + xMax = 0.5F + aspect; + } else { + // mirror is taller than the gui + // limit the height, so the complete width is filled + // and shift the gui to the bottom + yMax = (mirrorAspect / guiAspect); + } + + int x = (int) (xMin * MC.mainRenderTarget.width); + int y = (int) (yMin * MC.mainRenderTarget.height); + int width = (int) (xMax * MC.mainRenderTarget.width) - x; + int height = (int) (yMax * MC.mainRenderTarget.height) - y; + + blitToScreen(GuiHandler.GUI_FRAMEBUFFER, x, width, height, y, 0, 0, true, true); + } + /** * blits the given {@code source} RenderTarget to the screen/bound buffer
* the {@code source} is drawn to the rectangle at {@code left},{@code top} with a size of {@code width},{@code height}
@@ -433,10 +494,11 @@ public static void doFSAA(RenderTarget source, RenderTarget firstPass, RenderTar * @param xCropFactor vertical crop factor for the {@code source} * @param yCropFactor horizontal crop factor for the {@code source} * @param keepAspect keeps the aspect ratio in takt when cropping the buffer + * @param blend if alpha blending should be used */ public static void blitToScreen( RenderTarget source, int left, int width, int height, int top, float xCropFactor, float yCropFactor, - boolean keepAspect) + boolean keepAspect, boolean blend) { RenderSystem.assertOnRenderThread(); @@ -499,7 +561,11 @@ public static void blitToScreen( .createRenderPass(() -> "Vive Blit", MC.getMainRenderTarget().getColorTextureView(), OptionalInt.empty())) { - renderPass.setPipeline(VRShaders.BLIT_VR_PIPELINE); + if (blend) { + renderPass.setPipeline(VRShaders.BLIT_VR_BLEND_PIPELINE); + } else { + renderPass.setPipeline(VRShaders.BLIT_VR_PIPELINE); + } renderPass.setVertexBuffer(0, gpuBuffer); renderPass.bindSampler(VRShaders.BLIT_VR_COLOR_SAMPLER, source.getColorTextureView()); diff --git a/common/src/main/java/org/vivecraft/client_vr/render/ubos/MixedRealityUBO.java b/common/src/main/java/org/vivecraft/client_vr/render/ubos/MixedRealityUBO.java index 8a9dd59e4..e7d333ad1 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/ubos/MixedRealityUBO.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/ubos/MixedRealityUBO.java @@ -11,7 +11,7 @@ public class MixedRealityUBO { public static final String UBO_NAME = "MixedRealityUbo"; private static final int MIXED_REALITY_UBO_SIZE = new Std140SizeCalculator() - .putMat4f().putMat4f().putVec4().putVec4().putVec4().putInt().putInt().get(); + .putMat4f().putMat4f().putVec4().putVec4().putVec4().putInt().putInt().putInt().get(); private final MappableRingBuffer mixedRealityBuffer; public MixedRealityUBO() { @@ -21,7 +21,7 @@ public MixedRealityUBO() { public void updateBuffer( Matrix4fc thirdProjectionMat, Matrix4fc thirdViewMat, Vector3fc hmdViewPosition, - Vector3fc hmdPlaneNormal, boolean firstPersonPass, Vector3fc keyColor, boolean alphaMode) + Vector3fc hmdPlaneNormal, boolean firstPersonPass, Vector3fc keyColor, boolean alphaMode, int guiMask) { try (GpuBuffer.MappedView mappedView = RenderSystem.getDevice().createCommandEncoder() .mapBuffer(this.mixedRealityBuffer.currentBuffer(), false, true)) @@ -33,7 +33,8 @@ public void updateBuffer( .putVec4(hmdViewPosition.x(), hmdViewPosition.y(), hmdViewPosition.z(), 0) .putVec4(hmdPlaneNormal.x(), hmdPlaneNormal.y(), hmdPlaneNormal.z(), 0) .putInt(alphaMode ? 1 : 0) - .putInt(firstPersonPass ? 1 : 0); + .putInt(firstPersonPass ? 1 : 0) + .putInt(guiMask); } } 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 162f436e7..97c3fde1d 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 @@ -113,6 +113,19 @@ public enum MirrorMode implements OptionEnum { GUI } + public enum MirrorGui implements OptionEnum { + OFF, + HUD_ONLY, + ALWAYS + } + + public enum MixedRealityGui implements OptionEnum { + FIRST, + THIRD, + BOTH, + SEPARATE + } + public enum HUDLock implements OptionEnum { WRIST, HAND, @@ -444,6 +457,8 @@ public enum AimDevice implements OptionEnum { public boolean displayMirrorUseScreenshotCamera = false; @SettingField(VrOptions.MIRROR_OFF_TEXT) public boolean showMirrorOffText = true; + @SettingField(VrOptions.MIRROR_GUI) + public MirrorGui guiOnMirror = MirrorGui.OFF; @SettingField(VrOptions.SHOW_PLAYER_MODEL) public boolean shouldRenderSelf = false; @SettingField(VrOptions.MAIN_PLAYER_DATA) @@ -525,6 +540,8 @@ public enum AimDevice implements OptionEnum { public float handCameraResScale = 1.0f; @SettingField(VrOptions.MIXED_REALITY_RENDER_CAMERA_MODEL) public boolean mixedRealityRenderCameraModel = true; + @SettingField(VrOptions.MIXED_REALITY_GUI) + public MixedRealityGui mixedRealityGui = MixedRealityGui.FIRST; // // HUD/GUI @@ -1772,6 +1789,8 @@ String getDisplayString(String prefix, Object value) { } }, MIRROR_OFF_TEXT(false, true), // if text should be shown when the mirror is off + MIRROR_GUI(false, true), // if the gui should be overlaid on the mirror + MIXED_REALITY_GUI(false, true), // where the gui should show on the mixed reality mirror MIRROR_SCREENSHOT_CAMERA(false, true), MIXED_REALITY_KEY_COLOR(false, false) { // Key Color private static final List> COLORS; 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 e17a851ba..db7035f97 100644 --- a/common/src/main/resources/assets/vivecraft/lang/de_de.json +++ b/common/src/main/resources/assets/vivecraft/lang/de_de.json @@ -510,6 +510,13 @@ "vivecraft.options.datasource.realtime": "Echtzeit", "vivecraft.options.datasource.local": "Lokal", "vivecraft.options.datasource.server": "Server", + "vivecraft.options.mirrorgui.off": "AUS", + "vivecraft.options.mirrorgui.hudonly": "Nur HUD", + "vivecraft.options.mirrorgui.always": "Immer", + "vivecraft.options.mixedrealitygui.first": "1. Person", + "vivecraft.options.mixedrealitygui.third": "3. Person", + "vivecraft.options.mixedrealitygui.both": "Beide", + "vivecraft.options.mixedrealitygui.separate": "Separat", "_comment_m5": "Option names", "vivecraft.options.LOW_HEALTH_INDICATOR": "Gesundheit Indikator", "vivecraft.options.HIT_INDICATOR": "Schadens Indikator", @@ -548,6 +555,8 @@ "vivecraft.options.MIRROR_CROP": "Spiegel Zuschnitt", "vivecraft.options.MIRROR_SCREENSHOT_CAMERA": "Kamera als Desktop Spiegel", "vivecraft.options.MIRROR_OFF_TEXT": "Zeige Spiegel AUS Text", + "vivecraft.options.MIRROR_GUI": "GUI auf Spiegel", + "vivecraft.options.MIXED_REALITY_GUI": "Zeige GUI auf", "vivecraft.options.RENDER_DEBUG_HEAD_HITBOX": "Kopf Kollisionsboxen", "vivecraft.options.RENDER_DEBUG_DEVICE_AXES": "Lokale Geräte Achsen", "vivecraft.options.RENDER_DEBUG_PLAYER_AXES": "Remote Geräte Achsen", @@ -606,6 +615,8 @@ "vivecraft.options.MIRROR_CROP.tooltip": "Gibt an, um wie viel das VR Bild zugeschnitten wird. Der Standardwert von 15%% versteckt die Augenschablone ganz gut. Wenn Sie ohne Augenschablone spielen, können Sie den Wert reduzieren, um ein größeres Sichtfeld im Desktop Spiegel zu bekommen.", "vivecraft.options.MIRROR_SCREENSHOT_CAMERA.tooltip": "Zeigt das Bild der Screenshot-Kamera im Desktop Spiegel. Wenn die Kamera inaktiv ist, wird stattdessen der ausgewählte Spiegelmodus angezeigt.\nIm Mixed Reality modus wird nur das Bild des 1. Person Teil im Unity-Layout ersetzt.", "vivecraft.options.MIRROR_OFF_TEXT.tooltip": "Zeigt ein Text an, wenn der Desktop Spiegel deaktiviert ist.", + "vivecraft.options.MIRROR_GUI.tooltip": "Ob das GUI über dem Desktop Spiegel gezeigt werden soll.\n Aus: Zeigt das GUI nicht.\n Nur HUD: Zeigt das GUI nur, wenn kein Menü offen ist.\n Immer: Zeigt das GUI immer, auch in Menüs.", + "vivecraft.options.MIXED_REALITY_GUI.tooltip": "Gibt an, auf welchen Ansichten das GUI gezeigt wird.\n 1. Person: Zeigt das GUI auf der 1. Person Ansicht. (nur Unity)\n 3. Person: Zeigt das GUI auf der 3. Person Ansicht.\n Beide: Zeigt das GUI auf der 1. und 3. Person Ansicht.\n Separat: Zeigt das GUI im rechten oberen Viertel im Unity-Layout. (Alpha Maske muss deaktiviert sein)", "vivecraft.options.RENDER_DEBUG_HEAD_HITBOX.tooltip": "Zeigt Kopf Kollisionsboxen für alle Kreaturen, wenn die Debug Kollisionsboxen angezeigt werden.", "vivecraft.options.RENDER_DEBUG_DEVICE_AXES.tooltip": "Zeigt Debug Achsen für die VR Geräte des lokalen Spielers.", "vivecraft.options.RENDER_DEBUG_PLAYER_AXES.tooltip": "Zeigt Debug Achsen für die VR Geräte aller Spieler die vom Server empfangen wurden.", 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 4233a7319..4cd42af07 100644 --- a/common/src/main/resources/assets/vivecraft/lang/en_us.json +++ b/common/src/main/resources/assets/vivecraft/lang/en_us.json @@ -512,6 +512,13 @@ "vivecraft.options.datasource.realtime": "Realtime", "vivecraft.options.datasource.local": "Local", "vivecraft.options.datasource.server": "Server", + "vivecraft.options.mirrorgui.off": "OFF", + "vivecraft.options.mirrorgui.hudonly": "HUD Only", + "vivecraft.options.mirrorgui.always": "Always", + "vivecraft.options.mixedrealitygui.first": "1st Person", + "vivecraft.options.mixedrealitygui.third": "3rd Person", + "vivecraft.options.mixedrealitygui.both": "Both", + "vivecraft.options.mixedrealitygui.separate": "Separate", "_comment_m5": "Option names", "vivecraft.options.LOW_HEALTH_INDICATOR": "Health Indicator", "vivecraft.options.HIT_INDICATOR": "Damage Indicator", @@ -550,6 +557,8 @@ "vivecraft.options.MIRROR_CROP": "Mirror Cropping", "vivecraft.options.MIRROR_SCREENSHOT_CAMERA": "Camera as Desktop Mirror", "vivecraft.options.MIRROR_OFF_TEXT": "Show Mirror OFF Text", + "vivecraft.options.MIRROR_GUI": "GUI On Mirror", + "vivecraft.options.MIXED_REALITY_GUI": "Show GUI On", "vivecraft.options.RENDER_DEBUG_HEAD_HITBOX": "Head Hitboxes", "vivecraft.options.RENDER_DEBUG_DEVICE_AXES": "Local Device Axes", "vivecraft.options.RENDER_DEBUG_PLAYER_AXES": "Remote Device Axes", @@ -608,6 +617,8 @@ "vivecraft.options.MIRROR_CROP.tooltip": "Specifies how much of the VR image gets cropped. The default 15%% hides the stencil pretty good. If you play without stencil, you can reduce this, to get a bigger FOV for the mirror.", "vivecraft.options.MIRROR_SCREENSHOT_CAMERA.tooltip": "If enabled, the screenshot camera will be displayed as the desktop mirror. When the camera is inactive, the currently selected mirror mode is used instead.\nIn mixed reality mode, only applies to the first person viewport in the Unity layout.", "vivecraft.options.MIRROR_OFF_TEXT.tooltip": "If enabled, shows a text stating that the desktop mirror is disabled.", + "vivecraft.options.MIRROR_GUI.tooltip": "If the GUI should be overlaid on the desktop mirror.\n OFF: Doesn't show the GUI.\n HUD Only: Only shows the GUI when no screen is open.\n Always: Always shows the GUI, even menus.", + "vivecraft.options.MIXED_REALITY_GUI.tooltip": "Specifies on which views the GUI is overlaid.\n 1st Person: Shows the GUI on the first person view. (Unity only)\n 3st Person: Shows the GUI on the third person view.\n Both: Shows the GUI on the first and third person view.\n Separate: Shows the GUI in the top right quadrant with the Unity layout. (Alpha Mask needs to be disabled)", "vivecraft.options.RENDER_DEBUG_HEAD_HITBOX.tooltip": "If enabled, a head hitbox will be rendered for all entities when debug hitboxes are shown", "vivecraft.options.RENDER_DEBUG_DEVICE_AXES.tooltip": "If enabled, debug axes will be shown for the local players VR devices.", "vivecraft.options.RENDER_DEBUG_PLAYER_AXES.tooltip": "If enabled, debug axes will be shown for all VR players received from the server.", diff --git a/common/src/main/resources/assets/vivecraft/shaders/core/mixedreality_vr.fsh b/common/src/main/resources/assets/vivecraft/shaders/core/mixedreality_vr.fsh index 742700714..b41ae2938 100644 --- a/common/src/main/resources/assets/vivecraft/shaders/core/mixedreality_vr.fsh +++ b/common/src/main/resources/assets/vivecraft/shaders/core/mixedreality_vr.fsh @@ -1,10 +1,16 @@ #version 330 +#define GUI_FIRST 1 +#define GUI_THIRD 2 +#define GUI_SEPARATE 4 + uniform sampler2D firstPersonColor; uniform sampler2D thirdPersonColor; uniform sampler2D thirdPersonDepth; +uniform sampler2D guiColor; + layout(std140) uniform MixedRealityUbo { mat4 projectionMatrix; mat4 viewMatrix; @@ -16,6 +22,7 @@ layout(std140) uniform MixedRealityUbo { int alphaMode; int firstPersonPass; + int guiMask; }; in vec2 texCoordinates; @@ -42,46 +49,63 @@ vec3 avoidKeyColor(in vec3 color) { } } +vec4 sampleTexture(sampler2D colorSampler, vec2 coord, int gui) { + vec4 color = vec4(texture(colorSampler, coord).rgb, 0.0); + if ((guiMask & gui) != 0) { + vec4 guiColor = texture(guiColor, coord); + color.rgb = mix(color.rgb, guiColor.rgb, guiColor.a); + color.a = guiColor.a; + } + return color; +} + void main(void) { out_Color = vec4(keyColor.rgb, 1.0); if (firstPersonPass == 1) { // unity like - vec2 sampleTexcCoord = fract(texCoordinates * 2.0); - if (texCoordinates.x < 0.5 && texCoordinates.y < 0.5) { - // third person all - out_Color.rgb = texture(thirdPersonColor, sampleTexcCoord).rgb; - } else if (texCoordinates.y >= 0.5){ - // third person front - vec3 fragPos = getFragmentPosition(sampleTexcCoord); - if (dot(fragPos - hmdViewPosition.xyz, hmdPlaneNormal.xyz) >= 0.0) { - if (texCoordinates.x < 0.5) { - // color - out_Color.rgb = texture(thirdPersonColor, sampleTexcCoord).rgb; - if (alphaMode == 0) { - out_Color.rgb = avoidKeyColor(out_Color.rgb); + vec2 sampleTexCoord = fract(texCoordinates * 2.0); + if (texCoordinates.x >= 0.5 && texCoordinates.y < 0.5) { + // first person + out_Color.rgb = sampleTexture(firstPersonColor, sampleTexCoord, GUI_FIRST).rgb; + } else { + vec4 thirdColor = sampleTexture(thirdPersonColor, sampleTexCoord, GUI_THIRD); + if (texCoordinates.x < 0.5 && texCoordinates.y < 0.5) { + // third person all + out_Color.rgb = thirdColor.rgb; + } else if (texCoordinates.y >= 0.5) { + // third person front + vec3 fragPos = getFragmentPosition(sampleTexCoord); + if (texCoordinates.x >= 0.5 && (guiMask & GUI_SEPARATE) != 0 && alphaMode != 1) { + vec4 guiCol = texture(guiColor, sampleTexCoord); + out_Color.rgb = mix(out_Color.rgb, avoidKeyColor(guiCol.rgb), step(0.1, guiCol.a)); + } else if (dot(fragPos - hmdViewPosition.xyz, hmdPlaneNormal.xyz) >= 0.0 || thirdColor.a > 0.1) { + if (texCoordinates.x < 0.5) { + // color + out_Color.rgb = thirdColor.rgb; + if (alphaMode == 0) { + out_Color.rgb = avoidKeyColor(out_Color.rgb); + } + } else if (alphaMode == 1) { + // white mask + out_Color.rgb = vec3(1.0); } - } else if (alphaMode == 1){ - // white mask - out_Color.rgb = vec3(1.0); } } - } else if (texCoordinates.x >= 0.5 && texCoordinates.y < 0.5){ - // first person - out_Color.rgb = texture(firstPersonColor, sampleTexcCoord).rgb; } } else { // side by side - vec2 sampleTexcCoord = fract(texCoordinates * vec2(2.0, 1.0)); + vec2 sampleTexCoord = fract(texCoordinates * vec2(2.0, 1.0)); + vec4 thirdColor = sampleTexture(thirdPersonColor, sampleTexCoord, GUI_THIRD); if (texCoordinates.x >= 0.5) { // third person all - out_Color.rgb = texture(thirdPersonColor, sampleTexcCoord).rgb; + out_Color.rgb = thirdColor.rgb; } else { // third person front - vec3 fragPos = getFragmentPosition(sampleTexcCoord); - if (dot(fragPos - hmdViewPosition.xyz, hmdPlaneNormal.xyz) >= 0.0) { + vec3 fragPos = getFragmentPosition(sampleTexCoord); + if (dot(fragPos - hmdViewPosition.xyz, hmdPlaneNormal.xyz) >= 0.0 || thirdColor.a > 0.1) { // color - out_Color.rgb = avoidKeyColor(texture(thirdPersonColor, sampleTexcCoord).rgb); + out_Color.rgb = avoidKeyColor(thirdColor.rgb); } } } From 1cf8384c2a4aeacfd973913ee5c16af0c92dc338 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Wed, 12 Nov 2025 21:35:45 +0100 Subject: [PATCH 62/76] fix crash when opening the quick commands gui in nonvr --- .../vivecraft/client/gui/settings/GuiQuickCommandsInGame.java | 1 - 1 file changed, 1 deletion(-) diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiQuickCommandsInGame.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiQuickCommandsInGame.java index 1aeffd2da..9dc483773 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiQuickCommandsInGame.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiQuickCommandsInGame.java @@ -48,7 +48,6 @@ public void init() { @Override public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { - this.renderBackground(guiGraphics, mouseX, mouseY, partialTick); guiGraphics.drawCenteredString(this.font, this.getTitle(), this.width / 2, 16, 0xFFFFFFFF); super.render(guiGraphics, mouseX, mouseY, partialTick); } From c7e2b32378e6eb9359b3a2d0fbed8b496367f830 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sat, 15 Nov 2025 02:05:47 +0100 Subject: [PATCH 63/76] - allow smooth rotation to be activated with keybinds - allow radial menu keybinds to be hold - fix simulated keys not unpressing when switching to nonvr --- .../org/vivecraft/client_vr/MethodHolder.java | 7 +++ .../vivecraft/client_vr/gui/GuiRadial.java | 17 +++++- .../client_vr/provider/HandedKeyBinding.java | 4 ++ .../vivecraft/client_vr/provider/MCVR.java | 14 ++++- .../provider/openvr_lwjgl/VRInputAction.java | 56 +++++++++++++++++-- .../mixin/client_vr/MinecraftVRMixin.java | 6 ++ 6 files changed, 95 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/MethodHolder.java b/common/src/main/java/org/vivecraft/client_vr/MethodHolder.java index 0d62bf132..1ff48152c 100644 --- a/common/src/main/java/org/vivecraft/client_vr/MethodHolder.java +++ b/common/src/main/java/org/vivecraft/client_vr/MethodHolder.java @@ -1,5 +1,6 @@ package org.vivecraft.client_vr; +import com.mojang.blaze3d.platform.InputConstants; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.*; import org.lwjgl.glfw.GLFW; @@ -7,6 +8,12 @@ public abstract class MethodHolder { + + public static boolean isKeyDown(InputConstants.Key key) { + return key.getType() == InputConstants.Type.KEYSYM && key.getValue() != GLFW.GLFW_KEY_UNKNOWN && + isKeyDown(key.getValue()); + } + public static boolean isKeyDown(int i) { return GLFW.glfwGetKey(Minecraft.getInstance().getWindow().handle(), i) == 1 || InputSimulator.isKeyDown(i); } diff --git a/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java b/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java index 407a33d2c..17909cff4 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java +++ b/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java @@ -7,6 +7,7 @@ import net.minecraft.network.chat.Component; import org.vivecraft.client.gui.framework.screens.TwoHandedScreen; import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.MethodHolder; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.openvr_lwjgl.VRInputAction; @@ -39,12 +40,22 @@ public void init() { .filter(keymapping -> keymapping.getName().equalsIgnoreCase(current)) .findFirst() .ifPresent(keymapping -> { + VRInputAction vrinputaction = MCVR.get().getInputAction(this.arr[index]); String label = I18n.get(keymapping.getName()); + if (vrinputaction != null && + (vrinputaction.keyBinding.isDown() || MethodHolder.isKeyDown(vrinputaction.keyBinding.key))) + { + label = "§a" + label; + } this.addRenderableWidget(createButton(label, (p) -> { - VRInputAction vrinputaction = MCVR.get().getInputAction(this.arr[index]); if (vrinputaction != null) { - vrinputaction.pressBinding(); - vrinputaction.unpressBinding(2); + if (vrinputaction.keyBinding.isDown() || + MethodHolder.isKeyDown(vrinputaction.keyBinding.key)) + { + vrinputaction.stopHoldingBinding(2); + } else { + vrinputaction.holdBinding(); + } } }, index, centerX, centerY)); }); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/HandedKeyBinding.java b/common/src/main/java/org/vivecraft/client_vr/provider/HandedKeyBinding.java index 716e5cd04..5760a21c8 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/HandedKeyBinding.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/HandedKeyBinding.java @@ -38,6 +38,10 @@ public boolean isDown(ControllerType hand) { return this.pressed[hand.ordinal()]; } + public int presses(ControllerType hand) { + return this.pressTime[hand.ordinal()]; + } + public void pressKey(ControllerType hand) { this.pressed[hand.ordinal()] = true; this.pressTime[hand.ordinal()]++; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java index 4f5f9a8e8..24a086b52 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java @@ -834,8 +834,18 @@ public void processBindings() { } // single direction keys - ax -= Math.abs(this.getInputAction(MOD.keyRotateLeft).getAxis1DUseTracked()); - ax += Math.abs(this.getInputAction(MOD.keyRotateRight).getAxis1DUseTracked()); + float leftRot = Math.abs(this.getInputAction(MOD.keyRotateLeft).getAxis1DUseTracked()); + float rightRot = Math.abs(this.getInputAction(MOD.keyRotateRight).getAxis1DUseTracked()); + + if (leftRot == 0 && MOD.keyRotateLeft.isDown()) { + leftRot = 1F; + } + if (rightRot == 0 && MOD.keyRotateRight.isDown()) { + rightRot = 1F; + } + + ax -= leftRot; + ax += rightRot; if (ax != 0.0F) { float analogRotSpeed = this.dh.vrSettings.worldRotationXSensitivity * 10.0F * ax; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/VRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/VRInputAction.java index 1d50a312c..6b2d86c6e 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/VRInputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/VRInputAction.java @@ -36,6 +36,7 @@ public class VRInputAction { public long handle; private final boolean[] pressed = new boolean[ControllerType.values().length]; + private final boolean[] held = new boolean[ControllerType.values().length]; protected final int[] unpressInTicks = new int[ControllerType.values().length]; public final DigitalData[] digitalData = new DigitalData[ControllerType.values().length]; @@ -324,12 +325,20 @@ public boolean notifyListeners(boolean pressed, ControllerType hand) { public void tick() { if (this.isHanded()) { for (int c = 0; c < ControllerType.values().length; c++) { - if (this.unpressInTicks[c] > 0 && --this.unpressInTicks[c] == 0) { - this.unpressBindingImmediately(ControllerType.values()[c]); + ControllerType type = ControllerType.values()[c]; + HandedKeyBinding handedKeyBinding = (HandedKeyBinding) this.keyBinding; + if ((!this.held[c] && this.unpressInTicks[c] > 0 && --this.unpressInTicks[c] == 0) || + (this.held[c] && (!handedKeyBinding.isDown(type) || handedKeyBinding.presses(type) == 0))) + { + this.unpressBindingImmediately(type); } } - } else if (this.unpressInTicks[0] > 0 && --this.unpressInTicks[0] == 0) { - this.unpressBindingImmediately(null); + } else { + if ((!this.held[0] && this.unpressInTicks[0] > 0 && --this.unpressInTicks[0] == 0) || + (this.held[0] && (!this.keyBinding.isDown() || this.keyBinding.clickCount == 0))) + { + this.unpressBindingImmediately(null); + } } } @@ -341,6 +350,32 @@ public void setPressed(boolean pressed) { } } + public void holdBinding() { + this.holdBinding(this.currentHand); + } + + public void holdBinding(ControllerType hand) { + if (this.isHanded()) { + this.held[hand.ordinal()] = true; + } else { + this.held[0] = true; + } + this.pressBinding(this.currentHand); + } + + public void stopHoldingBinding(int unpressInTicks) { + this.stopHoldingBinding(unpressInTicks, this.currentHand); + } + + public void stopHoldingBinding(int unpressInTicks, ControllerType hand) { + if (this.isHanded()) { + this.held[hand.ordinal()] = false; + } else { + this.held[0] = false; + } + this.unpressBinding(unpressInTicks, this.currentHand); + } + private void pressBinding(ControllerType hand) { if (this.isHanded()) { if (hand == null || this.pressed[hand.ordinal()]) return; @@ -385,11 +420,23 @@ public void unpressBinding() { this.unpressBinding(1); } + public void unpressBindingImmediately() { + if (this.isHanded()) { + for (int c = 0; c < ControllerType.values().length; c++) { + this.unpressBindingImmediately(ControllerType.values()[c]); + } + } else { + + this.unpressBindingImmediately(null); + } + } + public void unpressBindingImmediately(ControllerType hand) { if (this.isHanded()) { if (hand == null || !this.pressed[hand.ordinal()]) return; this.pressed[hand.ordinal()] = false; + this.held[hand.ordinal()] = false; if (this.notifyListeners(false, hand)) return; @@ -398,6 +445,7 @@ public void unpressBindingImmediately(ControllerType hand) { if (!this.pressed[0]) return; this.pressed[0] = false; + this.held[0] = false; if (this.notifyListeners(false, null)) return; 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 412a061ca..95bb3dace 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 @@ -862,6 +862,12 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { mouseY); this.mouseHandler.grabMouse(); } + // unpress any keys we simulated for VR + if (MCVR.get() != null) { + for (VRInputAction action : MCVR.get().getInputActions()) { + action.unpressBindingImmediately(); + } + } } // send new VR state to the server From bb337c71511febc57399d012b72c33b0b3d4a13d Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sat, 15 Nov 2025 16:36:41 +0100 Subject: [PATCH 64/76] fix some menuworlds fail to load with serene season --- .../sereneseasons/mixin/ModClientMixin.java | 25 +++++++++++++++++++ .../mixin/SeasonColorHandlersMixin.java | 4 +-- .../vivecraft.sereneseasons.mixins.json | 1 + 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 common/src/main/java/org/vivecraft/mod_compat_vr/sereneseasons/mixin/ModClientMixin.java diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/sereneseasons/mixin/ModClientMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/sereneseasons/mixin/ModClientMixin.java new file mode 100644 index 000000000..25a4aff3a --- /dev/null +++ b/common/src/main/java/org/vivecraft/mod_compat_vr/sereneseasons/mixin/ModClientMixin.java @@ -0,0 +1,25 @@ +package org.vivecraft.mod_compat_vr.sereneseasons.mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.world.level.FoliageColor; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Pseudo +@Mixin(targets = "sereneseasons.init.ModClient") +public class ModClientMixin { + + /** + * menuworld fix + */ + @Inject(method = "lambda$registerBlockColors$0", at = @At("HEAD"), remap = false, cancellable = true) + private static void vivecraft$grassColor(CallbackInfoReturnable cir) { + if (Minecraft.getInstance().player == null) { + cir.setReturnValue(FoliageColor.FOLIAGE_BIRCH); + } + } + +} diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/sereneseasons/mixin/SeasonColorHandlersMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/sereneseasons/mixin/SeasonColorHandlersMixin.java index 507c36602..15b8478d7 100644 --- a/common/src/main/java/org/vivecraft/mod_compat_vr/sereneseasons/mixin/SeasonColorHandlersMixin.java +++ b/common/src/main/java/org/vivecraft/mod_compat_vr/sereneseasons/mixin/SeasonColorHandlersMixin.java @@ -4,6 +4,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.ColorResolver; +import net.minecraft.world.level.FoliageColor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.state.BlockState; import org.spongepowered.asm.mixin.Mixin; @@ -51,8 +52,7 @@ public class SeasonColorHandlersMixin { CallbackInfoReturnable cir) { if (Minecraft.getInstance().level == null) { - // this is now hardcoded since 1.21.4 - cir.setReturnValue(0xFF80A755); + cir.setReturnValue(FoliageColor.FOLIAGE_BIRCH); } } } diff --git a/common/src/main/resources/vivecraft.sereneseasons.mixins.json b/common/src/main/resources/vivecraft.sereneseasons.mixins.json index eb2736b69..9ec09bf28 100644 --- a/common/src/main/resources/vivecraft.sereneseasons.mixins.json +++ b/common/src/main/resources/vivecraft.sereneseasons.mixins.json @@ -4,6 +4,7 @@ "plugin": "org.vivecraft.MixinConfig", "compatibilityLevel": "JAVA_17", "client": [ + "ModClientMixin", "SeasonColorHandlersMixin" ], "minVersion": "0.8.4" From f7556e4934e471bbe688864f886038ec5bd7c30f Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sun, 16 Nov 2025 02:26:41 +0100 Subject: [PATCH 65/76] use fbt feet position for the player when available --- .../gui/settings/GuiStandingSettings.java | 3 ++- .../client_vr/gameplay/VRPlayer.java | 21 +++++++++++++++++-- .../client_vr/settings/VRSettings.java | 3 +++ .../sereneseasons/mixin/ModClientMixin.java | 1 - .../assets/vivecraft/lang/de_de.json | 2 ++ .../assets/vivecraft/lang/en_us.json | 2 ++ 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiStandingSettings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiStandingSettings.java index c80cbafc2..238c1670b 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiStandingSettings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiStandingSettings.java @@ -12,8 +12,9 @@ public class GuiStandingSettings extends GuiVROptionsBase { new VROptionEntry(VRSettings.VrOptions.WALK_MULTIPLIER), new VROptionEntry(VRSettings.VrOptions.WORLD_ROTATION_INCREMENT), new VROptionEntry(VRSettings.VrOptions.BCB_ON), - new VROptionEntry(VRSettings.VrOptions.ALLOW_STANDING_ORIGIN_OFFSET), + new VROptionEntry(VRSettings.VrOptions.FEET_BODY_POSITION), new VROptionEntry(VRSettings.VrOptions.WORLD_ROTATION_X_SENSITIVITY), + new VROptionEntry(VRSettings.VrOptions.ALLOW_STANDING_ORIGIN_OFFSET), new VROptionEntry(VRSettings.VrOptions.FORCE_STANDING_FREE_MOVE, true), new VROptionEntry(VRSettings.VrOptions.DUMMY, true), new VROptionEntry("vivecraft.options.screen.teleport.button", (button, mousePos) -> { diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java index 58b787502..d26f2a995 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/VRPlayer.java @@ -26,6 +26,8 @@ import org.joml.Vector3fc; import org.vivecraft.api.client.Tracker; import org.vivecraft.api.client.data.RenderPass; +import org.vivecraft.api.data.FBTMode; +import org.vivecraft.api.data.VRBodyPart; import org.vivecraft.client.VivecraftVRMod; import org.vivecraft.client.api_impl.VRClientAPIImpl; import org.vivecraft.client.network.ClientNetworking; @@ -472,10 +474,25 @@ public void doPlayerMoveInRoom(LocalPlayer player) { float playerHalfWidth = player.getBbWidth() / 2.0F; float playerHeight = player.getBbHeight(); + Vec3 feetPos = null; + if (!this.dh.vrSettings.seated && this.dh.vrSettings.feetBodyPosition && + this.vrdata_room_pre.fbtMode != FBTMode.ARMS_ONLY) + { + Vector3f leftFoot = this.vrdata_room_pre.getBodyPart(VRBodyPart.LEFT_FOOT).getPositionF(); + Vector3f rightFoot = this.vrdata_room_pre.getBodyPart(VRBodyPart.RIGHT_FOOT).getPositionF(); + if (leftFoot.y < 0.1F && rightFoot.y < 0.1F) { + feetPos = roomToWorldPos(leftFoot.add(rightFoot).mul(0.5F), this.vrdata_world_pre); + } else if (leftFoot.y < 0.1F) { + feetPos = roomToWorldPos(leftFoot, this.vrdata_world_pre); + } else if (rightFoot.y < 0.1F) { + feetPos = roomToWorldPos(rightFoot, this.vrdata_world_pre); + } + } + // OK this is the first place I've found where we really need to update the VR data before doing this calculation. - double x = newHeadPivot.x; + double x = feetPos == null ? newHeadPivot.x : feetPos.x; double y = player.getY(); - double z = newHeadPivot.z; + double z = feetPos == null ? newHeadPivot.z : feetPos.z; // create bounding box at dest position AABB bb = new AABB( 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 97c3fde1d..a9caf08a5 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 @@ -396,6 +396,8 @@ public enum AimDevice implements OptionEnum { public boolean allowCrawling = true; @SettingField(value = VrOptions.BCB_ON, config = "bcbOn") public boolean vrShowBlueCircleBuddy = true; + @SettingField(value = VrOptions.FEET_BODY_POSITION) + public boolean feetBodyPosition = true; @SettingField(VrOptions.VEHICLE_ROTATION) public boolean vehicleRotation = true; @SettingField(VrOptions.ANALOG_MOVEMENT) @@ -1923,6 +1925,7 @@ void onOptionChange() { } }, BCB_ON(false, true), // Show Body Position + FEET_BODY_POSITION(false, true), // uses the average of the fbt feet trackers as body position WORLD_SCALE(true, false, 0, 29, 1, 2) { // World Scale @Override diff --git a/common/src/main/java/org/vivecraft/mod_compat_vr/sereneseasons/mixin/ModClientMixin.java b/common/src/main/java/org/vivecraft/mod_compat_vr/sereneseasons/mixin/ModClientMixin.java index 25a4aff3a..35d1bcf48 100644 --- a/common/src/main/java/org/vivecraft/mod_compat_vr/sereneseasons/mixin/ModClientMixin.java +++ b/common/src/main/java/org/vivecraft/mod_compat_vr/sereneseasons/mixin/ModClientMixin.java @@ -21,5 +21,4 @@ public class ModClientMixin { cir.setReturnValue(FoliageColor.FOLIAGE_BIRCH); } } - } 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 db7035f97..ece18c1f8 100644 --- a/common/src/main/resources/assets/vivecraft/lang/de_de.json +++ b/common/src/main/resources/assets/vivecraft/lang/de_de.json @@ -581,6 +581,7 @@ "vivecraft.options.GAMEPLAY_TRACKER_TO_RENDER": "Gezeigter Gameplaytracker", "vivecraft.options.CONTROLLER_TRANSFORM": "Controller Transformation", "vivecraft.options.FULL_RELOAD_ON_INIT": "Neuladen bei Init", + "vivecraft.options.FEET_BODY_POSITION": "Benutze Fußposition", "_comment_m6": "Option tooltips", "vivecraft.options.LOW_HEALTH_INDICATOR.tooltip": "Pulsiert den Bildschirm Rot bei niedriger Gesundheit, um den derzeitigen Gesundheitszustand anzuzeigen.", "vivecraft.options.HIT_INDICATOR.tooltip": "Blinkt den Bildschirm Rot, wenn der Spieler Schaden nimmt.", @@ -644,6 +645,7 @@ "vivecraft.options.GAMEPLAY_TRACKER_TO_RENDER.tooltip": "Legt fest, welcher Gameplaytracker Debuginformationen zeigen soll.", "vivecraft.options.CONTROLLER_TRANSFORM.tooltip": "Legt fest, welche Drehtransformation für die Controller verwendet werden soll.\nAUTO fragt die VR Laufzeit für die Drehtransformation.", "vivecraft.options.FULL_RELOAD_ON_INIT.tooltip": "Erzwingt einen vollständiges Neuladen der Resourcen, wenn VR gewechselt wird, auf Kosten einer längeren Wartezeit.\nDies kann bei manchen Problemen mit anderen Mods helfen, welche ihre Resourcen nur bei einem vollständigen Neuladen reinitialisieren.", + "vivecraft.options.FEET_BODY_POSITION.tooltip": "Wenn dies aktiv ist, verwendet die Spielerposition das Mittel der Fußtracker nahe dem Boden.\n Wenn dies deaktiviert ist (oder ohne FBT Tracker), verwendet die Spielerposition die Kopfposition.", "_comment_m10": "Messages", "vivecraft.messages.mode": "Modus:", "vivecraft.messages.novrhotswitchinglegacy": "Veralteten Vivecraft server mod erkannt. Dieser Server unterstützt kein VR Schnellwechsel. Sie können den Modus nur im Hauptmenü wechseln.", 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 4cd42af07..3a4e1b7bd 100644 --- a/common/src/main/resources/assets/vivecraft/lang/en_us.json +++ b/common/src/main/resources/assets/vivecraft/lang/en_us.json @@ -583,6 +583,7 @@ "vivecraft.options.GAMEPLAY_TRACKER_TO_RENDER": "Gameplay Tracker To Show", "vivecraft.options.CONTROLLER_TRANSFORM": "Controller Transform", "vivecraft.options.FULL_RELOAD_ON_INIT": "Reload On Init", + "vivecraft.options.FEET_BODY_POSITION": "Use Feet Position", "_comment_m6": "Option tooltips", "vivecraft.options.LOW_HEALTH_INDICATOR.tooltip": "Pulses the screen red, when at low health, to indicate your current health status.", "vivecraft.options.HIT_INDICATOR.tooltip": "Flashes the screen red, when taking damage.", @@ -646,6 +647,7 @@ "vivecraft.options.GAMEPLAY_TRACKER_TO_RENDER.tooltip": "Determines which gameplay tracker should show debug info.", "vivecraft.options.CONTROLLER_TRANSFORM.tooltip": "Determines which rotation transforms the controllers should use.\nAUTO will ask the VR Runtime for the rotation transforms.", "vivecraft.options.FULL_RELOAD_ON_INIT.tooltip": "Forces a full resource reload when toggling VR, at the cost of longer wait times.\nThis can fix some issues with Mods that reinitialize some stuff only on a full resource reload.", + "vivecraft.options.FEET_BODY_POSITION.tooltip": "When enabled, the player position will use the average of the feet FBT trackers that are near the ground.\n When disabled (or without FBT trackers), the player position will use the head position.", "_comment_m10": "Messages", "vivecraft.messages.mode": "Mode:", "vivecraft.messages.novrhotswitchinglegacy": "Legacy Vivecraft server mod detected. This Server does not support VR hot switching, you can only change it in the main menu.", From 7e879dd50d2f515170155f764a6757803d8974ce Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sun, 16 Nov 2025 02:40:05 +0100 Subject: [PATCH 66/76] fix search button being offscreen on narrow windows sizes fix keyboard editors missing in the setting search --- .../gui/framework/screens/GuiVROptionsBase.java | 11 +++++++++-- .../client/gui/settings/GuiAllSettings.java | 12 ++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiVROptionsBase.java b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiVROptionsBase.java index 6c035794c..714e60d27 100644 --- a/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiVROptionsBase.java +++ b/common/src/main/java/org/vivecraft/client/gui/framework/screens/GuiVROptionsBase.java @@ -52,8 +52,15 @@ protected void addDefaultButtons() { .sprite(SEARCH_ICON, 15, 15) .size(20, 20) .build(); - search.setX(this.width / 2 - 180); - search.setY((int) Math.ceil((float) (this.height / 6) - 10.0F)); + if (this.width > 360) { + // but the search to the side + search.setX(this.width / 2 - 180); + search.setY((int) Math.ceil((float) (this.height / 6) - 10.0F)); + } else { + // but the search above + search.setX(this.width / 2 - 155); + search.setY((int) Math.ceil((float) (this.height / 6) - 31.0F)); + } search.setTooltip(Tooltip.create(Component.translatable("vivecraft.options.screen.search"))); this.addRenderableWidget(search); diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiAllSettings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiAllSettings.java index e78250754..415d4bdbf 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiAllSettings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiAllSettings.java @@ -40,6 +40,18 @@ protected List getEntries() { entries.add(new SettingsList.ScreenEntry( "vivecraft.options.screen.blocklist", GuiBlacklistEditor::new)); + // keyboard layouts + entries.add(new SettingsList.ScreenEntry( + "vivecraft.options.screen.activekeyboardlayouts", GuiActiveKeyboardLayoutSelector::new)); + + // custom keyboard layout editor + entries.add(new SettingsList.ScreenEntry( + "vivecraft.options.screen.customkeyboardeditor", GuiKeyboardLayoutEditor::new)); + + // keyboard theme editor + entries.add(new SettingsList.ScreenEntry( + "vivecraft.options.screen.customkeyboardthemeeditor", GuiKeyboardThemeEditor::new)); + // server settings for (ConfigBuilder.ConfigValue cv : ServerConfig.getConfigValues()) { entries.add(SettingsList.ConfigToEntry(cv)); From e10658e42fcd3b4d673b53520d3a993fe4fbd3fa Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Sun, 16 Nov 2025 20:27:15 +0100 Subject: [PATCH 67/76] Start working on Rebinding of keys (#412) --- .../org/vivecraft/client/VivecraftVRMod.java | 2 +- .../client/gui/framework/TwoHandedScreen.java | 2 +- .../gui/screens/FBTCalibrationScreen.java | 2 +- .../client/gui/settings/GuiBindings.java | 95 ++++++++++++++++ .../gui/settings/VivecraftMainSettings.java | 8 ++ .../gameplay/screenhandlers/GuiHandler.java | 4 +- .../screenhandlers/KeyboardHandler.java | 2 +- .../screenhandlers/RadialHandler.java | 2 +- .../gameplay/trackers/BowTracker.java | 2 +- .../gameplay/trackers/ClimbTracker.java | 2 +- .../gameplay/trackers/InteractTracker.java | 2 +- .../gameplay/trackers/SwingTracker.java | 2 +- .../client_vr/gui/PhysicalKeyboard.java | 2 +- .../client_vr/provider/HapticScheduler.java | 2 + .../vivecraft/client_vr/provider/MCVR.java | 78 +++++++------ .../provider/{ => control}/ActionParams.java | 8 +- .../provider/control/ActionType.java | 13 +++ .../{ => control}/ControllerType.java | 2 +- .../{ => control}/HandedKeyBinding.java | 2 +- .../provider/control/HapticMusicPlayer.java | 1 - .../control/TrackpadSwipeSampler.java | 2 - .../provider/control/VRInputAction.java | 60 ++++++---- .../client_vr/provider/nullvr/NullVR.java | 2 +- .../nullvr/NullVRHapticScheduler.java | 2 +- .../provider/openvr_lwjgl/MCOpenVR.java | 6 +- .../openvr_lwjgl/OpenVRHapticScheduler.java | 2 +- .../client_vr/provider/openxr/MCOpenXR.java | 106 +++++++++++------- .../openxr/OpenXRHapticScheduler.java | 2 +- .../client_vr/provider/openxr/XRBindings.java | 44 ++++---- .../openxr/control/RebindableBinding.java | 6 + .../openxr/control/WrappedBinding.java | 48 ++++++++ .../client_vr/render/VRArmRenderer.java | 2 +- .../render/helpers/VREffectsHelper.java | 2 +- .../ClientPacketListenerVRMixin.java | 2 +- .../client_vr/world/FishingHookVRMixin.java | 2 +- 35 files changed, 363 insertions(+), 158 deletions(-) create mode 100644 common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java rename common/src/main/java/org/vivecraft/client_vr/provider/{ => control}/ActionParams.java (62%) create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/control/ActionType.java rename common/src/main/java/org/vivecraft/client_vr/provider/{ => control}/ControllerType.java (50%) rename common/src/main/java/org/vivecraft/client_vr/provider/{ => control}/HandedKeyBinding.java (97%) create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/RebindableBinding.java create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/WrappedBinding.java diff --git a/common/src/main/java/org/vivecraft/client/VivecraftVRMod.java b/common/src/main/java/org/vivecraft/client/VivecraftVRMod.java index 29d8e0675..f80771e5c 100644 --- a/common/src/main/java/org/vivecraft/client/VivecraftVRMod.java +++ b/common/src/main/java/org/vivecraft/client/VivecraftVRMod.java @@ -4,7 +4,7 @@ import net.minecraft.client.Minecraft; import org.apache.commons.lang3.ArrayUtils; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; -import org.vivecraft.client_vr.provider.HandedKeyBinding; +import org.vivecraft.client_vr.provider.control.HandedKeyBinding; import java.util.*; diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/TwoHandedScreen.java b/common/src/main/java/org/vivecraft/client/gui/framework/TwoHandedScreen.java index 6c7e45316..1ffb3c416 100644 --- a/common/src/main/java/org/vivecraft/client/gui/framework/TwoHandedScreen.java +++ b/common/src/main/java/org/vivecraft/client/gui/framework/TwoHandedScreen.java @@ -10,7 +10,7 @@ import org.joml.Vector3f; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.render.helpers.RenderHelper; diff --git a/common/src/main/java/org/vivecraft/client/gui/screens/FBTCalibrationScreen.java b/common/src/main/java/org/vivecraft/client/gui/screens/FBTCalibrationScreen.java index 58ae24598..de5f53d5c 100644 --- a/common/src/main/java/org/vivecraft/client/gui/screens/FBTCalibrationScreen.java +++ b/common/src/main/java/org/vivecraft/client/gui/screens/FBTCalibrationScreen.java @@ -19,7 +19,7 @@ import org.vivecraft.client.gui.widgets.MultilineComponent; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.render.helpers.RenderHelper; import org.vivecraft.client_vr.settings.AutoCalibration; import org.vivecraft.common.utils.MathUtils; diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java new file mode 100644 index 000000000..47877d325 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java @@ -0,0 +1,95 @@ +package org.vivecraft.client.gui.settings; + +import com.google.common.collect.ImmutableList; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.narration.NarratableEntry; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import org.vivecraft.client.gui.widgets.SettingsList; +import org.vivecraft.client_vr.provider.control.ActionType; +import org.vivecraft.client_vr.provider.control.VRInputAction; +import org.vivecraft.client_vr.provider.openxr.MCOpenXR; + +import java.util.LinkedList; +import java.util.List; +import java.util.function.BooleanSupplier; +import java.util.function.Supplier; + +public class GuiBindings extends GuiListScreen { + + + public GuiBindings(Screen lastScreen) { + super(Component.translatable("vivecraft.options.screen.bindings"), lastScreen); + } + + @Override + protected List getEntries() { + List list = new LinkedList<>(); + for (var entry : MCOpenXR.get().pathBindings.entrySet()) { + var input = MCOpenXR.get().getInputActionByName(entry.getKey()); + if (input == null) continue; + list.add(new ResettableEntry(Component.translatable(entry.getKey()), input)); + } + return list; + } + + public static class ResettableEntry extends SettingsList.WidgetEntry { + public static final int VALUE_BUTTON_WIDTH = 125; + + private final Button resetButton; + private final BooleanSupplier canReset; + + public ResettableEntry(Component name, VRInputAction action) { + super(name, getBaseWidget(action, VALUE_BUTTON_WIDTH, 20).get()); + + this.canReset = () -> action.type != ActionType.BOOLEAN; + this.resetButton = Button.builder(Component.literal("X"), button -> { + action.setType(ActionType.BOOLEAN); + this.valueWidget = getBaseWidget(action, valueWidget.getWidth(), valueWidget.getHeight()).get(); + }) + .tooltip(Tooltip.create(Component.translatable("controls.reset"))) + .bounds(0, 0, 20, 20).build(); + } + + @Override + public void render( + GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, + boolean hovering, float partialTick) + { + super.render(guiGraphics, index, top, left, width, height, mouseX, mouseY, hovering, partialTick); + this.resetButton.setX(left + 230); + this.resetButton.setY(top); + this.resetButton.active = this.canReset.getAsBoolean(); + this.resetButton.render(guiGraphics, mouseX, mouseY, partialTick); + } + + @Override + public List children() { + return ImmutableList.of(this.valueWidget, this.resetButton); + } + + @Override + public List narratables() { + return ImmutableList.of(this.valueWidget, this.resetButton); + } + + @Override + public void setActive(boolean active) { + super.setActive(active); + this.resetButton.active = active; + } + } + + public static Supplier getBaseWidget(VRInputAction action, int width, int height) { + return () -> Button + .builder(Component.literal("" + action.type), button -> {}) + .bounds(0, 0, width, height) + .tooltip(Tooltip.create(Component.literal(action.name))) + .build(); + } + +} diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/VivecraftMainSettings.java b/common/src/main/java/org/vivecraft/client/gui/settings/VivecraftMainSettings.java index 792e81f3a..6a7df7979 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/VivecraftMainSettings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/VivecraftMainSettings.java @@ -68,6 +68,14 @@ protected List getEntries() { .build() )); + entries.add(new SettingsList.WidgetEntry( + Component.translatable("vivecraft.options.screen.bindings"), + Button.builder(Component.translatable("vivecraft.options.screen.bindings"), + button -> this.minecraft.setScreen(new GuiBindings(this))) + .size(SettingsList.WidgetEntry.VALUE_BUTTON_WIDTH, 20) + .build() + )); + return entries; } } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/GuiHandler.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/GuiHandler.java index 12591e9e1..7c86d82e5 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/GuiHandler.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/GuiHandler.java @@ -28,8 +28,8 @@ import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.extensions.WindowExtension; import org.vivecraft.client_vr.gameplay.VRPlayer; -import org.vivecraft.client_vr.provider.ControllerType; -import org.vivecraft.client_vr.provider.HandedKeyBinding; +import org.vivecraft.client_vr.provider.control.ControllerType; +import org.vivecraft.client_vr.provider.control.HandedKeyBinding; import org.vivecraft.client_vr.provider.InputSimulator; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.render.RenderPass; diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/KeyboardHandler.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/KeyboardHandler.java index e7000c04d..4a2973c5a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/KeyboardHandler.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/KeyboardHandler.java @@ -10,7 +10,7 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.gui.GuiKeyboard; import org.vivecraft.client_vr.gui.PhysicalKeyboard; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.common.utils.MathUtils; public class KeyboardHandler { diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/RadialHandler.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/RadialHandler.java index e96a0a0d7..cf465671d 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/RadialHandler.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/RadialHandler.java @@ -10,7 +10,7 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRData; import org.vivecraft.client_vr.gui.GuiRadial; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; public class RadialHandler { public static final ClientDataHolderVR DH = ClientDataHolderVR.getInstance(); diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/BowTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/BowTracker.java index 732237bc9..4300420eb 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/BowTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/BowTracker.java @@ -19,7 +19,7 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRData; import org.vivecraft.client_vr.extensions.PlayerExtension; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.common.network.packet.c2s.DrawPayloadC2S; import org.vivecraft.common.utils.MathUtils; diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/ClimbTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/ClimbTracker.java index 14df2fb6d..32731a1b4 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/ClimbTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/ClimbTracker.java @@ -23,7 +23,7 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.extensions.PlayerExtension; import org.vivecraft.client_vr.gameplay.VRPlayer; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.common.network.packet.c2s.ClimbingPayloadC2S; import org.vivecraft.data.BlockTags; import org.vivecraft.server.config.ClimbeyBlockmode; 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 dc2797724..545deebec 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 @@ -26,7 +26,7 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.MethodHolder; import org.vivecraft.client_vr.VRData; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.render.VRFirstPersonArmSwing; import org.vivecraft.client_vr.settings.VRHotkeys; diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java index 90bc5f33e..9bd7e7415 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java @@ -26,7 +26,7 @@ import org.vivecraft.client.network.ClientNetworking; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.Vector3fHistory; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.common.network.FBTMode; diff --git a/common/src/main/java/org/vivecraft/client_vr/gui/PhysicalKeyboard.java b/common/src/main/java/org/vivecraft/client_vr/gui/PhysicalKeyboard.java index 8812977ef..02b11a085 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gui/PhysicalKeyboard.java +++ b/common/src/main/java/org/vivecraft/client_vr/gui/PhysicalKeyboard.java @@ -25,7 +25,7 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.InputSimulator; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.render.helpers.RenderHelper; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/HapticScheduler.java b/common/src/main/java/org/vivecraft/client_vr/provider/HapticScheduler.java index 15574c363..b67578b75 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/HapticScheduler.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/HapticScheduler.java @@ -1,5 +1,7 @@ package org.vivecraft.client_vr.provider; +import org.vivecraft.client_vr.provider.control.ControllerType; + import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java index a2803c9db..41f43cce5 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java @@ -27,9 +27,7 @@ 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.provider.control.TrackpadSwipeSampler; -import org.vivecraft.client_vr.provider.control.VRInputAction; -import org.vivecraft.client_vr.provider.control.VRInputActionSet; +import org.vivecraft.client_vr.provider.control.*; import org.vivecraft.client_vr.provider.openxr.DeviceCompat; import org.vivecraft.client_vr.gameplay.trackers.ClimbTracker; import org.vivecraft.client_vr.render.RenderConfigException; @@ -1140,41 +1138,41 @@ public void populateInputActions() { public Map getSpecialActionParams() { Map map = new HashMap<>(); - this.addActionParams(map, this.mc.options.keyUp, "optional", "vector1", null); - this.addActionParams(map, this.mc.options.keyDown, "optional", "vector1", null); - this.addActionParams(map, this.mc.options.keyLeft, "optional", "vector1", null); - this.addActionParams(map, this.mc.options.keyRight, "optional", "vector1", null); - this.addActionParams(map, this.mc.options.keyInventory, "suggested", "boolean", VRInputActionSet.GLOBAL); - this.addActionParams(map, this.mc.options.keyAttack, "suggested", "boolean", null); - this.addActionParams(map, this.mc.options.keyUse, "suggested", "boolean", null); - this.addActionParams(map, this.mc.options.keyChat, "optional", "boolean", VRInputActionSet.GLOBAL); - this.addActionParams(map, MOD.keyHotbarScroll, "optional", "vector2", null); - this.addActionParams(map, MOD.keyHotbarSwipeX, "optional", "vector2", null); - this.addActionParams(map, MOD.keyHotbarSwipeY, "optional", "vector2", null); - this.addActionParams(map, MOD.keyMenuButton, "suggested", "boolean", VRInputActionSet.GLOBAL); - this.addActionParams(map, MOD.keyTeleportFallback, "suggested", "vector1", null); - this.addActionParams(map, MOD.keyFreeMoveRotate, "optional", "vector2", null); - this.addActionParams(map, MOD.keyFreeMoveStrafe, "optional", "vector2", null); - this.addActionParams(map, MOD.keyRotateLeft, "optional", "vector1", null); - this.addActionParams(map, MOD.keyRotateRight, "optional", "vector1", null); - this.addActionParams(map, MOD.keyRotateAxis, "optional", "vector2", null); - this.addActionParams(map, MOD.keyFlickStick, "optional", "vector2", null); - this.addActionParams(map, MOD.keyRadialMenu, "suggested", "boolean", null); - this.addActionParams(map, MOD.keySwapMirrorView, "optional", "boolean", VRInputActionSet.GLOBAL); - this.addActionParams(map, MOD.keyToggleKeyboard, "optional", "boolean", VRInputActionSet.GLOBAL); - this.addActionParams(map, MOD.keyMoveThirdPersonCam, "optional", "boolean", VRInputActionSet.GLOBAL); - this.addActionParams(map, MOD.keyToggleHandheldCam, "optional", "boolean", VRInputActionSet.GLOBAL); - this.addActionParams(map, MOD.keyQuickHandheldCam, "optional", "boolean", VRInputActionSet.GLOBAL); - this.addActionParams(map, MOD.keyTrackpadTouch, "optional", "boolean", VRInputActionSet.TECHNICAL); - this.addActionParams(map, MOD.keyVRInteract, "suggested", "boolean", VRInputActionSet.CONTEXTUAL); - this.addActionParams(map, MOD.keyClimbeyGrab, "suggested", "boolean", null); - this.addActionParams(map, MOD.keyClimbeyJump, "suggested", "boolean", null); - this.addActionParams(map, GuiHandler.KEY_LEFT_CLICK, "suggested", "boolean", null); - this.addActionParams(map, GuiHandler.KEY_SCROLL_AXIS, "optional", "vector2", null); - this.addActionParams(map, GuiHandler.KEY_RIGHT_CLICK, "suggested", "boolean", null); - this.addActionParams(map, GuiHandler.KEY_SHIFT, "suggested", "boolean", null); - this.addActionParams(map, GuiHandler.KEY_KEYBOARD_CLICK, "suggested", "boolean", null); - this.addActionParams(map, GuiHandler.KEY_KEYBOARD_SHIFT, "suggested", "boolean", null); + this.addActionParams(map, this.mc.options.keyUp, "optional", ActionType.VEC1, null); + this.addActionParams(map, this.mc.options.keyDown, "optional", ActionType.VEC1, null); + this.addActionParams(map, this.mc.options.keyLeft, "optional", ActionType.VEC1, null); + this.addActionParams(map, this.mc.options.keyRight, "optional", ActionType.VEC1, null); + this.addActionParams(map, this.mc.options.keyInventory, "suggested", ActionType.BOOLEAN, VRInputActionSet.GLOBAL); + this.addActionParams(map, this.mc.options.keyAttack, "suggested", ActionType.BOOLEAN, null); + this.addActionParams(map, this.mc.options.keyUse, "suggested", ActionType.BOOLEAN, null); + this.addActionParams(map, this.mc.options.keyChat, "optional", ActionType.BOOLEAN, VRInputActionSet.GLOBAL); + this.addActionParams(map, MOD.keyHotbarScroll, "optional", ActionType.VEC2, null); + this.addActionParams(map, MOD.keyHotbarSwipeX, "optional", ActionType.VEC2, null); + this.addActionParams(map, MOD.keyHotbarSwipeY, "optional", ActionType.VEC2, null); + this.addActionParams(map, MOD.keyMenuButton, "suggested", ActionType.BOOLEAN, VRInputActionSet.GLOBAL); + this.addActionParams(map, MOD.keyTeleportFallback, "suggested", ActionType.VEC1, null); + this.addActionParams(map, MOD.keyFreeMoveRotate, "optional", ActionType.VEC2, null); + this.addActionParams(map, MOD.keyFreeMoveStrafe, "optional", ActionType.VEC2, null); + this.addActionParams(map, MOD.keyRotateLeft, "optional", ActionType.VEC1, null); + this.addActionParams(map, MOD.keyRotateRight, "optional", ActionType.VEC1, null); + this.addActionParams(map, MOD.keyRotateAxis, "optional", ActionType.VEC2, null); + this.addActionParams(map, MOD.keyFlickStick, "optional", ActionType.VEC2, null); + this.addActionParams(map, MOD.keyRadialMenu, "suggested", ActionType.BOOLEAN, null); + this.addActionParams(map, MOD.keySwapMirrorView, "optional", ActionType.BOOLEAN, VRInputActionSet.GLOBAL); + this.addActionParams(map, MOD.keyToggleKeyboard, "optional", ActionType.BOOLEAN, VRInputActionSet.GLOBAL); + this.addActionParams(map, MOD.keyMoveThirdPersonCam, "optional", ActionType.BOOLEAN, VRInputActionSet.GLOBAL); + this.addActionParams(map, MOD.keyToggleHandheldCam, "optional", ActionType.BOOLEAN, VRInputActionSet.GLOBAL); + this.addActionParams(map, MOD.keyQuickHandheldCam, "optional", ActionType.BOOLEAN, VRInputActionSet.GLOBAL); + this.addActionParams(map, MOD.keyTrackpadTouch, "optional", ActionType.BOOLEAN, VRInputActionSet.TECHNICAL); + this.addActionParams(map, MOD.keyVRInteract, "suggested", ActionType.BOOLEAN, VRInputActionSet.CONTEXTUAL); + this.addActionParams(map, MOD.keyClimbeyGrab, "suggested", ActionType.BOOLEAN, null); + this.addActionParams(map, MOD.keyClimbeyJump, "suggested", ActionType.BOOLEAN, null); + this.addActionParams(map, GuiHandler.KEY_LEFT_CLICK, "suggested", ActionType.BOOLEAN, null); + this.addActionParams(map, GuiHandler.KEY_SCROLL_AXIS, "optional", ActionType.VEC2, null); + this.addActionParams(map, GuiHandler.KEY_RIGHT_CLICK, "suggested", ActionType.BOOLEAN, null); + this.addActionParams(map, GuiHandler.KEY_SHIFT, "suggested", ActionType.BOOLEAN, null); + this.addActionParams(map, GuiHandler.KEY_KEYBOARD_CLICK, "suggested", ActionType.BOOLEAN, null); + this.addActionParams(map, GuiHandler.KEY_KEYBOARD_SHIFT, "suggested", ActionType.BOOLEAN, null); // users can provide their own action parameters if they want // this allows them to split mod KeyMappings into GUI, INGAME and GLOBAL categories @@ -1210,7 +1208,7 @@ public Map getSpecialActionParams() { if (actionSet == null) { VRSettings.LOGGER.warn("Vivecraft: Unknown action set: {}", tokens[1]); } else { - this.addActionParams(map, keyMapping, "optional", "boolean", actionSet); + this.addActionParams(map, keyMapping, "optional", ActionType.BOOLEAN, actionSet); } } } @@ -1232,7 +1230,7 @@ public Map getSpecialActionParams() { * @param actionSetOverride actionset this should be in. See {@link ActionParams#actionSetOverride()} */ private void addActionParams( - Map map, KeyMapping keyMapping, String requirement, String type, + Map map, KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { ActionParams actionparams = new ActionParams(requirement, type, actionSetOverride); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/ActionParams.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/ActionParams.java similarity index 62% rename from common/src/main/java/org/vivecraft/client_vr/provider/ActionParams.java rename to common/src/main/java/org/vivecraft/client_vr/provider/control/ActionParams.java index 4e99173d3..72ff6be68 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/ActionParams.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/ActionParams.java @@ -1,6 +1,4 @@ -package org.vivecraft.client_vr.provider; - -import org.vivecraft.client_vr.provider.control.VRInputActionSet; +package org.vivecraft.client_vr.provider.control; /** * holds the parameters for a VR action key @@ -9,6 +7,6 @@ * @param type input type of the action. one of "boolean", "vector1, "vector2" or "vector3" * @param actionSetOverride action set to put it in, any of {@link VRInputActionSet} */ -public record ActionParams(String requirement, String type, VRInputActionSet actionSetOverride) { - public static final ActionParams DEFAULT = new ActionParams("optional", "boolean", null); +public record ActionParams(String requirement, ActionType type, VRInputActionSet actionSetOverride) { + public static final ActionParams DEFAULT = new ActionParams("optional", ActionType.BOOLEAN, null); } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/ActionType.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/ActionType.java new file mode 100644 index 000000000..b20488ab8 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/ActionType.java @@ -0,0 +1,13 @@ +package org.vivecraft.client_vr.provider.control; + +public enum ActionType { + BOOLEAN, + DOUBLE_PRESS, + LONG_PRESS, + HOLD, + TOGGLE, + VEC1, + VEC2, + POSE, + HAPTIC +} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/ControllerType.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/ControllerType.java similarity index 50% rename from common/src/main/java/org/vivecraft/client_vr/provider/ControllerType.java rename to common/src/main/java/org/vivecraft/client_vr/provider/control/ControllerType.java index a41ec6105..1b9b4e08a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/ControllerType.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/ControllerType.java @@ -1,4 +1,4 @@ -package org.vivecraft.client_vr.provider; +package org.vivecraft.client_vr.provider.control; public enum ControllerType { RIGHT, diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/HandedKeyBinding.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/HandedKeyBinding.java similarity index 97% rename from common/src/main/java/org/vivecraft/client_vr/provider/HandedKeyBinding.java rename to common/src/main/java/org/vivecraft/client_vr/provider/control/HandedKeyBinding.java index d790401b6..8df0c0fa6 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/HandedKeyBinding.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/HandedKeyBinding.java @@ -1,4 +1,4 @@ -package org.vivecraft.client_vr.provider; +package org.vivecraft.client_vr.provider.control; import net.minecraft.client.KeyMapping; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/HapticMusicPlayer.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/HapticMusicPlayer.java index b391ebe8a..46be0b906 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/HapticMusicPlayer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/HapticMusicPlayer.java @@ -1,7 +1,6 @@ package org.vivecraft.client_vr.provider.control; import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.provider.ControllerType; import javax.annotation.Nullable; import java.util.HashMap; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java index 5dfaa3b8f..70bc6a653 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java @@ -3,8 +3,6 @@ import org.joml.Vector2f; import org.joml.Vector2fc; import org.vivecraft.client.VivecraftVRMod; -import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.provider.ControllerType; import org.vivecraft.client_vr.provider.openvr_lwjgl.MCOpenVR; public class TrackpadSwipeSampler { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java index 9c924a8ea..555533152 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java @@ -9,8 +9,6 @@ import org.vivecraft.client.VivecraftVRMod; import org.vivecraft.client.Xplat; import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.provider.ControllerType; -import org.vivecraft.client_vr.provider.HandedKeyBinding; import org.vivecraft.client_vr.provider.InputSimulator; import javax.annotation.Nullable; @@ -23,7 +21,7 @@ public class VRInputAction { public final KeyMapping keyBinding; public final String name; public final String requirement; - public final String type; + public ActionType type; public final VRInputActionSet actionSet; private int priority = 0; @@ -36,11 +34,12 @@ public class VRInputAction { public long handle; private final boolean[] pressed = new boolean[ControllerType.values().length]; protected final int[] unpressInTicks = new int[ControllerType.values().length]; + private ControllerType hand; public final DigitalData[] digitalData = new DigitalData[ControllerType.values().length]; public final AnalogData[] analogData = new AnalogData[ControllerType.values().length]; - public VRInputAction(KeyMapping keyMapping, String requirement, String type, VRInputActionSet actionSetOverride) { + public VRInputAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { this.keyBinding = keyMapping; this.requirement = requirement; this.type = type; @@ -55,7 +54,7 @@ public VRInputAction(KeyMapping keyMapping, String requirement, String type, VRI } public boolean isButtonPressed() { - if (this.type.equals("boolean")) { + if (this.type == ActionType.BOOLEAN) { return this.digitalData().state; } else { Vector3fc axis = this.getAxis3D(false); @@ -64,7 +63,7 @@ public boolean isButtonPressed() { } public boolean isButtonChanged() { - if (this.type.equals("boolean")) { + if (this.type == ActionType.BOOLEAN) { return this.digitalData().isChanged; } else { Vector3fc axis = this.getAxis3D(false); @@ -77,18 +76,18 @@ public boolean isButtonChanged() { public float getAxis1D(boolean delta) { return switch (this.type) { - case "boolean" -> this.digitalToAnalog(delta); - case "vector1", "vector2", "vector3" -> delta ? this.analogData().deltaX : this.analogData().x; + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> this.digitalToAnalog(delta); + case VEC1, VEC2 -> delta ? this.analogData().deltaX : this.analogData().x; default -> 0.0F; }; } public Vector2fc getAxis2D(boolean delta) { return switch (this.type) { - case "boolean" -> new Vector2f(this.digitalToAnalog(delta), 0.0F); - case "vector1" -> + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> new Vector2f(this.digitalToAnalog(delta), 0.0F); + case VEC1 -> delta ? new Vector2f(this.analogData().deltaX, 0.0F) : new Vector2f(this.analogData().x, 0.0F); - case "vector2", "vector3" -> delta ? new Vector2f(this.analogData().deltaX, this.analogData().deltaY) : + case VEC2 -> delta ? new Vector2f(this.analogData().deltaX, this.analogData().deltaY) : new Vector2f(this.analogData().x, this.analogData().y); default -> new Vector2f(); }; @@ -96,14 +95,14 @@ public Vector2fc getAxis2D(boolean delta) { public Vector3fc getAxis3D(boolean delta) { return switch (this.type) { - case "boolean" -> new Vector3f(this.digitalToAnalog(delta), 0.0F, 0.0F); - case "vector1" -> delta ? new Vector3f(this.analogData().deltaX, 0.0F, 0.0F) : + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> new Vector3f(this.digitalToAnalog(delta), 0.0F, 0.0F); + case VEC1 -> delta ? new Vector3f(this.analogData().deltaX, 0.0F, 0.0F) : new Vector3f(this.analogData().x, 0.0F, 0.0F); - case "vector2" -> delta ? new Vector3f(this.analogData().deltaX, this.analogData().deltaY, 0.0F) : + case VEC2 -> delta ? new Vector3f(this.analogData().deltaX, this.analogData().deltaY, 0.0F) : new Vector3f(this.analogData().x, this.analogData().y, 0.0F); - case "vector3" -> - delta ? new Vector3f(this.analogData().deltaX, this.analogData().deltaY, this.analogData().deltaZ) : - new Vector3f(this.analogData().x, this.analogData().y, this.analogData().z); +// case "vector3" -> +// delta ? new Vector3f(this.analogData().deltaX, this.analogData().deltaY, this.analogData().deltaZ) : +// new Vector3f(this.analogData().x, this.analogData().y, this.analogData().z); default -> new Vector3f(); }; } @@ -167,8 +166,8 @@ private float digitalToAnalog(boolean delta) { public long getLastOrigin() { return switch (this.type) { - case "boolean" -> this.digitalData().activeOrigin; - case "vector1", "vector2", "vector3" -> this.analogData().activeOrigin; + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> this.digitalData().activeOrigin; + case VEC1, VEC2 -> this.analogData().activeOrigin; default -> 0L; }; } @@ -189,9 +188,13 @@ private AnalogData analogData() { return this.isHanded() ? this.analogData[this.currentHand.ordinal()] : this.analogData[0]; } + public void setType(ActionType type) { + this.type = type; + } + public void setHandle(long handle) { if (this.handle != 0L) { - throw new IllegalStateException("Handle already assigned!"); + //throw new IllegalStateException("Handle already assigned!"); } else { this.handle = handle; } @@ -270,8 +273,8 @@ public VRInputAction setEnabled(boolean enabled) { public boolean isActive() { return switch (this.type) { - case "boolean" -> this.digitalData().isActive; - case "vector1", "vector2", "vector3" -> this.analogData().isActive; + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> this.digitalData().isActive; + case VEC1, VEC2 -> this.analogData().isActive; default -> false; }; } @@ -456,6 +459,14 @@ public void unpressKey() { this.keyBinding.release(); } + public void setHand(ControllerType hand) { + this.hand = hand; + } + + public ControllerType getHand() { + return this.hand; + } + public static class AnalogData { public float x; public float y; @@ -473,6 +484,11 @@ public static class DigitalData { public boolean isChanged; public boolean isActive; public long activeOrigin; + public long lastChange; + public boolean longPress; + public boolean toggle; + public boolean doublePress; + public boolean hold; } public interface KeyListener { 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 572e9ca38..e492a8bbf 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 @@ -12,7 +12,7 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.MethodHolder; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.DeviceSource; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.VRRenderer; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRHapticScheduler.java b/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRHapticScheduler.java index 2fb0159f2..1822a140f 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRHapticScheduler.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRHapticScheduler.java @@ -1,7 +1,7 @@ package org.vivecraft.client_vr.provider.nullvr; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.HapticScheduler; public class NullVRHapticScheduler extends HapticScheduler { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index fdca4b509..79c8fc5e0 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -28,7 +28,7 @@ import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler; import org.vivecraft.client_vr.provider.*; -import org.vivecraft.client_vr.provider.control.TrackpadSwipeSampler; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.provider.control.VRInputActionSet; import org.vivecraft.client_vr.render.RenderConfigException; @@ -1507,7 +1507,7 @@ public ControllerType getOriginControllerType(long inputValueHandle) { */ private void readNewData(VRInputAction action) { switch (action.type) { - case "boolean" -> { + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> { if (action.isHanded()) { for (ControllerType type : ControllerType.values()) { this.readDigitalData(action, type); @@ -1517,7 +1517,7 @@ private void readNewData(VRInputAction action) { } } - case "vector1", "vector2", "vector3" -> { + case VEC1, VEC2 -> { if (action.isHanded()) { for (ControllerType type : ControllerType.values()) { this.readAnalogData(action, type); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRHapticScheduler.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRHapticScheduler.java index da1314635..d3289ee41 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRHapticScheduler.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRHapticScheduler.java @@ -2,7 +2,7 @@ import org.lwjgl.openvr.VR; import org.lwjgl.openvr.VRInput; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.HapticScheduler; import org.vivecraft.client_vr.settings.VRSettings; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index f0ca6df34..36dcdf4f2 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -20,15 +20,16 @@ import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ActionType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.VRRenderer; import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.provider.control.VRInputActionSet; +import org.vivecraft.client_vr.provider.openxr.control.WrappedBinding; import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.settings.VRSettings; -import javax.annotation.Nullable; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; @@ -71,6 +72,9 @@ public class MCOpenXR extends MCVR { public long[] haptics = new long[2]; public String systemName; + public Map mappedBindings = new HashMap<>(); + public Map pathBindings = new HashMap<>(); + public MCOpenXR(Minecraft mc, ClientDataHolderVR dh) { super(mc, dh, VivecraftVRMod.INSTANCE); @@ -314,8 +318,11 @@ private void updatePose() { } public void readNewData(VRInputAction action) { + if (action.handle == 0) { + return; + } switch (action.type) { - case "boolean" -> { + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> { if (action.isHanded()) { for (ControllerType controllertype1 : ControllerType.values()) { this.readBoolean(action, controllertype1); @@ -325,7 +332,7 @@ public void readNewData(VRInputAction action) { } } - case "vector1" -> { + case VEC1 -> { if (action.isHanded()) { for (ControllerType controllertype : ControllerType.values()) { this.readFloat(action, controllertype); @@ -335,7 +342,7 @@ public void readNewData(VRInputAction action) { } } - case "vector2" -> { + case VEC2 -> { if (action.isHanded()) { for (ControllerType controllertype : ControllerType.values()) { this.readVecData(action, controllertype); @@ -358,10 +365,23 @@ private void readBoolean(VRInputAction action, ControllerType hand) { info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); info.action(new XrAction(action.handle, new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); + info.subactionPath(action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); XrActionStateBoolean state = XrActionStateBoolean.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_BOOLEAN); int error = XR10.xrGetActionStateBoolean(this.session, info, state); logError(error, "xrGetActionStateBoolean", action.name); + if (state.changedSinceLastSync()) { + if (state.currentState()) { + action.digitalData[i].toggle = !action.digitalData[i].toggle; + action.digitalData[i].doublePress = System.nanoTime() - action.digitalData[i].lastChange > 250_000_000L; + } else { + action.digitalData[i].longPress = System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; + } + action.digitalData[i].lastChange = System.nanoTime(); + } else if (state.currentState()){ + action.digitalData[i].hold = System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; + } + action.digitalData[i].state = state.currentState(); action.digitalData[i].isActive = state.isActive(); action.digitalData[i].isChanged = state.changedSinceLastSync(); @@ -380,6 +400,7 @@ private void readFloat(VRInputAction action, ControllerType hand) { info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); info.action(new XrAction(action.handle, new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); + info.subactionPath(action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); XrActionStateFloat state = XrActionStateFloat.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_FLOAT); int error = XR10.xrGetActionStateFloat(this.session, info, state); logError(error, "xrGetActionStateFloat", action.name); @@ -403,6 +424,7 @@ private void readVecData(VRInputAction action, ControllerType hand) { info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); info.action(new XrAction(action.handle, new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); + info.subactionPath(action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); XrActionStateVector2f state = XrActionStateVector2f.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_VECTOR2F); int error = XR10.xrGetActionStateVector2f(this.session, info, state); logError(error, "xrGetActionStateVector2f", action.name); @@ -1017,33 +1039,35 @@ private void loadActionHandles() { for (VRInputActionSet vrinputactionset : VRInputActionSet.values()) { long actionSet = makeActionSet(this.instance, vrinputactionset.name, vrinputactionset.localizedName, 0); this.actionSetHandles.put(vrinputactionset, actionSet); - } - for (VRInputAction vrinputaction : this.inputActions.values()) { - long action = createAction(vrinputaction.name, vrinputaction.name, vrinputaction.type, - new XrActionSet(this.actionSetHandles.get(vrinputaction.actionSet), this.instance), BOTH_HANDS); - vrinputaction.setHandle(action); + //TODO select the proper headset + for (WrappedBinding binding: WrappedBinding.quest2Bindings()) { + long action = createAction(binding.path().replace("/","."), binding.path(), binding.type(), + new XrActionSet(actionSet, this.instance), binding.path().contains("left") ? BOTH_HANDS[0] : BOTH_HANDS[1]); + mappedBindings.put(binding, action); + pathBindings.put(binding.path(), binding); + } } setupControllers(); XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), this.instance); - this.haptics[RIGHT_CONTROLLER] = createAction("/actions/global/out/righthaptic", - "/actions/global/out/righthaptic", "haptic", actionSet, BOTH_HANDS); - this.haptics[LEFT_CONTROLLER] = createAction("/actions/global/out/lefthaptic", "/actions/global/out/lefthaptic", - "haptic", actionSet, BOTH_HANDS); + this.haptics[RIGHT_CONTROLLER] = createAction("righthaptic", + "/actions/global/out/righthaptic", ActionType.HAPTIC, actionSet, BOTH_HANDS[1]); + this.haptics[LEFT_CONTROLLER] = createAction("lefthaptic", "/actions/global/out/lefthaptic", + ActionType.HAPTIC, actionSet, BOTH_HANDS[0]); } private void setupControllers() { XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), this.instance); - this.grip[RIGHT_CONTROLLER] = createAction("/actions/global/in/righthand", "/actions/global/in/righthand", - "pose", actionSet, BOTH_HANDS); - this.grip[LEFT_CONTROLLER] = createAction("/actions/global/in/lefthand", "/actions/global/in/lefthand", "pose", - actionSet, BOTH_HANDS); - this.aim[RIGHT_CONTROLLER] = createAction("/actions/global/in/righthandaim", "/actions/global/in/righthandaim", - "pose", actionSet, BOTH_HANDS); - this.aim[LEFT_CONTROLLER] = createAction("/actions/global/in/lefthandaim", "/actions/global/in/lefthandaim", - "pose", actionSet, BOTH_HANDS); + this.grip[RIGHT_CONTROLLER] = createAction("righthand", "/actions/global/in/righthand", + ActionType.POSE, actionSet, BOTH_HANDS[1]); + this.grip[LEFT_CONTROLLER] = createAction("lefthand", "/actions/global/in/lefthand", ActionType.POSE, + actionSet, BOTH_HANDS[0]); + this.aim[RIGHT_CONTROLLER] = createAction("righthandaim", "/actions/global/in/righthandaim", + ActionType.POSE, actionSet, BOTH_HANDS[1]); + this.aim[LEFT_CONTROLLER] = createAction("lefthandaim", "/actions/global/in/lefthandaim", + ActionType.POSE, actionSet, BOTH_HANDS[0]); } private void loadDefaultBindings() { @@ -1051,6 +1075,9 @@ private void loadDefaultBindings() { int error; for (String headset : XRBindings.supportedHeadsets()) { VRSettings.LOGGER.info("loading defaults for {}", headset); + if (!"/interaction_profiles/oculus/touch_controller".equals(headset)) { + continue; + } Pair[] defaultBindings = XRBindings.getBinding(headset).toArray(new Pair[0]); XrActionSuggestedBinding.Buffer bindings = XrActionSuggestedBinding.calloc(defaultBindings.length + 6, stack); //TODO different way of adding controller poses @@ -1058,6 +1085,10 @@ private void loadDefaultBindings() { for (int i = 0; i < defaultBindings.length; i++) { Pair pair = defaultBindings[i]; VRInputAction binding = this.getInputActionByName(pair.getLeft()); + long handle = this.mappedBindings.get(this.pathBindings.get(pair.getRight())); + binding.setHandle(handle); + binding.setType(this.pathBindings.get(pair.getRight()).type()); + binding.setHand(this.pathBindings.get(pair.getRight()).path().contains("/left/") ? ControllerType.LEFT : ControllerType.RIGHT); if (binding.handle == 0L) { VRSettings.LOGGER.error("Handle for '{}'/'{}' is null", pair.getLeft(), pair.getRight()); continue; @@ -1164,37 +1195,30 @@ public long getPath(String pathString) { } private long createAction( - String name, String localisedName, String type, XrActionSet actionSet, @Nullable String[] subactionPaths) + String name, String localisedName, ActionType type, XrActionSet actionSet, String subactionPath) { try (MemoryStack stack = MemoryStack.stackPush()) { - String s = name.split("/")[name.split("/").length - 1].toLowerCase(); + String s = name.replace(".user.hand.", ""); XrActionCreateInfo hands = XrActionCreateInfo.calloc(stack); hands.type(XR10.XR_TYPE_ACTION_CREATE_INFO); hands.next(NULL); hands.actionName(memUTF8(s)); switch (type) { - case "boolean" -> hands.actionType(XR10.XR_ACTION_TYPE_BOOLEAN_INPUT); - case "vector1" -> hands.actionType(XR10.XR_ACTION_TYPE_FLOAT_INPUT); - case "vector2" -> hands.actionType(XR10.XR_ACTION_TYPE_VECTOR2F_INPUT); - case "pose" -> hands.actionType(XR10.XR_ACTION_TYPE_POSE_INPUT); - case "haptic" -> hands.actionType(XR10.XR_ACTION_TYPE_VIBRATION_OUTPUT); - } - if (subactionPaths != null) { - LongBuffer buffer = stackCallocLong(subactionPaths.length); - for (String path : subactionPaths) { - buffer.put(getPath(path)); - } - hands.countSubactionPaths(subactionPaths.length); - hands.subactionPaths(buffer.rewind()); - } else { - hands.countSubactionPaths(0); - hands.subactionPaths(null); + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> hands.actionType(XR10.XR_ACTION_TYPE_BOOLEAN_INPUT); + case VEC1 -> hands.actionType(XR10.XR_ACTION_TYPE_FLOAT_INPUT); + case VEC2 -> hands.actionType(XR10.XR_ACTION_TYPE_VECTOR2F_INPUT); + case POSE -> hands.actionType(XR10.XR_ACTION_TYPE_POSE_INPUT); + case HAPTIC -> hands.actionType(XR10.XR_ACTION_TYPE_VIBRATION_OUTPUT); } + LongBuffer lb = stackCallocLong(1); + lb.put(getPath(subactionPath)); + hands.countSubactionPaths(1); + hands.subactionPaths(lb.rewind()); hands.localizedActionName(memUTF8(s)); PointerBuffer buffer = stackCallocPointer(1); int error = XR10.xrCreateAction(actionSet, hands, buffer); - logError(error, "xrCreateAction", "name:", name, "type:", type); + logError(error, "xrCreateAction", "name:", name, "type:", type.name()); return buffer.get(0); } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticScheduler.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticScheduler.java index a0022a671..a97aeec82 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticScheduler.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticScheduler.java @@ -3,7 +3,7 @@ import org.lwjgl.openxr.*; import org.lwjgl.system.MemoryStack; import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.HapticScheduler; import org.vivecraft.client_vr.provider.control.VRInputActionSet; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java index 76ce8a5f6..0deb44cbf 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java @@ -31,38 +31,38 @@ private static HashSet> quest2Bindings() { set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/value")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/value")); + set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/value")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/value")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/value")); + set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/value")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/value")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/a/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); - set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick")); + //set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); + set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); - set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick")); + set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/value")); + //set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze/value")); + //set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/value")); + //set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/value")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger")); + //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/value")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/value")); + //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/value")); + //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/value")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger")); + //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/value")); + //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/value")); + //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/value")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/value")); return set; } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/RebindableBinding.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/RebindableBinding.java new file mode 100644 index 000000000..e17445bd2 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/RebindableBinding.java @@ -0,0 +1,6 @@ +package org.vivecraft.client_vr.provider.openxr.control; + +import org.vivecraft.client_vr.provider.control.ActionType; + +public record RebindableBinding(String binding, String path, ActionType type) { +} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/WrappedBinding.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/WrappedBinding.java new file mode 100644 index 000000000..bec67bd8e --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/WrappedBinding.java @@ -0,0 +1,48 @@ +package org.vivecraft.client_vr.provider.openxr.control; + +import org.vivecraft.client_vr.provider.control.ActionType; + +import java.util.ArrayList; +import java.util.List; + +public record WrappedBinding(String path, ActionType type) { + + public static List quest2Bindings() { + List bindings = new ArrayList<>(); + + bindings.add(new WrappedBinding("/user/hand/left/input/y/click", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/y/touch",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/x/click",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/x/touch",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/menu/click",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/squeeze/value",ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/left/input/trigger/value",ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/left/input/trigger/touch",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/trigger/proximity",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumb_resting_surfaces/proximity",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick",ActionType.VEC2)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/click",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/touch",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/y",ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/x",ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumbrest/touch",ActionType.BOOLEAN)); + + bindings.add(new WrappedBinding("/user/hand/right/input/a/click",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/a/touch",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/b/click",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/b/touch",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/system/click",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/squeeze/value",ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/right/input/trigger/value",ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/right/input/trigger/touch",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/trigger/proximity",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumb_resting_surfaces/proximity",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick",ActionType.VEC2)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/click",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/touch",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/y",ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/x",ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumbrest/touch",ActionType.BOOLEAN)); + return bindings; + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/render/VRArmRenderer.java b/common/src/main/java/org/vivecraft/client_vr/render/VRArmRenderer.java index cb867f8f1..691c22d4c 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/VRArmRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/VRArmRenderer.java @@ -12,7 +12,7 @@ import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.ARGB; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; public class VRArmRenderer extends PlayerRenderer { diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/VREffectsHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/VREffectsHelper.java index 5dec0783f..089a1cf80 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/VREffectsHelper.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/VREffectsHelper.java @@ -47,7 +47,7 @@ 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.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.common.utils.MathUtils; diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/multiplayer/ClientPacketListenerVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/multiplayer/ClientPacketListenerVRMixin.java index 6cb3ffe6f..cefd77382 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/multiplayer/ClientPacketListenerVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/multiplayer/ClientPacketListenerVRMixin.java @@ -20,7 +20,7 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.settings.VRSettings; @Mixin(ClientPacketListener.class) diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/world/FishingHookVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/world/FishingHookVRMixin.java index e8ecf9418..c2c40a0e3 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/world/FishingHookVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/world/FishingHookVRMixin.java @@ -13,7 +13,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.vivecraft.client_vr.VRState; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.MCVR; @Mixin(FishingHook.class) From b1b1f5e1728fcb5247c5ca0f69c981caf3b37700 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 17 Nov 2025 00:44:47 +0100 Subject: [PATCH 68/76] fixes for 1.21.10 and update --- .../client/gui/settings/GuiBindings.java | 14 +- .../gui/settings/VivecraftMainSettings.java | 8 +- .../vivecraft/client/utils/ClientUtils.java | 2 +- .../client_vr/VRLayeredRenderTarget.java | 56 ++++++++ .../vivecraft/client_vr/VRTextureTarget.java | 27 ---- .../vivecraft/client_vr/provider/MCVR.java | 84 +++++++++-- .../client_vr/provider/nullvr/NullVR.java | 1 + .../provider/nullvr/NullVRStereoRenderer.java | 48 ++++--- .../provider/openvr_lwjgl/MCOpenVR.java | 14 +- .../openvr_lwjgl/OpenVRStereoRenderer.java | 56 ++++---- .../provider/openxr/DeviceCompat.java | 2 +- .../client_vr/provider/openxr/MCOpenXR.java | 18 ++- .../provider/openxr/OpenXRStereoRenderer.java | 17 +-- .../vivecraft/client_vr/render/VRShaders.java | 13 +- .../render/helpers/ShaderHelper.java | 134 +++++++++++------- .../render/helpers/VRPassHelper.java | 1 - .../helpers/opengl/LayeredGlTexture.java | 47 ++++++ .../render/helpers/opengl/OpenGLHelper.java | 17 +++ .../mixin/client_vr/MinecraftVRMixin.java | 15 ++ .../assets/vivecraft/shaders/core/blit_vr.fsh | 11 ++ .../shaders/core/mixedreality_vr.fsh | 6 +- .../main/resources/vivecraft.accesswidener | 3 + 22 files changed, 397 insertions(+), 197 deletions(-) create mode 100644 common/src/main/java/org/vivecraft/client_vr/VRLayeredRenderTarget.java create mode 100644 common/src/main/java/org/vivecraft/client_vr/render/helpers/opengl/LayeredGlTexture.java create mode 100644 common/src/main/resources/assets/vivecraft/shaders/core/blit_vr.fsh diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java index 47877d325..ac36e7efb 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java @@ -9,7 +9,8 @@ import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; -import org.vivecraft.client.gui.widgets.SettingsList; +import org.vivecraft.client.gui.framework.screens.GuiListScreen; +import org.vivecraft.client.gui.framework.widgets.SettingsList; import org.vivecraft.client_vr.provider.control.ActionType; import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.provider.openxr.MCOpenXR; @@ -56,13 +57,12 @@ public ResettableEntry(Component name, VRInputAction action) { } @Override - public void render( - GuiGraphics guiGraphics, int index, int top, int left, int width, int height, int mouseX, int mouseY, - boolean hovering, float partialTick) + public void renderContent( + GuiGraphics guiGraphics, int mouseX, int mouseY, boolean hovering, float partialTick) { - super.render(guiGraphics, index, top, left, width, height, mouseX, mouseY, hovering, partialTick); - this.resetButton.setX(left + 230); - this.resetButton.setY(top); + super.renderContent(guiGraphics, mouseX, mouseY, hovering, partialTick); + this.resetButton.setX(this.getContentRight() - 20); + this.resetButton.setY(this.getContentY()); this.resetButton.active = this.canReset.getAsBoolean(); this.resetButton.render(guiGraphics, mouseX, mouseY, partialTick); } diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/VivecraftMainSettings.java b/common/src/main/java/org/vivecraft/client/gui/settings/VivecraftMainSettings.java index 73d46bd1a..b9e8a02a3 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/VivecraftMainSettings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/VivecraftMainSettings.java @@ -44,13 +44,7 @@ protected List getEntries() { entries.add(new SettingsList.ScreenEntry("vivecraft.options.screen.debug", GuiDebugSettings::new)); - entries.add(new SettingsList.WidgetEntry( - Component.translatable("vivecraft.options.screen.bindings"), - Button.builder(Component.translatable("vivecraft.options.screen.bindings"), - button -> this.minecraft.setScreen(new GuiBindings(this))) - .size(SettingsList.WidgetEntry.VALUE_BUTTON_WIDTH, 20) - .build() - )); + entries.add(new SettingsList.ScreenEntry("vivecraft.options.screen.bindings", GuiBindings::new)); return entries; } diff --git a/common/src/main/java/org/vivecraft/client/utils/ClientUtils.java b/common/src/main/java/org/vivecraft/client/utils/ClientUtils.java index 806d8c34f..7152fc799 100644 --- a/common/src/main/java/org/vivecraft/client/utils/ClientUtils.java +++ b/common/src/main/java/org/vivecraft/client/utils/ClientUtils.java @@ -17,7 +17,7 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.extensions.MinecraftExtension; -import org.vivecraft.client_vr.provider.ControllerType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.settings.VRSettings; import java.io.BufferedReader; diff --git a/common/src/main/java/org/vivecraft/client_vr/VRLayeredRenderTarget.java b/common/src/main/java/org/vivecraft/client_vr/VRLayeredRenderTarget.java new file mode 100644 index 000000000..245318b60 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/VRLayeredRenderTarget.java @@ -0,0 +1,56 @@ +package org.vivecraft.client_vr; + +import com.mojang.blaze3d.opengl.GlDevice; +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.AddressMode; +import com.mojang.blaze3d.textures.FilterMode; +import com.mojang.blaze3d.textures.GpuTexture; +import com.mojang.blaze3d.textures.TextureFormat; +import org.vivecraft.client_vr.render.helpers.opengl.LayeredGlTexture; + +/** + * RenderTarget that has a layer of a color texture and no depth + */ +public class VRLayeredRenderTarget extends RenderTarget { + + private final int layer; + + public VRLayeredRenderTarget(String name, int width, int height, int texId, int layer) { + super(name, false); + RenderSystem.assertOnRenderThread(); + + // need to set this first, because the forge/neoforge stencil enabled does a resize + this.width = width; + this.height = height; + this.layer = layer; + + // hardcoded opengl here + if (RenderSystem.getDevice() instanceof GlDevice glDevice) { + this.colorTexture = new LayeredGlTexture( + GpuTexture.USAGE_COPY_DST | GpuTexture.USAGE_COPY_SRC | GpuTexture.USAGE_TEXTURE_BINDING | + GpuTexture.USAGE_RENDER_ATTACHMENT, this.label + " / Color", TextureFormat.RGBA8, width, height, 1, + 1, texId, layer); + this.colorTextureView = glDevice.createTextureView(this.colorTexture); + this.colorTexture.setAddressMode(AddressMode.CLAMP_TO_EDGE); + this.setFilterMode(FilterMode.NEAREST); + } else { + throw new IllegalStateException("Only Opengl is currently supported by Vivecraft"); + } + } + + @Override + public String toString() { + return """ + + Vivecraft LayeredRenderTarget: %s + Size: %s x %s + Tex ID: %s + Layer: %s""" + .formatted( + this.label, + this.width, this.height, + this.colorTexture.getLabel(), + this.layer); + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java b/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java index 97c6a316d..fc8a9c856 100644 --- a/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java +++ b/common/src/main/java/org/vivecraft/client_vr/VRTextureTarget.java @@ -2,8 +2,6 @@ import com.mojang.blaze3d.opengl.GlDevice; import com.mojang.blaze3d.pipeline.RenderTarget; -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.platform.TextureUtil; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.textures.AddressMode; import com.mojang.blaze3d.textures.FilterMode; @@ -93,31 +91,6 @@ public void createBuffers(int width, int height) { } } - public VRTextureTarget(String name, int width, int height, int colorId, int index) { - super(false); - this.name = name; - RenderSystem.assertOnRenderThreadOrInit(); - this.resize(width, height); - - // free the old one when setting a new one - if (this.colorTextureId != -1) { - TextureUtil.releaseTextureId(this.colorTextureId); - } - this.colorTextureId = colorId; - - GlStateManager._glBindFramebuffer(GL30.GL_FRAMEBUFFER, this.frameBufferId); - // unset the old GL_COLOR_ATTACHMENT0 - GlStateManager._glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL30.GL_TEXTURE_2D, 0, - 0); - GL30.glFramebufferTextureLayer(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, colorId, 0, index); - - // unbind the framebuffer - this.unbindRead(); - this.unbindWrite(); - - this.setClearColor(0, 0, 0, 0); - } - @Override public String toString() { return """ diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java index 716cd6f7c..bf5a7f47b 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java @@ -145,6 +145,10 @@ public abstract class MCVR { protected int quickTorchPreviousSlot; protected Map inputActions = new HashMap<>(); protected Map inputActionsByKeyBinding = new HashMap<>(); + + private final Map> unpressedSetKeys = new EnumMap<>(VRInputActionSet.class); + private List activeActionSets = new ArrayList<>(); + protected final Map trackpadSwipeSamplers = new HashMap<>(); protected boolean inputInitialized; public final DeviceCompat device; @@ -183,6 +187,10 @@ public MCVR(Minecraft mc, ClientDataHolderVR dh, VivecraftVRMod vrMod) { } this.oscTrackers = new OSCTrackerReceiver(this); + + for (VRInputActionSet set : VRInputActionSet.values()) { + this.unpressedSetKeys.put(set, new HashSet<>()); + } } /** @@ -450,6 +458,15 @@ public boolean isControllerTracking(ControllerType controller) { return this.isControllerTracking(controller.ordinal()); } + protected void updateActiveActionSets(List activeSets) { + // clear any sets that got deactivated + this.activeActionSets.removeAll(activeSets); + for (VRInputActionSet set : this.activeActionSets) { + this.unpressedSetKeys.get(set).clear(); + } + this.activeActionSets = activeSets; + } + /** * @param controller controller/tracker to check * @return if the controller/tracker is currently tracking @@ -1442,7 +1459,10 @@ public List> getTrackers() { * processes the fetched inputs from the VR runtime, and maps them to the ingame keys */ public void processInputs() { - if (this.dh.vrSettings.seated || ClientDataHolderVR.VIEW_ONLY || !this.inputInitialized) return; + if (this.dh.vrSettings.seated || this.dh.viewOnly || !this.inputInitialized) { + this.ignorePressesNextFrame = false; + return; + } for (VRInputAction action : this.inputActions.values()) { if (action.isHanded()) { @@ -1480,8 +1500,8 @@ private void processInputAction(VRInputAction action) { // try to prevent double left clicks (!ClientDataHolderVR.getInstance().vrSettings.ingameBindingsInGui || !(action.actionSet == VRInputActionSet.INGAME && - action.keyBinding.key.getType() == InputConstants.Type.MOUSE && - action.keyBinding.key.getValue() == GLFW.GLFW_MOUSE_BUTTON_LEFT && this.mc.screen != null + action.keyBinding.key == InputConstants.Type.MOUSE.getOrCreate(GLFW.GLFW_MOUSE_BUTTON_LEFT) && + this.mc.screen != null ) )) { @@ -1489,18 +1509,66 @@ private void processInputAction(VRInputAction action) { if (action.isButtonPressed() && action.isEnabled()) { // We do this, so shit like closing a GUI by clicking a button won't // also click in the world immediately after. - if (!this.ignorePressesNextFrame) { - action.pressBinding(); + if (!this.ignorePressesNextFrame || canActionBeRepressed(action)) { + pressAction(action); } } else { - action.unpressBinding(); + unpressAction(action); } + } else if (action.isButtonPressed() && action.isEnabled() && !action.keyBinding.isDown() && + canActionBeRepressed(action)) + { + // allow repressing ingame buttons that were held before + pressAction(action); } - } else { - action.unpressBinding(); + } else if (checkIfNotMovement(action)) { + unpressAction(action); } } + /** + * @param action VRInputAction to check + * @return if the given VRInputAction was pressed before actionset changes and can be repressed + */ + private boolean canActionBeRepressed(VRInputAction action) { + // allow repressing ingame buttons that were held before the set change + return action.actionSet == VRInputActionSet.INGAME && + this.unpressedSetKeys.get(action.actionSet).contains(action); + } + + /** + * presses the given VRInputActions binding and removes it from the unpressed keys + * + * @param action VRInputAction to press + */ + private void pressAction(VRInputAction action) { + action.pressBinding(); + this.unpressedSetKeys.get(action.actionSet).remove(action); + } + + /** + * unpresses the given VRInputActions binding and adds it to the unpressed keys, if its actionSet is not active right now + * + * @param action VRInputAction to press + */ + private void unpressAction(VRInputAction action) { + if (!this.activeActionSets.contains(action.actionSet) && action.isButtonChanged()) { + this.unpressedSetKeys.get(action.actionSet).add(action); + } + action.unpressBinding(); + } + + /** + * @param action VRInputAction to check for + * @return if the given action does not correspond to one of the movement keys, or if the player didn't move + */ + private boolean checkIfNotMovement(VRInputAction action) { + return action.keyBinding != this.mc.options.keyLeft && + action.keyBinding != this.mc.options.keyRight && + action.keyBinding != this.mc.options.keyUp && + action.keyBinding != this.mc.options.keyDown || !this.isMovement; + } + /** * checks the axis input of the VRInputAction linked to {@code keyMapping} and runs the callbacks when it's non 0 * 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 8812bfdf8..1ab2717b6 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 @@ -13,6 +13,7 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.MethodHolder; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; +import org.vivecraft.client_vr.provider.ControllerTransform; import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.DeviceSource; import org.vivecraft.client_vr.provider.MCVR; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRStereoRenderer.java index 3a23624b3..56482758a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRStereoRenderer.java @@ -1,21 +1,22 @@ package org.vivecraft.client_vr.provider.nullvr; import com.mojang.blaze3d.opengl.GlStateManager; +import com.mojang.blaze3d.pipeline.RenderTarget; import net.minecraft.util.Mth; import net.minecraft.util.Tuple; import org.joml.Matrix4f; import org.lwjgl.opengl.GL11; +import org.vivecraft.api.client.data.RenderPass; import org.vivecraft.client_vr.VRTextureTarget; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.VRRenderer; -import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.render.helpers.RenderHelper; import org.vivecraft.client_vr.settings.VRSettings; public class NullVRStereoRenderer extends VRRenderer { - protected int LeftEyeTextureId = -1; - protected int RightEyeTextureId = -1; + protected int leftEyeTextureId = -1; + protected int rightEyeTextureId = -1; public RenderTarget framebufferEyeLeft; public RenderTarget framebufferEyeRight; @@ -45,41 +46,42 @@ protected Matrix4f getProjectionMatrix(int eyeType, float nearClip, float farCli public void createRenderTexture(int width, int height) { int boundTextureId = GlStateManager._getInteger(GL11.GL_TEXTURE_BINDING_2D); - this.LeftEyeTextureId = GlStateManager._genTexture(); - GlStateManager._bindTexture(this.LeftEyeTextureId); + this.leftEyeTextureId = GlStateManager._genTexture(); + GlStateManager._bindTexture(this.leftEyeTextureId); GlStateManager._texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); GlStateManager._texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); GlStateManager._texImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA, GL11.GL_INT, null); - this.RightEyeTextureId = GlStateManager._genTexture(); - GlStateManager._bindTexture(this.RightEyeTextureId); + this.rightEyeTextureId = GlStateManager._genTexture(); + GlStateManager._bindTexture(this.rightEyeTextureId); GlStateManager._texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); GlStateManager._texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); GlStateManager._texImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA, GL11.GL_INT, null); this.lastError = RenderHelper.checkGLError("create VR textures"); - - this.framebufferEyeLeft = new VRTextureTarget("L Eye", width, height, false, this.LeftEyeTextureId, true, false, - false); - + this.framebufferEyeLeft = VRTextureTarget.builder("L Eye") + .withSize(width, height) + .withTexId(this.leftEyeTextureId) + .withLinearFilter() + .build(); VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEyeLeft); - String leftError = RenderHelper.checkGLError("Left Eye framebuffer setup"); - this.framebufferEyeRight = new VRTextureTarget("R Eye", width, height, false, this.RightEyeTextureId, true, false, - false); - + this.framebufferEyeRight = VRTextureTarget.builder("R Eye") + .withSize(width, height) + .withTexId(this.rightEyeTextureId) + .withLinearFilter() + .build(); VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEyeRight); - String rightError = RenderHelper.checkGLError("Right Eye framebuffer setup"); if (this.lastError.isEmpty()) { this.lastError = !leftError.isEmpty() ? leftError : rightError; } - RenderSystem.bindTexture(boundTextureId); + GlStateManager._bindTexture(boundTextureId); } @Override @@ -126,14 +128,14 @@ public void destroy() { this.framebufferEyeRight = null; } - if (this.LeftEyeTextureId > -1) { - GlStateManager._deleteTexture(this.LeftEyeTextureId); - this.LeftEyeTextureId = -1; + if (this.leftEyeTextureId > -1) { + GlStateManager._deleteTexture(this.leftEyeTextureId); + this.leftEyeTextureId = -1; } - if (this.RightEyeTextureId > -1) { - GlStateManager._deleteTexture(this.RightEyeTextureId); - this.RightEyeTextureId = -1; + if (this.rightEyeTextureId > -1) { + GlStateManager._deleteTexture(this.rightEyeTextureId); + this.rightEyeTextureId = -1; } } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index f9cee9f77..ea8bdb87d 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -76,9 +76,6 @@ public class MCOpenVR extends MCVR { private final Map actionSetHandles = new EnumMap<>(VRInputActionSet.class); private VRActiveActionSet.Buffer activeActionSetsBuffer; - private final Map> unpressedSetKeys = new EnumMap<>(VRInputActionSet.class); - private List activeActionSets = new ArrayList<>(); - private Map controllerComponentNames; private Map controllerComponentTransforms; @@ -213,10 +210,6 @@ public MCOpenVR(Minecraft mc, ClientDataHolderVR dh) throws RenderConfigExceptio this.deviceVelocity[i] = new Vector3f(); } - for (VRInputActionSet set : VRInputActionSet.values()) { - this.unpressedSetKeys.put(set, new HashSet<>()); - } - // allocate memory this.poseData = InputPoseActionData.calloc(); this.originInfo = InputOriginInfo.calloc(); @@ -782,12 +775,7 @@ private boolean updateActiveActionSets() { .set(this.getActionSetHandle(activeSets.get(i)), k_ulInvalidInputValueHandle, 0, 0); } - // clear any sets that got deactivated - this.activeActionSets.removeAll(activeSets); - for (VRInputActionSet set : this.activeActionSets) { - this.unpressedSetKeys.get(set).clear(); - } - this.activeActionSets = activeSets; + this.updateActiveActionSets(activeSets); return !activeSets.isEmpty(); } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java index 5b34a5971..54d70b8dc 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRStereoRenderer.java @@ -1,6 +1,7 @@ package org.vivecraft.client_vr.provider.openvr_lwjgl; import com.mojang.blaze3d.opengl.GlStateManager; +import com.mojang.blaze3d.pipeline.RenderTarget; import net.minecraft.network.chat.Component; import net.minecraft.util.Tuple; import org.joml.Matrix4f; @@ -10,10 +11,10 @@ import org.lwjgl.openvr.VR; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; +import org.vivecraft.api.client.data.RenderPass; import org.vivecraft.client_vr.VRTextureTarget; import org.vivecraft.client_vr.provider.VRRenderer; import org.vivecraft.client_vr.render.RenderConfigException; -import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.render.helpers.RenderHelper; import org.vivecraft.client_vr.settings.VRSettings; @@ -24,8 +25,8 @@ public class OpenVRStereoRenderer extends VRRenderer { private final HiddenAreaMesh[] hiddenMeshes = new HiddenAreaMesh[2]; private final MCOpenVR openvr; - protected int LeftEyeTextureId = -1; - protected int RightEyeTextureId = -1; + protected int leftEyeTextureId = -1; + protected int rightEyeTextureId = -1; public RenderTarget framebufferEyeLeft; public RenderTarget framebufferEyeRight; @@ -100,52 +101,53 @@ public void createRenderTexture(int width, int height) { int boundTextureId = GlStateManager._getInteger(GL11C.GL_TEXTURE_BINDING_2D); // generate left eye texture - this.LeftEyeTextureId = GlStateManager._genTexture(); - GlStateManager._bindTexture(this.LeftEyeTextureId); + this.leftEyeTextureId = GlStateManager._genTexture(); + GlStateManager._bindTexture(this.leftEyeTextureId); GlStateManager._texParameter(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MIN_FILTER, GL11C.GL_LINEAR); GlStateManager._texParameter(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MAG_FILTER, GL11C.GL_LINEAR); GlStateManager._texImage2D(GL11C.GL_TEXTURE_2D, 0, GL11C.GL_RGBA8, width, height, 0, GL11C.GL_RGBA, GL11C.GL_INT, null); - this.openvr.texType0.handle(this.LeftEyeTextureId); + this.openvr.texType0.handle(this.leftEyeTextureId); this.openvr.texType0.eColorSpace(VR.EColorSpace_ColorSpace_Gamma); this.openvr.texType0.eType(VR.ETextureType_TextureType_OpenGL); // generate right eye texture - this.RightEyeTextureId = GlStateManager._genTexture(); - GlStateManager._bindTexture(this.RightEyeTextureId); + this.rightEyeTextureId = GlStateManager._genTexture(); + GlStateManager._bindTexture(this.rightEyeTextureId); GlStateManager._texParameter(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MIN_FILTER, GL11C.GL_LINEAR); GlStateManager._texParameter(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MAG_FILTER, GL11C.GL_LINEAR); GlStateManager._texImage2D(GL11C.GL_TEXTURE_2D, 0, GL11C.GL_RGBA8, width, height, 0, GL11C.GL_RGBA, GL11C.GL_INT, null); - this.openvr.texType1.handle(this.RightEyeTextureId); + this.openvr.texType1.handle(this.rightEyeTextureId); this.openvr.texType1.eColorSpace(VR.EColorSpace_ColorSpace_Gamma); this.openvr.texType1.eType(VR.ETextureType_TextureType_OpenGL); - VRSettings.LOGGER.info("Vivecraft: VR Provider supplied render texture IDs: {}, {}", this.LeftEyeTextureId, - this.RightEyeTextureId); + VRSettings.LOGGER.info("Vivecraft: VR Provider supplied render texture IDs: {}, {}", this.leftEyeTextureId, + this.rightEyeTextureId); this.lastError = RenderHelper.checkGLError("create VR textures"); - this.framebufferEyeLeft = new VRTextureTarget("L Eye", width, height, false, this.LeftEyeTextureId, true, false, - false); - + this.framebufferEyeLeft = VRTextureTarget.builder("L Eye") + .withSize(width, height) + .withTexId(this.leftEyeTextureId) + .withLinearFilter() + .build(); VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEyeLeft); - String leftError = RenderHelper.checkGLError("Left Eye framebuffer setup"); - this.framebufferEyeRight = new VRTextureTarget("R Eye", width, height, false, this.RightEyeTextureId, true, - false, - false); - + this.framebufferEyeRight = VRTextureTarget.builder("R Eye") + .withSize(width, height) + .withTexId(this.rightEyeTextureId) + .withLinearFilter() + .build(); VRSettings.LOGGER.info("Vivecraft: {}", this.framebufferEyeRight); - String rightError = RenderHelper.checkGLError("Right Eye framebuffer setup"); if (this.lastError.isEmpty()) { this.lastError = !leftError.isEmpty() ? leftError : rightError; } - RenderSystem.bindTexture(boundTextureId); + GlStateManager._bindTexture(boundTextureId); } @Override @@ -229,14 +231,14 @@ public void destroy() { this.framebufferEyeRight.destroyBuffers(); this.framebufferEyeRight = null; } - if (this.LeftEyeTextureId > -1) { - GlStateManager._deleteTexture(this.LeftEyeTextureId); - this.LeftEyeTextureId = -1; + if (this.leftEyeTextureId > -1) { + GlStateManager._deleteTexture(this.leftEyeTextureId); + this.leftEyeTextureId = -1; } - if (this.RightEyeTextureId > -1) { - GlStateManager._deleteTexture(this.RightEyeTextureId); - this.RightEyeTextureId = -1; + if (this.rightEyeTextureId > -1) { + GlStateManager._deleteTexture(this.rightEyeTextureId); + this.rightEyeTextureId = -1; } } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java index d763519f5..f741b4271 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java @@ -71,7 +71,7 @@ public Struct checkGraphics(MemoryStack stack, XrInstance instance, long systemI KHROpenGLEnable.xrGetOpenGLGraphicsRequirementsKHR(instance, systemID, graphicsRequirements); //Bind the OpenGL context to the OpenXR instance and create the session Window window = Minecraft.getInstance().getWindow(); - long windowHandle = window.getWindow(); + long windowHandle = window.handle(); if (Platform.getOSType() == Platform.WINDOWS) { return XrGraphicsBindingOpenGLWin32KHR.calloc(stack).set( KHROpenGLEnable.XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR, diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 36dcdf4f2..0912425bb 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -15,6 +15,7 @@ import org.lwjgl.openxr.*; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; +import org.vivecraft.api.client.data.RenderPass; import org.vivecraft.client.VivecraftVRMod; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; @@ -27,7 +28,6 @@ import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.provider.control.VRInputActionSet; import org.vivecraft.client_vr.provider.openxr.control.WrappedBinding; -import org.vivecraft.client_vr.render.RenderPass; import org.vivecraft.client_vr.settings.VRSettings; import java.nio.ByteBuffer; @@ -167,13 +167,6 @@ public void poll(long frameIndex) { Profiler.get().push("controllers"); Profiler.get().push("gui"); - if (this.mc.screen == null && this.dh.vrSettings.vrTouchHotbar) { - - if (this.dh.vrSettings.vrHudLockMode != VRSettings.HUDLock.HEAD && this.hudPopup) { - this.processHotbar(); - } - } - Profiler.get().pop(); } Profiler.get().popPush("updatePose/Vsync"); @@ -581,6 +574,11 @@ public Vector2f getPlayAreaSize() { } } + @Override + public void refreshControllerTransforms() { + // TODO controller type overrides + } + @Override public boolean init() { if (this.initialized) { @@ -1044,8 +1042,8 @@ private void loadActionHandles() { for (WrappedBinding binding: WrappedBinding.quest2Bindings()) { long action = createAction(binding.path().replace("/","."), binding.path(), binding.type(), new XrActionSet(actionSet, this.instance), binding.path().contains("left") ? BOTH_HANDS[0] : BOTH_HANDS[1]); - mappedBindings.put(binding, action); - pathBindings.put(binding.path(), binding); + this.mappedBindings.put(binding, action); + this.pathBindings.put(binding.path(), binding); } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java index 13b89a698..9a63e5809 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java @@ -6,6 +6,7 @@ import org.lwjgl.PointerBuffer; import org.lwjgl.openxr.*; import org.lwjgl.system.MemoryStack; +import org.vivecraft.client_vr.VRLayeredRenderTarget; import org.vivecraft.client_vr.VRTextureTarget; import org.vivecraft.client_vr.provider.VRRenderer; import org.vivecraft.client_vr.render.RenderConfigException; @@ -17,8 +18,8 @@ public class OpenXRStereoRenderer extends VRRenderer { private final MCOpenXR openxr; private int swapIndex; - private VRTextureTarget[] leftFramebuffers; - private VRTextureTarget[] rightFramebuffers; + private VRLayeredRenderTarget[] leftFramebuffers; + private VRLayeredRenderTarget[] rightFramebuffers; private boolean render; private XrCompositionLayerProjectionView.Buffer projectionLayerViews; private boolean recalculateProjectionMatrix = true; @@ -47,14 +48,14 @@ public void createRenderTexture(int width, int height) { XrSwapchainImageBaseHeader.create(swapchainImageBuffer.address(), swapchainImageBuffer.capacity())); this.openxr.logError(error, "xrEnumerateSwapchainImages", "get images"); - this.leftFramebuffers = new VRTextureTarget[imageCount]; - this.rightFramebuffers = new VRTextureTarget[imageCount]; + this.leftFramebuffers = new VRLayeredRenderTarget[imageCount]; + this.rightFramebuffers = new VRLayeredRenderTarget[imageCount]; for (int i = 0; i < imageCount; i++) { XrSwapchainImageOpenGLKHR openxrImage = swapchainImageBuffer.get(i); - this.leftFramebuffers[i] = new VRTextureTarget("L Eye " + i, width, height, openxrImage.image(), 0); + this.leftFramebuffers[i] = new VRLayeredRenderTarget("L Eye " + i, width, height, openxrImage.image(), 0); String leftError = RenderHelper.checkGLError("Left Eye " + i + " framebuffer setup"); - this.rightFramebuffers[i] = new VRTextureTarget("R Eye " + i, width, height, openxrImage.image(), 1); + this.rightFramebuffers[i] = new VRLayeredRenderTarget("R Eye " + i, width, height, openxrImage.image(), 1); String rightError = RenderHelper.checkGLError("Right Eye " + i + " framebuffer setup"); if (this.lastError.isEmpty()) { @@ -190,14 +191,14 @@ public void destroy() { super.destroy(); if (this.leftFramebuffers != null) { - for (VRTextureTarget leftFramebuffer : this.leftFramebuffers) { + for (VRLayeredRenderTarget leftFramebuffer : this.leftFramebuffers) { leftFramebuffer.destroyBuffers(); } this.leftFramebuffers = null; } if (this.rightFramebuffers != null) { - for (VRTextureTarget rightFramebuffer : this.rightFramebuffers) { + for (VRLayeredRenderTarget rightFramebuffer : this.rightFramebuffers) { rightFramebuffer.destroyBuffers(); } this.rightFramebuffers = null; diff --git a/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java b/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java index 7a5146e93..b9ef2be9f 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/VRShaders.java @@ -37,7 +37,6 @@ public class VRShaders { // mixed reality shader and its uniforms public static MixedRealityUBO MIXED_REALITY_UBO; - public static final String MIXED_REALITY_FIRST_COLOR_SAMPLER = "firstPersonColor"; public static final String MIXED_REALITY_THIRD_COLOR_SAMPLER = "thirdPersonColor"; public static final String MIXED_REALITY_THIRD_DEPTH_SAMPLER = "thirdPersonDepth"; public static final String MIXED_REALITY_GUI_COLOR_SAMPLER = "guiColor"; @@ -50,13 +49,13 @@ public class VRShaders { .withVertexShader(ResourceLocation.fromNamespaceAndPath("vivecraft", "core/passthrough_vr")) .withFragmentShader(ResourceLocation.fromNamespaceAndPath("vivecraft", "core/mixedreality_vr")) .withUniform(MixedRealityUBO.UBO_NAME, UniformType.UNIFORM_BUFFER) - .withSampler(MIXED_REALITY_FIRST_COLOR_SAMPLER) .withSampler(MIXED_REALITY_THIRD_COLOR_SAMPLER) .withSampler(MIXED_REALITY_THIRD_DEPTH_SAMPLER) .withSampler(MIXED_REALITY_GUI_COLOR_SAMPLER) .withVertexFormat(DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.QUADS) .withDepthWrite(false) .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withBlend(BlendFunction.TRANSLUCENT) .build(); // vr post shader and its uniforms @@ -77,16 +76,6 @@ public class VRShaders { // blit shader public static final String BLIT_VR_COLOR_SAMPLER = "DiffuseSampler"; - public static final RenderPipeline BLIT_VR_PIPELINE = RenderPipeline.builder() - .withLocation("pipeline/vivecraft_blit") - .withVertexShader(ResourceLocation.fromNamespaceAndPath("vivecraft", "core/passthrough_vr")) - .withFragmentShader(ResourceLocation.fromNamespaceAndPath("vivecraft", "core/blit_vr")) - .withSampler(BLIT_VR_COLOR_SAMPLER) - .withVertexFormat(DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.QUADS) - .withDepthWrite(false) - .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) - .build(); - public static final RenderPipeline BLIT_VR_BLEND_PIPELINE = RenderPipeline.builder() .withLocation("pipeline/vivecraft_blit") .withVertexShader(ResourceLocation.fromNamespaceAndPath("vivecraft", "core/passthrough_vr")) diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java index 674be93f6..734633a71 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/ShaderHelper.java @@ -3,7 +3,6 @@ import com.mojang.blaze3d.buffers.GpuBuffer; import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.pipeline.RenderTarget; -import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.textures.GpuTextureView; import com.mojang.blaze3d.vertex.*; @@ -18,12 +17,14 @@ import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; import org.joml.Vector3f; +import org.lwjgl.opengl.GL11C; import org.vivecraft.api.client.data.RenderPass; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.extensions.GameRendererExtension; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; import org.vivecraft.client_vr.render.MirrorNotification; import org.vivecraft.client_vr.render.VRShaders; +import org.vivecraft.client_vr.render.helpers.opengl.OpenGLHelper; import org.vivecraft.client_vr.render.ubos.LanczosUBO; import org.vivecraft.client_vr.render.ubos.MixedRealityUBO; import org.vivecraft.client_vr.render.ubos.PostProcessUBO; @@ -321,8 +322,8 @@ public static void drawMirror() { // source = DataHolder.getInstance().vrRenderer.telescopeFramebufferR; // if (source != null) { - blitFramebufferCrop(source, 0, 0, MC.mainRenderTarget.width, MC.mainRenderTarget.height, - xCrop, yCrop, keepAspect, false); + ShaderHelper.blitFramebufferCrop(source, 0, 0, MC.mainRenderTarget.width, MC.mainRenderTarget.height, + xCrop, yCrop, keepAspect); } if (source != GuiHandler.GUI_FRAMEBUFFER) { blitGui(); @@ -334,6 +335,23 @@ public static void drawMirror() { } public static void doMixedRealityMirror() { + if (DATA_HOLDER.vrSettings.mixedRealityUnityLike) { + RenderTarget source; + if (DATA_HOLDER.vrSettings.displayMirrorUseScreenshotCamera && DATA_HOLDER.cameraTracker.isVisible()) { + source = DATA_HOLDER.vrRenderer.cameraFramebuffer; + } else if (DATA_HOLDER.vrSettings.mixedRealityUndistorted) { + source = DATA_HOLDER.vrRenderer.framebufferUndistorted; + } else { + if (DATA_HOLDER.vrSettings.displayMirrorLeftEye) { + source = DATA_HOLDER.vrRenderer.getLeftEyeTarget(); + } else { + source = DATA_HOLDER.vrRenderer.getRightEyeTarget(); + } + } + blitFramebuffer(source, MC.mainRenderTarget.width / 2, 0, + MC.mainRenderTarget.width, MC.mainRenderTarget.height / 2); + } + Vector3f camPlayer = DATA_HOLDER.vrPlayer.vrdata_room_pre.getHeadPivotF() .sub(DATA_HOLDER.vrPlayer.vrdata_room_pre.getEye(RenderPass.THIRD).getPositionF()); @@ -371,8 +389,6 @@ public static void doMixedRealityMirror() { guiMask ); - GpuTextureView black = RenderHelper.getGpuTexture(RenderHelper.BLACK_TEXTURE); - renderFullscreenQuad(() -> "Vive mixed reality", VRShaders.MIXED_REALITY_PIPELINE, renderPass -> { // set uniforms renderPass.setUniform(MixedRealityUBO.UBO_NAME, VRShaders.MIXED_REALITY_UBO.getBuffer()); @@ -385,24 +401,6 @@ public static void doMixedRealityMirror() { renderPass.bindSampler(VRShaders.MIXED_REALITY_GUI_COLOR_SAMPLER, GuiHandler.GUI_FRAMEBUFFER.getColorTextureView()); - - if (DATA_HOLDER.vrSettings.mixedRealityUnityLike) { - RenderTarget source; - if (DATA_HOLDER.vrSettings.displayMirrorUseScreenshotCamera && DATA_HOLDER.cameraTracker.isVisible()) { - source = DATA_HOLDER.vrRenderer.cameraFramebuffer; - } else if (DATA_HOLDER.vrSettings.mixedRealityUndistorted) { - source = DATA_HOLDER.vrRenderer.framebufferUndistorted; - } else { - if (DATA_HOLDER.vrSettings.displayMirrorLeftEye) { - source = DATA_HOLDER.vrRenderer.getLeftEyeTarget(); - } else { - source = DATA_HOLDER.vrRenderer.getRightEyeTarget(); - } - } - renderPass.bindSampler(VRShaders.MIXED_REALITY_FIRST_COLOR_SAMPLER, source.getColorTextureView()); - } else { - renderPass.bindSampler(VRShaders.MIXED_REALITY_FIRST_COLOR_SAMPLER, black); - } }, null); VRShaders.MIXED_REALITY_UBO.endFrame(); } @@ -452,46 +450,80 @@ public static void blitGui() { float mirrorAspect = (float) MC.mainRenderTarget.width / (float) MC.mainRenderTarget.height; float guiAspect = (float) GuiHandler.GUI_FRAMEBUFFER.width / (float) GuiHandler.GUI_FRAMEBUFFER.height; - float xMin = 0; - float yMin = 0; + float xMin = -1.0F; + float yMin = -1.0F; float xMax = 1.0F; float yMax = 1.0F; if (mirrorAspect > guiAspect) { // mirror is wider than the gui // limit the width, so the complete height is filled - float aspect = (guiAspect / mirrorAspect) * 0.5F; + float aspect = guiAspect / mirrorAspect; - xMin = 0.5F - aspect; - xMax = 0.5F + aspect; + xMin = -aspect; + xMax = aspect; } else { // mirror is taller than the gui // limit the height, so the complete width is filled // and shift the gui to the bottom - yMax = (mirrorAspect / guiAspect); + yMax = (mirrorAspect / guiAspect) * 2F - 1F; } - int x = (int) (xMin * MC.mainRenderTarget.width); - int y = (int) (yMin * MC.mainRenderTarget.height); - int width = (int) (xMax * MC.mainRenderTarget.width) - x; - int height = (int) (yMax * MC.mainRenderTarget.height) - y; + BufferBuilder bufferBuilder = Tesselator.getInstance() + .begin(VertexFormat.Mode.QUADS, VRShaders.BLIT_VR_BLEND_PIPELINE.getVertexFormat()); + + // position quad + bufferBuilder.addVertex(xMin, yMin, 0.0F).setUv(xMin, yMin); + bufferBuilder.addVertex(xMax, yMin, 0.0F).setUv(xMax, yMin); + bufferBuilder.addVertex(xMax, yMax, 0.0F).setUv(xMax, yMax); + bufferBuilder.addVertex(xMin, yMax, 0.0F).setUv(xMin, yMax); + + try (MeshData meshData = bufferBuilder.buildOrThrow()) { + GpuBuffer gpuBuffer = VRShaders.BLIT_VR_BLEND_PIPELINE.getVertexFormat() + .uploadImmediateVertexBuffer(meshData.vertexBuffer()); + + GpuBuffer indexBuffer; + VertexFormat.IndexType indexType; + if (meshData.indexBuffer() == null) { + RenderSystem.AutoStorageIndexBuffer autoStorageIndexBuffer = RenderSystem.getSequentialBuffer( + VertexFormat.Mode.QUADS); + indexBuffer = autoStorageIndexBuffer.getBuffer(6); + indexType = autoStorageIndexBuffer.type(); + } else { + indexBuffer = VRShaders.BLIT_VR_BLEND_PIPELINE.getVertexFormat() + .uploadImmediateIndexBuffer(meshData.indexBuffer()); + indexType = meshData.drawState().indexType(); + } + + try (com.mojang.blaze3d.systems.RenderPass renderPass = RenderSystem.getDevice().createCommandEncoder() + .createRenderPass(() -> "Vive Blit", MC.getMainRenderTarget().getColorTextureView(), + OptionalInt.empty())) + { + renderPass.setPipeline(VRShaders.BLIT_VR_BLEND_PIPELINE); + renderPass.setVertexBuffer(0, gpuBuffer); + + renderPass.bindSampler(VRShaders.BLIT_VR_COLOR_SAMPLER, + GuiHandler.GUI_FRAMEBUFFER.getColorTextureView()); - blitToScreen(GuiHandler.GUI_FRAMEBUFFER, x, width, height, y, 0, 0, true, true); + renderPass.setIndexBuffer(indexBuffer, indexType); + renderPass.drawIndexed(0, 0, 6, 1); + } + } } /** * blits the given {@code source} RenderTarget to the bound framebuffer
* the {@code source} is drawn to the rectangle at {@code left},{@code top} with a size of {@code width},{@code height}
* if {@code xCropFactor} or {@code yCropFactor} are non 0 the {@code source} gets zoomed in - * @param source RenderTarget to draw to the screen - * @param left left edge of the target area - * @param top top edge of the target area - * @param right right edge width of the target area - * @param bottom bottom edge of the target area + * + * @param source RenderTarget to draw to the screen + * @param left left edge of the target area + * @param top top edge of the target area + * @param right right edge width of the target area + * @param bottom bottom edge of the target area * @param xCropFactor vertical crop factor for the {@code source} * @param yCropFactor horizontal crop factor for the {@code source} - * @param keepAspect keeps the aspect ratio in takt when cropping the buffer - * @param blend if alpha blending should be used + * @param keepAspect keeps the aspect ratio in takt when cropping the buffer */ private static void blitFramebufferCrop( RenderTarget source, int left, int top, int right, int bottom, @@ -499,7 +531,7 @@ private static void blitFramebufferCrop( { if (keepAspect) { float drawAspect = (float) MC.mainRenderTarget.width / (float) MC.mainRenderTarget.height; - float bufferAspect = (float) source.viewWidth / (float) source.viewHeight; + float bufferAspect = (float) source.width / (float) source.height; if (drawAspect > bufferAspect) { // destination is wider than the buffer float heightAspect = (bufferAspect / drawAspect) * (0.5F - yCropFactor); @@ -518,29 +550,29 @@ private static void blitFramebufferCrop( int xMax = source.width - xMin; int yMax = source.height - yMin; - GlStateManager._glBindFramebuffer(GL30C.GL_READ_FRAMEBUFFER, source.frameBufferId); - GlStateManager._glBlitFrameBuffer( + OpenGLHelper.blitFramebuffer( + source.getColorTexture(), MC.mainRenderTarget.getColorTexture(), xMin, yMin, xMax, yMax, left, top, right, bottom, GL11C.GL_COLOR_BUFFER_BIT, GL11C.GL_LINEAR); - GlStateManager._glBindFramebuffer(GL30C.GL_READ_FRAMEBUFFER, 0); } + /** * blits the given {@code source} RenderTarget to the bound framebuffer + * * @param source RenderTarget to draw to the screen - * @param left left edge of the target area - * @param top top edge of the target area - * @param right right edge width of the target area + * @param left left edge of the target area + * @param top top edge of the target area + * @param right right edge width of the target area * @param bottom bottom edge of the target area */ private static void blitFramebuffer( RenderTarget source, int left, int top, int right, int bottom) { - GlStateManager._glBindFramebuffer(GL30C.GL_READ_FRAMEBUFFER, source.frameBufferId); - GlStateManager._glBlitFrameBuffer( + OpenGLHelper.blitFramebuffer( + source.getColorTexture(), MC.mainRenderTarget.getColorTexture(), 0, 0, source.width, source.height, left, top, right, bottom, GL11C.GL_COLOR_BUFFER_BIT, GL11C.GL_LINEAR); - GlStateManager._glBindFramebuffer(GL30C.GL_READ_FRAMEBUFFER, 0); } } 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 5c0064102..0ae4dcab9 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 @@ -220,7 +220,6 @@ public static void renderAndSubmit(boolean renderLevel, DeltaTracker.Timer delta Profiler.get().push("vrMirror"); // use the vanilla target for the mirror RenderPassManager.setMirrorRenderPass(); - MC.mainRenderTarget.bindWrite(true); ShaderHelper.drawMirror(); RenderHelper.checkGLError("post-mirror"); diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/opengl/LayeredGlTexture.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/opengl/LayeredGlTexture.java new file mode 100644 index 000000000..10c9a411a --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/opengl/LayeredGlTexture.java @@ -0,0 +1,47 @@ +package org.vivecraft.client_vr.render.helpers.opengl; + +import com.mojang.blaze3d.opengl.DirectStateAccess; +import com.mojang.blaze3d.opengl.GlStateManager; +import com.mojang.blaze3d.opengl.GlTexture; +import com.mojang.blaze3d.textures.GpuTexture; +import com.mojang.blaze3d.textures.TextureFormat; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GL30C; + +public class LayeredGlTexture extends GlTexture { + + protected final int id; + private final int layer; + private final Int2IntMap fboCache = new Int2IntOpenHashMap(); + + public LayeredGlTexture( + int usage, String label, TextureFormat format, int width, int height, int depthOrLayers, int mipLevels, int id, + int layer) + { + super(usage, label, format, width, height, depthOrLayers, mipLevels, id); + this.id = id; + this.layer = layer; + } + + @Override + public int getFbo(DirectStateAccess directStateAccess, @Nullable GpuTexture depthTexture) { + int depthId = depthTexture == null ? 0 : ((GlTexture) depthTexture).glId(); + return this.fboCache.computeIfAbsent(depthId, (tex) -> { + int frameBuffer = GlStateManager.glGenFramebuffers(); + int oldFbo = GlStateManager.getFrameBuffer(GL30C.GL_DRAW_FRAMEBUFFER); + GlStateManager._glBindFramebuffer(GL30C.GL_DRAW_FRAMEBUFFER, frameBuffer); + + GL30.glFramebufferTextureLayer(GL30C.GL_DRAW_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, this.id, 0, + this.layer); + GL30.glFramebufferTexture2D(GL30C.GL_DRAW_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL30.GL_TEXTURE_2D, + depthId, 0); + + GlStateManager._glBindFramebuffer(GL30C.GL_DRAW_FRAMEBUFFER, oldFbo); + + return frameBuffer; + }); + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/render/helpers/opengl/OpenGLHelper.java b/common/src/main/java/org/vivecraft/client_vr/render/helpers/opengl/OpenGLHelper.java index 0548a6105..e0b19f6f6 100644 --- a/common/src/main/java/org/vivecraft/client_vr/render/helpers/opengl/OpenGLHelper.java +++ b/common/src/main/java/org/vivecraft/client_vr/render/helpers/opengl/OpenGLHelper.java @@ -50,6 +50,23 @@ public static void genMipmaps(GpuTexture texture) { } } + public static void blitFramebuffer( + GpuTexture source, GpuTexture target, int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, + int dstX1, int dstY1, int mask, int filter) + { + if (RenderSystem.getDevice() instanceof GlDevice glDevice && source instanceof GlTexture glSource && + target instanceof GlTexture glTarget) + { + glDevice.directStateAccess().blitFrameBuffers(glSource.getFbo(glDevice.directStateAccess(), null), + glTarget.getFbo(glDevice.directStateAccess(), null), + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, filter); + } else { + throw new IllegalStateException("Vivecraft: only opengl textures are supported"); + } + } + /** * enabled anisotropic filtering for the given GpuTexture * 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 75fad3d1f..b49f1c73b 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 @@ -75,6 +75,7 @@ import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.render.VRFirstPersonArmSwing; import org.vivecraft.client_vr.render.helpers.RenderHelper; +import org.vivecraft.client_vr.render.helpers.ShaderHelper; import org.vivecraft.client_vr.settings.VRHotkeys; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.client_xr.render_pass.RenderPassManager; @@ -305,6 +306,20 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { } } + @WrapOperation(method = "runTick", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/pipeline/RenderTarget;blitToScreen()V")) + private void vivecraft$blitMirror(RenderTarget instance, Operation original) { + if (VRState.VR_RUNNING) { + original.call(this.mainRenderTarget); + RenderPassManager.setGUIRenderPass(); + } else { + if (VRState.VR_ENABLED && !VRState.VR_INITIALIZED) { + // show message that the game is connecting to the vr runtime + RenderHelper.drawVRConnectingMessage(); + } + original.call(instance); + } + } + @Inject(method = "setCameraEntity", at = @At("HEAD")) private void vivecraft$rideEntity(Entity entity, CallbackInfo ci) { if (VRState.VR_INITIALIZED && entity != null) { diff --git a/common/src/main/resources/assets/vivecraft/shaders/core/blit_vr.fsh b/common/src/main/resources/assets/vivecraft/shaders/core/blit_vr.fsh new file mode 100644 index 000000000..72185769e --- /dev/null +++ b/common/src/main/resources/assets/vivecraft/shaders/core/blit_vr.fsh @@ -0,0 +1,11 @@ +#version 330 + +uniform sampler2D DiffuseSampler; + +in vec2 texCoordinates; + +out vec4 fragColor; + +void main(){ + fragColor = texture(DiffuseSampler, texCoordinates.st); +} diff --git a/common/src/main/resources/assets/vivecraft/shaders/core/mixedreality_vr.fsh b/common/src/main/resources/assets/vivecraft/shaders/core/mixedreality_vr.fsh index 946804df4..7dae5dfaf 100644 --- a/common/src/main/resources/assets/vivecraft/shaders/core/mixedreality_vr.fsh +++ b/common/src/main/resources/assets/vivecraft/shaders/core/mixedreality_vr.fsh @@ -65,7 +65,11 @@ void main(void) { vec2 sampleTexCoord = fract(texCoordinates * 2.0); if (texCoordinates.x >= 0.5 && texCoordinates.y < 0.5) { // first person - out_Color.rgb = sampleTexture(firstPersonColor, sampleTexCoord, GUI_FIRST).rgb; + if ((GUI_FIRST & guiMask) != 0) { + out_Color = texture(guiColor, sampleTexCoord); + } else { + out_Color = vec4(0); + } } else { vec4 thirdColor = sampleTexture(thirdPersonColor, sampleTexCoord, GUI_THIRD); if (texCoordinates.x < 0.5 && texCoordinates.y < 0.5) { diff --git a/common/src/main/resources/vivecraft.accesswidener b/common/src/main/resources/vivecraft.accesswidener index d05e9a050..9ee9b0e9d 100644 --- a/common/src/main/resources/vivecraft.accesswidener +++ b/common/src/main/resources/vivecraft.accesswidener @@ -52,6 +52,9 @@ accessible field net/minecraft/client/KeyMapping key Lcom/mojang/blaze3d/platfor # to create custom GL textures accessible method com/mojang/blaze3d/opengl/GlTexture (ILjava/lang/String;Lcom/mojang/blaze3d/textures/TextureFormat;IIIII)V +# to blit framebuffers +accessible method com/mojang/blaze3d/opengl/DirectStateAccess blitFrameBuffers (IIIIIIIIIIII)V + # to render vr hands accessible method net/minecraft/client/renderer/ItemInHandRenderer renderArmWithItem (Lnet/minecraft/client/player/AbstractClientPlayer;FFLnet/minecraft/world/InteractionHand;FLnet/minecraft/world/item/ItemStack;FLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;I)V From 51caad7d57027e483c0ec36febe46470d1f70e18 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 17 Nov 2025 00:51:09 +0100 Subject: [PATCH 69/76] fix lang keys --- common/src/main/resources/assets/vivecraft/lang/en_us.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 15952548c..949ab5435 100644 --- a/common/src/main/resources/assets/vivecraft/lang/en_us.json +++ b/common/src/main/resources/assets/vivecraft/lang/en_us.json @@ -391,9 +391,6 @@ "vivecraft.options.aimdevice.hmd": "HMD", "vivecraft.options.searchtype.fuzzy": "Fuzzy", "vivecraft.options.searchtype.exact": "Exact", - "vivecraft.options.vrprovider.openvr": "OpenVR", - "vivecraft.options.vrprovider.openxr": "OpenXR", - "vivecraft.options.vrprovider.nullvr": "NullVR", "_comment8": "Button text", "vivecraft.gui.ok": "OK", "vivecraft.gui.clear": "Clear", @@ -503,6 +500,7 @@ "vivecraft.options.menuworldfallback.dirtbox": "Dirtbox", "vivecraft.options.menuworldfallback.panorama": "Panorama", "vivecraft.options.vrprovider.openvr": "OpenVR/SteamVR", + "vivecraft.options.vrprovider.openxr": "OpenXR", "vivecraft.options.vrprovider.nullvr": "NullVR", "vivecraft.options.realisticjump.auto": "Auto", "vivecraft.options.autoopenkeyboard.chat": "Chat", From 9fb821ce08ddc61455055e0dc0541ecb3972c245 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Mon, 17 Nov 2025 00:55:42 +0100 Subject: [PATCH 70/76] formatting --- .../framework/screens/TwoHandedScreen.java | 2 +- .../client/gui/settings/GuiBindings.java | 1 - .../gameplay/screenhandlers/GuiHandler.java | 4 +- .../gameplay/trackers/SwingTracker.java | 2 +- .../client_vr/gui/PhysicalKeyboard.java | 2 +- .../vivecraft/client_vr/provider/MCVR.java | 7 +- .../client_vr/provider/VRRenderer.java | 1 + .../provider/control/VRInputAction.java | 10 +- .../client_vr/provider/nullvr/NullVR.java | 2 +- .../nullvr/NullVRHapticScheduler.java | 2 +- .../openvr_lwjgl/OpenVRHapticScheduler.java | 2 +- .../provider/openxr/DeviceCompat.java | 3 +- .../client_vr/provider/openxr/MCOpenXR.java | 49 ++-- .../openxr/OpenXRHapticScheduler.java | 11 +- .../provider/openxr/OpenXRStereoRenderer.java | 7 +- .../client_vr/provider/openxr/XRBindings.java | 258 ++++++++++++------ .../openxr/control/WrappedBinding.java | 62 ++--- .../mixin/client_vr/KeyboardInputVRMixin.java | 1 - .../mixin/client_vr/MinecraftVRMixin.java | 1 - .../ClientPacketListenerVRMixin.java | 2 - .../client_vr/world/FishingHookVRMixin.java | 2 +- .../main/java/org/vivecraft/util/VLoader.java | 5 + 22 files changed, 268 insertions(+), 168 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client/gui/framework/screens/TwoHandedScreen.java b/common/src/main/java/org/vivecraft/client/gui/framework/screens/TwoHandedScreen.java index 4cb177d62..3475724d0 100644 --- a/common/src/main/java/org/vivecraft/client/gui/framework/screens/TwoHandedScreen.java +++ b/common/src/main/java/org/vivecraft/client/gui/framework/screens/TwoHandedScreen.java @@ -10,8 +10,8 @@ import org.joml.Vector3f; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; -import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.MCVR; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.render.helpers.RenderHelper; public abstract class TwoHandedScreen extends Screen { diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java index ac36e7efb..03cb978c0 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java @@ -91,5 +91,4 @@ public static Supplier getBaseWidget(VRInputAction action, int w .tooltip(Tooltip.create(Component.literal(action.name))) .build(); } - } diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/GuiHandler.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/GuiHandler.java index e080fe2ce..1819fac19 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/GuiHandler.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/screenhandlers/GuiHandler.java @@ -32,10 +32,10 @@ import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.extensions.WindowExtension; import org.vivecraft.client_vr.gameplay.VRPlayer; -import org.vivecraft.client_vr.provider.control.ControllerType; -import org.vivecraft.client_vr.provider.control.HandedKeyBinding; import org.vivecraft.client_vr.provider.InputSimulator; import org.vivecraft.client_vr.provider.MCVR; +import org.vivecraft.client_vr.provider.control.ControllerType; +import org.vivecraft.client_vr.provider.control.HandedKeyBinding; import org.vivecraft.client_vr.render.helpers.RenderHelper; import org.vivecraft.client_vr.settings.AutoCalibration; import org.vivecraft.client_vr.settings.VRSettings; diff --git a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java index b76eb5811..66f2871e3 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java +++ b/common/src/main/java/org/vivecraft/client_vr/gameplay/trackers/SwingTracker.java @@ -33,8 +33,8 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRData; import org.vivecraft.client_vr.Vector3fHistory; -import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.MCVR; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.render.helpers.DebugRenderHelper; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.common.utils.MathUtils; diff --git a/common/src/main/java/org/vivecraft/client_vr/gui/PhysicalKeyboard.java b/common/src/main/java/org/vivecraft/client_vr/gui/PhysicalKeyboard.java index 860928c70..27088874f 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gui/PhysicalKeyboard.java +++ b/common/src/main/java/org/vivecraft/client_vr/gui/PhysicalKeyboard.java @@ -20,8 +20,8 @@ import org.vivecraft.client_vr.gui.keyboard.EasterEggTheme; import org.vivecraft.client_vr.gui.keyboard.KeyboardKeys; import org.vivecraft.client_vr.gui.keyboard.KeyboardTheme; -import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.MCVR; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.render.helpers.RenderHelper; import org.vivecraft.client_vr.render.rendertypes.VRRenderTypes; import org.vivecraft.client_vr.utils.RGBAColor; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java index bf5a7f47b..1172145e1 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java @@ -32,9 +32,9 @@ 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.ClimbTracker; import org.vivecraft.client_vr.provider.control.*; import org.vivecraft.client_vr.provider.openxr.DeviceCompat; -import org.vivecraft.client_vr.gameplay.trackers.ClimbTracker; import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.settings.AutoCalibration; import org.vivecraft.client_vr.settings.VRHotkeys; @@ -372,7 +372,7 @@ public Vector3f getHandVector(int controller) { * @return position of the given eye, in room space */ public Vector3f getEyePosition(RenderPass eye) { - Matrix4fc pose = switch (eye) { + Matrix4fc pose = switch (eye) { case LEFT -> this.hmdPoseLeftEye; case RIGHT -> this.hmdPoseRightEye; default -> this.hmdPose; @@ -1212,7 +1212,8 @@ public Map getSpecialActionParams() { this.addActionParams(map, this.mc.options.keyDown, "optional", ActionType.VEC1, null); this.addActionParams(map, this.mc.options.keyLeft, "optional", ActionType.VEC1, null); this.addActionParams(map, this.mc.options.keyRight, "optional", ActionType.VEC1, null); - this.addActionParams(map, this.mc.options.keyInventory, "suggested", ActionType.BOOLEAN, VRInputActionSet.GLOBAL); + this.addActionParams(map, this.mc.options.keyInventory, "suggested", ActionType.BOOLEAN, + VRInputActionSet.GLOBAL); this.addActionParams(map, this.mc.options.keyAttack, "suggested", ActionType.BOOLEAN, null); this.addActionParams(map, this.mc.options.keyUse, "suggested", ActionType.BOOLEAN, null); this.addActionParams(map, this.mc.options.keyChat, "optional", ActionType.BOOLEAN, VRInputActionSet.GLOBAL); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java index 1e3979d3d..fc8ad10ff 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/VRRenderer.java @@ -154,6 +154,7 @@ public Matrix4f getCachedProjectionMatrix(int eyeType, float nearClip, float far * @return the right eye rendertarget */ public abstract RenderTarget getRightEyeTarget(); + /** * gets an array with the vertex info of the stencil mesh, if there is one provided by this renderer * diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java index 2bce9ee4b..232e84f97 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java @@ -40,7 +40,9 @@ public class VRInputAction { public final DigitalData[] digitalData = new DigitalData[ControllerType.values().length]; public final AnalogData[] analogData = new AnalogData[ControllerType.values().length]; - public VRInputAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { + public VRInputAction( + KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) + { this.keyBinding = keyMapping; this.requirement = requirement; this.type = type; @@ -86,8 +88,7 @@ public float getAxis1D(boolean delta) { public Vector2fc getAxis2D(boolean delta) { return switch (this.type) { case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> new Vector2f(this.digitalToAnalog(delta), 0.0F); - case VEC1 -> - delta ? new Vector2f(this.analogData().deltaX, 0.0F) : new Vector2f(this.analogData().x, 0.0F); + case VEC1 -> delta ? new Vector2f(this.analogData().deltaX, 0.0F) : new Vector2f(this.analogData().x, 0.0F); case VEC2 -> delta ? new Vector2f(this.analogData().deltaX, this.analogData().deltaY) : new Vector2f(this.analogData().x, this.analogData().y); default -> new Vector2f(); @@ -96,7 +97,8 @@ public Vector2fc getAxis2D(boolean delta) { public Vector3fc getAxis3D(boolean delta) { return switch (this.type) { - case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> new Vector3f(this.digitalToAnalog(delta), 0.0F, 0.0F); + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> + new Vector3f(this.digitalToAnalog(delta), 0.0F, 0.0F); case VEC1 -> delta ? new Vector3f(this.analogData().deltaX, 0.0F, 0.0F) : new Vector3f(this.analogData().x, 0.0F, 0.0F); case VEC2 -> delta ? new Vector3f(this.analogData().deltaX, this.analogData().deltaY, 0.0F) : 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 1ab2717b6..b910db88e 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 @@ -14,10 +14,10 @@ import org.vivecraft.client_vr.MethodHolder; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; import org.vivecraft.client_vr.provider.ControllerTransform; -import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.DeviceSource; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.VRRenderer; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.render.MirrorNotification; import org.vivecraft.client_vr.settings.VRSettings; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRHapticScheduler.java b/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRHapticScheduler.java index 1822a140f..0eeeb91c4 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRHapticScheduler.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/nullvr/NullVRHapticScheduler.java @@ -1,8 +1,8 @@ package org.vivecraft.client_vr.provider.nullvr; -import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.HapticScheduler; +import org.vivecraft.client_vr.provider.control.ControllerType; public class NullVRHapticScheduler extends HapticScheduler { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRHapticScheduler.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRHapticScheduler.java index d3289ee41..4fe93efdf 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRHapticScheduler.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/OpenVRHapticScheduler.java @@ -2,8 +2,8 @@ import org.lwjgl.openvr.VR; import org.lwjgl.openvr.VRInput; -import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.HapticScheduler; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.settings.VRSettings; import java.util.concurrent.TimeUnit; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java index f741b4271..009008420 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/DeviceCompat.java @@ -14,7 +14,6 @@ import org.lwjgl.system.linux.X11; import org.lwjgl.system.windows.User32; import org.vivecraft.client_vr.settings.VRSettings; -import org.vivecraft.util.VLoader; import java.util.Objects; @@ -117,7 +116,7 @@ public long getPlatformInfo(MemoryStack stack) { // VLoader.getDalvikVM(), // VLoader.getDalvikActivity() // ).address(); - return NULL; + return NULL; } @Override diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 0912425bb..1dc9d603d 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -21,10 +21,10 @@ import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler; -import org.vivecraft.client_vr.provider.control.ActionType; -import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.VRRenderer; +import org.vivecraft.client_vr.provider.control.ActionType; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.provider.control.VRInputActionSet; import org.vivecraft.client_vr.provider.openxr.control.WrappedBinding; @@ -358,7 +358,8 @@ private void readBoolean(VRInputAction action, ControllerType hand) { info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); info.action(new XrAction(action.handle, new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); - info.subactionPath(action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); + info.subactionPath( + action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); XrActionStateBoolean state = XrActionStateBoolean.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_BOOLEAN); int error = XR10.xrGetActionStateBoolean(this.session, info, state); logError(error, "xrGetActionStateBoolean", action.name); @@ -366,12 +367,14 @@ private void readBoolean(VRInputAction action, ControllerType hand) { if (state.changedSinceLastSync()) { if (state.currentState()) { action.digitalData[i].toggle = !action.digitalData[i].toggle; - action.digitalData[i].doublePress = System.nanoTime() - action.digitalData[i].lastChange > 250_000_000L; + action.digitalData[i].doublePress = + System.nanoTime() - action.digitalData[i].lastChange > 250_000_000L; } else { - action.digitalData[i].longPress = System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; + action.digitalData[i].longPress = + System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; } action.digitalData[i].lastChange = System.nanoTime(); - } else if (state.currentState()){ + } else if (state.currentState()) { action.digitalData[i].hold = System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; } @@ -393,7 +396,8 @@ private void readFloat(VRInputAction action, ControllerType hand) { info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); info.action(new XrAction(action.handle, new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); - info.subactionPath(action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); + info.subactionPath( + action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); XrActionStateFloat state = XrActionStateFloat.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_FLOAT); int error = XR10.xrGetActionStateFloat(this.session, info, state); logError(error, "xrGetActionStateFloat", action.name); @@ -417,7 +421,8 @@ private void readVecData(VRInputAction action, ControllerType hand) { info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); info.action(new XrAction(action.handle, new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); - info.subactionPath(action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); + info.subactionPath( + action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); XrActionStateVector2f state = XrActionStateVector2f.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_VECTOR2F); int error = XR10.xrGetActionStateVector2f(this.session, info, state); logError(error, "xrGetActionStateVector2f", action.name); @@ -894,12 +899,14 @@ private void initializeOpenXRSwapChain() { private void initDisplayRefreshRate() { if (this.session.getCapabilities().XR_FB_display_refresh_rate) { try (MemoryStack stack = MemoryStack.stackPush()) { - IntBuffer refreshRateCount = stack.callocInt(1); - FBDisplayRefreshRate.xrEnumerateDisplayRefreshRatesFB(this.session, refreshRateCount, null); - FloatBuffer refreshRateBuffer = stack.callocFloat(refreshRateCount.get(0)); - FBDisplayRefreshRate.xrEnumerateDisplayRefreshRatesFB(this.session, refreshRateCount, refreshRateBuffer); - refreshRateBuffer.rewind(); - FBDisplayRefreshRate.xrRequestDisplayRefreshRateFB(this.session, refreshRateBuffer.get(refreshRateCount.get(0) -1)); + IntBuffer refreshRateCount = stack.callocInt(1); + FBDisplayRefreshRate.xrEnumerateDisplayRefreshRatesFB(this.session, refreshRateCount, null); + FloatBuffer refreshRateBuffer = stack.callocFloat(refreshRateCount.get(0)); + FBDisplayRefreshRate.xrEnumerateDisplayRefreshRatesFB(this.session, refreshRateCount, + refreshRateBuffer); + refreshRateBuffer.rewind(); + FBDisplayRefreshRate.xrRequestDisplayRefreshRateFB(this.session, + refreshRateBuffer.get(refreshRateCount.get(0) - 1)); } } } @@ -1039,9 +1046,10 @@ private void loadActionHandles() { this.actionSetHandles.put(vrinputactionset, actionSet); //TODO select the proper headset - for (WrappedBinding binding: WrappedBinding.quest2Bindings()) { - long action = createAction(binding.path().replace("/","."), binding.path(), binding.type(), - new XrActionSet(actionSet, this.instance), binding.path().contains("left") ? BOTH_HANDS[0] : BOTH_HANDS[1]); + for (WrappedBinding binding : WrappedBinding.quest2Bindings()) { + long action = createAction(binding.path().replace("/", "."), binding.path(), binding.type(), + new XrActionSet(actionSet, this.instance), + binding.path().contains("left") ? BOTH_HANDS[0] : BOTH_HANDS[1]); this.mappedBindings.put(binding, action); this.pathBindings.put(binding.path(), binding); } @@ -1086,7 +1094,9 @@ private void loadDefaultBindings() { long handle = this.mappedBindings.get(this.pathBindings.get(pair.getRight())); binding.setHandle(handle); binding.setType(this.pathBindings.get(pair.getRight()).type()); - binding.setHand(this.pathBindings.get(pair.getRight()).path().contains("/left/") ? ControllerType.LEFT : ControllerType.RIGHT); + binding.setHand( + this.pathBindings.get(pair.getRight()).path().contains("/left/") ? ControllerType.LEFT : + ControllerType.RIGHT); if (binding.handle == 0L) { VRSettings.LOGGER.error("Handle for '{}'/'{}' is null", pair.getLeft(), pair.getRight()); continue; @@ -1202,7 +1212,8 @@ private long createAction( hands.next(NULL); hands.actionName(memUTF8(s)); switch (type) { - case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> hands.actionType(XR10.XR_ACTION_TYPE_BOOLEAN_INPUT); + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> + hands.actionType(XR10.XR_ACTION_TYPE_BOOLEAN_INPUT); case VEC1 -> hands.actionType(XR10.XR_ACTION_TYPE_FLOAT_INPUT); case VEC2 -> hands.actionType(XR10.XR_ACTION_TYPE_VECTOR2F_INPUT); case POSE -> hands.actionType(XR10.XR_ACTION_TYPE_POSE_INPUT); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticScheduler.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticScheduler.java index a97aeec82..c57676168 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticScheduler.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRHapticScheduler.java @@ -3,8 +3,8 @@ import org.lwjgl.openxr.*; import org.lwjgl.system.MemoryStack; import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.HapticScheduler; +import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.control.VRInputActionSet; import java.util.concurrent.TimeUnit; @@ -16,12 +16,13 @@ public class OpenXRHapticScheduler extends HapticScheduler { private void triggerHapticPulse( ControllerType controller, float durationSeconds, float frequency, float amplitude) { - try (MemoryStack stack = MemoryStack.stackPush()){ + try (MemoryStack stack = MemoryStack.stackPush()) { int i = controller == ControllerType.RIGHT ? 0 : 1; if (ClientDataHolderVR.getInstance().vrSettings.reverseHands) { i = controller == ControllerType.RIGHT ? 1 : 0; } - XrActionSet actionSet = new XrActionSet(MCOpenXR.get().getActionSetHandle(VRInputActionSet.GLOBAL), MCOpenXR.get().instance); + XrActionSet actionSet = new XrActionSet(MCOpenXR.get().getActionSetHandle(VRInputActionSet.GLOBAL), + MCOpenXR.get().instance); XrHapticActionInfo info = XrHapticActionInfo.calloc(stack); info.type(XR10.XR_TYPE_HAPTIC_ACTION_INFO); info.next(NULL); @@ -40,7 +41,9 @@ private void triggerHapticPulse( } @Override - public void queueHapticPulse(ControllerType controller, float durationSeconds, float frequency, float amplitude, float delaySeconds) { + public void queueHapticPulse( + ControllerType controller, float durationSeconds, float frequency, float amplitude, float delaySeconds) + { this.executor.schedule(() -> { this.triggerHapticPulse(controller, durationSeconds, frequency, amplitude); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java index 9a63e5809..baf94125b 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/OpenXRStereoRenderer.java @@ -7,7 +7,6 @@ import org.lwjgl.openxr.*; import org.lwjgl.system.MemoryStack; import org.vivecraft.client_vr.VRLayeredRenderTarget; -import org.vivecraft.client_vr.VRTextureTarget; import org.vivecraft.client_vr.provider.VRRenderer; import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.render.helpers.RenderHelper; @@ -53,9 +52,11 @@ public void createRenderTexture(int width, int height) { for (int i = 0; i < imageCount; i++) { XrSwapchainImageOpenGLKHR openxrImage = swapchainImageBuffer.get(i); - this.leftFramebuffers[i] = new VRLayeredRenderTarget("L Eye " + i, width, height, openxrImage.image(), 0); + this.leftFramebuffers[i] = new VRLayeredRenderTarget("L Eye " + i, width, height, openxrImage.image(), + 0); String leftError = RenderHelper.checkGLError("Left Eye " + i + " framebuffer setup"); - this.rightFramebuffers[i] = new VRLayeredRenderTarget("R Eye " + i, width, height, openxrImage.image(), 1); + this.rightFramebuffers[i] = new VRLayeredRenderTarget("R Eye " + i, width, height, openxrImage.image(), + 1); String rightError = RenderHelper.checkGLError("Right Eye " + i + " framebuffer setup"); if (this.lastError.isEmpty()) { diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java index 0deb44cbf..c2e245434 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java @@ -28,84 +28,114 @@ public static HashSet supportedHeadsets() { private static HashSet> quest2Bindings() { HashSet> set = new HashSet<>(); - set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); + set.add( + new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/value")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/value")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/value")); + set.add( + new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/value")); + set.add( + new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/value")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); + set.add( + new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/value")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/value")); + set.add( + new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/value")); + set.add( + new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/value")); set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/value")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/value")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/a/click")); //set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); + set.add( + new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/value")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", + "/user/hand/left/input/squeeze/value")); //set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze/value")); //set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/value")); //set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/value")); //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/value")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/value")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/squeeze/value")); //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/value")); //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/value")); //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/value")); //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/value")); //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/value")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/value")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/trigger/value")); return set; } private static HashSet> viveBindings() { HashSet> set = new HashSet<>(); - set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click")); + set.add( + new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click")); set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/right/input/trackpad/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad/click")); + set.add( + new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click")); + set.add( + new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); + set.add( + new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/trackpad/y")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click")); + set.add( + new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click")); + set.add( + new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click")); set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/menu/click")); set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/trackpad/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", + "/user/hand/left/input/trigger/value")); set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/trackpad/x")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/trackpad")); set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/left/input/trackpad/y")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/trackpad")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click")); - - set.add(new MutablePair<>("/actions/technical/in/vivecraft.key.trackpadTouch", "/user/hand/left/input/trackpad/click")); - set.add(new MutablePair<>("/actions/technical/in/vivecraft.key.trackpadTouch", "/user/hand/right/input/trackpad/touch")); - - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/click")); - - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", + "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/right/input/trigger/click")); + + set.add(new MutablePair<>("/actions/technical/in/vivecraft.key.trackpadTouch", + "/user/hand/left/input/trackpad/click")); + set.add(new MutablePair<>("/actions/technical/in/vivecraft.key.trackpadTouch", + "/user/hand/right/input/trackpad/touch")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/trigger/click")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/trigger/click")); return set; } @@ -113,54 +143,75 @@ private static HashSet> viveBindings() { private static HashSet> cosmosBindings() { HashSet> set = new HashSet<>(); - set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); + set.add( + new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); + set.add( + new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click")); + set.add( + new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click")); + set.add( + new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click")); + set.add( + new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click")); set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/a/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); + set.add( + new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", + "/user/hand/left/input/trigger/value")); set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/shoulder/click")); set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/shoulder/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click")); - - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/click")); - - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", + "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/right/input/trigger/click")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/trigger/click")); + + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/squeeze/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/trigger/click")); return set; } private static HashSet> picoBindings() { HashSet> set = new HashSet<>(); - set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); + set.add( + new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); + set.add( + new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); + set.add( + new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze")); @@ -168,40 +219,53 @@ private static HashSet> picoBindings() { set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/a/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", + "/user/hand/left/input/trigger/value")); set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); + set.add( + new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click")); + set.add( + new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/right/input/trigger/click")); set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze")); set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/trigger/click")); set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/click")); + set.add( + new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/trigger/click")); return set; } private static HashSet> indexBindings() { HashSet> set = new HashSet<>(); - set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/b/click")); + set.add( + new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/b/click")); set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/a/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); + set.add( + new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); + set.add( + new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/trackpad/y")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze")); @@ -210,52 +274,70 @@ private static HashSet> indexBindings() { set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/trackpad")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", + "/user/hand/left/input/trigger/value")); set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); + set.add( + new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/a/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click")); + set.add( + new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/right/input/trigger/click")); set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze")); set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/trigger/click")); set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/click")); + set.add( + new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/trigger/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/trigger/click")); return set; } private static HashSet> defaultBindings() { HashSet> set = new HashSet<>(); - set.add(new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click")); + set.add( + new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click")); set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/select/click")); set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/select/click")); set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/select/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/select/click")); + set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", + "/user/hand/left/input/select/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/select/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/select/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/left/input/select/click")); + set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/right/input/select/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/select/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/select/click")); + set.add( + new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/select/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/select/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/select/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/select/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/select/click")); + set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/select/click")); return set; } - public static HashSet> getBinding(String Headset){ + public static HashSet> getBinding(String Headset) { switch (Headset) { case "/interaction_profiles/htc/vive_cosmos_controller" -> { return cosmosBindings(); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/WrappedBinding.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/WrappedBinding.java index bec67bd8e..533dae9ef 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/WrappedBinding.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/WrappedBinding.java @@ -11,38 +11,38 @@ public static List quest2Bindings() { List bindings = new ArrayList<>(); bindings.add(new WrappedBinding("/user/hand/left/input/y/click", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/y/touch",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/x/click",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/x/touch",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/menu/click",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/squeeze/value",ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/left/input/trigger/value",ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/left/input/trigger/touch",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/trigger/proximity",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumb_resting_surfaces/proximity",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick",ActionType.VEC2)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/click",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/touch",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/y",ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/x",ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumbrest/touch",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/y/touch", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/x/click", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/x/touch", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/menu/click", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/squeeze/value", ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/left/input/trigger/value", ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/left/input/trigger/touch", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/trigger/proximity", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumb_resting_surfaces/proximity", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick", ActionType.VEC2)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/click", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/touch", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/y", ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/x", ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/left/input/thumbrest/touch", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/a/click",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/a/touch",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/b/click",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/b/touch",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/system/click",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/squeeze/value",ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/right/input/trigger/value",ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/right/input/trigger/touch",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/trigger/proximity",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumb_resting_surfaces/proximity",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick",ActionType.VEC2)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/click",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/touch",ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/y",ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/x",ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumbrest/touch",ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/a/click", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/a/touch", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/b/click", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/b/touch", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/system/click", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/squeeze/value", ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/right/input/trigger/value", ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/right/input/trigger/touch", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/trigger/proximity", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumb_resting_surfaces/proximity", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick", ActionType.VEC2)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/click", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/touch", ActionType.BOOLEAN)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/y", ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/x", ActionType.VEC1)); + bindings.add(new WrappedBinding("/user/hand/right/input/thumbrest/touch", ActionType.BOOLEAN)); return bindings; } } diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java index 705dbb568..a9f153ca2 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/KeyboardInputVRMixin.java @@ -14,7 +14,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.vivecraft.client.VivecraftVRMod; -import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.provider.MCVR; 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 b49f1c73b..93211cc83 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 @@ -75,7 +75,6 @@ import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.render.VRFirstPersonArmSwing; import org.vivecraft.client_vr.render.helpers.RenderHelper; -import org.vivecraft.client_vr.render.helpers.ShaderHelper; import org.vivecraft.client_vr.settings.VRHotkeys; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.client_xr.render_pass.RenderPassManager; diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/multiplayer/ClientPacketListenerVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/multiplayer/ClientPacketListenerVRMixin.java index 042112710..710c6c2c6 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/multiplayer/ClientPacketListenerVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/multiplayer/ClientPacketListenerVRMixin.java @@ -18,8 +18,6 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.VRState; import org.vivecraft.client_vr.gameplay.screenhandlers.GuiHandler; -import org.vivecraft.client_vr.provider.control.ControllerType; -import org.vivecraft.client_vr.settings.VRSettings; @Mixin(ClientPacketListener.class) public abstract class ClientPacketListenerVRMixin extends ClientCommonPacketListenerImpl { diff --git a/common/src/main/java/org/vivecraft/mixin/client_vr/world/FishingHookVRMixin.java b/common/src/main/java/org/vivecraft/mixin/client_vr/world/FishingHookVRMixin.java index c2c40a0e3..f9daafd53 100644 --- a/common/src/main/java/org/vivecraft/mixin/client_vr/world/FishingHookVRMixin.java +++ b/common/src/main/java/org/vivecraft/mixin/client_vr/world/FishingHookVRMixin.java @@ -13,8 +13,8 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.vivecraft.client_vr.VRState; -import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.MCVR; +import org.vivecraft.client_vr.provider.control.ControllerType; @Mixin(FishingHook.class) public abstract class FishingHookVRMixin extends Entity { diff --git a/common/src/main/java/org/vivecraft/util/VLoader.java b/common/src/main/java/org/vivecraft/util/VLoader.java index cecdd9a10..72d00bb08 100644 --- a/common/src/main/java/org/vivecraft/util/VLoader.java +++ b/common/src/main/java/org/vivecraft/util/VLoader.java @@ -6,9 +6,14 @@ public class VLoader { } public static native long getEGLContext(); + public static native long getEGLConfig(); + public static native long getEGLDisplay(); + public static native long getDalvikVM(); + public static native long getDalvikActivity(); + public static native void setupAndroid(); } From 3d06876d36fb4bb70b3dd6d06cc92c5e885bb138 Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Tue, 18 Nov 2025 17:52:07 +0100 Subject: [PATCH 71/76] small cleanup --- .../client/gui/settings/GuiBindings.java | 4 +- .../client_vr/provider/openxr/MCOpenXR.java | 53 ++++---- .../openxr/control/ControllerMapping.java | 50 +++++++ .../openxr/control/RebindableBinding.java | 6 - .../openxr/control/WrappedBinding.java | 48 ------- .../XRBinding.java} | 126 +++++++++--------- 6 files changed, 147 insertions(+), 140 deletions(-) create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/ControllerMapping.java delete mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/RebindableBinding.java delete mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/WrappedBinding.java rename common/src/main/java/org/vivecraft/client_vr/provider/openxr/{XRBindings.java => control/XRBinding.java} (75%) diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java index 03cb978c0..8402f5d58 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java @@ -30,10 +30,10 @@ public GuiBindings(Screen lastScreen) { @Override protected List getEntries() { List list = new LinkedList<>(); - for (var entry : MCOpenXR.get().pathBindings.entrySet()) { + for (var entry : MCOpenXR.get().getBinds().entrySet()) { var input = MCOpenXR.get().getInputActionByName(entry.getKey()); if (input == null) continue; - list.add(new ResettableEntry(Component.translatable(entry.getKey()), input)); + list.add(new ResettableEntry(Component.translatable(input.name), input)); } return list; } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 1dc9d603d..816979ebf 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -3,7 +3,6 @@ import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; import net.minecraft.util.profiling.Profiler; -import org.apache.commons.lang3.tuple.Pair; import org.joml.Matrix4f; import org.joml.Vector2f; import org.joml.Vector3f; @@ -27,7 +26,8 @@ import org.vivecraft.client_vr.provider.control.ControllerType; import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.provider.control.VRInputActionSet; -import org.vivecraft.client_vr.provider.openxr.control.WrappedBinding; +import org.vivecraft.client_vr.provider.openxr.control.ControllerMapping; +import org.vivecraft.client_vr.provider.openxr.control.XRBinding; import org.vivecraft.client_vr.settings.VRSettings; import java.nio.ByteBuffer; @@ -72,9 +72,9 @@ public class MCOpenXR extends MCVR { public long[] haptics = new long[2]; public String systemName; - public Map mappedBindings = new HashMap<>(); - public Map pathBindings = new HashMap<>(); + public record ActionBind(VRInputActionSet actionSet, String path) {} + public Map mappedBindings = new HashMap<>(); public MCOpenXR(Minecraft mc, ClientDataHolderVR dh) { super(mc, dh, VivecraftVRMod.INSTANCE); @@ -1046,12 +1046,11 @@ private void loadActionHandles() { this.actionSetHandles.put(vrinputactionset, actionSet); //TODO select the proper headset - for (WrappedBinding binding : WrappedBinding.quest2Bindings()) { - long action = createAction(binding.path().replace("/", "."), binding.path(), binding.type(), + for (var binding : ControllerMapping.quest2Bindings().entrySet()) { + long action = createAction(binding.getKey().replace("/", "."), binding.getKey(), binding.getValue(), new XrActionSet(actionSet, this.instance), - binding.path().contains("left") ? BOTH_HANDS[0] : BOTH_HANDS[1]); - this.mappedBindings.put(binding, action); - this.pathBindings.put(binding.path(), binding); + binding.getKey().contains("left") ? BOTH_HANDS[0] : BOTH_HANDS[1]); + this.mappedBindings.put(new ActionBind(vrinputactionset, binding.getKey()), action); } } @@ -1079,32 +1078,35 @@ private void setupControllers() { private void loadDefaultBindings() { try (MemoryStack stack = MemoryStack.stackPush()) { int error; - for (String headset : XRBindings.supportedHeadsets()) { + for (String headset : XRBinding.supportedHeadsets()) { VRSettings.LOGGER.info("loading defaults for {}", headset); if (!"/interaction_profiles/oculus/touch_controller".equals(headset)) { continue; } - Pair[] defaultBindings = XRBindings.getBinding(headset).toArray(new Pair[0]); + XRBinding[] defaultBindings = XRBinding.getBinding(headset).toArray(new XRBinding[0]); XrActionSuggestedBinding.Buffer bindings = XrActionSuggestedBinding.calloc(defaultBindings.length + 6, stack); //TODO different way of adding controller poses for (int i = 0; i < defaultBindings.length; i++) { - Pair pair = defaultBindings[i]; - VRInputAction binding = this.getInputActionByName(pair.getLeft()); - long handle = this.mappedBindings.get(this.pathBindings.get(pair.getRight())); - binding.setHandle(handle); - binding.setType(this.pathBindings.get(pair.getRight()).type()); - binding.setHand( - this.pathBindings.get(pair.getRight()).path().contains("/left/") ? ControllerType.LEFT : + XRBinding binding = defaultBindings[i]; + VRInputAction inputAction = this.getInputActionByName(binding.key()); + if (binding.actionSet() != null) { + //inputAction.actionSet = binding.actionSet(); TODO? + } + long handle = this.mappedBindings.get(new ActionBind(inputAction.actionSet, binding.controller())); + inputAction.setHandle(handle); + inputAction.setType(ControllerMapping.quest2Bindings().get(binding.controller())); + inputAction.setHand( + binding.controller().contains("/left/") ? ControllerType.LEFT : ControllerType.RIGHT); - if (binding.handle == 0L) { - VRSettings.LOGGER.error("Handle for '{}'/'{}' is null", pair.getLeft(), pair.getRight()); + if (inputAction.handle == 0L) { + VRSettings.LOGGER.error("Handle for '{}'/'{}' is null", binding.key(), binding.controller()); continue; } bindings.get(i).set( - new XrAction(binding.handle, - new XrActionSet(this.actionSetHandles.get(binding.actionSet), this.instance)), - getPath(pair.getRight()) + new XrAction(inputAction.handle, + new XrActionSet(this.actionSetHandles.get(inputAction.actionSet), this.instance)), + getPath(binding.controller()) ); } @@ -1347,4 +1349,9 @@ protected void logError(int xrResult, String caller, String... args) { VRSettings.LOGGER.error("{} for {} errored: {}", caller, String.join(" ", args), getResultName(xrResult)); } } + + //TODO remove/rework + public Map getBinds() { + return inputActions; + } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/ControllerMapping.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/ControllerMapping.java new file mode 100644 index 000000000..e6efa67aa --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/ControllerMapping.java @@ -0,0 +1,50 @@ +package org.vivecraft.client_vr.provider.openxr.control; + +import org.vivecraft.client_vr.provider.control.ActionType; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ControllerMapping { + + public static Map quest2Bindings() { + Map bindings = new HashMap<>(); + + bindings.put("/user/hand/left/input/y/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/y/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/x/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/x/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/menu/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/squeeze/value", ActionType.VEC1); + bindings.put("/user/hand/left/input/trigger/value", ActionType.VEC1); + bindings.put("/user/hand/left/input/trigger/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/trigger/proximity", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/thumb_resting_surfaces/proximity", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/thumbstick", ActionType.VEC2); + bindings.put("/user/hand/left/input/thumbstick/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/thumbstick/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/thumbstick/y", ActionType.VEC1); + bindings.put("/user/hand/left/input/thumbstick/x", ActionType.VEC1); + bindings.put("/user/hand/left/input/thumbrest/touch", ActionType.BOOLEAN); + + bindings.put("/user/hand/right/input/a/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/a/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/b/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/b/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/system/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/squeeze/value", ActionType.VEC1); + bindings.put("/user/hand/right/input/trigger/value", ActionType.VEC1); + bindings.put("/user/hand/right/input/trigger/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/trigger/proximity", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/thumb_resting_surfaces/proximity", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/thumbstick", ActionType.VEC2); + bindings.put("/user/hand/right/input/thumbstick/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/thumbstick/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/thumbstick/y", ActionType.VEC1); + bindings.put("/user/hand/right/input/thumbstick/x", ActionType.VEC1); + bindings.put("/user/hand/right/input/thumbrest/touch", ActionType.BOOLEAN); + return bindings; + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/RebindableBinding.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/RebindableBinding.java deleted file mode 100644 index e17445bd2..000000000 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/RebindableBinding.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.vivecraft.client_vr.provider.openxr.control; - -import org.vivecraft.client_vr.provider.control.ActionType; - -public record RebindableBinding(String binding, String path, ActionType type) { -} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/WrappedBinding.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/WrappedBinding.java deleted file mode 100644 index 533dae9ef..000000000 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/WrappedBinding.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.vivecraft.client_vr.provider.openxr.control; - -import org.vivecraft.client_vr.provider.control.ActionType; - -import java.util.ArrayList; -import java.util.List; - -public record WrappedBinding(String path, ActionType type) { - - public static List quest2Bindings() { - List bindings = new ArrayList<>(); - - bindings.add(new WrappedBinding("/user/hand/left/input/y/click", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/y/touch", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/x/click", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/x/touch", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/menu/click", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/squeeze/value", ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/left/input/trigger/value", ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/left/input/trigger/touch", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/trigger/proximity", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumb_resting_surfaces/proximity", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick", ActionType.VEC2)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/click", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/touch", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/y", ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumbstick/x", ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/left/input/thumbrest/touch", ActionType.BOOLEAN)); - - bindings.add(new WrappedBinding("/user/hand/right/input/a/click", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/a/touch", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/b/click", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/b/touch", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/system/click", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/squeeze/value", ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/right/input/trigger/value", ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/right/input/trigger/touch", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/trigger/proximity", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumb_resting_surfaces/proximity", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick", ActionType.VEC2)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/click", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/touch", ActionType.BOOLEAN)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/y", ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumbstick/x", ActionType.VEC1)); - bindings.add(new WrappedBinding("/user/hand/right/input/thumbrest/touch", ActionType.BOOLEAN)); - return bindings; - } -} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java similarity index 75% rename from common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java rename to common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java index c2e245434..07fd2691f 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/XRBindings.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java @@ -1,11 +1,15 @@ -package org.vivecraft.client_vr.provider.openxr; +package org.vivecraft.client_vr.provider.openxr.control; import org.apache.commons.lang3.tuple.MutablePair; import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.Nullable; +import org.vivecraft.client_vr.provider.control.ActionType; +import org.vivecraft.client_vr.provider.control.VRInputActionSet; +import org.vivecraft.client_vr.provider.openxr.MCOpenXR; import java.util.HashSet; -public class XRBindings { +public record XRBinding(@Nullable VRInputActionSet actionSet, String key, String controller, ActionType actionType) { public static HashSet supportedHeadsets() { HashSet set = new HashSet<>(); @@ -25,54 +29,54 @@ public static HashSet supportedHeadsets() { return set; } - private static HashSet> quest2Bindings() { - HashSet> set = new HashSet<>(); + private static HashSet quest2Bindings() { + HashSet set = new HashSet<>(); set.add( - new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); - set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); + new XRBinding(null, "/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/global/in/key.inventory", "/user/hand/left/input/x/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/value")); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/value", ActionType.VEC1)); set.add( - new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/value")); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/value", ActionType.VEC1)); set.add( - new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/value")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click")); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y", ActionType.VEC1)); set.add( - new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/value")); + new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/value", ActionType.VEC1)); set.add( - new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/value")); - set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/value")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/value")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); - set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/a/click")); - //set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value")); - set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick/click")); + new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/key.use", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); + //set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick/click", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); - set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); + new XRBinding(null, "/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", ActionType.VEC2)); + set.add(new XRBinding(null, "/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick", ActionType.VEC2)); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", - "/user/hand/left/input/squeeze/value")); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardShift", + "/user/hand/left/input/squeeze/value", ActionType.VEC1)); //set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze/value")); //set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/value")); //set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/value")); //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/value")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/right/input/squeeze/value")); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/squeeze/value", ActionType.VEC1)); //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/value")); //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/value")); //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/value")); //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/value")); //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/value")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/right/input/trigger/value")); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/trigger/value", ActionType.VEC1)); return set; } @@ -307,54 +311,54 @@ private static HashSet> indexBindings() { return set; } - private static HashSet> defaultBindings() { - HashSet> set = new HashSet<>(); + private static HashSet defaultBindings() { + HashSet set = new HashSet<>(); set.add( - new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/select/click")); + new XRBinding(null, "/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/select/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/select/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/select/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", - "/user/hand/left/input/select/click")); + set.add(new XRBinding(null, "/actions/ingame/in/key.attack", "/user/hand/right/input/select/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/select/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleportFallback", + "/user/hand/left/input/select/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", - "/user/hand/left/input/select/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", - "/user/hand/right/input/select/click")); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/left/input/select/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/right/input/select/click", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/select/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/right/input/select/click")); + new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/select/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/select/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/left/input/select/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/right/input/select/click")); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/select/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/select/click", ActionType.BOOLEAN)); return set; } - public static HashSet> getBinding(String Headset) { + public static HashSet getBinding(String Headset) { switch (Headset) { - case "/interaction_profiles/htc/vive_cosmos_controller" -> { - return cosmosBindings(); - } - case "/interaction_profiles/htc/vive_controller" -> { - return viveBindings(); - } - case "/interaction_profiles/valve/index_controller" -> { - return indexBindings(); - } +// case "/interaction_profiles/htc/vive_cosmos_controller" -> { +// return cosmosBindings(); +// } +// case "/interaction_profiles/htc/vive_controller" -> { +// return viveBindings(); +// } +// case "/interaction_profiles/valve/index_controller" -> { +// return indexBindings(); +// } case "/interaction_profiles/oculus/touch_controller" -> { return quest2Bindings(); } - case "/interaction_profiles/bytedance/pico4_controller", - "/interaction_profiles/bytedance/pico_neo3_controller" -> { - return picoBindings(); - } +// case "/interaction_profiles/bytedance/pico4_controller", +// "/interaction_profiles/bytedance/pico_neo3_controller" -> { +// return picoBindings(); +// } default -> { return defaultBindings(); } From 53276c4033e702bb485fb08094172e0eee89be8c Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Wed, 19 Nov 2025 23:48:47 +0100 Subject: [PATCH 72/76] split input actions - Give each env their own actions - XRInputActions support multiple suggested bindings --- .../client/gui/settings/GuiBindings.java | 2 +- .../client_vr/ClientDataHolderVR.java | 3 +- .../vivecraft/client_vr/gui/GuiRadial.java | 3 +- .../vivecraft/client_vr/provider/MCVR.java | 80 ++-- .../provider/control/InputAction.java | 410 ++++++++++++++++++ .../control/TrackpadSwipeSampler.java | 1 + .../provider/control/VRInputAction.java | 389 +---------------- .../client_vr/provider/nullvr/NullVR.java | 12 +- .../provider/openvr_lwjgl/MCOpenVR.java | 15 +- .../client_vr/provider/openxr/MCOpenXR.java | 311 ++++++++----- .../openxr/control/XRInputAction.java | 153 +++++++ .../mixin/client_vr/MinecraftVRMixin.java | 5 +- 12 files changed, 846 insertions(+), 538 deletions(-) create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/control/InputAction.java create mode 100644 common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java index 8402f5d58..a89b4a9b3 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java @@ -33,7 +33,7 @@ protected List getEntries() { for (var entry : MCOpenXR.get().getBinds().entrySet()) { var input = MCOpenXR.get().getInputActionByName(entry.getKey()); if (input == null) continue; - list.add(new ResettableEntry(Component.translatable(input.name), input)); + //list.add(new ResettableEntry(Component.translatable(input.name), input)); } return list; } diff --git a/common/src/main/java/org/vivecraft/client_vr/ClientDataHolderVR.java b/common/src/main/java/org/vivecraft/client_vr/ClientDataHolderVR.java index 7dbb2057b..ace8dfba4 100644 --- a/common/src/main/java/org/vivecraft/client_vr/ClientDataHolderVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/ClientDataHolderVR.java @@ -14,6 +14,7 @@ import org.vivecraft.client_vr.menuworlds.MenuWorldRenderer; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.VRRenderer; +import org.vivecraft.client_vr.provider.control.InputAction; import org.vivecraft.client_vr.render.VRFirstPersonArmSwing; import org.vivecraft.client_vr.settings.VRSettings; @@ -41,7 +42,7 @@ public class ClientDataHolderVR { public boolean isFpHand; public VRPlayer vrPlayer; - public MCVR vr; + public MCVR vr; public VRRenderer vrRenderer; public MenuWorldRenderer menuWorldRenderer; diff --git a/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java b/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java index 70b0039fd..b2f843c80 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java +++ b/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java @@ -9,6 +9,7 @@ import org.vivecraft.client_vr.ClientDataHolderVR; import org.vivecraft.client_vr.MethodHolder; import org.vivecraft.client_vr.provider.MCVR; +import org.vivecraft.client_vr.provider.control.InputAction; import org.vivecraft.client_vr.provider.control.VRInputAction; import java.util.Arrays; @@ -40,7 +41,7 @@ public void init() { .filter(keymapping -> keymapping.getName().equalsIgnoreCase(current)) .findFirst() .ifPresent(keymapping -> { - VRInputAction vrinputaction = MCVR.get().getInputAction(this.arr[index]); + InputAction vrinputaction = MCVR.get().getInputAction(this.arr[index]); String label = I18n.get(keymapping.getName()); if (vrinputaction != null && (vrinputaction.keyBinding.isDown() || MethodHolder.isKeyDown(vrinputaction.keyBinding.key))) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java index 1172145e1..c6596e992 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java @@ -52,7 +52,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -public abstract class MCVR { +public abstract class MCVR { public static final int MAIN_CONTROLLER = 0; public static final int OFFHAND_CONTROLLER = 1; @@ -71,7 +71,7 @@ public abstract class MCVR { protected Minecraft mc; protected ClientDataHolderVR dh; - protected static MCVR ME; + protected static MCVR ME; protected static VivecraftVRMod MOD; protected HardwareType detectedHardware = HardwareType.VIVE; @@ -143,10 +143,10 @@ public abstract class MCVR { protected float hmdForwardYaw = 180; public boolean ignorePressesNextFrame = false; protected int quickTorchPreviousSlot; - protected Map inputActions = new HashMap<>(); - protected Map inputActionsByKeyBinding = new HashMap<>(); + protected Map inputActions = new HashMap<>(); + protected Map inputActionsByKeyBinding = new HashMap<>(); - private final Map> unpressedSetKeys = new EnumMap<>(VRInputActionSet.class); + private final Map> unpressedSetKeys = new EnumMap<>(VRInputActionSet.class); private List activeActionSets = new ArrayList<>(); protected final Map trackpadSwipeSamplers = new HashMap<>(); @@ -196,7 +196,7 @@ public MCVR(Minecraft mc, ClientDataHolderVR dh, VivecraftVRMod vrMod) { /** * @return the current active MCVR implementation */ - public static MCVR get() { + public static MCVR get() { return ME; } @@ -409,35 +409,35 @@ public Vector3f getHmdVector() { } /** - * @param keyMapping KeyMapping to get the VRInputAction for - * @return VRInputAction that is linked to the given KeyMapping + * @param keyMapping KeyMapping to get the InputAction for + * @return InputAction that is linked to the given KeyMapping */ - public VRInputAction getInputAction(KeyMapping keyMapping) { + public T getInputAction(KeyMapping keyMapping) { return this.getInputAction(keyMapping.getName()); } /** - * @param name name of the KeyMapping to get the VRInputAction for - * @return VRInputAction that is linked to the given KeyMapping + * @param name name of the KeyMapping to get the InputAction for + * @return InputAction that is linked to the given KeyMapping */ - public VRInputAction getInputAction(String name) { + public T getInputAction(String name) { return this.inputActionsByKeyBinding.get(name); } /** - * gets the VRInputAction by name, a VRInputAction name is built like "(action set)/in/(keyMapping name)" + * gets the InputAction by name, a InputAction name is built like "(action set)/in/(keyMapping name)" * - * @param name name of the VRInputAction to get - * @return VRInputAction that is linked to the given action name + * @param name name of the InputAction to get + * @return InputAction that is linked to the given action name */ - public VRInputAction getInputActionByName(String name) { + public T getInputActionByName(String name) { return this.inputActions.get(name); } /** * @return unmodifiable collection of all loaded VRInputActions */ - public Collection getInputActions() { + public Collection getInputActions() { return Collections.unmodifiableCollection(this.inputActions.values()); } @@ -445,7 +445,7 @@ public Collection getInputActions() { * @param set VRInputActionSet to get the VRInputActions for * @return unmodifiable collection of all VRInputActions in the given set */ - public Collection getInputActionsInSet(VRInputActionSet set) { + public Collection getInputActionsInSet(VRInputActionSet set) { return Collections.unmodifiableCollection(this.inputActions.values().stream().filter((action) -> action.actionSet == set).collect(Collectors.toList())); } @@ -1174,6 +1174,8 @@ public void processBindings() { } } + public abstract T createAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride); + /** * creates VRInputActions for all registered keyMappings, should be called in {@link #init} */ @@ -1184,15 +1186,17 @@ public void populateInputActions() { for (KeyMapping keyMapping : Stream.concat(Arrays.stream(this.mc.options.keyMappings), MOD.getHiddenKeyBindings().stream()).toList()) { ActionParams params = actionParams.getOrDefault(keyMapping.getName(), ActionParams.DEFAULT); - VRInputAction action = new VRInputAction(keyMapping, params.requirement(), params.type(), + T action = createAction(keyMapping, params.requirement(), params.type(), params.actionSetOverride()); this.inputActions.put(action.name, action); this.inputActionsByKeyBinding.put(action.keyBinding.getName(), action); } - this.getInputAction(MOD.keyVRInteract).setPriority(5).setEnabled(false); - this.getInputAction(MOD.keyClimbeyGrab).setPriority(10).setEnabled(false); + this.getInputAction(MOD.keyVRInteract).setPriority(5); + this.getInputAction(MOD.keyVRInteract).setEnabled(false); + this.getInputAction(MOD.keyClimbeyGrab).setPriority(10); + this.getInputAction(MOD.keyClimbeyGrab).setEnabled(false); this.getInputAction(MOD.keyClimbeyJump).setEnabled(false); this.getInputAction(GuiHandler.KEY_KEYBOARD_CLICK).setPriority(50); this.getInputAction(GuiHandler.KEY_KEYBOARD_SHIFT).setPriority(50); @@ -1465,7 +1469,7 @@ public void processInputs() { return; } - for (VRInputAction action : this.inputActions.values()) { + for (T action : this.inputActions.values()) { if (action.isHanded()) { for (ControllerType controllertype : ControllerType.values()) { action.setCurrentHand(controllertype); @@ -1492,11 +1496,11 @@ public void processInputs() { } /** - * updates the KeyMapping state that is linked to the given VRInputAction + * updates the KeyMapping state that is linked to the given InputAction * - * @param action VRInputAction to process + * @param action InputAction to process */ - private void processInputAction(VRInputAction action) { + private void processInputAction(T action) { if (action.isActive() && action.isEnabledRaw() && // try to prevent double left clicks (!ClientDataHolderVR.getInstance().vrSettings.ingameBindingsInGui || @@ -1528,10 +1532,10 @@ private void processInputAction(VRInputAction action) { } /** - * @param action VRInputAction to check - * @return if the given VRInputAction was pressed before actionset changes and can be repressed + * @param action InputAction to check + * @return if the given InputAction was pressed before actionset changes and can be repressed */ - private boolean canActionBeRepressed(VRInputAction action) { + private boolean canActionBeRepressed(T action) { // allow repressing ingame buttons that were held before the set change return action.actionSet == VRInputActionSet.INGAME && this.unpressedSetKeys.get(action.actionSet).contains(action); @@ -1540,9 +1544,9 @@ private boolean canActionBeRepressed(VRInputAction action) { /** * presses the given VRInputActions binding and removes it from the unpressed keys * - * @param action VRInputAction to press + * @param action InputAction to press */ - private void pressAction(VRInputAction action) { + private void pressAction(T action) { action.pressBinding(); this.unpressedSetKeys.get(action.actionSet).remove(action); } @@ -1550,9 +1554,9 @@ private void pressAction(VRInputAction action) { /** * unpresses the given VRInputActions binding and adds it to the unpressed keys, if its actionSet is not active right now * - * @param action VRInputAction to press + * @param action InputAction to press */ - private void unpressAction(VRInputAction action) { + private void unpressAction(T action) { if (!this.activeActionSets.contains(action.actionSet) && action.isButtonChanged()) { this.unpressedSetKeys.get(action.actionSet).add(action); } @@ -1560,10 +1564,10 @@ private void unpressAction(VRInputAction action) { } /** - * @param action VRInputAction to check for + * @param action InputAction to check for * @return if the given action does not correspond to one of the movement keys, or if the player didn't move */ - private boolean checkIfNotMovement(VRInputAction action) { + private boolean checkIfNotMovement(T action) { return action.keyBinding != this.mc.options.keyLeft && action.keyBinding != this.mc.options.keyRight && action.keyBinding != this.mc.options.keyUp && @@ -1571,14 +1575,14 @@ private boolean checkIfNotMovement(VRInputAction action) { } /** - * checks the axis input of the VRInputAction linked to {@code keyMapping} and runs the callbacks when it's non 0 + * checks the axis input of the InputAction linked to {@code keyMapping} and runs the callbacks when it's non 0 * * @param keyMapping KeyMapping to check * @param upCallback action to do when the axis input is positive * @param downCallback action to do when the axis input is negative */ private void processScrollInput(KeyMapping keyMapping, Runnable upCallback, Runnable downCallback) { - VRInputAction action = this.getInputAction(keyMapping); + T action = this.getInputAction(keyMapping); /** {@link org.lwjgl.openvr.VR.k_ulInvalidInputValueHandle} and {@link org.lwjgl.system.MemoryUtil.NULL} are both 0 */ if (action.isEnabled() && action.getLastOrigin() != 0L) { float value = action.getAxis2D(false).y(); @@ -1605,7 +1609,7 @@ private void processSwipeInput( KeyMapping keyMapping, Runnable leftCallback, Runnable rightCallback, Runnable upCallback, Runnable downCallback) { - VRInputAction action = this.getInputAction(keyMapping); + T action = this.getInputAction(keyMapping); /** {@link org.lwjgl.openvr.VR.k_ulInvalidInputValueHandle} and {@link org.lwjgl.system.MemoryUtil.NULL} are both 0 */ if (action.isEnabled() && action.getLastOrigin() != 0L) { @@ -1708,7 +1712,7 @@ public boolean hasExtendedFBT() { * @param action VRInputAction to query origins for * @return a list containing all currently active origin handles for that action */ - public abstract List getOrigins(VRInputAction action); + public abstract List getOrigins(I action); /** * @param origin the origin handle of an input action diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/InputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/InputAction.java new file mode 100644 index 000000000..f444f32f9 --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/InputAction.java @@ -0,0 +1,410 @@ +package org.vivecraft.client_vr.provider.control; + +import com.mojang.blaze3d.platform.InputConstants; +import net.minecraft.client.KeyMapping; +import org.joml.Vector2f; +import org.joml.Vector2fc; +import org.vivecraft.Xplat; +import org.vivecraft.client.VivecraftVRMod; +import org.vivecraft.client_vr.ClientDataHolderVR; +import org.vivecraft.client_vr.provider.InputSimulator; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +public class InputAction { + public final KeyMapping keyBinding; + public final String name; + public final String requirement; + public ActionType type; + public final VRInputActionSet actionSet; + + protected int priority = 0; + protected final List listeners = new ArrayList<>(); + protected ControllerType currentHand = ControllerType.RIGHT; + // Only used for the UseTracked axis methods + protected boolean currentlyInUse; + + protected final boolean[] enabled = new boolean[ControllerType.values().length]; + protected final boolean[] pressed = new boolean[ControllerType.values().length]; + protected final boolean[] held = new boolean[ControllerType.values().length]; + protected final int[] unpressInTicks = new int[ControllerType.values().length]; + + public InputAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { + this.keyBinding = keyMapping; + this.requirement = requirement; + this.type = type; + this.actionSet = actionSetOverride != null ? actionSetOverride : VRInputActionSet.fromKeyBinding(keyMapping); + this.name = this.actionSet.name + "/in/" + keyMapping.getName().replace('/', '_'); + } + + public void setType(ActionType type) { + this.type = type; + } + + public int getPriority() { + return this.priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } + + public boolean isHanded() { + return this.keyBinding instanceof HandedKeyBinding; + } + + public ControllerType getCurrentHand() { + return this.currentHand; + } + + public void setCurrentHand(ControllerType currentHand) { + this.currentHand = currentHand; + } + + /** + * check if the InputAction is enabled, if it is handed, checks for {@link VRInputAction#currentHand}
+ * also checks if any other InputAction with higher priority is active, then this InputAction is treated as disabled + */ + public boolean isEnabled() { + if (!this.isEnabledRaw(this.currentHand)) return false; + if (ClientDataHolderVR.getInstance().vr == null) return false; + + long lastOrigin = this.getLastOrigin(); + ControllerType hand = ClientDataHolderVR.getInstance().vr.getOriginControllerType(lastOrigin); + + if (hand == null && this.isHanded()) return false; + + // iterate over all actions, and check if another action has a higher priority + for (InputAction action : ClientDataHolderVR.getInstance().vr.getInputActions()) { + if (action != this && action.isEnabledRaw(hand) && action.isActive() && + action.getPriority() > this.getPriority() && + ClientDataHolderVR.getInstance().vr.getOrigins(action).contains(lastOrigin)) + { + if (action.isHanded()) { + return !((HandedKeyBinding) action.keyBinding).isPriorityOnController(hand); + } + return false; + } + } + + return true; + } + + public boolean isEnabledRaw(ControllerType hand) { + if (this.isHanded()) { + return hand != null && this.enabled[hand.ordinal()]; + } else { + return this.enabled[0]; + } + } + + public boolean isEnabledRaw() { + return Arrays.stream(ControllerType.values()).anyMatch(this::isEnabledRaw); + } + + public void setEnabled(ControllerType hand, boolean enabled) { + if (!this.isHanded()) { + throw new IllegalStateException("Not a handed key binding!"); + } else { + this.enabled[hand.ordinal()] = enabled; + } + } + + public void setEnabled(boolean enabled) { + if (this.isHanded()) { + for (ControllerType controllertype : ControllerType.values()) { + this.enabled[controllertype.ordinal()] = enabled; + } + } else { + this.enabled[0] = enabled; + } + } + + public boolean isActive() { + return true; + } + + public boolean isButtonPressed() { + return false; + } + + public boolean isButtonChanged() { + return false; + } + + public void setPressed(boolean pressed) { + if (pressed) { + this.pressBinding(); + } else { + this.unpressBinding(); + } + } + + private void pressBinding(ControllerType hand) { + if (this.isHanded()) { + if (hand == null || this.pressed[hand.ordinal()]) return; + + this.pressed[hand.ordinal()] = true; + + if (this.notifyListeners(true, hand)) return; + + ((HandedKeyBinding) this.keyBinding).pressKey(hand); + } else { + if (this.pressed[0]) return; + + this.pressed[0] = true; + + if (this.notifyListeners(true, null)) return; + + this.pressKey(); + } + } + + public void pressBinding() { + this.pressBinding(this.currentHand); + } + + public void unpressBinding(int unpressInTicks, ControllerType hand) { + if (this.isHanded()) { + if (hand == null || !this.pressed[hand.ordinal()]) return; + + this.unpressInTicks[hand.ordinal()] = unpressInTicks; + } else { + if (!this.pressed[0]) return; + + this.unpressInTicks[0] = unpressInTicks; + } + } + + public void unpressBinding(int unpressInTicks) { + this.unpressBinding(unpressInTicks, this.currentHand); + } + + public void unpressBinding() { + this.unpressBinding(1); + } + + /** + * presses the KeyMapping assigned to this InputAction
+ * if the KeyMapping has a modifier key also presses that + */ + private void pressKey() { + InputConstants.Key key = this.keyBinding.key; + + // need to simulate the modifier or the binding wouldn't be pressed + if (key.getValue() != -1 && + (!VivecraftVRMod.INSTANCE.isSafeBinding(this.keyBinding) || Xplat.hasKeyModifier(this.keyBinding))) + { + if (key.getType() == InputConstants.Type.KEYSYM) { + if (Xplat.hasKeyModifier(this.keyBinding)) { + InputSimulator.pressModifier(Xplat.getKeyModifierKey(this.keyBinding)); + } + InputSimulator.pressKey(key.getValue(), Xplat.getKeyModifier(this.keyBinding)); + return; + } + + if (key.getType() == InputConstants.Type.MOUSE) { + InputSimulator.pressMouse(key.getValue()); + return; + } + } + + setKeyBindState(this.keyBinding, true); + } + + /** + * unpresses the KeyMapping assigned to this InputAction
+ * if the KeyMapping has a modifier key also unpresses that + */ + public void unpressKey() { + InputConstants.Key key = this.keyBinding.key; + + if (key.getValue() != -1 && + (!VivecraftVRMod.INSTANCE.isSafeBinding(this.keyBinding) || Xplat.hasKeyModifier(this.keyBinding))) + { + if (key.getType() == InputConstants.Type.KEYSYM) { + InputSimulator.releaseKey(key.getValue()); + if (Xplat.hasKeyModifier(this.keyBinding)) { + InputSimulator.releaseModifier(Xplat.getKeyModifierKey(this.keyBinding)); + } + return; + } + + if (key.getType() == InputConstants.Type.MOUSE) { + InputSimulator.releaseMouse(key.getValue()); + return; + } + } + + this.keyBinding.release(); + } + + public void holdBinding() { + this.holdBinding(this.currentHand); + } + + public void holdBinding(ControllerType hand) { + if (this.isHanded()) { + this.held[hand.ordinal()] = true; + } else { + this.held[0] = true; + } + this.pressBinding(this.currentHand); + } + + public void stopHoldingBinding(int unpressInTicks) { + this.stopHoldingBinding(unpressInTicks, this.currentHand); + } + + public void stopHoldingBinding(int unpressInTicks, ControllerType hand) { + if (this.isHanded()) { + this.held[hand.ordinal()] = false; + } else { + this.held[0] = false; + } + this.unpressBinding(unpressInTicks, this.currentHand); + } + + public void unpressBindingImmediately() { + if (this.isHanded()) { + for (int c = 0; c < ControllerType.values().length; c++) { + this.unpressBindingImmediately(ControllerType.values()[c]); + } + } else { + + this.unpressBindingImmediately(null); + } + } + + public void unpressBindingImmediately(ControllerType hand) { + if (this.isHanded()) { + if (hand == null || !this.pressed[hand.ordinal()]) return; + + this.pressed[hand.ordinal()] = false; + this.held[hand.ordinal()] = false; + + if (this.notifyListeners(false, hand)) return; + + ((HandedKeyBinding) this.keyBinding).unpressKey(hand); + } else { + if (!this.pressed[0]) return; + + this.pressed[0] = false; + this.held[0] = false; + + if (this.notifyListeners(false, null)) return; + + this.unpressKey(); + } + } + + public static void setKeyBindState(KeyMapping keyMapping, boolean pressed) { + if (keyMapping != null) { + keyMapping.setDown(pressed); + keyMapping.clickCount += 1; + } + } + + public void tick() { + if (this.isHanded()) { + for (int c = 0; c < ControllerType.values().length; c++) { + ControllerType type = ControllerType.values()[c]; + HandedKeyBinding handedKeyBinding = (HandedKeyBinding) this.keyBinding; + if ((!this.held[c] && this.unpressInTicks[c] > 0 && --this.unpressInTicks[c] == 0) || + (this.held[c] && (!handedKeyBinding.isDown(type) || handedKeyBinding.presses(type) == 0))) + { + this.unpressBindingImmediately(type); + } + } + } else { + if ((!this.held[0] && this.unpressInTicks[0] > 0 && --this.unpressInTicks[0] == 0) || + (this.held[0] && (!this.keyBinding.isDown() || this.keyBinding.clickCount == 0))) + { + this.unpressBindingImmediately(null); + } + } + } + + /** + * adds a KeyListener that gets notified for state changes + * + * @param listener KeyListener to register + */ + public void registerListener(KeyListener listener) { + this.listeners.add(listener); + this.listeners.sort(Comparator.comparingInt(KeyListener::getPriority).reversed()); + } + + /** + * removes the specified KeyListeners + */ + public void unregisterListener(KeyListener listener) { + this.listeners.remove(listener); + } + + /** + * notifies all registered KeyListener in priority order + * + * @param pressed if presses or released + * @param hand controller this was triggered by + * @return if any KeyListener triggered + */ + public boolean notifyListeners(boolean pressed, ControllerType hand) { + for (KeyListener listener : this.listeners) { + if (pressed) { + if (listener.onPressed(hand)) { + return true; + } + } else if (listener.onUnpressed(hand)) { + return true; + } + } + + return false; + } + + /** + * @return the last origin the vr runtime sent, if the VRInputAction is not currently in an active set this is likely 0 + */ + public long getLastOrigin() { + return 0; + } + + public float getAxis1D(boolean delta) { + return 0; + } + + /** + * This special variant of getAxis1D internally handles the isEnabled check and will continue + * to give an output even after disabled until the user lets go of the input. + * Cannot provide delta values as it wouldn't make any sense. + */ + public float getAxis1DUseTracked() { + return 0; + } + + public Vector2fc getAxis2D(boolean delta) { + return new Vector2f(); + } + + /** + * This special variant of getAxis2D internally handles the isEnabled check and will continue + * to give an output even after disabled until the user lets go of the input. + * Cannot provide delta values as it wouldn't make any sense. + */ + public Vector2fc getAxis2DUseTracked() { + return new Vector2f(); + } + + public interface KeyListener { + boolean onPressed(@Nullable ControllerType controllerType); + + boolean onUnpressed(@Nullable ControllerType controllerType); + + int getPriority(); + } +} diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java index 70bc6a653..bb99e3ec2 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java @@ -4,6 +4,7 @@ import org.joml.Vector2fc; import org.vivecraft.client.VivecraftVRMod; import org.vivecraft.client_vr.provider.openvr_lwjgl.MCOpenVR; +import org.vivecraft.client_vr.provider.openxr.control.XRInputAction; public class TrackpadSwipeSampler { private static final int UP = 0; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java index 232e84f97..3ee93f981 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java @@ -17,37 +17,16 @@ import java.util.Comparator; import java.util.List; -public class VRInputAction { - public final KeyMapping keyBinding; - public final String name; - public final String requirement; - public ActionType type; - public final VRInputActionSet actionSet; - - private int priority = 0; - private final boolean[] enabled = new boolean[ControllerType.values().length]; - private final List listeners = new ArrayList<>(); - private ControllerType currentHand = ControllerType.RIGHT; - // Only used for the UseTracked axis methods - private boolean currentlyInUse; +public class VRInputAction extends InputAction { public long handle; - private final boolean[] pressed = new boolean[ControllerType.values().length]; - private final boolean[] held = new boolean[ControllerType.values().length]; - protected final int[] unpressInTicks = new int[ControllerType.values().length]; - private ControllerType hand; - public final DigitalData[] digitalData = new DigitalData[ControllerType.values().length]; public final AnalogData[] analogData = new AnalogData[ControllerType.values().length]; public VRInputAction( KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { - this.keyBinding = keyMapping; - this.requirement = requirement; - this.type = type; - this.actionSet = actionSetOverride != null ? actionSetOverride : VRInputActionSet.fromKeyBinding(keyMapping); - this.name = this.actionSet.name + "/in/" + keyMapping.getName().replace('/', '_'); + super(keyMapping, requirement, type, actionSetOverride); for (int c = 0; c < ControllerType.values().length; c++) { this.enabled[c] = true; @@ -56,6 +35,7 @@ public VRInputAction( } } + @Override public boolean isButtonPressed() { if (this.type == ActionType.BOOLEAN) { return this.digitalData().state; @@ -65,6 +45,7 @@ public boolean isButtonPressed() { } } + @Override public boolean isButtonChanged() { if (this.type == ActionType.BOOLEAN) { return this.digitalData().isChanged; @@ -77,6 +58,7 @@ public boolean isButtonChanged() { } } + @Override public float getAxis1D(boolean delta) { return switch (this.type) { case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> this.digitalToAnalog(delta); @@ -85,6 +67,7 @@ public float getAxis1D(boolean delta) { }; } + @Override public Vector2fc getAxis2D(boolean delta) { return switch (this.type) { case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> new Vector2f(this.digitalToAnalog(delta), 0.0F); @@ -95,6 +78,7 @@ public Vector2fc getAxis2D(boolean delta) { }; } + //TODO remove public Vector3fc getAxis3D(boolean delta) { return switch (this.type) { case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> @@ -115,6 +99,7 @@ public Vector3fc getAxis3D(boolean delta) { * to give an output even after disabled until the user lets go of the input. * Cannot provide delta values as it wouldn't make any sense. */ + @Override public float getAxis1DUseTracked() { if (this.currentlyInUse || this.isEnabled()) { float axis = this.getAxis1D(false); @@ -130,6 +115,7 @@ public float getAxis1DUseTracked() { * to give an output even after disabled until the user lets go of the input. * Cannot provide delta values as it wouldn't make any sense. */ + @Override public Vector2fc getAxis2DUseTracked() { if (this.currentlyInUse || this.isEnabled()) { Vector2fc axis = this.getAxis2D(false); @@ -140,21 +126,6 @@ public Vector2fc getAxis2DUseTracked() { } } - /** - * This special variant of getAxis3D internally handles the isEnabled check and will continue - * to give an output even after disabled until the user lets go of the input. - * Cannot provide delta values as it wouldn't make any sense. - */ - public Vector3fc getAxis3DUseTracked() { - if (this.currentlyInUse || this.isEnabled()) { - Vector3fc axis = this.getAxis3D(false); - this.currentlyInUse = axis.x() != 0.0F || axis.y() != 0.0F || axis.z() != 0.0F; - return axis; - } else { - return new Vector3f(); - } - } - private float digitalToAnalog(boolean delta) { if (delta) { if (this.digitalData().isChanged) { @@ -170,6 +141,7 @@ private float digitalToAnalog(boolean delta) { /** * @return the last origin the vr runtime sent, if the VRInputAction is not currently in an active set this is likely 0 */ + @Override public long getLastOrigin() { return switch (this.type) { case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> this.digitalData().activeOrigin; @@ -178,14 +150,6 @@ public long getLastOrigin() { }; } - public ControllerType getCurrentHand() { - return this.currentHand; - } - - public void setCurrentHand(ControllerType currentHand) { - this.currentHand = currentHand; - } - private DigitalData digitalData() { return this.isHanded() ? this.digitalData[this.currentHand.ordinal()] : this.digitalData[0]; } @@ -194,89 +158,15 @@ private AnalogData analogData() { return this.isHanded() ? this.analogData[this.currentHand.ordinal()] : this.analogData[0]; } - public void setType(ActionType type) { - this.type = type; - } - public void setHandle(long handle) { if (this.handle != 0L) { - //throw new IllegalStateException("Handle already assigned!"); + throw new IllegalStateException("Handle already assigned!"); } else { this.handle = handle; } } - public int getPriority() { - return this.priority; - } - - public VRInputAction setPriority(int priority) { - this.priority = priority; - return this; - } - - /** - * check if the InputAction is enabled, if it is handed, checks for {@link VRInputAction#currentHand}
- * also checks if any other InputAction with higher priority is active, then this InputAction is treated as disabled - */ - public boolean isEnabled() { - if (!this.isEnabledRaw(this.currentHand)) return false; - if (ClientDataHolderVR.getInstance().vr == null) return false; - - long lastOrigin = this.getLastOrigin(); - ControllerType hand = ClientDataHolderVR.getInstance().vr.getOriginControllerType(lastOrigin); - - if (hand == null && this.isHanded()) return false; - - // iterate over all actions, and check if another action has a higher priority - for (VRInputAction action : ClientDataHolderVR.getInstance().vr.getInputActions()) { - if (action != this && action.isEnabledRaw(hand) && action.isActive() && - action.getPriority() > this.getPriority() && - ClientDataHolderVR.getInstance().vr.getOrigins(action).contains(lastOrigin)) - { - if (action.isHanded()) { - return !((HandedKeyBinding) action.keyBinding).isPriorityOnController(hand); - } - return false; - } - } - - return true; - } - - public boolean isEnabledRaw(ControllerType hand) { - if (this.isHanded()) { - return hand != null && this.enabled[hand.ordinal()]; - } else { - return this.enabled[0]; - } - } - - public boolean isEnabledRaw() { - return Arrays.stream(ControllerType.values()).anyMatch(this::isEnabledRaw); - } - - public VRInputAction setEnabled(ControllerType hand, boolean enabled) { - if (!this.isHanded()) { - throw new IllegalStateException("Not a handed key binding!"); - } else { - this.enabled[hand.ordinal()] = enabled; - return this; - } - } - - public VRInputAction setEnabled(boolean enabled) { - if (this.isHanded()) { - for (ControllerType controllertype : ControllerType.values()) { - this.enabled[controllertype.ordinal()] = enabled; - } - } else { - this.enabled[0] = enabled; - } - - return this; - } - + @Override public boolean isActive() { return switch (this.type) { case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> this.digitalData().isActive; @@ -285,249 +175,6 @@ public boolean isActive() { }; } - public boolean isHanded() { - return this.keyBinding instanceof HandedKeyBinding; - } - - /** - * adds a KeyListener that gets notified for state changes - * - * @param listener KeyListener to register - */ - public void registerListener(KeyListener listener) { - this.listeners.add(listener); - this.listeners.sort(Comparator.comparingInt(KeyListener::getPriority).reversed()); - } - - /** - * removes the specified KeyListeners - */ - public void unregisterListener(KeyListener listener) { - this.listeners.remove(listener); - } - - /** - * notifies all registered KeyListener in priority order - * - * @param pressed if presses or released - * @param hand controller this was triggered by - * @return if any KeyListener triggered - */ - public boolean notifyListeners(boolean pressed, ControllerType hand) { - for (KeyListener listener : this.listeners) { - if (pressed) { - if (listener.onPressed(hand)) { - return true; - } - } else if (listener.onUnpressed(hand)) { - return true; - } - } - - return false; - } - - public void tick() { - if (this.isHanded()) { - for (int c = 0; c < ControllerType.values().length; c++) { - ControllerType type = ControllerType.values()[c]; - HandedKeyBinding handedKeyBinding = (HandedKeyBinding) this.keyBinding; - if ((!this.held[c] && this.unpressInTicks[c] > 0 && --this.unpressInTicks[c] == 0) || - (this.held[c] && (!handedKeyBinding.isDown(type) || handedKeyBinding.presses(type) == 0))) - { - this.unpressBindingImmediately(type); - } - } - } else { - if ((!this.held[0] && this.unpressInTicks[0] > 0 && --this.unpressInTicks[0] == 0) || - (this.held[0] && (!this.keyBinding.isDown() || this.keyBinding.clickCount == 0))) - { - this.unpressBindingImmediately(null); - } - } - } - - public void setPressed(boolean pressed) { - if (pressed) { - this.pressBinding(); - } else { - this.unpressBinding(); - } - } - - public void holdBinding() { - this.holdBinding(this.currentHand); - } - - public void holdBinding(ControllerType hand) { - if (this.isHanded()) { - this.held[hand.ordinal()] = true; - } else { - this.held[0] = true; - } - this.pressBinding(this.currentHand); - } - - public void stopHoldingBinding(int unpressInTicks) { - this.stopHoldingBinding(unpressInTicks, this.currentHand); - } - - public void stopHoldingBinding(int unpressInTicks, ControllerType hand) { - if (this.isHanded()) { - this.held[hand.ordinal()] = false; - } else { - this.held[0] = false; - } - this.unpressBinding(unpressInTicks, this.currentHand); - } - - private void pressBinding(ControllerType hand) { - if (this.isHanded()) { - if (hand == null || this.pressed[hand.ordinal()]) return; - - this.pressed[hand.ordinal()] = true; - - if (this.notifyListeners(true, hand)) return; - - ((HandedKeyBinding) this.keyBinding).pressKey(hand); - } else { - if (this.pressed[0]) return; - - this.pressed[0] = true; - - if (this.notifyListeners(true, null)) return; - - this.pressKey(); - } - } - - public void pressBinding() { - this.pressBinding(this.currentHand); - } - - public void unpressBinding(int unpressInTicks, ControllerType hand) { - if (this.isHanded()) { - if (hand == null || !this.pressed[hand.ordinal()]) return; - - this.unpressInTicks[hand.ordinal()] = unpressInTicks; - } else { - if (!this.pressed[0]) return; - - this.unpressInTicks[0] = unpressInTicks; - } - } - - public void unpressBinding(int unpressInTicks) { - this.unpressBinding(unpressInTicks, this.currentHand); - } - - public void unpressBinding() { - this.unpressBinding(1); - } - - public void unpressBindingImmediately() { - if (this.isHanded()) { - for (int c = 0; c < ControllerType.values().length; c++) { - this.unpressBindingImmediately(ControllerType.values()[c]); - } - } else { - - this.unpressBindingImmediately(null); - } - } - - public void unpressBindingImmediately(ControllerType hand) { - if (this.isHanded()) { - if (hand == null || !this.pressed[hand.ordinal()]) return; - - this.pressed[hand.ordinal()] = false; - this.held[hand.ordinal()] = false; - - if (this.notifyListeners(false, hand)) return; - - ((HandedKeyBinding) this.keyBinding).unpressKey(hand); - } else { - if (!this.pressed[0]) return; - - this.pressed[0] = false; - this.held[0] = false; - - if (this.notifyListeners(false, null)) return; - - this.unpressKey(); - } - } - - public static void setKeyBindState(KeyMapping keyMapping, boolean pressed) { - if (keyMapping != null) { - keyMapping.setDown(pressed); - keyMapping.clickCount += 1; - } - } - - /** - * presses the KeyMapping assigned to this InputAction
- * if the KeyMapping has a modifier key also presses that - */ - private void pressKey() { - InputConstants.Key key = this.keyBinding.key; - - // need to simulate the modifier or the binding wouldn't be pressed - if (key.getValue() != -1 && - (!VivecraftVRMod.INSTANCE.isSafeBinding(this.keyBinding) || Xplat.hasKeyModifier(this.keyBinding))) - { - if (key.getType() == InputConstants.Type.KEYSYM) { - if (Xplat.hasKeyModifier(this.keyBinding)) { - InputSimulator.pressModifier(Xplat.getKeyModifierKey(this.keyBinding)); - } - InputSimulator.pressKey(key.getValue(), Xplat.getKeyModifier(this.keyBinding)); - return; - } - - if (key.getType() == InputConstants.Type.MOUSE) { - InputSimulator.pressMouse(key.getValue()); - return; - } - } - - setKeyBindState(this.keyBinding, true); - } - - /** - * unpresses the KeyMapping assigned to this InputAction
- * if the KeyMapping has a modifier key also unpresses that - */ - public void unpressKey() { - InputConstants.Key key = this.keyBinding.key; - - if (key.getValue() != -1 && - (!VivecraftVRMod.INSTANCE.isSafeBinding(this.keyBinding) || Xplat.hasKeyModifier(this.keyBinding))) - { - if (key.getType() == InputConstants.Type.KEYSYM) { - InputSimulator.releaseKey(key.getValue()); - if (Xplat.hasKeyModifier(this.keyBinding)) { - InputSimulator.releaseModifier(Xplat.getKeyModifierKey(this.keyBinding)); - } - return; - } - - if (key.getType() == InputConstants.Type.MOUSE) { - InputSimulator.releaseMouse(key.getValue()); - return; - } - } - - this.keyBinding.release(); - } - - public void setHand(ControllerType hand) { - this.hand = hand; - } - - public ControllerType getHand() { - return this.hand; - } - public static class AnalogData { public float x; public float y; @@ -546,17 +193,5 @@ public static class DigitalData { public boolean isActive; public long activeOrigin; public long lastChange; - public boolean longPress; - public boolean toggle; - public boolean doublePress; - public boolean hold; - } - - public interface KeyListener { - boolean onPressed(@Nullable ControllerType controllerType); - - boolean onUnpressed(@Nullable ControllerType controllerType); - - int getPriority(); } } 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 b910db88e..a1283d8c7 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 @@ -17,8 +17,7 @@ import org.vivecraft.client_vr.provider.DeviceSource; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.VRRenderer; -import org.vivecraft.client_vr.provider.control.ControllerType; -import org.vivecraft.client_vr.provider.control.VRInputAction; +import org.vivecraft.client_vr.provider.control.*; import org.vivecraft.client_vr.render.MirrorNotification; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.common.utils.MathUtils; @@ -29,7 +28,7 @@ /** * MCVR implementation that does not interact with any runtime. */ -public class NullVR extends MCVR { +public class NullVR extends MCVR { private static final float IPD = 0.1F; protected static NullVR OME; @@ -89,6 +88,11 @@ public void destroy() { this.initialized = false; } + @Override + public InputAction createAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { + return new InputAction(keyMapping, requirement, type, actionSetOverride); + } + @Override public String getName() { return "nullDriver"; @@ -265,7 +269,7 @@ public List> getTrackers() { } @Override - public List getOrigins(VRInputAction action) { + public List getOrigins(InputAction action) { return List.of(); } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index ea8bdb87d..06e97459e 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -28,9 +28,7 @@ import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler; import org.vivecraft.client_vr.provider.*; -import org.vivecraft.client_vr.provider.control.ControllerType; -import org.vivecraft.client_vr.provider.control.VRInputAction; -import org.vivecraft.client_vr.provider.control.VRInputActionSet; +import org.vivecraft.client_vr.provider.control.*; import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.client_vr.utils.external.jinfinadeck; @@ -63,7 +61,7 @@ /** * MCVR implementation to communicate with OpenVR/SteamVR */ -public class MCOpenVR extends MCVR { +public class MCOpenVR extends MCVR { protected static MCOpenVR OME; // action paths @@ -264,6 +262,11 @@ public void destroy() { } } + @Override + public VRInputAction createAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { + return new VRInputAction(keyMapping, requirement, type, actionSetOverride); + } + /** * @param EVRInputError input error code to get the name for * @return Name of the error associated with that error code @@ -1667,12 +1670,12 @@ public List> getTrackers() { } @Override - public List getOrigins(VRInputAction action) { + public List getOrigins(I action) { List list = new ArrayList<>(); if (OpenVR.VRInput != null) { try (MemoryStack stack = MemoryStack.stackPush()) { LongBuffer longRef = stack.callocLong(16); - int error = VRInput_GetActionOrigins(this.getActionSetHandle(action.actionSet), action.handle, longRef); + int error = VRInput_GetActionOrigins(this.getActionSetHandle(action.actionSet), ((VRInputAction)action).handle, longRef); if (error != 0) { throw new RuntimeException( diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 816979ebf..aeec2886a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -24,22 +24,21 @@ import org.vivecraft.client_vr.provider.VRRenderer; import org.vivecraft.client_vr.provider.control.ActionType; import org.vivecraft.client_vr.provider.control.ControllerType; -import org.vivecraft.client_vr.provider.control.VRInputAction; +import org.vivecraft.client_vr.provider.control.InputAction; import org.vivecraft.client_vr.provider.control.VRInputActionSet; import org.vivecraft.client_vr.provider.openxr.control.ControllerMapping; import org.vivecraft.client_vr.provider.openxr.control.XRBinding; +import org.vivecraft.client_vr.provider.openxr.control.XRInputAction; import org.vivecraft.client_vr.settings.VRSettings; -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.LongBuffer; +import java.nio.*; +import java.nio.charset.StandardCharsets; import java.util.*; import static org.lwjgl.system.MemoryStack.*; import static org.lwjgl.system.MemoryUtil.*; -public class MCOpenXR extends MCVR { +public class MCOpenXR extends MCVR { private static MCOpenXR OME; public XrInstance instance; @@ -60,6 +59,7 @@ public class MCOpenXR extends MCVR { private XrActiveActionSet.Buffer activeActionSetsBuffer; private boolean isActive; private final HashMap paths = new HashMap<>(); + private final HashMap strings = new HashMap<>(); //TODO bimap? private final long[] grip = new long[2]; private final long[] aim = new long[2]; private final XrSpace[] gripSpace = new XrSpace[2]; @@ -71,6 +71,7 @@ public class MCOpenXR extends MCVR { public boolean shouldRender = true; public long[] haptics = new long[2]; public String systemName; + private String activeController; public record ActionBind(VRInputActionSet actionSet, String path) {} @@ -121,6 +122,11 @@ public void destroy() { this.eventDataBuffer.close(); } + @Override + public XRInputAction createAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { + return new XRInputAction(keyMapping, requirement, type, actionSetOverride); + } + @Override protected ControllerType findActiveBindingControllerType(KeyMapping keyMapping) { if (!this.inputInitialized) { @@ -245,7 +251,13 @@ private void updatePose() { logError(error, "xrSyncActions", ""); } - this.inputActions.values().forEach(this::readNewData); + XrInteractionProfileState state = XrInteractionProfileState.calloc(stack); + state.type(XR10.XR_TYPE_INTERACTION_PROFILE_STATE); + error = XR10.xrGetCurrentInteractionProfile(this.session, getPath("/user/hand/left"), state); //TODO left and right can be different + logError(error, "xrGetCurrentInteractionProfile"); + this.activeController = getString(state.interactionProfile()); + + this.inputActions.values().forEach(a -> this.readNewData(a, activeController)); //TODO Not needed it seems? Poses come from the action space XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), @@ -310,130 +322,187 @@ private void updatePose() { } } - public void readNewData(VRInputAction action) { - if (action.handle == 0) { + public void readNewData(XRInputAction action, String controller) { + if (action.getHandle(controller).isEmpty()) { return; } switch (action.type) { case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> { if (action.isHanded()) { for (ControllerType controllertype1 : ControllerType.values()) { - this.readBoolean(action, controllertype1); + this.readBoolean(action, controllertype1, controller); } } else { - this.readBoolean(action, null); + this.readBoolean(action, null, controller); } } case VEC1 -> { if (action.isHanded()) { for (ControllerType controllertype : ControllerType.values()) { - this.readFloat(action, controllertype); + this.readFloat(action, controllertype, controller); } } else { - this.readFloat(action, null); + this.readFloat(action, null, controller); } } case VEC2 -> { if (action.isHanded()) { for (ControllerType controllertype : ControllerType.values()) { - this.readVecData(action, controllertype); + this.readVecData(action, controllertype, controller); } } else { - this.readVecData(action, null); + this.readVecData(action, null, controller); } } } } - private void readBoolean(VRInputAction action, ControllerType hand) { + private void readBoolean(XRInputAction action, ControllerType hand, String controller) { int i = 0; if (hand != null) { i = hand.ordinal(); } try (MemoryStack stack = MemoryStack.stackPush()) { - XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); - info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); - info.action(new XrAction(action.handle, - new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); - info.subactionPath( - action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); - XrActionStateBoolean state = XrActionStateBoolean.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_BOOLEAN); - int error = XR10.xrGetActionStateBoolean(this.session, info, state); - logError(error, "xrGetActionStateBoolean", action.name); - - if (state.changedSinceLastSync()) { - if (state.currentState()) { - action.digitalData[i].toggle = !action.digitalData[i].toggle; - action.digitalData[i].doublePress = - System.nanoTime() - action.digitalData[i].lastChange > 250_000_000L; - } else { - action.digitalData[i].longPress = - System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; + for (long handle : action.getHandle(controller)) { + XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); + info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); + info.action(new XrAction(handle, + new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); + info.subactionPath( + action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); + XrActionStateBoolean state = XrActionStateBoolean.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_BOOLEAN); + int error = XR10.xrGetActionStateBoolean(this.session, info, state); + logError(error, "xrGetActionStateBoolean", action.name); + + if (state.changedSinceLastSync()) { + if (state.currentState()) { + action.digitalData[i].toggle = !action.digitalData[i].toggle; + action.digitalData[i].doublePress = + System.nanoTime() - action.digitalData[i].lastChange > 250_000_000L; + } else { + action.digitalData[i].longPress = + System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; + } + action.digitalData[i].lastChange = System.nanoTime(); + } else if (state.currentState()) { + action.digitalData[i].hold = System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; } - action.digitalData[i].lastChange = System.nanoTime(); - } else if (state.currentState()) { - action.digitalData[i].hold = System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; - } - action.digitalData[i].state = state.currentState(); - action.digitalData[i].isActive = state.isActive(); - action.digitalData[i].isChanged = state.changedSinceLastSync(); - action.digitalData[i].activeOrigin = getOrigins(action).get(0); + action.digitalData[i].state = state.currentState(); + action.digitalData[i].isActive = state.isActive(); + action.digitalData[i].isChanged = state.changedSinceLastSync(); + action.digitalData[i].activeOrigin = getOrigins(action).get(0); + + action.analogData[i].deltaX = state.changedSinceLastSync() ? state.currentState() ? 1.0F : -1.0F : 0.0F; + action.analogData[i].x = state.currentState() ? 1.0f : 0.0f; + action.analogData[i].activeOrigin = getOrigins(action).get(0); + action.analogData[i].isActive = state.isActive(); + action.analogData[i].isChanged = state.changedSinceLastSync(); + } } } - private void readFloat(VRInputAction action, ControllerType hand) { + private void readFloat(XRInputAction action, ControllerType hand, String controller) { int i = 0; if (hand != null) { i = hand.ordinal(); } try (MemoryStack stack = MemoryStack.stackPush()) { - XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); - info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); - info.action(new XrAction(action.handle, - new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); - info.subactionPath( - action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); - XrActionStateFloat state = XrActionStateFloat.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_FLOAT); - int error = XR10.xrGetActionStateFloat(this.session, info, state); - logError(error, "xrGetActionStateFloat", action.name); - - action.analogData[i].deltaX = state.currentState() - action.analogData[i].x; - action.analogData[i].x = state.currentState(); - action.analogData[i].activeOrigin = getOrigins(action).get(0); - action.analogData[i].isActive = state.isActive(); - action.analogData[i].isChanged = state.changedSinceLastSync(); + for (long handle : action.getHandle(controller)) { + XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); + info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); + info.action(new XrAction(handle, + new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); + info.subactionPath( + action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); + XrActionStateFloat state = XrActionStateFloat.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_FLOAT); + int error = XR10.xrGetActionStateFloat(this.session, info, state); + logError(error, "xrGetActionStateFloat", action.name); + + action.analogData[i].deltaX = state.currentState() - action.analogData[i].x; + action.analogData[i].x = state.currentState(); + action.analogData[i].activeOrigin = getOrigins(action).get(0); + action.analogData[i].isActive = state.isActive(); + action.analogData[i].isChanged = state.changedSinceLastSync(); + + //Write digital data + boolean on = Math.abs(state.currentState()) > 0.5F; + boolean changed = Math.abs(action.analogData[i].x - action.analogData[i].deltaX) > 0.5F != on; + if (changed) { + if (on) { + action.digitalData[i].toggle = !action.digitalData[i].toggle; + action.digitalData[i].doublePress = + System.nanoTime() - action.digitalData[i].lastChange > 250_000_000L; + } else { + action.digitalData[i].longPress = + System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; + } + action.digitalData[i].lastChange = System.nanoTime(); + } else if (on) { + action.digitalData[i].hold = System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; + } + + action.digitalData[i].state = on; + action.digitalData[i].isActive = state.isActive(); + action.digitalData[i].isChanged = changed; + action.digitalData[i].activeOrigin = getOrigins(action).get(0); + } } } - private void readVecData(VRInputAction action, ControllerType hand) { + private void readVecData(XRInputAction action, ControllerType hand, String controller) { int i = 0; if (hand != null) { i = hand.ordinal(); } try (MemoryStack stack = MemoryStack.stackPush()) { - XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); - info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); - info.action(new XrAction(action.handle, - new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); - info.subactionPath( - action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); - XrActionStateVector2f state = XrActionStateVector2f.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_VECTOR2F); - int error = XR10.xrGetActionStateVector2f(this.session, info, state); - logError(error, "xrGetActionStateVector2f", action.name); - - action.analogData[i].deltaX = state.currentState().x() - action.analogData[i].x; - action.analogData[i].deltaY = state.currentState().y() - action.analogData[i].y; - action.analogData[i].x = state.currentState().x(); - action.analogData[i].y = state.currentState().y(); - action.analogData[i].activeOrigin = getOrigins(action).get(0); - action.analogData[i].isActive = state.isActive(); - action.analogData[i].isChanged = state.changedSinceLastSync(); + for (long handle : action.getHandle(controller)) { + XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); + info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); + info.action(new XrAction(handle, + new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); + info.subactionPath( + action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); + XrActionStateVector2f state = XrActionStateVector2f.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_VECTOR2F); + int error = XR10.xrGetActionStateVector2f(this.session, info, state); + logError(error, "xrGetActionStateVector2f", action.name); + + action.analogData[i].deltaX = state.currentState().x() - action.analogData[i].x; + action.analogData[i].deltaY = state.currentState().y() - action.analogData[i].y; + action.analogData[i].x = state.currentState().x(); + action.analogData[i].y = state.currentState().y(); + action.analogData[i].activeOrigin = getOrigins(action).get(0); + action.analogData[i].isActive = state.isActive(); + action.analogData[i].isChanged = state.changedSinceLastSync(); + + //Write digital data + boolean on = Math.abs(state.currentState().x()) > 0.5F || Math.abs(state.currentState().y()) > 0.5F; + boolean changed = Math.abs(action.analogData[i].x - action.analogData[i].deltaX) > 0.5F != Math.abs(action.analogData[i].x) > 0.5F || + Math.abs(action.analogData[i].y - action.analogData[i].deltaY) > 0.5F != Math.abs(action.analogData[i].y) > 0.5F; + if (changed) { + if (on) { + action.digitalData[i].toggle = !action.digitalData[i].toggle; + action.digitalData[i].doublePress = + System.nanoTime() - action.digitalData[i].lastChange > 250_000_000L; + } else { + action.digitalData[i].longPress = + System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; + } + action.digitalData[i].lastChange = System.nanoTime(); + } else if (on) { + action.digitalData[i].hold = System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; + } + + action.digitalData[i].state = on; + action.digitalData[i].isActive = state.isActive(); + action.digitalData[i].isChanged = changed; + action.digitalData[i].activeOrigin = getOrigins(action).get(0); + } } } @@ -948,39 +1017,44 @@ public boolean hasCameraTracker() { } @Override - public List getOrigins(VRInputAction action) { + public List getOrigins(I action) { + List origins = new ArrayList<>(); try (MemoryStack stack = MemoryStack.stackPush()) { - XrBoundSourcesForActionEnumerateInfo info = XrBoundSourcesForActionEnumerateInfo.calloc(stack); - info.type(XR10.XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO); - info.next(NULL); - info.action(new XrAction(action.handle, - new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); - IntBuffer buf = stack.callocInt(1); - int error = XR10.xrEnumerateBoundSourcesForAction(this.session, info, buf, null); - logError(error, "xrEnumerateBoundSourcesForAction", action.name); + for (long handle : ((XRInputAction)action).getHandle(this.activeController)) { + XrBoundSourcesForActionEnumerateInfo info = XrBoundSourcesForActionEnumerateInfo.calloc(stack); + info.type(XR10.XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO); + info.next(NULL); + info.action(new XrAction(handle, + new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); + IntBuffer buf = stack.callocInt(1); + int error = XR10.xrEnumerateBoundSourcesForAction(this.session, info, buf, null); + logError(error, "xrEnumerateBoundSourcesForAction", action.name); - int size = buf.get(); - if (size <= 0) { - return List.of(0L); - } + int size = buf.get(); + if (size <= 0) { + continue; + } - buf = stack.callocInt(size); - LongBuffer longbuf = stack.callocLong(size); - error = XR10.xrEnumerateBoundSourcesForAction(this.session, info, buf, longbuf); - logError(error, "xrEnumerateBoundSourcesForAction", action.name); - long[] array; - if (longbuf.hasArray()) { //TODO really? - array = longbuf.array(); - } else { - longbuf.rewind(); - array = new long[longbuf.remaining()]; - int index = 0; - while (longbuf.hasRemaining()) { - array[index++] = longbuf.get(); + buf = stack.callocInt(size); + LongBuffer longbuf = stack.callocLong(size); + error = XR10.xrEnumerateBoundSourcesForAction(this.session, info, buf, longbuf); + logError(error, "xrEnumerateBoundSourcesForAction", action.name); + long[] array; + if (longbuf.hasArray()) { //TODO really? + array = longbuf.array(); + } else { + longbuf.rewind(); + array = new long[longbuf.remaining()]; + int index = 0; + while (longbuf.hasRemaining()) { + array[index++] = longbuf.get(); + } } + origins.addAll(Arrays.stream(array).boxed().toList()); } - return Arrays.stream(array).boxed().toList(); } + origins.add(0L); + return origins; } @Override @@ -1089,22 +1163,22 @@ private void loadDefaultBindings() { for (int i = 0; i < defaultBindings.length; i++) { XRBinding binding = defaultBindings[i]; - VRInputAction inputAction = this.getInputActionByName(binding.key()); + XRInputAction inputAction = this.getInputActionByName(binding.key()); if (binding.actionSet() != null) { //inputAction.actionSet = binding.actionSet(); TODO? } long handle = this.mappedBindings.get(new ActionBind(inputAction.actionSet, binding.controller())); - inputAction.setHandle(handle); + inputAction.addHandle(headset, handle); inputAction.setType(ControllerMapping.quest2Bindings().get(binding.controller())); inputAction.setHand( binding.controller().contains("/left/") ? ControllerType.LEFT : ControllerType.RIGHT); - if (inputAction.handle == 0L) { + if (inputAction.getHandle(headset).isEmpty() || handle == 0L) { VRSettings.LOGGER.error("Handle for '{}'/'{}' is null", binding.key(), binding.controller()); continue; } bindings.get(i).set( - new XrAction(inputAction.handle, + new XrAction(handle, new XrActionSet(this.actionSetHandles.get(inputAction.actionSet), this.instance)), getPath(binding.controller()) ); @@ -1204,6 +1278,27 @@ public long getPath(String pathString) { }); } + public String getString(long path) { + if (path == 0L) { //Quest takes some time to loas what controller is used + return ""; + } + return this.strings.computeIfAbsent(path, l -> { + try (MemoryStack ignored = stackPush()) { + IntBuffer size = stackCallocInt(1); + int error = XR10.xrPathToString(this.instance, l, size, null); + logError(error, "getString", l.toString()); + int i = size.get(0); + size.put(0, i); + ByteBuffer string = stackCalloc(i); + error = XR10.xrPathToString(this.instance, l, size, string); + logError(error, "getString", l.toString()); + byte[] data = new byte[i]; + string.get(data); + return new String(data).trim(); + } + }); + } + private long createAction( String name, String localisedName, ActionType type, XrActionSet actionSet, String subactionPath) { @@ -1351,7 +1446,7 @@ protected void logError(int xrResult, String caller, String... args) { } //TODO remove/rework - public Map getBinds() { + public Map getBinds() { return inputActions; } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java new file mode 100644 index 000000000..3bbd55b6a --- /dev/null +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java @@ -0,0 +1,153 @@ +package org.vivecraft.client_vr.provider.openxr.control; + +import net.minecraft.client.KeyMapping; +import org.joml.Vector2f; +import org.joml.Vector2fc; +import org.joml.Vector3fc; +import org.vivecraft.client_vr.provider.control.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class XRInputAction extends InputAction { + + private ControllerType hand; + private final Map> handles = new HashMap<>(); + + public final DigitalData[] digitalData = new DigitalData[ControllerType.values().length]; + public final AnalogData[] analogData = new AnalogData[ControllerType.values().length]; + + public XRInputAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { + super(keyMapping, requirement, type, actionSetOverride); + + for (int c = 0; c < ControllerType.values().length; c++) { + this.enabled[c] = true; + this.analogData[c] = new AnalogData(); + this.digitalData[c] = new DigitalData(); + } + } + + public ControllerType getHand() { + return hand; + } + + public void setHand(ControllerType hand) { + this.hand = hand; + } + + public List getHandle(String controller) { + return handles.getOrDefault(controller, List.of()); + } + + public void addHandle(String controller, Long handle) { + if (!handles.containsKey(controller)) { + var list = new ArrayList(); + list.add(handle); + handles.put(controller, list); + } else { + handles.get(controller).add(handle); + } + } + + private DigitalData digitalData() { + return this.isHanded() ? this.digitalData[this.currentHand.ordinal()] : this.digitalData[0]; + } + + private AnalogData analogData() { + return this.isHanded() ? this.analogData[this.currentHand.ordinal()] : this.analogData[0]; + } + + @Override + public boolean isActive() { + return switch (this.type) { + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> this.digitalData().isActive; + case VEC1, VEC2 -> this.analogData().isActive; + default -> false; + }; + } + + @Override + public boolean isButtonPressed() { + return this.digitalData().state; + } + + @Override + public boolean isButtonChanged() { + return this.digitalData().isChanged; + } + + @Override + public long getLastOrigin() { + return switch (this.type) { + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> this.digitalData().activeOrigin; + case VEC1, VEC2 -> this.analogData().activeOrigin; + default -> 0L; + }; + } + + @Override + public float getAxis1D(boolean delta) { + return switch (this.type) { + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> this.analogData().x; + case VEC1, VEC2 -> delta ? this.analogData().deltaX : this.analogData().x; + default -> 0.0F; + }; + } + + @Override + public float getAxis1DUseTracked() { + if (this.currentlyInUse || this.isEnabled()) { + float axis = this.getAxis1D(false); + this.currentlyInUse = axis != 0.0F; + return axis; + } else { + return 0.0F; + } + } + + @Override + public Vector2fc getAxis2D(boolean delta) { + return switch (this.type) { + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> new Vector2f(this.analogData().x, 0.0F); + case VEC1 -> delta ? new Vector2f(this.analogData().deltaX, 0.0F) : new Vector2f(this.analogData().x, 0.0F); + case VEC2 -> delta ? new Vector2f(this.analogData().deltaX, this.analogData().deltaY) : + new Vector2f(this.analogData().x, this.analogData().y); + default -> new Vector2f(); + }; + } + + @Override + public Vector2fc getAxis2DUseTracked() { + if (this.currentlyInUse || this.isEnabled()) { + Vector2fc axis = this.getAxis2D(false); + this.currentlyInUse = axis.x() != 0.0F || axis.y() != 0.0F; + return axis; + } else { + return new Vector2f(); + } + } + + public static class AnalogData { + public float x; + public float y; + public float deltaX; + public float deltaY; + public boolean isChanged; + public boolean isActive; + public long activeOrigin; + } + + public static class DigitalData { + public boolean state; + public boolean isChanged; + public boolean isActive; + public long activeOrigin; + public long lastChange; + public boolean longPress; + public boolean toggle; + public boolean doublePress; + public boolean hold; + } +} 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 93211cc83..f094e3bdd 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 @@ -70,6 +70,7 @@ import org.vivecraft.client_vr.menuworlds.MenuWorldDownloader; import org.vivecraft.client_vr.menuworlds.MenuWorldExporter; import org.vivecraft.client_vr.provider.MCVR; +import org.vivecraft.client_vr.provider.control.InputAction; import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.render.MirrorNotification; import org.vivecraft.client_vr.render.RenderConfigException; @@ -560,7 +561,7 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { dataHolder.vr.processBindings(); Profiler.get().popPush("vrInputActionsTick"); - for (VRInputAction vrinputaction : dataHolder.vr.getInputActions()) { + for (InputAction vrinputaction : dataHolder.vr.getInputActions()) { vrinputaction.tick(); } @@ -863,7 +864,7 @@ public abstract class MinecraftVRMixin implements MinecraftExtension { } // unpress any keys we simulated for VR if (MCVR.get() != null) { - for (VRInputAction action : MCVR.get().getInputActions()) { + for (InputAction action : MCVR.get().getInputActions()) { action.unpressBindingImmediately(); } } From ec5d9f211032b2da652e32478e219e59388322ed Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Sat, 22 Nov 2025 14:54:16 +0100 Subject: [PATCH 73/76] fix multibinds and origins --- .../client_vr/provider/openxr/MCOpenXR.java | 423 ++++++++---------- .../openxr/control/ControllerMapping.java | 8 +- .../provider/openxr/control/XRBinding.java | 20 +- .../openxr/control/XRInputAction.java | 179 ++++++-- 4 files changed, 341 insertions(+), 289 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index aeec2886a..5ae5579ab 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -1,5 +1,6 @@ package org.vivecraft.client_vr.provider.openxr; +import com.google.common.collect.HashBiMap; import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; import net.minecraft.util.profiling.Profiler; @@ -32,7 +33,6 @@ import org.vivecraft.client_vr.settings.VRSettings; import java.nio.*; -import java.nio.charset.StandardCharsets; import java.util.*; import static org.lwjgl.system.MemoryStack.*; @@ -58,8 +58,7 @@ public class MCOpenXR extends MCVR { // TODO Move to MCVR private XrActiveActionSet.Buffer activeActionSetsBuffer; private boolean isActive; - private final HashMap paths = new HashMap<>(); - private final HashMap strings = new HashMap<>(); //TODO bimap? + private final HashBiMap paths = HashBiMap.create(); private final long[] grip = new long[2]; private final long[] aim = new long[2]; private final XrSpace[] gripSpace = new XrSpace[2]; @@ -69,9 +68,9 @@ public class MCOpenXR extends MCVR { XrVector3f.calloc() ); public boolean shouldRender = true; - public long[] haptics = new long[2]; + public final long[] haptics = new long[2]; public String systemName; - private String activeController; + private final String[] activeController = new String[2]; public record ActionBind(VRInputActionSet actionSet, String path) {} @@ -127,34 +126,27 @@ public XRInputAction createAction(KeyMapping keyMapping, String requirement, Act return new XRInputAction(keyMapping, requirement, type, actionSetOverride); } + //TODO fix, action origins don't work like that on openXR @Override protected ControllerType findActiveBindingControllerType(KeyMapping keyMapping) { if (!this.inputInitialized) { return null; } else { - long path = this.getInputAction(keyMapping).getLastOrigin(); - try (MemoryStack stack = MemoryStack.stackPush()) { - IntBuffer buf = stack.callocInt(1); - int error = XR10.xrPathToString(this.instance, path, buf, null); - logError(error, "xrPathToString", "get string length for", keyMapping.getName()); - - int size = buf.get(); - if (size <= 0) { - return null; - } - - buf = stack.callocInt(size); - ByteBuffer byteBuffer = stack.calloc(size); - error = XR10.xrPathToString(this.instance, path, buf, byteBuffer); - logError(error, "xrPathToString", "get string for", keyMapping.getName()); - byte[] bytes = new byte[byteBuffer.remaining()]; - byteBuffer.get(bytes); - String name = new String(bytes); - if (name.contains("right")) { - return ControllerType.RIGHT; + var action = this.getInputAction(keyMapping); + for (ControllerType controllerType : ControllerType.values()) { + var handedaction = action.getHandle(this.activeController[controllerType.ordinal()]).get(action.activeAction); + if (handedaction.hand() != controllerType) { + continue; } - return ControllerType.LEFT; + return handedaction.hand(); } + return null; +// long path = this.getInputAction(keyMapping).getLastOrigin(); +// String name = getString(path); +// if (name.contains("right")) { +// return ControllerType.RIGHT; +// } +// return ControllerType.LEFT; } } @@ -253,11 +245,14 @@ private void updatePose() { XrInteractionProfileState state = XrInteractionProfileState.calloc(stack); state.type(XR10.XR_TYPE_INTERACTION_PROFILE_STATE); - error = XR10.xrGetCurrentInteractionProfile(this.session, getPath("/user/hand/left"), state); //TODO left and right can be different - logError(error, "xrGetCurrentInteractionProfile"); - this.activeController = getString(state.interactionProfile()); + error = XR10.xrGetCurrentInteractionProfile(this.session, getPath("/user/hand/right"), state); + logError(error, "xrGetCurrentInteractionProfile", "right"); + this.activeController[RIGHT_CONTROLLER] = getString(state.interactionProfile()); + error = XR10.xrGetCurrentInteractionProfile(this.session, getPath("/user/hand/left"), state); + logError(error, "xrGetCurrentInteractionProfile", "left"); + this.activeController[LEFT_CONTROLLER] = getString(state.interactionProfile()); - this.inputActions.values().forEach(a -> this.readNewData(a, activeController)); + this.inputActions.values().forEach(this::readNewData); //TODO Not needed it seems? Poses come from the action space XrActionSet actionSet = new XrActionSet(this.actionSetHandles.get(VRInputActionSet.GLOBAL), @@ -322,187 +317,163 @@ private void updatePose() { } } - public void readNewData(XRInputAction action, String controller) { - if (action.getHandle(controller).isEmpty()) { - return; - } - switch (action.type) { - case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> { - if (action.isHanded()) { - for (ControllerType controllertype1 : ControllerType.values()) { - this.readBoolean(action, controllertype1, controller); - } - } else { - this.readBoolean(action, null, controller); + public void readNewData(XRInputAction action) { + for (var controller : ControllerType.values()) { + for (int i = 0; i < action.getHandle(this.activeController[controller.ordinal()]).size(); i++) { + var handedAction = action.getHandle(this.activeController[controller.ordinal()]).get(i); + if (handedAction.handle() == 0L) { + continue; } - } - - case VEC1 -> { - if (action.isHanded()) { - for (ControllerType controllertype : ControllerType.values()) { - this.readFloat(action, controllertype, controller); - } - } else { - this.readFloat(action, null, controller); + if (handedAction.hand() != controller) { + continue; } - } + switch (handedAction.action()) { + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> + this.readBoolean(action, handedAction.hand(), i); - case VEC2 -> { - if (action.isHanded()) { - for (ControllerType controllertype : ControllerType.values()) { - this.readVecData(action, controllertype, controller); - } - } else { - this.readVecData(action, null, controller); + case VEC1 -> this.readFloat(action, handedAction.hand(), i); + + case VEC2 -> this.readVecData(action, handedAction.hand(), i); } } } } - private void readBoolean(XRInputAction action, ControllerType hand, String controller) { - int i = 0; - - if (hand != null) { - i = hand.ordinal(); - } + private void readBoolean(XRInputAction action, ControllerType hand, int index) { try (MemoryStack stack = MemoryStack.stackPush()) { - for (long handle : action.getHandle(controller)) { - XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); - info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); - info.action(new XrAction(handle, - new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); - info.subactionPath( - action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); - XrActionStateBoolean state = XrActionStateBoolean.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_BOOLEAN); - int error = XR10.xrGetActionStateBoolean(this.session, info, state); - logError(error, "xrGetActionStateBoolean", action.name); - - if (state.changedSinceLastSync()) { - if (state.currentState()) { - action.digitalData[i].toggle = !action.digitalData[i].toggle; - action.digitalData[i].doublePress = - System.nanoTime() - action.digitalData[i].lastChange > 250_000_000L; - } else { - action.digitalData[i].longPress = - System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; - } - action.digitalData[i].lastChange = System.nanoTime(); - } else if (state.currentState()) { - action.digitalData[i].hold = System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; + XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); + info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); + XRInputAction.HandedAction handedAction = action.getHandle(this.activeController[hand.ordinal()]) + .get(index); + info.action(new XrAction(handedAction.handle(), + new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); + info.subactionPath( + hand == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); + XrActionStateBoolean state = XrActionStateBoolean.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_BOOLEAN); + int error = XR10.xrGetActionStateBoolean(this.session, info, state); + logError(error, "xrGetActionStateBoolean", action.name); + + if (state.changedSinceLastSync()) { + if (state.currentState()) { + action.digitalData.get(index).toggle = !action.digitalData.get(index).toggle; + action.digitalData.get(index).doublePress = + System.nanoTime() - action.digitalData.get(index).lastChange > 250_000_000L; + } else { + action.digitalData.get(index).longPress = + System.nanoTime() - action.digitalData.get(index).lastChange > 500_000_000L; } - - action.digitalData[i].state = state.currentState(); - action.digitalData[i].isActive = state.isActive(); - action.digitalData[i].isChanged = state.changedSinceLastSync(); - action.digitalData[i].activeOrigin = getOrigins(action).get(0); - - action.analogData[i].deltaX = state.changedSinceLastSync() ? state.currentState() ? 1.0F : -1.0F : 0.0F; - action.analogData[i].x = state.currentState() ? 1.0f : 0.0f; - action.analogData[i].activeOrigin = getOrigins(action).get(0); - action.analogData[i].isActive = state.isActive(); - action.analogData[i].isChanged = state.changedSinceLastSync(); + action.digitalData.get(index).lastChange = System.nanoTime(); + } else if (state.currentState()) { + action.digitalData.get(index).hold = System.nanoTime() - action.digitalData.get(index).lastChange > 500_000_000L; } + + action.digitalData.get(index).state = state.currentState(); + action.digitalData.get(index).isActive = state.isActive(); + action.digitalData.get(index).isChanged = state.changedSinceLastSync(); + action.digitalData.get(index).activeOrigin = getOrigins(handedAction,action).getFirst(); + action.digitalData.get(index).type = handedAction.action(); + action.digitalData.get(index).hand = handedAction.hand(); + + action.analogData.get(index).deltaX = state.changedSinceLastSync() ? state.currentState() ? 1.0F : -1.0F : 0.0F; + action.analogData.get(index).x = state.currentState() ? 1.0f : 0.0f; + action.analogData.get(index).activeOrigin = getOrigins(handedAction,action).getFirst(); + action.analogData.get(index).isActive = state.isActive(); + action.analogData.get(index).isChanged = state.changedSinceLastSync(); } } - private void readFloat(XRInputAction action, ControllerType hand, String controller) { - int i = 0; - - if (hand != null) { - i = hand.ordinal(); - } + private void readFloat(XRInputAction action, ControllerType hand, int index) { try (MemoryStack stack = MemoryStack.stackPush()) { - for (long handle : action.getHandle(controller)) { - XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); - info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); - info.action(new XrAction(handle, - new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); - info.subactionPath( - action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); - XrActionStateFloat state = XrActionStateFloat.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_FLOAT); - int error = XR10.xrGetActionStateFloat(this.session, info, state); - logError(error, "xrGetActionStateFloat", action.name); - - action.analogData[i].deltaX = state.currentState() - action.analogData[i].x; - action.analogData[i].x = state.currentState(); - action.analogData[i].activeOrigin = getOrigins(action).get(0); - action.analogData[i].isActive = state.isActive(); - action.analogData[i].isChanged = state.changedSinceLastSync(); - - //Write digital data - boolean on = Math.abs(state.currentState()) > 0.5F; - boolean changed = Math.abs(action.analogData[i].x - action.analogData[i].deltaX) > 0.5F != on; - if (changed) { - if (on) { - action.digitalData[i].toggle = !action.digitalData[i].toggle; - action.digitalData[i].doublePress = - System.nanoTime() - action.digitalData[i].lastChange > 250_000_000L; - } else { - action.digitalData[i].longPress = - System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; - } - action.digitalData[i].lastChange = System.nanoTime(); - } else if (on) { - action.digitalData[i].hold = System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; + XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); + info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); + XRInputAction.HandedAction handedAction = action.getHandle(this.activeController[hand.ordinal()]) + .get(index); + info.action(new XrAction(handedAction.handle(), + new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); + info.subactionPath( + hand == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); + XrActionStateFloat state = XrActionStateFloat.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_FLOAT); + int error = XR10.xrGetActionStateFloat(this.session, info, state); + logError(error, "xrGetActionStateFloat", action.name); + + action.analogData.get(index).deltaX = state.currentState() - action.analogData.get(index).x; + action.analogData.get(index).x = state.currentState(); + action.analogData.get(index).activeOrigin = getOrigins(action).getFirst(); + action.analogData.get(index).isActive = state.isActive(); + action.analogData.get(index).isChanged = state.changedSinceLastSync(); + + //Write digital data + boolean on = Math.abs(state.currentState()) > 0.5F; + boolean changed = Math.abs(action.analogData.get(index).x - action.analogData.get(index).deltaX) > 0.5F != on; + if (changed) { + if (on) { + action.digitalData.get(index).toggle = !action.digitalData.get(index).toggle; + action.digitalData.get(index).doublePress = + System.nanoTime() - action.digitalData.get(index).lastChange > 250_000_000L; + } else { + action.digitalData.get(index).longPress = + System.nanoTime() - action.digitalData.get(index).lastChange > 500_000_000L; } - - action.digitalData[i].state = on; - action.digitalData[i].isActive = state.isActive(); - action.digitalData[i].isChanged = changed; - action.digitalData[i].activeOrigin = getOrigins(action).get(0); + action.digitalData.get(index).lastChange = System.nanoTime(); + } else if (on) { + action.digitalData.get(index).hold = System.nanoTime() - action.digitalData.get(index).lastChange > 500_000_000L; } + + action.digitalData.get(index).state = on; + action.digitalData.get(index).isActive = state.isActive(); + action.digitalData.get(index).isChanged = changed; + action.digitalData.get(index).activeOrigin = getOrigins(action).getFirst(); + action.digitalData.get(index).type = handedAction.action(); + action.digitalData.get(index).hand = handedAction.hand(); } } - private void readVecData(XRInputAction action, ControllerType hand, String controller) { - int i = 0; - - if (hand != null) { - i = hand.ordinal(); - } + private void readVecData(XRInputAction action, ControllerType hand, int index) { try (MemoryStack stack = MemoryStack.stackPush()) { - for (long handle : action.getHandle(controller)) { - XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); - info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); - info.action(new XrAction(handle, - new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); - info.subactionPath( - action.getHand() == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); - XrActionStateVector2f state = XrActionStateVector2f.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_VECTOR2F); - int error = XR10.xrGetActionStateVector2f(this.session, info, state); - logError(error, "xrGetActionStateVector2f", action.name); - - action.analogData[i].deltaX = state.currentState().x() - action.analogData[i].x; - action.analogData[i].deltaY = state.currentState().y() - action.analogData[i].y; - action.analogData[i].x = state.currentState().x(); - action.analogData[i].y = state.currentState().y(); - action.analogData[i].activeOrigin = getOrigins(action).get(0); - action.analogData[i].isActive = state.isActive(); - action.analogData[i].isChanged = state.changedSinceLastSync(); - - //Write digital data - boolean on = Math.abs(state.currentState().x()) > 0.5F || Math.abs(state.currentState().y()) > 0.5F; - boolean changed = Math.abs(action.analogData[i].x - action.analogData[i].deltaX) > 0.5F != Math.abs(action.analogData[i].x) > 0.5F || - Math.abs(action.analogData[i].y - action.analogData[i].deltaY) > 0.5F != Math.abs(action.analogData[i].y) > 0.5F; - if (changed) { - if (on) { - action.digitalData[i].toggle = !action.digitalData[i].toggle; - action.digitalData[i].doublePress = - System.nanoTime() - action.digitalData[i].lastChange > 250_000_000L; - } else { - action.digitalData[i].longPress = - System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; - } - action.digitalData[i].lastChange = System.nanoTime(); - } else if (on) { - action.digitalData[i].hold = System.nanoTime() - action.digitalData[i].lastChange > 500_000_000L; + XrActionStateGetInfo info = XrActionStateGetInfo.calloc(stack); + info.type(XR10.XR_TYPE_ACTION_STATE_GET_INFO); + XRInputAction.HandedAction handedAction = action.getHandle(this.activeController[hand.ordinal()]) + .get(index); + info.action(new XrAction(handedAction.handle(), + new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); + info.subactionPath( + hand == ControllerType.LEFT ? getPath(BOTH_HANDS[0]) : getPath(BOTH_HANDS[1])); + XrActionStateVector2f state = XrActionStateVector2f.calloc(stack).type(XR10.XR_TYPE_ACTION_STATE_VECTOR2F); + int error = XR10.xrGetActionStateVector2f(this.session, info, state); + logError(error, "xrGetActionStateVector2f", action.name); + + action.analogData.get(index).deltaX = state.currentState().x() - action.analogData.get(index).x; + action.analogData.get(index).deltaY = state.currentState().y() - action.analogData.get(index).y; + action.analogData.get(index).x = state.currentState().x(); + action.analogData.get(index).y = state.currentState().y(); + action.analogData.get(index).activeOrigin = getOrigins(action).getFirst(); + action.analogData.get(index).isActive = state.isActive(); + action.analogData.get(index).isChanged = state.changedSinceLastSync(); + + //Write digital data + boolean on = Math.abs(state.currentState().x()) > 0.5F || Math.abs(state.currentState().y()) > 0.5F; + boolean changed = Math.abs(action.analogData.get(index).x - action.analogData.get(index).deltaX) > 0.5F != Math.abs(action.analogData.get(index).x) > 0.5F || + Math.abs(action.analogData.get(index).y - action.analogData.get(index).deltaY) > 0.5F != Math.abs(action.analogData.get(index).y) > 0.5F; + if (changed) { + if (on) { + action.digitalData.get(index).toggle = !action.digitalData.get(index).toggle; + action.digitalData.get(index).doublePress = + System.nanoTime() - action.digitalData.get(index).lastChange > 250_000_000L; + } else { + action.digitalData.get(index).longPress = + System.nanoTime() - action.digitalData.get(index).lastChange > 500_000_000L; } - - action.digitalData[i].state = on; - action.digitalData[i].isActive = state.isActive(); - action.digitalData[i].isChanged = changed; - action.digitalData[i].activeOrigin = getOrigins(action).get(0); + action.digitalData.get(index).lastChange = System.nanoTime(); + } else if (on) { + action.digitalData.get(index).hold = System.nanoTime() - action.digitalData.get(index).lastChange > 500_000_000L; } + + action.digitalData.get(index).state = on; + action.digitalData.get(index).isActive = state.isActive(); + action.digitalData.get(index).isChanged = changed; + action.digitalData.get(index).activeOrigin = getOrigins(action).getFirst(); + action.digitalData.get(index).type = handedAction.action(); + action.digitalData.get(index).hand = handedAction.hand(); } } @@ -1016,45 +987,40 @@ public boolean hasCameraTracker() { return false; } - @Override - public List getOrigins(I action) { - List origins = new ArrayList<>(); + public List getOrigins(XRInputAction.HandedAction handedAction, XRInputAction action) { try (MemoryStack stack = MemoryStack.stackPush()) { - for (long handle : ((XRInputAction)action).getHandle(this.activeController)) { - XrBoundSourcesForActionEnumerateInfo info = XrBoundSourcesForActionEnumerateInfo.calloc(stack); - info.type(XR10.XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO); - info.next(NULL); - info.action(new XrAction(handle, - new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); - IntBuffer buf = stack.callocInt(1); - int error = XR10.xrEnumerateBoundSourcesForAction(this.session, info, buf, null); - logError(error, "xrEnumerateBoundSourcesForAction", action.name); - - int size = buf.get(); - if (size <= 0) { - continue; - } + XrBoundSourcesForActionEnumerateInfo info = XrBoundSourcesForActionEnumerateInfo.calloc(stack); + info.type(XR10.XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO); + info.next(NULL); + info.action(new XrAction(handedAction.handle(), + new XrActionSet(this.actionSetHandles.get(action.actionSet), this.instance))); + IntBuffer buf = stack.callocInt(1); + int error = XR10.xrEnumerateBoundSourcesForAction(this.session, info, buf, null); + logError(error, "xrEnumerateBoundSourcesForAction", action.name); - buf = stack.callocInt(size); - LongBuffer longbuf = stack.callocLong(size); - error = XR10.xrEnumerateBoundSourcesForAction(this.session, info, buf, longbuf); - logError(error, "xrEnumerateBoundSourcesForAction", action.name); - long[] array; - if (longbuf.hasArray()) { //TODO really? - array = longbuf.array(); - } else { - longbuf.rewind(); - array = new long[longbuf.remaining()]; - int index = 0; - while (longbuf.hasRemaining()) { - array[index++] = longbuf.get(); - } - } - origins.addAll(Arrays.stream(array).boxed().toList()); + int size = buf.get(); + if (size <= 0) { + return List.of(0L); } + + buf = stack.callocInt(size); + LongBuffer longbuf = stack.callocLong(size); + error = XR10.xrEnumerateBoundSourcesForAction(this.session, info, buf, longbuf); + logError(error, "xrEnumerateBoundSourcesForAction", action.name); + longbuf.rewind(); + long[] array = new long[longbuf.remaining()]; + longbuf.get(array); + return Arrays.stream(array).boxed().toList(); + } + } + + //TODO fix me! Origins needs to be done differently + @Override + public List getOrigins(I action) { + if (action instanceof XRInputAction xrAction) { + return getOrigins(xrAction.getActiveAction(this.activeController), xrAction); } - origins.add(0L); - return origins; + return List.of(0L); } @Override @@ -1168,11 +1134,10 @@ private void loadDefaultBindings() { //inputAction.actionSet = binding.actionSet(); TODO? } long handle = this.mappedBindings.get(new ActionBind(inputAction.actionSet, binding.controller())); - inputAction.addHandle(headset, handle); - inputAction.setType(ControllerMapping.quest2Bindings().get(binding.controller())); - inputAction.setHand( - binding.controller().contains("/left/") ? ControllerType.LEFT : - ControllerType.RIGHT); + ActionType type = ControllerMapping.quest2Bindings().get(binding.controller()); + inputAction.addHandle(headset, handle, binding.controller().contains("/left/") ? ControllerType.LEFT : + ControllerType.RIGHT, type); + inputAction.setType(binding.actionType()); if (inputAction.getHandle(headset).isEmpty() || handle == 0L) { VRSettings.LOGGER.error("Handle for '{}'/'{}' is null", binding.key(), binding.controller()); continue; @@ -1282,7 +1247,7 @@ public String getString(long path) { if (path == 0L) { //Quest takes some time to loas what controller is used return ""; } - return this.strings.computeIfAbsent(path, l -> { + return this.paths.inverse().computeIfAbsent(path, l -> { try (MemoryStack ignored = stackPush()) { IntBuffer size = stackCallocInt(1); int error = XR10.xrPathToString(this.instance, l, size, null); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/ControllerMapping.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/ControllerMapping.java index e6efa67aa..c17aeaa60 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/ControllerMapping.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/ControllerMapping.java @@ -20,8 +20,8 @@ public static Map quest2Bindings() { bindings.put("/user/hand/left/input/squeeze/value", ActionType.VEC1); bindings.put("/user/hand/left/input/trigger/value", ActionType.VEC1); bindings.put("/user/hand/left/input/trigger/touch", ActionType.BOOLEAN); - bindings.put("/user/hand/left/input/trigger/proximity", ActionType.BOOLEAN); - bindings.put("/user/hand/left/input/thumb_resting_surfaces/proximity", ActionType.BOOLEAN); + //bindings.put("/user/hand/left/input/trigger/proximity", ActionType.BOOLEAN); openxr 1.1 + //bindings.put("/user/hand/left/input/thumb_resting_surfaces/proximity", ActionType.BOOLEAN); openxr 1.1 bindings.put("/user/hand/left/input/thumbstick", ActionType.VEC2); bindings.put("/user/hand/left/input/thumbstick/click", ActionType.BOOLEAN); bindings.put("/user/hand/left/input/thumbstick/touch", ActionType.BOOLEAN); @@ -37,8 +37,8 @@ public static Map quest2Bindings() { bindings.put("/user/hand/right/input/squeeze/value", ActionType.VEC1); bindings.put("/user/hand/right/input/trigger/value", ActionType.VEC1); bindings.put("/user/hand/right/input/trigger/touch", ActionType.BOOLEAN); - bindings.put("/user/hand/right/input/trigger/proximity", ActionType.BOOLEAN); - bindings.put("/user/hand/right/input/thumb_resting_surfaces/proximity", ActionType.BOOLEAN); + //bindings.put("/user/hand/right/input/trigger/proximity", ActionType.BOOLEAN); openxr 1.1 + //bindings.put("/user/hand/right/input/thumb_resting_surfaces/proximity", ActionType.BOOLEAN); openxr 1.1 bindings.put("/user/hand/right/input/thumbstick", ActionType.VEC2); bindings.put("/user/hand/right/input/thumbstick/click", ActionType.BOOLEAN); bindings.put("/user/hand/right/input/thumbstick/touch", ActionType.BOOLEAN); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java index 07fd2691f..90931907f 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java @@ -53,7 +53,7 @@ private static HashSet quest2Bindings() { set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/value", ActionType.VEC1)); set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", ActionType.BOOLEAN)); set.add(new XRBinding(null, "/actions/ingame/in/key.use", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); - //set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value", ActionType.VEC1)); set.add(new XRBinding(null, "/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick/click", ActionType.BOOLEAN)); set.add( new XRBinding(null, "/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", ActionType.VEC2)); @@ -62,19 +62,19 @@ private static HashSet quest2Bindings() { set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/value", ActionType.VEC1)); - //set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze/value")); - //set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/value")); - //set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/value")); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/value", ActionType.VEC1)); - //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/value")); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/value", ActionType.VEC1)); set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/value", ActionType.VEC1)); - //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/value")); - //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/value")); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/value", ActionType.VEC1)); - //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/value")); - //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/value")); - //set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/value")); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/value", ActionType.VEC1)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/value", ActionType.VEC1)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/value", ActionType.VEC1)); set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/value", ActionType.VEC1)); return set; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java index 3bbd55b6a..da662b604 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java @@ -3,7 +3,6 @@ import net.minecraft.client.KeyMapping; import org.joml.Vector2f; import org.joml.Vector2fc; -import org.joml.Vector3fc; import org.vivecraft.client_vr.provider.control.*; import java.util.ArrayList; @@ -13,87 +12,164 @@ public class XRInputAction extends InputAction { - private ControllerType hand; - private final Map> handles = new HashMap<>(); + private final Map> handles = new HashMap<>(); + public int activeAction; - public final DigitalData[] digitalData = new DigitalData[ControllerType.values().length]; - public final AnalogData[] analogData = new AnalogData[ControllerType.values().length]; + public record HandedAction(Long handle, ControllerType hand, ActionType action) {} + + public final List digitalData = new ArrayList<>(); + public final List analogData = new ArrayList<>(); public XRInputAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { super(keyMapping, requirement, type, actionSetOverride); + this.type = null; //No global type, type is part of the for (int c = 0; c < ControllerType.values().length; c++) { this.enabled[c] = true; - this.analogData[c] = new AnalogData(); - this.digitalData[c] = new DigitalData(); } } - public ControllerType getHand() { - return hand; - } - - public void setHand(ControllerType hand) { - this.hand = hand; - } - - public List getHandle(String controller) { + public List getHandle(String controller) { return handles.getOrDefault(controller, List.of()); } - public void addHandle(String controller, Long handle) { + public void addHandle(String controller, Long handle, ControllerType hand, ActionType actionType) { if (!handles.containsKey(controller)) { - var list = new ArrayList(); - list.add(handle); + var list = new ArrayList(); + list.add(new HandedAction(handle, hand, actionType)); handles.put(controller, list); } else { - handles.get(controller).add(handle); + handles.get(controller).add(new HandedAction(handle, hand, actionType)); } + this.analogData.add(new AnalogData()); + this.digitalData.add(new DigitalData()); } - private DigitalData digitalData() { - return this.isHanded() ? this.digitalData[this.currentHand.ordinal()] : this.digitalData[0]; + private List digitalData() { + return this.digitalData; } - private AnalogData analogData() { - return this.isHanded() ? this.analogData[this.currentHand.ordinal()] : this.analogData[0]; + private List analogData() { + return this.analogData; + } + + public HandedAction getActiveAction(String[] controllers) { + return this.handles.get(controllers[this.digitalData().get(this.activeAction).hand.ordinal()]).get(this.activeAction); } @Override public boolean isActive() { - return switch (this.type) { - case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> this.digitalData().isActive; - case VEC1, VEC2 -> this.analogData().isActive; - default -> false; - }; + for (int i = 0; i < this.digitalData().size(); i++) { + switch (this.type) { + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> { + if (this.digitalData().get(i).isActive) { + this.activeAction = i; + return true; + } + } + case VEC1, VEC2 -> { + if (this.analogData().get(i).isActive) { + this.activeAction = i; + return true; + } + } + } + } + return false; } @Override public boolean isButtonPressed() { - return this.digitalData().state; + for (int i = 0; i < this.digitalData().size(); i++) { + DigitalData data = this.digitalData().get(i); + switch (data.type) { + case DOUBLE_PRESS -> { + if (data.doublePress) { + this.activeAction = i; + return true; + } + } + case LONG_PRESS -> { + if (data.longPress) { + this.activeAction = i; + return true; + } + } + case HOLD -> { + if (data.hold) { + this.activeAction = i; + return true; + } + } + case TOGGLE -> { + if (data.toggle) { + this.activeAction = i; + return true; + } + } + } + if (data.state) { + this.activeAction = i; + return true; + } + } + return false; } @Override public boolean isButtonChanged() { - return this.digitalData().isChanged; + for (int i = 0; i < this.digitalData().size(); i++) { + if (this.digitalData().get(i).isChanged) { + this.activeAction = i; + return true; + } + } + return false; } @Override public long getLastOrigin() { return switch (this.type) { - case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> this.digitalData().activeOrigin; - case VEC1, VEC2 -> this.analogData().activeOrigin; + case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> { + if (this.activeAction == 0) { + yield 0; + } + if (this.digitalData().isEmpty()) { + yield 0; + } + yield this.digitalData().get(activeAction).activeOrigin; + } + case VEC1, VEC2 -> { + if (this.activeAction == 0) { + yield 0; + } + if (this.analogData().isEmpty()) { + yield 0; + } + yield this.analogData().get(activeAction).activeOrigin; + } default -> 0L; }; } + //Multi-binds are a bit messy @Override public float getAxis1D(boolean delta) { - return switch (this.type) { - case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> this.analogData().x; - case VEC1, VEC2 -> delta ? this.analogData().deltaX : this.analogData().x; - default -> 0.0F; - }; + for (int i = 0; i < this.analogData().size(); i++) { + AnalogData data = this.analogData().get(i); + if (delta) { + if (Math.abs(data.deltaX) > 0.0f) { + this.activeAction = i; + return data.deltaX; + } + } else { + if (Math.abs(data.x) > 0.0f) { + this.activeAction = i; + return data.x; + } + } + } + return 0; } @Override @@ -107,15 +183,24 @@ public float getAxis1DUseTracked() { } } + //Multi-binds are a bit messy @Override public Vector2fc getAxis2D(boolean delta) { - return switch (this.type) { - case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> new Vector2f(this.analogData().x, 0.0F); - case VEC1 -> delta ? new Vector2f(this.analogData().deltaX, 0.0F) : new Vector2f(this.analogData().x, 0.0F); - case VEC2 -> delta ? new Vector2f(this.analogData().deltaX, this.analogData().deltaY) : - new Vector2f(this.analogData().x, this.analogData().y); - default -> new Vector2f(); - }; + for (int i = 0; i < this.analogData().size(); i++) { + AnalogData data = this.analogData().get(i); + if (delta) { + if (Math.abs(data.deltaX) > 0.0f || Math.abs(data.deltaY) > 0.0f) { + this.activeAction = i; + return new Vector2f(data.deltaX, data.deltaY); + } + } else { + if (Math.abs(data.x) > 0.0f || Math.abs(data.y) > 0.0f) { + this.activeAction = i; + return new Vector2f(data.x, data.y); + } + } + } + return new Vector2f(); } @Override @@ -143,11 +228,13 @@ public static class DigitalData { public boolean state; public boolean isChanged; public boolean isActive; - public long activeOrigin; public long lastChange; public boolean longPress; public boolean toggle; public boolean doublePress; public boolean hold; + public long activeOrigin; + public ActionType type; + public ControllerType hand; } } From b463bbaf0c5828c454696565be088b7f6d523a09 Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:38:15 +0100 Subject: [PATCH 74/76] re-enable other controllers --- .../client/gui/settings/GuiBindings.java | 6 +- .../vivecraft/client_vr/gui/GuiRadial.java | 1 - .../menuworlds/MenuWorldRenderer.java | 2 +- .../provider/control/InputAction.java | 6 +- .../control/TrackpadSwipeSampler.java | 3 +- .../client_vr/provider/nullvr/NullVR.java | 5 +- .../provider/openvr_lwjgl/MCOpenVR.java | 6 +- .../control/VRInputAction.java | 19 +- .../client_vr/provider/openxr/MCOpenXR.java | 34 +- .../openxr/control/ControllerMapping.java | 178 +++++++- .../provider/openxr/control/XRBinding.java | 388 +++++++++--------- .../openxr/control/XRInputAction.java | 44 +- .../client_vr/settings/VRSettings.java | 2 +- .../mixin/client_vr/MinecraftVRMixin.java | 1 - 14 files changed, 433 insertions(+), 262 deletions(-) rename common/src/main/java/org/vivecraft/client_vr/provider/{ => openvr_lwjgl}/control/VRInputAction.java (92%) diff --git a/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java b/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java index a89b4a9b3..f88b9a63e 100644 --- a/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java +++ b/common/src/main/java/org/vivecraft/client/gui/settings/GuiBindings.java @@ -12,7 +12,7 @@ import org.vivecraft.client.gui.framework.screens.GuiListScreen; import org.vivecraft.client.gui.framework.widgets.SettingsList; import org.vivecraft.client_vr.provider.control.ActionType; -import org.vivecraft.client_vr.provider.control.VRInputAction; +import org.vivecraft.client_vr.provider.control.InputAction; import org.vivecraft.client_vr.provider.openxr.MCOpenXR; import java.util.LinkedList; @@ -44,7 +44,7 @@ public static class ResettableEntry extends SettingsList.WidgetEntry { private final Button resetButton; private final BooleanSupplier canReset; - public ResettableEntry(Component name, VRInputAction action) { + public ResettableEntry(Component name, InputAction action) { super(name, getBaseWidget(action, VALUE_BUTTON_WIDTH, 20).get()); this.canReset = () -> action.type != ActionType.BOOLEAN; @@ -84,7 +84,7 @@ public void setActive(boolean active) { } } - public static Supplier getBaseWidget(VRInputAction action, int width, int height) { + public static Supplier getBaseWidget(InputAction action, int width, int height) { return () -> Button .builder(Component.literal("" + action.type), button -> {}) .bounds(0, 0, width, height) diff --git a/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java b/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java index b2f843c80..95d885620 100644 --- a/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java +++ b/common/src/main/java/org/vivecraft/client_vr/gui/GuiRadial.java @@ -10,7 +10,6 @@ import org.vivecraft.client_vr.MethodHolder; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.control.InputAction; -import org.vivecraft.client_vr.provider.control.VRInputAction; import java.util.Arrays; diff --git a/common/src/main/java/org/vivecraft/client_vr/menuworlds/MenuWorldRenderer.java b/common/src/main/java/org/vivecraft/client_vr/menuworlds/MenuWorldRenderer.java index 8bd5ff127..93a4feb9a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/menuworlds/MenuWorldRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/menuworlds/MenuWorldRenderer.java @@ -67,8 +67,8 @@ import java.io.InputStream; import java.lang.Math; import java.nio.ByteBuffer; -import java.util.*; import java.util.Random; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/InputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/InputAction.java index f444f32f9..c1c4a9a03 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/InputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/InputAction.java @@ -23,7 +23,7 @@ public class InputAction { public final VRInputActionSet actionSet; protected int priority = 0; - protected final List listeners = new ArrayList<>(); + protected final List listeners = new ArrayList<>(); protected ControllerType currentHand = ControllerType.RIGHT; // Only used for the UseTracked axis methods protected boolean currentlyInUse; @@ -66,7 +66,7 @@ public void setCurrentHand(ControllerType currentHand) { } /** - * check if the InputAction is enabled, if it is handed, checks for {@link VRInputAction#currentHand}
+ * check if the InputAction is enabled, if it is handed, checks for {@link InputAction#currentHand}
* also checks if any other InputAction with higher priority is active, then this InputAction is treated as disabled */ public boolean isEnabled() { @@ -368,7 +368,7 @@ public boolean notifyListeners(boolean pressed, ControllerType hand) { } /** - * @return the last origin the vr runtime sent, if the VRInputAction is not currently in an active set this is likely 0 + * @return the last origin the vr runtime sent, if the InputAction is not currently in an active set this is likely 0 */ public long getLastOrigin() { return 0; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java index bb99e3ec2..96c13957e 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/TrackpadSwipeSampler.java @@ -4,7 +4,6 @@ import org.joml.Vector2fc; import org.vivecraft.client.VivecraftVRMod; import org.vivecraft.client_vr.provider.openvr_lwjgl.MCOpenVR; -import org.vivecraft.client_vr.provider.openxr.control.XRInputAction; public class TrackpadSwipeSampler { private static final int UP = 0; @@ -26,7 +25,7 @@ public TrackpadSwipeSampler() { } public void update(ControllerType hand, Vector2fc position) { - VRInputAction trackpad = MCOpenVR.get().getInputAction(VivecraftVRMod.INSTANCE.keyTrackpadTouch); + InputAction trackpad = MCOpenVR.get().getInputAction(VivecraftVRMod.INSTANCE.keyTrackpadTouch); trackpad.setCurrentHand(hand); if (trackpad.isButtonPressed()) { 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 a1283d8c7..4aac635c3 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 @@ -17,7 +17,10 @@ import org.vivecraft.client_vr.provider.DeviceSource; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.VRRenderer; -import org.vivecraft.client_vr.provider.control.*; +import org.vivecraft.client_vr.provider.control.ActionType; +import org.vivecraft.client_vr.provider.control.ControllerType; +import org.vivecraft.client_vr.provider.control.InputAction; +import org.vivecraft.client_vr.provider.control.VRInputActionSet; import org.vivecraft.client_vr.render.MirrorNotification; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.common.utils.MathUtils; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index 06e97459e..c7549aa7a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -28,7 +28,11 @@ import org.vivecraft.client_vr.gameplay.screenhandlers.KeyboardHandler; import org.vivecraft.client_vr.gameplay.screenhandlers.RadialHandler; import org.vivecraft.client_vr.provider.*; -import org.vivecraft.client_vr.provider.control.*; +import org.vivecraft.client_vr.provider.control.ActionType; +import org.vivecraft.client_vr.provider.control.ControllerType; +import org.vivecraft.client_vr.provider.control.InputAction; +import org.vivecraft.client_vr.provider.control.VRInputActionSet; +import org.vivecraft.client_vr.provider.openvr_lwjgl.control.VRInputAction; import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.settings.VRSettings; import org.vivecraft.client_vr.utils.external.jinfinadeck; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VRInputAction.java similarity index 92% rename from common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java rename to common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VRInputAction.java index 3ee93f981..cf10970dd 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/VRInputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VRInputAction.java @@ -1,21 +1,14 @@ -package org.vivecraft.client_vr.provider.control; +package org.vivecraft.client_vr.provider.openvr_lwjgl.control; -import com.mojang.blaze3d.platform.InputConstants; import net.minecraft.client.KeyMapping; import org.joml.Vector2f; import org.joml.Vector2fc; import org.joml.Vector3f; import org.joml.Vector3fc; -import org.vivecraft.Xplat; -import org.vivecraft.client.VivecraftVRMod; -import org.vivecraft.client_vr.ClientDataHolderVR; -import org.vivecraft.client_vr.provider.InputSimulator; - -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; +import org.vivecraft.client_vr.provider.control.ActionType; +import org.vivecraft.client_vr.provider.control.ControllerType; +import org.vivecraft.client_vr.provider.control.InputAction; +import org.vivecraft.client_vr.provider.control.VRInputActionSet; public class VRInputAction extends InputAction { @@ -24,7 +17,7 @@ public class VRInputAction extends InputAction { public final AnalogData[] analogData = new AnalogData[ControllerType.values().length]; public VRInputAction( - KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) + KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { super(keyMapping, requirement, type, actionSetOverride); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index 5ae5579ab..fe535d951 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -32,7 +32,10 @@ import org.vivecraft.client_vr.provider.openxr.control.XRInputAction; import org.vivecraft.client_vr.settings.VRSettings; -import java.nio.*; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.LongBuffer; import java.util.*; import static org.lwjgl.system.MemoryStack.*; @@ -1014,11 +1017,13 @@ public List getOrigins(XRInputAction.HandedAction handedAction, XRInputAct } } - //TODO fix me! Origins needs to be done differently @Override public List getOrigins(I action) { if (action instanceof XRInputAction xrAction) { - return getOrigins(xrAction.getActiveAction(this.activeController), xrAction); + var handedAction = xrAction.getActiveAction(this.activeController); + if (handedAction != null) { + return getOrigins(handedAction, xrAction); + } } return List.of(0L); } @@ -1085,12 +1090,13 @@ private void loadActionHandles() { long actionSet = makeActionSet(this.instance, vrinputactionset.name, vrinputactionset.localizedName, 0); this.actionSetHandles.put(vrinputactionset, actionSet); - //TODO select the proper headset - for (var binding : ControllerMapping.quest2Bindings().entrySet()) { - long action = createAction(binding.getKey().replace("/", "."), binding.getKey(), binding.getValue(), - new XrActionSet(actionSet, this.instance), - binding.getKey().contains("left") ? BOTH_HANDS[0] : BOTH_HANDS[1]); - this.mappedBindings.put(new ActionBind(vrinputactionset, binding.getKey()), action); + for (String headset: XRBinding.supportedHeadsets()) { + for (var binding : ControllerMapping.getMapping(headset).entrySet()) { + long action = createAction((binding.getKey()+ "." + headset.replace("/interaction_profiles/","")).replace("/", ".") , binding.getKey(), binding.getValue(), + new XrActionSet(actionSet, this.instance), + binding.getKey().contains("left") ? BOTH_HANDS[0] : BOTH_HANDS[1]); + this.mappedBindings.put(new ActionBind(vrinputactionset, binding.getKey()), action); + } } } @@ -1120,9 +1126,9 @@ private void loadDefaultBindings() { int error; for (String headset : XRBinding.supportedHeadsets()) { VRSettings.LOGGER.info("loading defaults for {}", headset); - if (!"/interaction_profiles/oculus/touch_controller".equals(headset)) { - continue; - } +// if (!"/interaction_profiles/oculus/touch_controller".equals(headset)) { +// continue; +// } XRBinding[] defaultBindings = XRBinding.getBinding(headset).toArray(new XRBinding[0]); XrActionSuggestedBinding.Buffer bindings = XrActionSuggestedBinding.calloc(defaultBindings.length + 6, stack); //TODO different way of adding controller poses @@ -1131,10 +1137,10 @@ private void loadDefaultBindings() { XRBinding binding = defaultBindings[i]; XRInputAction inputAction = this.getInputActionByName(binding.key()); if (binding.actionSet() != null) { - //inputAction.actionSet = binding.actionSet(); TODO? + //inputAction.actionSet = binding.actionSet(); //TODO? } long handle = this.mappedBindings.get(new ActionBind(inputAction.actionSet, binding.controller())); - ActionType type = ControllerMapping.quest2Bindings().get(binding.controller()); + ActionType type = ControllerMapping.getMapping(headset).get(binding.controller()); inputAction.addHandle(headset, handle, binding.controller().contains("/left/") ? ControllerType.LEFT : ControllerType.RIGHT, type); inputAction.setType(binding.actionType()); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/ControllerMapping.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/ControllerMapping.java index c17aeaa60..3cb9486a8 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/ControllerMapping.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/ControllerMapping.java @@ -2,9 +2,7 @@ import org.vivecraft.client_vr.provider.control.ActionType; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; public class ControllerMapping { @@ -47,4 +45,180 @@ public static Map quest2Bindings() { bindings.put("/user/hand/right/input/thumbrest/touch", ActionType.BOOLEAN); return bindings; } + + public static Map cosmosBindings() { + Map bindings = new HashMap<>(); + bindings.put("/user/hand/left/input/y/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/x/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/menu/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/squeeze/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/trigger/value", ActionType.VEC1); + bindings.put("/user/hand/left/input/trigger/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/thumbstick", ActionType.VEC2); + bindings.put("/user/hand/left/input/thumbstick/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/thumbstick/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/thumbstick/y", ActionType.VEC1); + bindings.put("/user/hand/left/input/thumbstick/x", ActionType.VEC1); + bindings.put("/user/hand/left/input/shoulder/click", ActionType.BOOLEAN); + + bindings.put("/user/hand/right/input/a/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/b/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/system/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/squeeze/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/trigger/value", ActionType.VEC1); + bindings.put("/user/hand/right/input/trigger/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/thumbstick", ActionType.VEC2); + bindings.put("/user/hand/right/input/thumbstick/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/thumbstick/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/thumbstick/y", ActionType.VEC1); + bindings.put("/user/hand/right/input/thumbstick/x", ActionType.VEC1); + bindings.put("/user/hand/right/input/shoulder/click", ActionType.BOOLEAN); + return bindings; + } + + public static Map viveBindings() { + Map bindings = new HashMap<>(); + bindings.put("/user/hand/left/input/menu/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/system/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/trigger/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/trigger/value", ActionType.VEC1); + bindings.put("/user/hand/left/input/trackpad", ActionType.VEC2); + bindings.put("/user/hand/left/input/trackpad/x", ActionType.VEC1); + bindings.put("/user/hand/left/input/trackpad/y", ActionType.VEC1); + bindings.put("/user/hand/left/input/trackpad/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/trackpad/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/squeeze/click", ActionType.BOOLEAN); + + bindings.put("/user/hand/right/input/menu/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/system/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/trigger/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/trigger/value", ActionType.VEC1); + bindings.put("/user/hand/right/input/trackpad", ActionType.VEC2); + bindings.put("/user/hand/right/input/trackpad/x", ActionType.VEC1); + bindings.put("/user/hand/right/input/trackpad/y", ActionType.VEC1); + bindings.put("/user/hand/right/input/trackpad/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/trackpad/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/squeeze/click", ActionType.BOOLEAN); + return bindings; + } + + public static Map indexBindings() { + Map bindings = new HashMap<>(); + bindings.put("/user/hand/left/input/a/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/a/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/b/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/b/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/system/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/system/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/trigger/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/trigger/value", ActionType.VEC1); + bindings.put("/user/hand/left/input/trigger/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/thumbstick", ActionType.VEC2); + bindings.put("/user/hand/left/input/thumbstick/x", ActionType.VEC1); + bindings.put("/user/hand/left/input/thumbstick/y", ActionType.VEC1); + bindings.put("/user/hand/left/input/thumbstick/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/thumbstick/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/trackpad", ActionType.VEC2); + bindings.put("/user/hand/left/input/trackpad/x", ActionType.VEC1); + bindings.put("/user/hand/left/input/trackpad/y", ActionType.VEC1); + bindings.put("/user/hand/left/input/trackpad/force", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/trackpad/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/squeeze/force", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/squeeze/value", ActionType.VEC1); + + bindings.put("/user/hand/right/input/a/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/a/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/b/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/b/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/system/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/system/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/trigger/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/trigger/value", ActionType.VEC1); + bindings.put("/user/hand/right/input/trigger/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/thumbstick", ActionType.VEC2); + bindings.put("/user/hand/right/input/thumbstick/x", ActionType.VEC1); + bindings.put("/user/hand/right/input/thumbstick/y", ActionType.VEC1); + bindings.put("/user/hand/right/input/thumbstick/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/thumbstick/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/trackpad", ActionType.VEC2); + bindings.put("/user/hand/right/input/trackpad/x", ActionType.VEC1); + bindings.put("/user/hand/right/input/trackpad/y", ActionType.VEC1); + bindings.put("/user/hand/right/input/trackpad/force", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/trackpad/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/squeeze/force", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/squeeze/value", ActionType.VEC1); + return bindings; + } + + public static Map picoBindings() { + Map bindings = new HashMap<>(); + bindings.put("/user/hand/left/input/x/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/x/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/y/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/y/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/menu/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/system/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/trigger/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/trigger/value", ActionType.VEC1); + bindings.put("/user/hand/left/input/trigger/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/thumbstick", ActionType.VEC2); + bindings.put("/user/hand/left/input/thumbstick/x", ActionType.VEC1); + bindings.put("/user/hand/left/input/thumbstick/y", ActionType.VEC1); + bindings.put("/user/hand/left/input/thumbstick/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/thumbstick/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/squeeze/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/squeeze/value", ActionType.VEC1); + + bindings.put("/user/hand/right/input/a/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/a/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/b/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/b/touch", ActionType.BOOLEAN); + //bindings.put("/user/hand/right/input/menu/click", ActionType.BOOLEAN); //not present on pico4, is present on neo3 + bindings.put("/user/hand/right/input/system/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/trigger/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/trigger/value", ActionType.VEC1); + bindings.put("/user/hand/right/input/trigger/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/thumbstick", ActionType.VEC2); + bindings.put("/user/hand/right/input/thumbstick/x", ActionType.VEC1); + bindings.put("/user/hand/right/input/thumbstick/y", ActionType.VEC1); + bindings.put("/user/hand/right/input/thumbstick/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/thumbstick/touch", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/squeeze/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/squeeze/value", ActionType.VEC1); + return bindings; + } + + public static Map defaultBindings() { + Map bindings = new HashMap<>(); + bindings.put("/user/hand/left/input/menu/click", ActionType.BOOLEAN); + bindings.put("/user/hand/left/input/select/click", ActionType.BOOLEAN); + + bindings.put("/user/hand/right/input/menu/click", ActionType.BOOLEAN); + bindings.put("/user/hand/right/input/select/click", ActionType.BOOLEAN); + return bindings; + } + + public static Map getMapping(String Headset) { + switch (Headset) { + case "/interaction_profiles/htc/vive_cosmos_controller" -> { + return cosmosBindings(); + } + case "/interaction_profiles/htc/vive_controller" -> { + return viveBindings(); + } + case "/interaction_profiles/valve/index_controller" -> { + return indexBindings(); + } + case "/interaction_profiles/oculus/touch_controller" -> { + return quest2Bindings(); + } + case "/interaction_profiles/bytedance/pico4_controller", + "/interaction_profiles/bytedance/pico_neo3_controller" -> { + return picoBindings(); + } + default -> { + return defaultBindings(); + } + } + } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java index 90931907f..9dd05794e 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java @@ -1,7 +1,5 @@ package org.vivecraft.client_vr.provider.openxr.control; -import org.apache.commons.lang3.tuple.MutablePair; -import org.apache.commons.lang3.tuple.Pair; import org.jetbrains.annotations.Nullable; import org.vivecraft.client_vr.provider.control.ActionType; import org.vivecraft.client_vr.provider.control.VRInputActionSet; @@ -80,234 +78,232 @@ private static HashSet quest2Bindings() { return set; } - private static HashSet> viveBindings() { - HashSet> set = new HashSet<>(); + private static HashSet viveBindings() { + HashSet set = new HashSet<>(); set.add( - new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click")); - set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/right/input/trackpad/click")); + new XRBinding(null,"/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/global/in/key.inventory", "/user/hand/right/input/trackpad/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click")); + set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click")); + new XRBinding(null,"/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); + new XRBinding(null,"/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/trackpad/y")); + new XRBinding(null,"/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/trackpad/y", ActionType.VEC1)); set.add( - new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click")); + new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click")); - set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/menu/click")); - set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/trackpad/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", - "/user/hand/left/input/trigger/value")); - set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/trackpad/x")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/trackpad")); - set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/left/input/trackpad/y")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/trackpad")); + new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/menu/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/key.use", "/user/hand/right/input/trackpad/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleportFallback", + "/user/hand/left/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null,"/actions/ingame/in/key.jump", "/user/hand/left/input/trackpad/x", ActionType.VEC1)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/trackpad", ActionType.VEC2)); + set.add(new XRBinding(null,"/actions/ingame/in/key.sneak", "/user/hand/left/input/trackpad/y", ActionType.VEC1)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/trackpad", ActionType.VEC2)); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", - "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", - "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", - "/user/hand/right/input/trigger/click")); + set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardShift", + "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/technical/in/vivecraft.key.trackpadTouch", - "/user/hand/left/input/trackpad/click")); - set.add(new MutablePair<>("/actions/technical/in/vivecraft.key.trackpadTouch", - "/user/hand/right/input/trackpad/touch")); + set.add(new XRBinding(null,"/actions/technical/in/vivecraft.key.trackpadTouch", + "/user/hand/left/input/trackpad/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/technical/in/vivecraft.key.trackpadTouch", + "/user/hand/right/input/trackpad/touch", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/right/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/right/input/trigger/click")); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/right/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/right/input/trigger/click")); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); return set; } - private static HashSet> cosmosBindings() { - HashSet> set = new HashSet<>(); - - set.add( - new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); - set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); - - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click")); - set.add( - new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click")); - set.add( - new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick")); - - set.add( - new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click")); - set.add( - new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click")); - set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); - set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/a/click")); - set.add( - new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", - "/user/hand/left/input/trigger/value")); - set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/shoulder/click")); - set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/shoulder/click")); - - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", - "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", - "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", - "/user/hand/right/input/trigger/click")); - - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/right/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/right/input/trigger/click")); - - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/left/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/right/input/squeeze/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/right/input/trigger/click")); + private static HashSet cosmosBindings() { + HashSet set = new HashSet<>(); + + set.add( + new XRBinding(null, "/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/global/in/key.inventory", "/user/hand/left/input/x/click", ActionType.BOOLEAN)); + + set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add( + new XRBinding(null,"/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add( + new XRBinding(null,"/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick", ActionType.VEC2)); + + set.add( + new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add( + new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/key.use", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); + set.add( + new XRBinding(null,"/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", ActionType.VEC2)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick", ActionType.VEC2)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleportFallback", + "/user/hand/left/input/trigger/value", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/key.jump", "/user/hand/left/input/shoulder/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/key.sneak", "/user/hand/right/input/shoulder/click", ActionType.BOOLEAN)); + + set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardShift", + "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); + + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); + + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); return set; } - private static HashSet> picoBindings() { - HashSet> set = new HashSet<>(); + private static HashSet picoBindings() { + HashSet set = new HashSet<>(); set.add( - new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click")); - set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/x/click")); + new XRBinding(null,"/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/global/in/key.inventory", "/user/hand/left/input/x/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze")); + set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click")); + new XRBinding(null,"/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); + new XRBinding(null,"/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y", ActionType.VEC1)); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); - set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/a/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", - "/user/hand/left/input/trigger/value")); - set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick")); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/key.use", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleportFallback", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick/click", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); - set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); + new XRBinding(null,"/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", ActionType.VEC2)); + set.add(new XRBinding(null,"/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick", ActionType.VEC2)); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze")); + set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", - "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", - "/user/hand/right/input/trigger/click")); + new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/right/input/trigger/click")); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze")); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/right/input/trigger/click")); + new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); return set; } - private static HashSet> indexBindings() { - HashSet> set = new HashSet<>(); + private static HashSet indexBindings() { + HashSet set = new HashSet<>(); set.add( - new MutablePair<>("/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/b/click")); - set.add(new MutablePair<>("/actions/global/in/key.inventory", "/user/hand/left/input/a/click")); + new XRBinding(null,"/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/b/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/global/in/key.inventory", "/user/hand/left/input/a/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze")); + set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad")); + new XRBinding(null,"/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y")); - set.add(new MutablePair<>("/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/trackpad/y")); + new XRBinding(null,"/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y", ActionType.VEC1)); + set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/trackpad/y", ActionType.VEC1)); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click")); - set.add(new MutablePair<>("/actions/ingame/in/key.use", "/user/hand/right/input/trackpad")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.teleportFallback", - "/user/hand/left/input/trigger/value")); - set.add(new MutablePair<>("/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick")); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/key.use", "/user/hand/right/input/trackpad", ActionType.VEC2)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleportFallback", + "/user/hand/left/input/trigger/value", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick", ActionType.VEC2)); set.add( - new MutablePair<>("/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick")); - set.add(new MutablePair<>("/actions/ingame/in/key.sneak", "/user/hand/right/input/a/click")); - set.add(new MutablePair<>("/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick")); + new XRBinding(null,"/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", ActionType.VEC2)); + set.add(new XRBinding(null,"/actions/ingame/in/key.sneak", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick", ActionType.VEC2)); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze")); + set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", - "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/keyboard/in/vivecraft.key.keyboardClick", - "/user/hand/right/input/trigger/click")); + new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.vrInteract", - "/user/hand/right/input/trigger/click")); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze")); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); set.add( - new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/left/input/trigger/click")); - set.add(new MutablePair<>("/actions/contextual/in/vivecraft.key.climbeyGrab", - "/user/hand/right/input/trigger/click")); + new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); return set; } @@ -343,22 +339,22 @@ private static HashSet defaultBindings() { public static HashSet getBinding(String Headset) { switch (Headset) { -// case "/interaction_profiles/htc/vive_cosmos_controller" -> { -// return cosmosBindings(); -// } -// case "/interaction_profiles/htc/vive_controller" -> { -// return viveBindings(); -// } -// case "/interaction_profiles/valve/index_controller" -> { -// return indexBindings(); -// } + case "/interaction_profiles/htc/vive_cosmos_controller" -> { + return cosmosBindings(); + } + case "/interaction_profiles/htc/vive_controller" -> { + return viveBindings(); + } + case "/interaction_profiles/valve/index_controller" -> { + return indexBindings(); + } case "/interaction_profiles/oculus/touch_controller" -> { return quest2Bindings(); } -// case "/interaction_profiles/bytedance/pico4_controller", -// "/interaction_profiles/bytedance/pico_neo3_controller" -> { -// return picoBindings(); -// } + case "/interaction_profiles/bytedance/pico4_controller", + "/interaction_profiles/bytedance/pico_neo3_controller" -> { + return picoBindings(); + } default -> { return defaultBindings(); } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java index da662b604..49579b79a 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java @@ -1,9 +1,13 @@ package org.vivecraft.client_vr.provider.openxr.control; import net.minecraft.client.KeyMapping; +import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; import org.joml.Vector2fc; -import org.vivecraft.client_vr.provider.control.*; +import org.vivecraft.client_vr.provider.control.ActionType; +import org.vivecraft.client_vr.provider.control.ControllerType; +import org.vivecraft.client_vr.provider.control.InputAction; +import org.vivecraft.client_vr.provider.control.VRInputActionSet; import java.util.ArrayList; import java.util.HashMap; @@ -53,14 +57,22 @@ private List analogData() { return this.analogData; } + @Nullable public HandedAction getActiveAction(String[] controllers) { + if (this.activeAction == 0) { + return null; + } return this.handles.get(controllers[this.digitalData().get(this.activeAction).hand.ordinal()]).get(this.activeAction); } @Override public boolean isActive() { for (int i = 0; i < this.digitalData().size(); i++) { - switch (this.type) { + DigitalData data = this.digitalData().get(i); + if (data.type == null) { + continue; + } + switch (data.type) { case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> { if (this.digitalData().get(i).isActive) { this.activeAction = i; @@ -82,6 +94,9 @@ public boolean isActive() { public boolean isButtonPressed() { for (int i = 0; i < this.digitalData().size(); i++) { DigitalData data = this.digitalData().get(i); + if (data.type == null) { + continue; + } switch (data.type) { case DOUBLE_PRESS -> { if (data.doublePress) { @@ -129,27 +144,10 @@ public boolean isButtonChanged() { @Override public long getLastOrigin() { - return switch (this.type) { - case BOOLEAN, DOUBLE_PRESS, LONG_PRESS, HOLD, TOGGLE -> { - if (this.activeAction == 0) { - yield 0; - } - if (this.digitalData().isEmpty()) { - yield 0; - } - yield this.digitalData().get(activeAction).activeOrigin; - } - case VEC1, VEC2 -> { - if (this.activeAction == 0) { - yield 0; - } - if (this.analogData().isEmpty()) { - yield 0; - } - yield this.analogData().get(activeAction).activeOrigin; - } - default -> 0L; - }; + if(this.activeAction == 0) { + return 0; + } + return digitalData().get(this.activeAction).activeOrigin; } //Multi-binds are a bit messy 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 5493fe83f..79e233b18 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 @@ -49,8 +49,8 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; -import java.util.*; import java.util.List; +import java.util.*; import java.util.function.BooleanSupplier; import java.util.function.Function; import java.util.function.Supplier; 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 f094e3bdd..b1c70eb07 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 @@ -71,7 +71,6 @@ import org.vivecraft.client_vr.menuworlds.MenuWorldExporter; import org.vivecraft.client_vr.provider.MCVR; import org.vivecraft.client_vr.provider.control.InputAction; -import org.vivecraft.client_vr.provider.control.VRInputAction; import org.vivecraft.client_vr.render.MirrorNotification; import org.vivecraft.client_vr.render.RenderConfigException; import org.vivecraft.client_vr.render.VRFirstPersonArmSwing; From 2599010d722af1e5ea14487ae194b08f0cbb65ee Mon Sep 17 00:00:00 2001 From: ferriarnus <61201275+ferriarnus@users.noreply.github.com> Date: Sun, 23 Nov 2025 02:33:21 +0100 Subject: [PATCH 75/76] add steam names to ActionType for the manifest --- .../provider/control/ActionType.java | 28 +++++++++++++------ .../provider/openvr_lwjgl/MCOpenVR.java | 2 +- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/control/ActionType.java b/common/src/main/java/org/vivecraft/client_vr/provider/control/ActionType.java index b20488ab8..6041925db 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/control/ActionType.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/control/ActionType.java @@ -1,13 +1,23 @@ package org.vivecraft.client_vr.provider.control; public enum ActionType { - BOOLEAN, - DOUBLE_PRESS, - LONG_PRESS, - HOLD, - TOGGLE, - VEC1, - VEC2, - POSE, - HAPTIC + BOOLEAN("boolean"), + DOUBLE_PRESS("boolean"), + LONG_PRESS("boolean"), + HOLD("boolean"), + TOGGLE("boolean"), + VEC1("vector1"), + VEC2("vector2"), + POSE("pose"), + HAPTIC("vibration"); + + final String steamName; + + ActionType(String steamName) { + this.steamName = steamName; + } + + public String getSteamName() { + return steamName; + } } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index c7549aa7a..7ce11154e 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -566,7 +566,7 @@ private void generateActionManifest() { for (VRInputAction action : sortedActions) { actions.add( ImmutableMap.builder().put("name", action.name).put("requirement", action.requirement) - .put("type", action.type).build()); + .put("type", action.type.getSteamName()).build()); } // controller poses From 99106527add54b1252795b3ac6d6eec2fcca27a8 Mon Sep 17 00:00:00 2001 From: fayer3 Date: Sun, 23 Nov 2025 15:25:19 +0100 Subject: [PATCH 76/76] formatting --- .../menuworlds/MenuWorldRenderer.java | 2 +- .../vivecraft/client_vr/provider/MCVR.java | 3 +- .../client_vr/provider/nullvr/NullVR.java | 4 +- .../provider/openvr_lwjgl/MCOpenVR.java | 7 +- .../openvr_lwjgl/control/VRInputAction.java | 2 +- .../client_vr/provider/openxr/MCOpenXR.java | 43 +- .../provider/openxr/control/XRBinding.java | 426 +++++++++++------- .../openxr/control/XRInputAction.java | 9 +- .../client_vr/settings/VRSettings.java | 2 +- 9 files changed, 320 insertions(+), 178 deletions(-) diff --git a/common/src/main/java/org/vivecraft/client_vr/menuworlds/MenuWorldRenderer.java b/common/src/main/java/org/vivecraft/client_vr/menuworlds/MenuWorldRenderer.java index 93a4feb9a..8bd5ff127 100644 --- a/common/src/main/java/org/vivecraft/client_vr/menuworlds/MenuWorldRenderer.java +++ b/common/src/main/java/org/vivecraft/client_vr/menuworlds/MenuWorldRenderer.java @@ -67,8 +67,8 @@ import java.io.InputStream; import java.lang.Math; import java.nio.ByteBuffer; -import java.util.Random; import java.util.*; +import java.util.Random; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java index c6596e992..71023baa9 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/MCVR.java @@ -1174,7 +1174,8 @@ public void processBindings() { } } - public abstract T createAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride); + public abstract T createAction( + KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride); /** * creates VRInputActions for all registered keyMappings, should be called in {@link #init} 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 4aac635c3..9c5ab5d6f 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 @@ -92,7 +92,9 @@ public void destroy() { } @Override - public InputAction createAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { + public InputAction createAction( + KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) + { return new InputAction(keyMapping, requirement, type, actionSetOverride); } diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java index 7ce11154e..c278063c6 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/MCOpenVR.java @@ -267,7 +267,9 @@ public void destroy() { } @Override - public VRInputAction createAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { + public VRInputAction createAction( + KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) + { return new VRInputAction(keyMapping, requirement, type, actionSetOverride); } @@ -1679,7 +1681,8 @@ public List getOrigins(I action) { if (OpenVR.VRInput != null) { try (MemoryStack stack = MemoryStack.stackPush()) { LongBuffer longRef = stack.callocLong(16); - int error = VRInput_GetActionOrigins(this.getActionSetHandle(action.actionSet), ((VRInputAction)action).handle, longRef); + int error = VRInput_GetActionOrigins(this.getActionSetHandle(action.actionSet), + ((VRInputAction) action).handle, longRef); if (error != 0) { throw new RuntimeException( diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VRInputAction.java index cf10970dd..6ea9c698e 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VRInputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openvr_lwjgl/control/VRInputAction.java @@ -17,7 +17,7 @@ public class VRInputAction extends InputAction { public final AnalogData[] analogData = new AnalogData[ControllerType.values().length]; public VRInputAction( - KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) + KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { super(keyMapping, requirement, type, actionSetOverride); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java index fe535d951..6cff951be 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/MCOpenXR.java @@ -125,7 +125,9 @@ public void destroy() { } @Override - public XRInputAction createAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { + public XRInputAction createAction( + KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) + { return new XRInputAction(keyMapping, requirement, type, actionSetOverride); } @@ -137,7 +139,8 @@ protected ControllerType findActiveBindingControllerType(KeyMapping keyMapping) } else { var action = this.getInputAction(keyMapping); for (ControllerType controllerType : ControllerType.values()) { - var handedaction = action.getHandle(this.activeController[controllerType.ordinal()]).get(action.activeAction); + var handedaction = action.getHandle(this.activeController[controllerType.ordinal()]) + .get(action.activeAction); if (handedaction.hand() != controllerType) { continue; } @@ -367,19 +370,21 @@ private void readBoolean(XRInputAction action, ControllerType hand, int index) { } action.digitalData.get(index).lastChange = System.nanoTime(); } else if (state.currentState()) { - action.digitalData.get(index).hold = System.nanoTime() - action.digitalData.get(index).lastChange > 500_000_000L; + action.digitalData.get(index).hold = + System.nanoTime() - action.digitalData.get(index).lastChange > 500_000_000L; } action.digitalData.get(index).state = state.currentState(); action.digitalData.get(index).isActive = state.isActive(); action.digitalData.get(index).isChanged = state.changedSinceLastSync(); - action.digitalData.get(index).activeOrigin = getOrigins(handedAction,action).getFirst(); + action.digitalData.get(index).activeOrigin = getOrigins(handedAction, action).getFirst(); action.digitalData.get(index).type = handedAction.action(); action.digitalData.get(index).hand = handedAction.hand(); - action.analogData.get(index).deltaX = state.changedSinceLastSync() ? state.currentState() ? 1.0F : -1.0F : 0.0F; + action.analogData.get(index).deltaX = + state.changedSinceLastSync() ? state.currentState() ? 1.0F : -1.0F : 0.0F; action.analogData.get(index).x = state.currentState() ? 1.0f : 0.0f; - action.analogData.get(index).activeOrigin = getOrigins(handedAction,action).getFirst(); + action.analogData.get(index).activeOrigin = getOrigins(handedAction, action).getFirst(); action.analogData.get(index).isActive = state.isActive(); action.analogData.get(index).isChanged = state.changedSinceLastSync(); } @@ -407,7 +412,8 @@ private void readFloat(XRInputAction action, ControllerType hand, int index) { //Write digital data boolean on = Math.abs(state.currentState()) > 0.5F; - boolean changed = Math.abs(action.analogData.get(index).x - action.analogData.get(index).deltaX) > 0.5F != on; + boolean changed = + Math.abs(action.analogData.get(index).x - action.analogData.get(index).deltaX) > 0.5F != on; if (changed) { if (on) { action.digitalData.get(index).toggle = !action.digitalData.get(index).toggle; @@ -419,7 +425,8 @@ private void readFloat(XRInputAction action, ControllerType hand, int index) { } action.digitalData.get(index).lastChange = System.nanoTime(); } else if (on) { - action.digitalData.get(index).hold = System.nanoTime() - action.digitalData.get(index).lastChange > 500_000_000L; + action.digitalData.get(index).hold = + System.nanoTime() - action.digitalData.get(index).lastChange > 500_000_000L; } action.digitalData.get(index).state = on; @@ -455,8 +462,10 @@ private void readVecData(XRInputAction action, ControllerType hand, int index) { //Write digital data boolean on = Math.abs(state.currentState().x()) > 0.5F || Math.abs(state.currentState().y()) > 0.5F; - boolean changed = Math.abs(action.analogData.get(index).x - action.analogData.get(index).deltaX) > 0.5F != Math.abs(action.analogData.get(index).x) > 0.5F || - Math.abs(action.analogData.get(index).y - action.analogData.get(index).deltaY) > 0.5F != Math.abs(action.analogData.get(index).y) > 0.5F; + boolean changed = Math.abs(action.analogData.get(index).x - action.analogData.get(index).deltaX) > 0.5F != + Math.abs(action.analogData.get(index).x) > 0.5F || + Math.abs(action.analogData.get(index).y - action.analogData.get(index).deltaY) > 0.5F != + Math.abs(action.analogData.get(index).y) > 0.5F; if (changed) { if (on) { action.digitalData.get(index).toggle = !action.digitalData.get(index).toggle; @@ -468,7 +477,8 @@ private void readVecData(XRInputAction action, ControllerType hand, int index) { } action.digitalData.get(index).lastChange = System.nanoTime(); } else if (on) { - action.digitalData.get(index).hold = System.nanoTime() - action.digitalData.get(index).lastChange > 500_000_000L; + action.digitalData.get(index).hold = + System.nanoTime() - action.digitalData.get(index).lastChange > 500_000_000L; } action.digitalData.get(index).state = on; @@ -1090,9 +1100,11 @@ private void loadActionHandles() { long actionSet = makeActionSet(this.instance, vrinputactionset.name, vrinputactionset.localizedName, 0); this.actionSetHandles.put(vrinputactionset, actionSet); - for (String headset: XRBinding.supportedHeadsets()) { + for (String headset : XRBinding.supportedHeadsets()) { for (var binding : ControllerMapping.getMapping(headset).entrySet()) { - long action = createAction((binding.getKey()+ "." + headset.replace("/interaction_profiles/","")).replace("/", ".") , binding.getKey(), binding.getValue(), + long action = createAction( + (binding.getKey() + "." + headset.replace("/interaction_profiles/", "")).replace("/", "."), + binding.getKey(), binding.getValue(), new XrActionSet(actionSet, this.instance), binding.getKey().contains("left") ? BOTH_HANDS[0] : BOTH_HANDS[1]); this.mappedBindings.put(new ActionBind(vrinputactionset, binding.getKey()), action); @@ -1141,8 +1153,9 @@ private void loadDefaultBindings() { } long handle = this.mappedBindings.get(new ActionBind(inputAction.actionSet, binding.controller())); ActionType type = ControllerMapping.getMapping(headset).get(binding.controller()); - inputAction.addHandle(headset, handle, binding.controller().contains("/left/") ? ControllerType.LEFT : - ControllerType.RIGHT, type); + inputAction.addHandle(headset, handle, + binding.controller().contains("/left/") ? ControllerType.LEFT : + ControllerType.RIGHT, type); inputAction.setType(binding.actionType()); if (inputAction.getHandle(headset).isEmpty() || handle == 0L) { VRSettings.LOGGER.error("Handle for '{}'/'{}' is null", binding.key(), binding.controller()); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java index 9dd05794e..def89eee1 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRBinding.java @@ -31,48 +31,75 @@ private static HashSet quest2Bindings() { HashSet set = new HashSet<>(); set.add( - new XRBinding(null, "/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null, "/actions/global/in/key.inventory", "/user/hand/left/input/x/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/global/in/key.inventory", "/user/hand/left/input/x/click", + ActionType.BOOLEAN)); - set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/value", + ActionType.VEC1)); set.add( - new XRBinding(null, "/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/value", ActionType.VEC1)); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/value", + ActionType.VEC1)); set.add( - new XRBinding(null, "/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/value", ActionType.VEC1)); - set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/value", + ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click", + ActionType.BOOLEAN)); set.add( - new XRBinding(null, "/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y", ActionType.VEC1)); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y", + ActionType.VEC1)); set.add( - new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/value", ActionType.VEC1)); + new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/value", + ActionType.VEC1)); set.add( - new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/value", ActionType.VEC1)); - set.add(new XRBinding(null, "/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/value", ActionType.VEC1)); - set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/value", ActionType.VEC1)); - set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null, "/actions/ingame/in/key.use", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value", ActionType.VEC1)); - set.add(new XRBinding(null, "/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/value", + ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/value", + ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/value", + ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", + ActionType.BOOLEAN)); set.add( - new XRBinding(null, "/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", ActionType.VEC2)); - set.add(new XRBinding(null, "/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick", ActionType.VEC2)); + new XRBinding(null, "/actions/ingame/in/key.use", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleportFallback", + "/user/hand/left/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick/click", + ActionType.BOOLEAN)); + set.add( + new XRBinding(null, "/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", + ActionType.VEC2)); + set.add(new XRBinding(null, "/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick", + ActionType.VEC2)); set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/value", ActionType.VEC1)); - set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze/value", ActionType.VEC1)); - set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/value", ActionType.VEC1)); - set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardShift", + "/user/hand/right/input/squeeze/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/left/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/right/input/trigger/value", ActionType.VEC1)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/squeeze/value", ActionType.VEC1)); set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/value", ActionType.VEC1)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/value", ActionType.VEC1)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/trigger/value", ActionType.VEC1)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/value", ActionType.VEC1)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/value", ActionType.VEC1)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/squeeze/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/squeeze/value", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/trigger/value", ActionType.VEC1)); set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/value", ActionType.VEC1)); return set; @@ -82,61 +109,78 @@ private static HashSet viveBindings() { HashSet set = new HashSet<>(); set.add( - new XRBinding(null,"/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/global/in/key.inventory", "/user/hand/right/input/trackpad/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/global/in/key.inventory", "/user/hand/right/input/trackpad/click", + ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click", + ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click", + ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click", + ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/trackpad/y", ActionType.VEC1)); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/trackpad/y", + ActionType.VEC1)); set.add( - new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click", + ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/menu/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/key.use", "/user/hand/right/input/trackpad/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleportFallback", + new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/menu/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/key.use", "/user/hand/right/input/trackpad/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value", ActionType.VEC1)); - set.add(new XRBinding(null,"/actions/ingame/in/key.jump", "/user/hand/left/input/trackpad/x", ActionType.VEC1)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/trackpad", ActionType.VEC2)); - set.add(new XRBinding(null,"/actions/ingame/in/key.sneak", "/user/hand/left/input/trackpad/y", ActionType.VEC1)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/trackpad", ActionType.VEC2)); + set.add( + new XRBinding(null, "/actions/ingame/in/key.jump", "/user/hand/left/input/trackpad/x", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/trackpad", + ActionType.VEC2)); + set.add( + new XRBinding(null, "/actions/ingame/in/key.sneak", "/user/hand/left/input/trackpad/y", ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/trackpad", + ActionType.VEC2)); - set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardShift", + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/technical/in/vivecraft.key.trackpadTouch", + set.add(new XRBinding(null, "/actions/technical/in/vivecraft.key.trackpadTouch", "/user/hand/left/input/trackpad/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/technical/in/vivecraft.key.trackpadTouch", + set.add(new XRBinding(null, "/actions/technical/in/vivecraft.key.trackpadTouch", "/user/hand/right/input/trackpad/touch", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); return set; @@ -146,56 +190,73 @@ private static HashSet cosmosBindings() { HashSet set = new HashSet<>(); set.add( - new XRBinding(null, "/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/global/in/key.inventory", "/user/hand/left/input/x/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/global/in/key.inventory", "/user/hand/left/input/x/click", + ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click", + ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click", + ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick", ActionType.VEC2)); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick", + ActionType.VEC2)); set.add( - new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click", + ActionType.BOOLEAN)); + set.add( + new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", + ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/key.use", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/ingame/in/key.use", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", ActionType.VEC2)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick", ActionType.VEC2)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleportFallback", + new XRBinding(null, "/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", + ActionType.VEC2)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick", + ActionType.VEC2)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/key.jump", "/user/hand/left/input/shoulder/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/key.sneak", "/user/hand/right/input/shoulder/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/key.jump", "/user/hand/left/input/shoulder/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/key.sneak", "/user/hand/right/input/shoulder/click", + ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardShift", + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); return set; } @@ -204,52 +265,78 @@ private static HashSet picoBindings() { HashSet set = new HashSet<>(); set.add( - new XRBinding(null,"/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/global/in/key.inventory", "/user/hand/left/input/x/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/y/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/global/in/key.inventory", "/user/hand/left/input/x/click", + ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/click", + ActionType.BOOLEAN)); + set.add( + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/click", + ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/a/click", + ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y", ActionType.VEC1)); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y", + ActionType.VEC1)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/key.use", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleportFallback", + set.add( + new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/click", + ActionType.BOOLEAN)); + set.add( + new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", + ActionType.BOOLEAN)); + set.add( + new XRBinding(null, "/actions/ingame/in/key.use", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick/click", + ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", ActionType.VEC2)); - set.add(new XRBinding(null,"/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick", ActionType.VEC2)); + new XRBinding(null, "/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", + ActionType.VEC2)); + set.add(new XRBinding(null, "/actions/ingame/in/key.sneak", "/user/hand/right/input/thumbstick/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick", + ActionType.VEC2)); - set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardShift", + "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", + new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardShift", + "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/squeeze/click", ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/squeeze/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); return set; } @@ -258,51 +345,79 @@ private static HashSet indexBindings() { HashSet set = new HashSet<>(); set.add( - new XRBinding(null,"/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/b/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/global/in/key.inventory", "/user/hand/left/input/a/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/b/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/global/in/key.inventory", "/user/hand/left/input/a/click", + ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiShift", "/user/hand/left/input/squeeze/force", + ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiMiddleClick", "/user/hand/right/input/squeeze/force", + ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y", ActionType.VEC1)); - set.add(new XRBinding(null,"/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/trackpad/y", ActionType.VEC1)); + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/trigger/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiRightClick", "/user/hand/right/input/trackpad", + ActionType.BOOLEAN)); + set.add( + new XRBinding(null, "/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/thumbstick/y", + ActionType.VEC1)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiScrollAxis", "/user/hand/right/input/trackpad/y", + ActionType.VEC1)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/key.use", "/user/hand/right/input/trackpad", ActionType.VEC2)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.teleportFallback", + set.add( + new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarPrev", "/user/hand/left/input/squeeze/force", + ActionType.BOOLEAN)); + set.add( + new XRBinding(null, "/actions/ingame/in/vivecraft.key.hotbarNext", "/user/hand/right/input/squeeze/force", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/key.attack", "/user/hand/right/input/trigger/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/trigger/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.radialMenu", "/user/hand/right/input/b/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/key.use", "/user/hand/right/input/trackpad", ActionType.VEC2)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/trigger/value", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick", ActionType.VEC2)); set.add( - new XRBinding(null,"/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", ActionType.VEC2)); - set.add(new XRBinding(null,"/actions/ingame/in/key.sneak", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick", ActionType.VEC2)); + new XRBinding(null, "/actions/ingame/in/key.jump", "/user/hand/left/input/thumbstick", ActionType.VEC2)); + set.add( + new XRBinding(null, "/actions/ingame/in/vivecraft.key.freeMoveStrafe", "/user/hand/left/input/thumbstick", + ActionType.VEC2)); + set.add( + new XRBinding(null, "/actions/ingame/in/key.sneak", "/user/hand/right/input/a/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.rotateAxis", "/user/hand/right/input/thumbstick", + ActionType.VEC2)); - set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardShift", + "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardShift", "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/keyboard/in/vivecraft.key.keyboardClick", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardShift", + "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/keyboard/in/vivecraft.key.keyboardClick", + "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); - set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", + "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.vrInteract", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/left/input/squeeze/force", ActionType.BOOLEAN)); set.add( - new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", + "/user/hand/right/input/squeeze/force", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/left/input/trigger/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null,"/actions/contextual/in/vivecraft.key.climbeyGrab", + set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.climbeyGrab", "/user/hand/right/input/trigger/click", ActionType.BOOLEAN)); return set; } @@ -311,11 +426,15 @@ private static HashSet defaultBindings() { HashSet set = new HashSet<>(); set.add( - new XRBinding(null, "/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/select/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/global/in/vivecraft.key.ingameMenuButton", "/user/hand/left/input/menu/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/gui/in/vivecraft.key.guiLeftClick", "/user/hand/right/input/select/click", + ActionType.BOOLEAN)); - set.add(new XRBinding(null, "/actions/ingame/in/key.attack", "/user/hand/right/input/select/click", ActionType.BOOLEAN)); - set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/select/click", ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/key.attack", "/user/hand/right/input/select/click", + ActionType.BOOLEAN)); + set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleport", "/user/hand/left/input/select/click", + ActionType.BOOLEAN)); set.add(new XRBinding(null, "/actions/ingame/in/vivecraft.key.teleportFallback", "/user/hand/left/input/select/click", ActionType.BOOLEAN)); @@ -325,7 +444,8 @@ private static HashSet defaultBindings() { "/user/hand/right/input/select/click", ActionType.BOOLEAN)); set.add( - new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/select/click", ActionType.BOOLEAN)); + new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/left/input/select/click", + ActionType.BOOLEAN)); set.add(new XRBinding(null, "/actions/contextual/in/vivecraft.key.vrInteract", "/user/hand/right/input/select/click", ActionType.BOOLEAN)); diff --git a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java index 49579b79a..f3bb1a31c 100644 --- a/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java +++ b/common/src/main/java/org/vivecraft/client_vr/provider/openxr/control/XRInputAction.java @@ -24,7 +24,9 @@ public record HandedAction(Long handle, ControllerType hand, ActionType action) public final List digitalData = new ArrayList<>(); public final List analogData = new ArrayList<>(); - public XRInputAction(KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) { + public XRInputAction( + KeyMapping keyMapping, String requirement, ActionType type, VRInputActionSet actionSetOverride) + { super(keyMapping, requirement, type, actionSetOverride); this.type = null; //No global type, type is part of the @@ -62,7 +64,8 @@ public HandedAction getActiveAction(String[] controllers) { if (this.activeAction == 0) { return null; } - return this.handles.get(controllers[this.digitalData().get(this.activeAction).hand.ordinal()]).get(this.activeAction); + return this.handles.get(controllers[this.digitalData().get(this.activeAction).hand.ordinal()]) + .get(this.activeAction); } @Override @@ -144,7 +147,7 @@ public boolean isButtonChanged() { @Override public long getLastOrigin() { - if(this.activeAction == 0) { + if (this.activeAction == 0) { return 0; } return digitalData().get(this.activeAction).activeOrigin; 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 79e233b18..5493fe83f 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 @@ -49,8 +49,8 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; -import java.util.List; import java.util.*; +import java.util.List; import java.util.function.BooleanSupplier; import java.util.function.Function; import java.util.function.Supplier;