From 2b5b0994f353bd7ca34589a2f3ce30bc66959195 Mon Sep 17 00:00:00 2001 From: hhliow Date: Fri, 10 Apr 2026 18:03:56 -0400 Subject: [PATCH 1/3] Emulate button states so they still work even if ZInput gets unpatched Fixes incompatibility issue with Adventure Backpacks due to Jotunn unpatching ZInput --- ValheimVRMod/VRCore/UI/VRControls.cs | 52 ++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/ValheimVRMod/VRCore/UI/VRControls.cs b/ValheimVRMod/VRCore/UI/VRControls.cs index 512df097..98bad85c 100644 --- a/ValheimVRMod/VRCore/UI/VRControls.cs +++ b/ValheimVRMod/VRCore/UI/VRControls.cs @@ -897,6 +897,58 @@ private void init() poseR = SteamVR_Actions.valheim_PoseR; initIgnoredZInputs(); initQuickActionOnly(); + + // Patching ZInput may not be sufficient to emulate button iput in some cases + // since Jotunn could undo those patches. In those cases, we need to alter the + // actual button states in ZInput. + registerBooleanActionListeners(); + } + + private void registerBooleanActionListeners() + { + foreach (var entry in zInputToBooleanAction) + { + // TODO: consider listening to valheim_ToggleMap to button "Map" + // when VHVRConfig.MinimapPanelPlacement().Equals("Legacy") + var buttonName = entry.Key; + foreach (var action in entry.Value) + { + // TODO: add listener of map zoom too + if (buttonName == "Jump") + { + action.AddOnStateDownListener( + (fromAction, fromSource) => { + if (canJump()) + { + GetButtonPatchUtils.Press(buttonName); + } + + }, + SteamVR_Input_Sources.Any); + } + else if (buttonName == "Remove") + { + action.AddOnStateDownListener( + (fromAction, fromSource) => { + if (canRemovePiece()) + { + GetButtonPatchUtils.Press(buttonName); + } + }, + SteamVR_Input_Sources.Any); + } + else + { + action.AddOnStateDownListener( + (fromAction, fromSource) => GetButtonPatchUtils.Press(buttonName), + SteamVR_Input_Sources.Any); + } + + action.AddOnStateUpListener( + (fromAction, fromSource) => GetButtonPatchUtils.Release(buttonName), + SteamVR_Input_Sources.Any); + } + } } private void initQuickActionOnly() From 693bb23be762e10cb1720d0890e5b4464e0c6ca9 Mon Sep 17 00:00:00 2001 From: hhliow Date: Sat, 11 Apr 2026 20:24:03 -0400 Subject: [PATCH 2/3] Update VRControls.cs --- ValheimVRMod/VRCore/UI/VRControls.cs | 174 +++++++++++++++------------ 1 file changed, 99 insertions(+), 75 deletions(-) diff --git a/ValheimVRMod/VRCore/UI/VRControls.cs b/ValheimVRMod/VRCore/UI/VRControls.cs index 98bad85c..e5f19a97 100644 --- a/ValheimVRMod/VRCore/UI/VRControls.cs +++ b/ValheimVRMod/VRCore/UI/VRControls.cs @@ -28,9 +28,9 @@ class VRControls : MonoBehaviour private float altPieceRotationElapsedTime = 0f; private bool altPieceTriggered = false; private bool wasAltPieceTriggered = false; - private float altMapZoomElapsedTime = 0f; - private bool altMapZoomTriggered = false; private float buildQuickActionTimer; + float? altMapZoomInHoldCountdown = null; + float? altMapZoomOutHoldCountdown = null; private HashSet ignoredZInputs = new HashSet(); private HashSet quickActionEnabled = new HashSet(); // never ignore these @@ -158,14 +158,7 @@ void FixedUpdate() { updateSmoothWalk(Time.fixedDeltaTime); updateAltPieceRotationTimer(); - updateAltMapZoomTimer(); - } - - void LateUpdate() - { - // Reset this at the complete end of the update to allow for - // both MapZoomIn and MapZoomOut to test the zoom input. - altMapZoomTriggered = false; + updateAltMapZoomTimer(Time.fixedDeltaTime); } private void updateSmoothWalk(float deltaTime) @@ -322,13 +315,52 @@ private void updateAltPieceRotationTimer() } } - private void updateAltMapZoomTimer() + private void updateAltMapZoomTimer(float deltaTime) { - altMapZoomElapsedTime += Time.unscaledDeltaTime; - if (altMapZoomElapsedTime >= ALT_MAP_ZOOM_TIME_DELAY) + if (altMapZoomInHoldCountdown.HasValue) + { + bool wasHolding = (altMapZoomInHoldCountdown.Value >= 0); + altMapZoomInHoldCountdown -= deltaTime; + if (wasHolding && altMapZoomInHoldCountdown.Value < 0) + { + GetButtonPatchUtils.Release("MapZoomIn"); + } + } + + if (altMapZoomOutHoldCountdown.HasValue) + { + bool wasHolding = (altMapZoomOutHoldCountdown.Value >= 0); + altMapZoomOutHoldCountdown -= deltaTime; + if (wasHolding && altMapZoomOutHoldCountdown.Value < 0) + { + GetButtonPatchUtils.Release("MapZoomOut"); + } + } + + if (altMapZoomInHoldCountdown == null || altMapZoomInHoldCountdown <= -ALT_MAP_ZOOM_TIME_DELAY) + { + if (getAltMapZoom() > 0) + { + GetButtonPatchUtils.Press("MapZoomIn"); + altMapZoomInHoldCountdown = ALT_MAP_ZOOM_TIME_DELAY; + } + else + { + altMapZoomInHoldCountdown = null; + } + } + + if (altMapZoomOutHoldCountdown == null || altMapZoomOutHoldCountdown <= -ALT_MAP_ZOOM_TIME_DELAY) { - altMapZoomTriggered = true; - altMapZoomElapsedTime = 0f; + if (getAltMapZoom() < 0) + { + GetButtonPatchUtils.Press("MapZoomOut"); + altMapZoomOutHoldCountdown = ALT_MAP_ZOOM_TIME_DELAY; + } + else + { + altMapZoomOutHoldCountdown = null; + } } } @@ -467,37 +499,15 @@ public bool GetButtonDown(string zinput) } // Handle Map zoom specially using context scroll input - if (zinput == "MapZoomOut") + if (contextScroll.activeBinding) { - if (contextScroll.activeBinding) + if (zinput == "MapZoomOut") { - if (contextScroll.axis.y < 0) - { - return true; - } - else - { - return false; - } - } else - { - return (getAltMapZoom() < 0); + return contextScroll.axis.y < 0; } - } else if (zinput == "MapZoomIn") - { - if (contextScroll.activeBinding) + else if (zinput == "MapZoomIn") { - if (contextScroll.axis.y > 0) - { - return true; - } - else - { - return false; - } - } else - { - return (getAltMapZoom() > 0); + return contextScroll.axis.y > 0; } } SteamVR_Action_Boolean[] action; @@ -788,27 +798,13 @@ public int getPieceRefModifier() private int getAltMapZoom() { - if (!altMapZoomTriggered) + if (contextScroll.activeBinding || + !SteamVR_Actions.valheim_Grab.GetState(SteamVR_Input_Sources.RightHand)) { return 0; } - bool rightGrip = SteamVR_Actions.valheim_Grab.GetState(SteamVR_Input_Sources.RightHand); - if (!rightGrip) - { - return 0; - } - float yAxis = GetJoyRightStickY(); - if (yAxis > 0.5f) - { - return -1; - } else if (yAxis < -0.5f) - { - return 1; - } else - { - return 0; - } - + float y = GetJoyRightStickY(); + return y > 0.5f ? -1 : y < -0.5f ? 1 : 0; } private bool inPlaceMode() @@ -898,18 +894,16 @@ private void init() initIgnoredZInputs(); initQuickActionOnly(); - // Patching ZInput may not be sufficient to emulate button iput in some cases - // since Jotunn could undo those patches. In those cases, we need to alter the - // actual button states in ZInput. - registerBooleanActionListeners(); + // TODO: consider altering the actual button states in ZInput so that VR controller inputs + // still work even if ZInput patches get unpatched by Jotunn: + // registerBooleanActionListeners(); + // registerContextScrollListener(); } private void registerBooleanActionListeners() { foreach (var entry in zInputToBooleanAction) { - // TODO: consider listening to valheim_ToggleMap to button "Map" - // when VHVRConfig.MinimapPanelPlacement().Equals("Legacy") var buttonName = entry.Key; foreach (var action in entry.Value) { @@ -918,11 +912,7 @@ private void registerBooleanActionListeners() { action.AddOnStateDownListener( (fromAction, fromSource) => { - if (canJump()) - { - GetButtonPatchUtils.Press(buttonName); - } - + if (canJump()) GetButtonPatchUtils.Press(buttonName); }, SteamVR_Input_Sources.Any); } @@ -930,10 +920,7 @@ private void registerBooleanActionListeners() { action.AddOnStateDownListener( (fromAction, fromSource) => { - if (canRemovePiece()) - { - GetButtonPatchUtils.Press(buttonName); - } + if (canRemovePiece()) GetButtonPatchUtils.Press(buttonName); }, SteamVR_Input_Sources.Any); } @@ -949,6 +936,43 @@ private void registerBooleanActionListeners() SteamVR_Input_Sources.Any); } } + + SteamVR_Actions.valheim_ToggleMap.AddOnStateDownListener( + (fromAction, fromSource) => { + if (VHVRConfig.MinimapPanelPlacement().Equals("Legacy")) + GetButtonPatchUtils.Press("Map"); + }, + SteamVR_Input_Sources.Any); + SteamVR_Actions.valheim_ToggleMap.AddOnStateUpListener( + (fromAction, fromSource) => { + if (VHVRConfig.MinimapPanelPlacement().Equals("Legacy")) + GetButtonPatchUtils.Release("Map"); + }, + SteamVR_Input_Sources.Any); + } + + private void registerContextScrollListener() + { + contextScroll.AddOnChangeListener( + (fromAction, fromSource, axis, delta) => { + if (axis.y <= 0 && delta.y < axis.y) + { + GetButtonPatchUtils.Release("MapZoomIn"); + } + if (axis.y >= 0 && delta.y > axis.y) { + GetButtonPatchUtils.Release("MapZoomOut"); + } + + if (axis.y > 0) + { + GetButtonPatchUtils.Press("MapZoomIn"); + } + else if (axis.y < 0) + { + GetButtonPatchUtils.Press("MapZoomOut"); + } + }, + SteamVR_Input_Sources.Any); } private void initQuickActionOnly() From de26f9cde43e9245298d0caa13b91679d82f462c Mon Sep 17 00:00:00 2001 From: hhliow Date: Sat, 11 Apr 2026 20:25:15 -0400 Subject: [PATCH 3/3] Update VRControls.cs --- ValheimVRMod/VRCore/UI/VRControls.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ValheimVRMod/VRCore/UI/VRControls.cs b/ValheimVRMod/VRCore/UI/VRControls.cs index e5f19a97..26c56b2e 100644 --- a/ValheimVRMod/VRCore/UI/VRControls.cs +++ b/ValheimVRMod/VRCore/UI/VRControls.cs @@ -894,10 +894,11 @@ private void init() initIgnoredZInputs(); initQuickActionOnly(); - // TODO: consider altering the actual button states in ZInput so that VR controller inputs - // still work even if ZInput patches get unpatched by Jotunn: - // registerBooleanActionListeners(); - // registerContextScrollListener(); + // Patching ZInput may not be sufficient to emulate button iput in some cases + // since Jotunn could undo those patches. In those cases, we need to alter the + // actual button states in ZInput. + registerBooleanActionListeners(); + registerContextScrollListener(); } private void registerBooleanActionListeners()