diff --git a/Assets/Gothic-Core/Scripts/GlobalEventDispatcher.cs b/Assets/Gothic-Core/Scripts/GlobalEventDispatcher.cs
index aa7fefb6b..d8566a242 100644
--- a/Assets/Gothic-Core/Scripts/GlobalEventDispatcher.cs
+++ b/Assets/Gothic-Core/Scripts/GlobalEventDispatcher.cs
@@ -63,6 +63,11 @@ public static class GlobalEventDispatcher
// Fight events
+
+ ///
+ /// HINT: Left/Right have other values than Gothic.VR.Interaction.Models.VrHandSide (Left=0, Right=1).
+ /// Map them with VrHandSideExtensions, never cast.
+ ///
public enum HandSide
{
None = 0,
@@ -99,7 +104,8 @@ public enum HandSide
// LockPicking events
// 1. VobContainer -> LockPick
// 2. VobContainer -> Door/Chest
- // 3. HandSide (for VR) -> (0 = Left, 1 = Right)
+ // 3. HandSide (for VR) -> int of Gothic.VR.Interaction.Models.VrHandSide (0 = Left, 1 = Right),
+ // not GlobalEventDispatcher.HandSide.
public static readonly UnityEvent LockPickComboCorrect = new();
public static readonly UnityEvent LockPickComboWrong = new();
public static readonly UnityEvent LockPickComboFinished = new();
diff --git a/Assets/Gothic-VR/Scripts/Adapters/HVROverrides/VRPlayerController.cs b/Assets/Gothic-VR/Scripts/Adapters/HVROverrides/VRPlayerController.cs
index 12e790799..3a6e12e06 100644
--- a/Assets/Gothic-VR/Scripts/Adapters/HVROverrides/VRPlayerController.cs
+++ b/Assets/Gothic-VR/Scripts/Adapters/HVROverrides/VRPlayerController.cs
@@ -5,6 +5,8 @@
using Gothic.Core.Services;
using Gothic.Core.Services.Config;
using Gothic.VR.Adapters.UI;
+using Gothic.VR.Interaction.Backends.Hvr;
+using Gothic.VR.Interaction.Models;
using HurricaneVR.Framework.Core.Player;
using MyBox;
using Reflex.Attributes;
@@ -64,29 +66,35 @@ public void SetNormalControls(bool useDefaultValues = false)
// We have our player created before Gothic inis are loaded. We therefore need to set some default values.
if (useDefaultValues)
{
- CameraRig.SetSitStandMode(HVRSitStand.PlayerHeight);
- DirectionStyle = PlayerDirectionMode.Camera;
- RotationType = RotationType.Snap;
- SnapAmount = 45f;
- SmoothTurnSpeed = 90f;
-
+ ApplyComfortSettings(VrSitStand.PlayerHeight, VrMoveDirection.Camera, VrTurnType.Snap, 45f, 90f);
return;
}
- var sitStandSetting =
- _configService.Gothic.GetInt(VRConstants.IniNames.SitStand, (int)HVRSitStand.PlayerHeight);
- CameraRig.SetSitStandMode((HVRSitStand)sitStandSetting);
-
- DirectionStyle = (PlayerDirectionMode)_configService.Gothic.GetInt(VRConstants.IniNames.MoveDirection, (int)PlayerDirectionMode.Camera);
- RotationType = (RotationType)_configService.Gothic.GetInt(VRConstants.IniNames.RotationType, (int)RotationType.Snap);
+ var gothicIni = _configService.Gothic;
+ var sitStand = (VrSitStand)gothicIni.GetInt(VRConstants.IniNames.SitStand, (int)VrSitStand.PlayerHeight);
+ var moveDirection =
+ (VrMoveDirection)gothicIni.GetInt(VRConstants.IniNames.MoveDirection, (int)VrMoveDirection.Camera);
+ var turnType = (VrTurnType)gothicIni.GetInt(VRConstants.IniNames.RotationType, (int)VrTurnType.Snap);
- var snapSetting = _configService.Gothic.GetInt(VRConstants.IniNames.SnapRotationAmount, VRConstants.SnapRotationDefaultValue);
+ var snapSetting = gothicIni.GetInt(VRConstants.IniNames.SnapRotationAmount, VRConstants.SnapRotationDefaultValue);
// e.g., 20° = 5° + 3*5°
- SnapAmount = VRConstants.SnapRotationAmountSettingTickAmount + VRConstants.SnapRotationAmountSettingTickAmount * snapSetting;
-
- var smoothSetting = _configService.Gothic.GetFloat(VRConstants.IniNames.SmoothRotationSpeed, VRConstants.SmoothRotationDefaultValue);
+ var snapDegrees = VRConstants.SnapRotationAmountSettingTickAmount + VRConstants.SnapRotationAmountSettingTickAmount * snapSetting;
+
+ var smoothSetting = gothicIni.GetFloat(VRConstants.IniNames.SmoothRotationSpeed, VRConstants.SmoothRotationDefaultValue);
// e.g., 50 = 5 + 90 * 0.5f
- SmoothTurnSpeed = VRConstants.SmoothRotationMinSpeed + VRConstants.SmoothRotationMaxAdditionalSpeed * smoothSetting;
+ var smoothSpeed = VRConstants.SmoothRotationMinSpeed + VRConstants.SmoothRotationMaxAdditionalSpeed * smoothSetting;
+
+ ApplyComfortSettings(sitStand, moveDirection, turnType, snapDegrees, smoothSpeed);
+ }
+
+ public void ApplyComfortSettings(VrSitStand sitStand, VrMoveDirection moveDirection, VrTurnType turnType,
+ float snapDegrees, float smoothSpeed)
+ {
+ CameraRig.SetSitStandMode(sitStand.ToHvr());
+ DirectionStyle = moveDirection.ToHvr();
+ RotationType = turnType.ToHvr();
+ SnapAmount = snapDegrees;
+ SmoothTurnSpeed = smoothSpeed;
}
///
diff --git a/Assets/Gothic-VR/Scripts/Adapters/Player/VRPlayerWeaponInteraction.cs b/Assets/Gothic-VR/Scripts/Adapters/Player/VRPlayerWeaponInteraction.cs
index 4bb3622e3..2ceb096ba 100644
--- a/Assets/Gothic-VR/Scripts/Adapters/Player/VRPlayerWeaponInteraction.cs
+++ b/Assets/Gothic-VR/Scripts/Adapters/Player/VRPlayerWeaponInteraction.cs
@@ -5,6 +5,7 @@
using Gothic.Core.Models.Marvin;
using Gothic.Core.Models.Vm;
using Gothic.Core.Services;
+using Gothic.VR.Interaction.Backends.Hvr;
using Gothic.VR.Models.Vob;
using Gothic.VR.Services;
using HurricaneVR.Framework.Core;
@@ -56,7 +57,7 @@ public void OnGrabbed(HVRGrabberBase hand, HVRGrabbable item)
if (itemInstance!.MainFlag != (int)VmGothicEnums.ItemFlags.ItemKatNf)
return;
- _weaponService.OnGrabbed(((HVRHandGrabber)hand).HandSide, vobContainer, GetWeaponPhysicsConfig());
+ _weaponService.OnGrabbed(((HVRHandGrabber)hand).HandSide.ToVr(), vobContainer, GetWeaponPhysicsConfig());
SyncEquippedWeaponToHero(itemInstance, equip: true);
}
@@ -75,7 +76,7 @@ public void OnReleased(HVRGrabberBase hand, HVRGrabbable item)
if (itemInstance!.MainFlag != (int)VmGothicEnums.ItemFlags.ItemKatNf)
return;
- _weaponService.OnReleased(((HVRHandGrabber)hand).HandSide, GetWeaponPhysicsConfig());
+ _weaponService.OnReleased(((HVRHandGrabber)hand).HandSide.ToVr(), GetWeaponPhysicsConfig());
SyncEquippedWeaponToHero(itemInstance, equip: false);
}
diff --git a/Assets/Gothic-VR/Scripts/Adapters/Vob/LockPicking/VRContainerDoorPickingInteraction.cs b/Assets/Gothic-VR/Scripts/Adapters/Vob/LockPicking/VRContainerDoorPickingInteraction.cs
index 7d7c94e22..a56cf5691 100644
--- a/Assets/Gothic-VR/Scripts/Adapters/Vob/LockPicking/VRContainerDoorPickingInteraction.cs
+++ b/Assets/Gothic-VR/Scripts/Adapters/Vob/LockPicking/VRContainerDoorPickingInteraction.cs
@@ -9,8 +9,8 @@
using Gothic.Core.Services.Vm;
using Gothic.VR.Services;
using Gothic.VR.Adapters.Vob.VobItem;
+using Gothic.VR.Interaction.Models;
using HurricaneVR.Framework.Components;
-using HurricaneVR.Framework.Shared;
using Reflex.Attributes;
using UnityEngine;
using ZenKit.Vobs;
@@ -33,7 +33,7 @@ public class VRContainerDoorPickingInteraction : MonoBehaviour
private bool _isLocked;
private string _combination;
private string _keyInstance;
- private HVRHandSide _handSide;
+ private VrHandSide _handSide;
private VobContainer _lockPick;
private VobContainer _lockable;
@@ -101,12 +101,12 @@ private void OnTriggerEnter(Collider other)
if (IsHeldItem(_vrPlayerService.GrabbedItemLeft, other.gameObject))
{
holdingHand = _vrPlayerService.GrabbedItemLeft.transform;
- _handSide = HVRHandSide.Left;
+ _handSide = VrHandSide.Left;
}
else if (IsHeldItem(_vrPlayerService.GrabbedItemRight, other.gameObject))
{
holdingHand = _vrPlayerService.GrabbedItemRight.transform;
- _handSide = HVRHandSide.Right;
+ _handSide = VrHandSide.Right;
}
else
{
@@ -115,7 +115,7 @@ private void OnTriggerEnter(Collider other)
_combinationPos = 0;
PlaySound(_vmService.DoorLockSoundName);
- _hapticsService.Vibrate(_handSide, VrHapticsService.VibrationType.Info);
+ _hapticsService.Vibrate(_handSide, VrHapticPreset.Info);
// For later event usage.
_lockPick = other.gameObject.GetComponentInParent().Container;
@@ -213,13 +213,13 @@ private void TryUnlockWithKey(Collider other)
return;
// The player must actively hold the key (not just a dropped/flying item).
- HVRHandSide hand;
+ VrHandSide hand;
var leftRoot = _vrPlayerService.GrabbedItemLeft;
var rightRoot = _vrPlayerService.GrabbedItemRight;
if (leftRoot != null && leftRoot.GetComponentInParent() == vobLoader)
- hand = HVRHandSide.Left;
+ hand = VrHandSide.Left;
else if (rightRoot != null && rightRoot.GetComponentInParent() == vobLoader)
- hand = HVRHandSide.Right;
+ hand = VrHandSide.Right;
else
return;
diff --git a/Assets/Gothic-VR/Scripts/Domain/Player/VrWeaponAttackDomain.cs b/Assets/Gothic-VR/Scripts/Domain/Player/VrWeaponAttackDomain.cs
index 926e79758..1b32e7341 100644
--- a/Assets/Gothic-VR/Scripts/Domain/Player/VrWeaponAttackDomain.cs
+++ b/Assets/Gothic-VR/Scripts/Domain/Player/VrWeaponAttackDomain.cs
@@ -13,9 +13,9 @@
using Gothic.Core.Models.Vm;
using Gothic.Core.Services.Caches;
using Gothic.VR.Models.Vob;
+using Gothic.VR.Interaction.Models;
using Gothic.VR.Services;
using HurricaneVR.Framework.Core.Utils;
-using HurricaneVR.Framework.Shared;
using Reflex.Attributes;
using UnityEngine;
using ZenKit;
@@ -87,7 +87,7 @@ private static readonly (float attackWindowTime, float comboWindowStart, float c
/// FALSE, when:
/// 1. Already handling one weapon, but another one is provided.
///
- public bool TryHandle(VobContainer vobContainer, WeaponPhysicsConfig weaponConfig, HVRHandSide handSide, NpcContainer playerNpcContainer)
+ public bool TryHandle(VobContainer vobContainer, WeaponPhysicsConfig weaponConfig, VrHandSide handSide, NpcContainer playerNpcContainer)
{
if (!CanHandle(vobContainer))
return false;
@@ -135,9 +135,9 @@ public bool TryHandle(VobContainer vobContainer, WeaponPhysicsConfig weaponConfi
windowTimes.comboWindowStart, windowTimes.comboWindowTime);
}
- if (handSide == HVRHandSide.Left)
+ if (handSide == VrHandSide.Left)
_handlesLeftHand = true;
- else if (handSide == HVRHandSide.Right)
+ else if (handSide == VrHandSide.Right)
_handlesRightHand = true;
AlterWeaponWeights(weaponConfig);
@@ -168,14 +168,14 @@ private bool CanHandle(VobContainer newWeapon)
return false;
}
- public bool TryUnHandle(WeaponPhysicsConfig weaponConfig, HVRHandSide handSide)
+ public bool TryUnHandle(WeaponPhysicsConfig weaponConfig, VrHandSide handSide)
{
if (!CanUnHandle(handSide))
return false;
- if (handSide == HVRHandSide.Left)
+ if (handSide == VrHandSide.Left)
_handlesLeftHand = false;
- else if (handSide == HVRHandSide.Right)
+ else if (handSide == VrHandSide.Right)
_handlesRightHand = false;
// Alter weight now, before we potentially unset VobContainer and Rigidbody.
@@ -191,9 +191,9 @@ public bool TryUnHandle(WeaponPhysicsConfig weaponConfig, HVRHandSide handSide)
/// Unhandle means: Do we released item in hand which we handled?
/// Hint: We can only have one item in a hand at a time. Therefore, we don't need to check for the rigidbody itself.
///
- private bool CanUnHandle(HVRHandSide releasedHandSide)
+ private bool CanUnHandle(VrHandSide releasedHandSide)
{
- if (releasedHandSide == HVRHandSide.Left)
+ if (releasedHandSide == VrHandSide.Left)
return _handlesLeftHand;
else
return _handlesRightHand;
diff --git a/Assets/Gothic-VR/Scripts/Interaction.meta b/Assets/Gothic-VR/Scripts/Interaction.meta
new file mode 100644
index 000000000..a5ce655ce
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c17fb20ae6868424d94ea9dc7d7e3465
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Backends.meta b/Assets/Gothic-VR/Scripts/Interaction/Backends.meta
new file mode 100644
index 000000000..92a4f1536
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Backends.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 2c7c846aa1d858e40893acb91583324c
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr.meta b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr.meta
new file mode 100644
index 000000000..8e0147cd7
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0091983ca36e5ee43bf1d30f0b009682
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrEnumExtensions.cs b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrEnumExtensions.cs
new file mode 100644
index 000000000..fa554aa4c
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrEnumExtensions.cs
@@ -0,0 +1,69 @@
+#if GOTHIC_HVR_INSTALLED
+using System;
+using Gothic.VR.Interaction.Models;
+using HurricaneVR.Framework.Core.Player;
+using HurricaneVR.Framework.Shared;
+
+namespace Gothic.VR.Interaction.Backends.Hvr
+{
+ ///
+ /// Maps our VR models to HVR types and back. Only used inside the HVR backend.
+ ///
+ public static class HvrEnumExtensions
+ {
+ public static HVRHandSide ToHvr(this VrHandSide side)
+ {
+ return side == VrHandSide.Left ? HVRHandSide.Left : HVRHandSide.Right;
+ }
+
+ public static VrHandSide ToVr(this HVRHandSide side)
+ {
+ return side == HVRHandSide.Left ? VrHandSide.Left : VrHandSide.Right;
+ }
+
+ public static HVRButtons ToHvr(this VrButton button)
+ {
+ return button switch
+ {
+ VrButton.Grip => HVRButtons.Grip,
+ VrButton.Trigger => HVRButtons.Trigger,
+ VrButton.Primary => HVRButtons.Primary,
+ VrButton.Secondary => HVRButtons.Secondary,
+ VrButton.Menu => HVRButtons.Menu,
+ VrButton.JoystickButton => HVRButtons.JoystickButton,
+ _ => throw new ArgumentOutOfRangeException(nameof(button), button, null)
+ };
+ }
+
+ public static VrButtonState ToVr(this HVRButtonState state)
+ {
+ return new VrButtonState(state.Active, state.JustActivated, state.JustDeactivated);
+ }
+
+ public static HVRSitStand ToHvr(this VrSitStand sitStand)
+ {
+ return sitStand switch
+ {
+ VrSitStand.Sitting => HVRSitStand.Sitting,
+ VrSitStand.Standing => HVRSitStand.Standing,
+ _ => HVRSitStand.PlayerHeight
+ };
+ }
+
+ public static PlayerDirectionMode ToHvr(this VrMoveDirection direction)
+ {
+ return direction switch
+ {
+ VrMoveDirection.LeftController => PlayerDirectionMode.LeftController,
+ VrMoveDirection.RightController => PlayerDirectionMode.RightController,
+ _ => PlayerDirectionMode.Camera
+ };
+ }
+
+ public static RotationType ToHvr(this VrTurnType turnType)
+ {
+ return turnType == VrTurnType.Smooth ? RotationType.Smooth : RotationType.Snap;
+ }
+ }
+}
+#endif
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrEnumExtensions.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrEnumExtensions.cs.meta
new file mode 100644
index 000000000..a54b1c782
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrEnumExtensions.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: b30f5f87f90ba3b4690126ff005a8a5c
\ No newline at end of file
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models.meta b/Assets/Gothic-VR/Scripts/Interaction/Models.meta
new file mode 100644
index 000000000..ca85f8718
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b880831f62bf2d447adb6325ed4ec0e7
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrButton.cs b/Assets/Gothic-VR/Scripts/Interaction/Models/VrButton.cs
new file mode 100644
index 000000000..7cf606c86
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrButton.cs
@@ -0,0 +1,15 @@
+namespace Gothic.VR.Interaction.Models
+{
+ ///
+ /// Controller buttons we read in game code. The active VR backend maps them to the device buttons.
+ ///
+ public enum VrButton
+ {
+ Grip,
+ Trigger,
+ Primary,
+ Secondary,
+ Menu,
+ JoystickButton
+ }
+}
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrButton.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Models/VrButton.cs.meta
new file mode 100644
index 000000000..96d07cc2c
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrButton.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 8c026c8910e7f494bbb5de7a3557734d
\ No newline at end of file
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrButtonState.cs b/Assets/Gothic-VR/Scripts/Interaction/Models/VrButtonState.cs
new file mode 100644
index 000000000..738d661fd
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrButtonState.cs
@@ -0,0 +1,30 @@
+namespace Gothic.VR.Interaction.Models
+{
+ ///
+ /// State of a controller button in the current frame.
+ ///
+ public readonly struct VrButtonState
+ {
+ ///
+ /// The button is held down.
+ ///
+ public readonly bool IsActive;
+
+ ///
+ /// The button went down this frame.
+ ///
+ public readonly bool IsJustActivated;
+
+ ///
+ /// The button went up this frame.
+ ///
+ public readonly bool IsJustDeactivated;
+
+ public VrButtonState(bool isActive, bool isJustActivated, bool isJustDeactivated)
+ {
+ IsActive = isActive;
+ IsJustActivated = isJustActivated;
+ IsJustDeactivated = isJustDeactivated;
+ }
+ }
+}
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrButtonState.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Models/VrButtonState.cs.meta
new file mode 100644
index 000000000..3d2310c1b
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrButtonState.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: c88e863b76ceab849857f40deb620293
\ No newline at end of file
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrGrabberKind.cs b/Assets/Gothic-VR/Scripts/Interaction/Models/VrGrabberKind.cs
new file mode 100644
index 000000000..33aec975e
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrGrabberKind.cs
@@ -0,0 +1,12 @@
+namespace Gothic.VR.Interaction.Models
+{
+ ///
+ /// What grabbed (or released) an interactable.
+ ///
+ public enum VrGrabberKind
+ {
+ Hand,
+ Distance,
+ Socket
+ }
+}
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrGrabberKind.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Models/VrGrabberKind.cs.meta
new file mode 100644
index 000000000..8b603377f
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrGrabberKind.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: fafd204bff1d1d14191c07bfd3fb9b62
\ No newline at end of file
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrHandSide.cs b/Assets/Gothic-VR/Scripts/Interaction/Models/VrHandSide.cs
new file mode 100644
index 000000000..b8b18c21e
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrHandSide.cs
@@ -0,0 +1,14 @@
+namespace Gothic.VR.Interaction.Models
+{
+ ///
+ /// A hand/controller of the VR player.
+ /// HINT: The lock picking events (GlobalEventDispatcher.LockPickCombo*) pass these values as int.
+ /// They differ from GlobalEventDispatcher.HandSide (None=0, Left=1, Right=2, Both=3). Use
+ /// VrHandSideExtensions to map between both.
+ ///
+ public enum VrHandSide
+ {
+ Left = 0,
+ Right = 1
+ }
+}
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrHandSide.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Models/VrHandSide.cs.meta
new file mode 100644
index 000000000..3342049a2
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrHandSide.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 246dfc7049342c34392fdb668551b85c
\ No newline at end of file
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrHandSideExtensions.cs b/Assets/Gothic-VR/Scripts/Interaction/Models/VrHandSideExtensions.cs
new file mode 100644
index 000000000..685dd51b3
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrHandSideExtensions.cs
@@ -0,0 +1,36 @@
+using Gothic.Core;
+
+namespace Gothic.VR.Interaction.Models
+{
+ ///
+ /// The only place where GlobalEventDispatcher.HandSide (fight events) and VrHandSide are mapped.
+ ///
+ public static class VrHandSideExtensions
+ {
+ ///
+ /// false for HandSide.None and HandSide.Both, as they have no single VR hand.
+ ///
+ public static bool TryToVrHandSide(this GlobalEventDispatcher.HandSide handSide, out VrHandSide vrHandSide)
+ {
+ switch (handSide)
+ {
+ case GlobalEventDispatcher.HandSide.Left:
+ vrHandSide = VrHandSide.Left;
+ return true;
+ case GlobalEventDispatcher.HandSide.Right:
+ vrHandSide = VrHandSide.Right;
+ return true;
+ default:
+ vrHandSide = default;
+ return false;
+ }
+ }
+
+ public static GlobalEventDispatcher.HandSide ToHandSide(this VrHandSide vrHandSide)
+ {
+ return vrHandSide == VrHandSide.Left
+ ? GlobalEventDispatcher.HandSide.Left
+ : GlobalEventDispatcher.HandSide.Right;
+ }
+ }
+}
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrHandSideExtensions.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Models/VrHandSideExtensions.cs.meta
new file mode 100644
index 000000000..0ef669772
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrHandSideExtensions.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 21fcabfad52958848a59f168ec14d816
\ No newline at end of file
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrHapticPreset.cs b/Assets/Gothic-VR/Scripts/Interaction/Models/VrHapticPreset.cs
new file mode 100644
index 000000000..f9c2e8aba
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrHapticPreset.cs
@@ -0,0 +1,28 @@
+namespace Gothic.VR.Interaction.Models
+{
+ ///
+ /// Vibration patterns. The VR backend defines amplitude, duration and frequency of each.
+ ///
+ public enum VrHapticPreset
+ {
+ ///
+ /// e.g., you are inside an interaction collider
+ ///
+ Info,
+
+ ///
+ /// e.g., your lock pick rotation is invalid
+ ///
+ Warning,
+
+ ///
+ /// e.g., your key is broken
+ ///
+ Error,
+
+ ///
+ /// e.g., you opened a chest
+ ///
+ Success
+ }
+}
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrHapticPreset.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Models/VrHapticPreset.cs.meta
new file mode 100644
index 000000000..4ef1cfb86
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrHapticPreset.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: cd4d994077c26ea49a904516edc12339
\ No newline at end of file
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrMoveDirection.cs b/Assets/Gothic-VR/Scripts/Interaction/Models/VrMoveDirection.cs
new file mode 100644
index 000000000..2eef267e2
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrMoveDirection.cs
@@ -0,0 +1,13 @@
+namespace Gothic.VR.Interaction.Models
+{
+ ///
+ /// Which device defines "forward" for thumbstick movement.
+ /// HINT: Stored as int in Gothic.ini (VRConstants.IniNames.MoveDirection). Never change the values.
+ ///
+ public enum VrMoveDirection
+ {
+ Camera = 0,
+ LeftController = 1,
+ RightController = 2
+ }
+}
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrMoveDirection.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Models/VrMoveDirection.cs.meta
new file mode 100644
index 000000000..1f3279a37
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrMoveDirection.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: aae46023bc545074093e3691112278b0
\ No newline at end of file
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrSitStand.cs b/Assets/Gothic-VR/Scripts/Interaction/Models/VrSitStand.cs
new file mode 100644
index 000000000..96e6ec9dc
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrSitStand.cs
@@ -0,0 +1,13 @@
+namespace Gothic.VR.Interaction.Models
+{
+ ///
+ /// How the camera height is calculated.
+ /// HINT: Stored as int in Gothic.ini (VRConstants.IniNames.SitStand). Never change the values.
+ ///
+ public enum VrSitStand
+ {
+ Sitting = 0,
+ Standing = 1,
+ PlayerHeight = 2
+ }
+}
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrSitStand.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Models/VrSitStand.cs.meta
new file mode 100644
index 000000000..a79f7c1b7
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrSitStand.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 5d8c6e1091c15294294f29ae420a7520
\ No newline at end of file
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrTurnType.cs b/Assets/Gothic-VR/Scripts/Interaction/Models/VrTurnType.cs
new file mode 100644
index 000000000..8b35fa5fe
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrTurnType.cs
@@ -0,0 +1,12 @@
+namespace Gothic.VR.Interaction.Models
+{
+ ///
+ /// Thumbstick turning.
+ /// HINT: Stored as int in Gothic.ini (VRConstants.IniNames.RotationType). Never change the values.
+ ///
+ public enum VrTurnType
+ {
+ Smooth = 0,
+ Snap = 1
+ }
+}
diff --git a/Assets/Gothic-VR/Scripts/Interaction/Models/VrTurnType.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Models/VrTurnType.cs.meta
new file mode 100644
index 000000000..e816770a0
--- /dev/null
+++ b/Assets/Gothic-VR/Scripts/Interaction/Models/VrTurnType.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: a5df2400195474f4e8e30c2e737120cc
\ No newline at end of file
diff --git a/Assets/Gothic-VR/Scripts/Services/Context/VRContextInteractionService.cs b/Assets/Gothic-VR/Scripts/Services/Context/VRContextInteractionService.cs
index a2473cca4..a84b90855 100644
--- a/Assets/Gothic-VR/Scripts/Services/Context/VRContextInteractionService.cs
+++ b/Assets/Gothic-VR/Scripts/Services/Context/VRContextInteractionService.cs
@@ -14,6 +14,8 @@
using Gothic.VR.Adapters.Marvin;
using Gothic.VR.Adapters.Player;
using Gothic.VR.Adapters.UI;
+using Gothic.VR.Interaction.Backends.Hvr;
+using Gothic.VR.Interaction.Models;
using HurricaneVR.Framework.Core.UI;
using HurricaneVRExtensions.Simulator;
using Reflex.Attributes;
@@ -133,7 +135,7 @@ private void OnMarvinLogoPoked(PointerEventData eventData)
}
ReflexProjectInstaller.DIContainer.Resolve()
- .Vibrate(pointer.HandSide, VrHapticsService.VibrationType.Info);
+ .Vibrate(pointer.HandSide.ToVr(), VrHapticPreset.Info);
}
private void PlayerPrefsUpdated(string key, object value)
diff --git a/Assets/Gothic-VR/Scripts/Services/Context/VRContextMenuService.cs b/Assets/Gothic-VR/Scripts/Services/Context/VRContextMenuService.cs
index c1af0a34c..8f20d3690 100644
--- a/Assets/Gothic-VR/Scripts/Services/Context/VRContextMenuService.cs
+++ b/Assets/Gothic-VR/Scripts/Services/Context/VRContextMenuService.cs
@@ -9,7 +9,7 @@
using Gothic.Core;
using Gothic.Core.Const;
using Gothic.Core.Extensions;
-using HurricaneVR.Framework.Core.Player;
+using Gothic.VR.Interaction.Models;
using Reflex.Attributes;
using UnityEngine;
using ZenKit.Daedalus;
@@ -112,7 +112,7 @@ private AbstractMenuItemInstance CreateSitStandLabel(AbstractMenuInstance gameMe
var sitStandSetting = new MutableMenuItemInstance("MENUITEM_GOTHIC_OPT_VR_ACCESSIBILITY_SIT_STAND_CHOICE", subtitlesChoice);
sitStandSetting.PosY = posY;
- sitStandSetting.SetUserFloat(3, (int)HVRSitStand.PlayerHeight); // Default value if no INI value exists.
+ sitStandSetting.SetUserFloat(3, (int)VrSitStand.PlayerHeight); // Default value if no INI value exists.
sitStandSetting.SetText(0, _localizationService.GetText("menuitem.sitStand.value"));
sitStandSetting.OnChgSetOption = VRConstants.IniNames.SitStand;
@@ -167,7 +167,7 @@ private AbstractMenuItemInstance CreateRotationTypeChoicebox(AbstractMenuInstanc
var rotationTypeSetting = new MutableMenuItemInstance("MENUITEM_GOTHIC_OPT_VR_ACCESSIBILITY_ROTATION_TYPE_CHOICE", subtitlesChoice);
rotationTypeSetting.PosY = posY;
- rotationTypeSetting.SetUserFloat(3, (int)RotationType.Snap); // Default value if no INI value exists.
+ rotationTypeSetting.SetUserFloat(3, (int)VrTurnType.Snap); // Default value if no INI value exists.
rotationTypeSetting.SetText(0, _localizationService.GetText("menuitem.rotationType.value"));
rotationTypeSetting.OnChgSetOption = VRConstants.IniNames.RotationType;
diff --git a/Assets/Gothic-VR/Scripts/Services/VRWeaponService.cs b/Assets/Gothic-VR/Scripts/Services/VRWeaponService.cs
index 38e9d54aa..f47a13de2 100644
--- a/Assets/Gothic-VR/Scripts/Services/VRWeaponService.cs
+++ b/Assets/Gothic-VR/Scripts/Services/VRWeaponService.cs
@@ -7,10 +7,10 @@
using Gothic.Core.Models.Vm;
using Gothic.Core.Services.Player;
using Gothic.VR.Domain.Player;
+using Gothic.VR.Interaction.Models;
using Gothic.VR.Models.Vob;
using Gothic.Core.Extensions;
using HurricaneVR.Framework.Core.Utils;
-using HurricaneVR.Framework.Shared;
using Reflex.Attributes;
using UnityEngine;
@@ -45,7 +45,7 @@ public void FixedUpdate()
_secondAttackDomain.FixedUpdate();
}
- public void OnGrabbed(HVRHandSide handSide, VobContainer vobContainer, WeaponPhysicsConfig weaponConfig)
+ public void OnGrabbed(VrHandSide handSide, VobContainer vobContainer, WeaponPhysicsConfig weaponConfig)
{
var heroContainer = _playerService.HeroContainer;
@@ -56,7 +56,7 @@ public void OnGrabbed(HVRHandSide handSide, VobContainer vobContainer, WeaponPhy
}
}
- public void OnReleased(HVRHandSide handSide, WeaponPhysicsConfig weaponConfig)
+ public void OnReleased(VrHandSide handSide, WeaponPhysicsConfig weaponConfig)
{
if (!_firstAttackDomain.TryUnHandle(weaponConfig, handSide))
{
diff --git a/Assets/Gothic-VR/Scripts/Services/VrHapticsService.cs b/Assets/Gothic-VR/Scripts/Services/VrHapticsService.cs
index d54dddb7b..3916460c3 100644
--- a/Assets/Gothic-VR/Scripts/Services/VrHapticsService.cs
+++ b/Assets/Gothic-VR/Scripts/Services/VrHapticsService.cs
@@ -1,6 +1,8 @@
#if GOTHIC_HVR_INSTALLED
using Gothic.Core;
using Gothic.Core.Models.Container;
+using Gothic.VR.Interaction.Backends.Hvr;
+using Gothic.VR.Interaction.Models;
using HurricaneVR.Framework.Shared;
using Reflex.Attributes;
@@ -8,17 +10,10 @@ namespace Gothic.VR.Services
{
public class VrHapticsService
{
- public enum VibrationType
- {
- Info,
- Warning,
- Error,
- Success
- }
-
[Inject] private readonly VRPlayerService _vrPlayerService;
[Inject] private readonly VRWeaponService _vrWeaponService;
+ // Indexed by VrHapticPreset.
private readonly HapticData[] _vibrationData =
{
// Info - e.g., you are inside an interaction collider
@@ -37,42 +32,38 @@ public enum VibrationType
public VrHapticsService()
{
// Fight
- GlobalEventDispatcher.FightWindowAttack.AddListener(combatant => AttackVibration(combatant, VibrationType.Success)); // Attack can happen now
- GlobalEventDispatcher.FightWindowCombo.AddListener(combatant => AttackVibration(combatant, VibrationType.Info)); // Now you can start another attack
- GlobalEventDispatcher.FightWindowComboFailed.AddListener(combatant => AttackVibration(combatant, VibrationType.Error)); // Attack window passed
+ GlobalEventDispatcher.FightWindowAttack.AddListener(combatant => AttackVibration(combatant, VrHapticPreset.Success)); // Attack can happen now
+ GlobalEventDispatcher.FightWindowCombo.AddListener(combatant => AttackVibration(combatant, VrHapticPreset.Info)); // Now you can start another attack
+ GlobalEventDispatcher.FightWindowComboFailed.AddListener(combatant => AttackVibration(combatant, VrHapticPreset.Error)); // Attack window passed
// Lock picking
- GlobalEventDispatcher.LockPickComboWrong.AddListener((_, _, handSide) => Vibrate((HVRHandSide)handSide, VibrationType.Warning));
- GlobalEventDispatcher.LockPickComboBroken.AddListener((_, _, handSide) => Vibrate((HVRHandSide)handSide, VibrationType.Error));
- GlobalEventDispatcher.LockPickComboCorrect.AddListener((_, _, handSide) => Vibrate((HVRHandSide)handSide, VibrationType.Success));
- GlobalEventDispatcher.LockPickComboFinished.AddListener((_, _, handSide) => Vibrate((HVRHandSide)handSide, VibrationType.Success));
+ GlobalEventDispatcher.LockPickComboWrong.AddListener((_, _, handSide) => Vibrate((VrHandSide)handSide, VrHapticPreset.Warning));
+ GlobalEventDispatcher.LockPickComboBroken.AddListener((_, _, handSide) => Vibrate((VrHandSide)handSide, VrHapticPreset.Error));
+ GlobalEventDispatcher.LockPickComboCorrect.AddListener((_, _, handSide) => Vibrate((VrHandSide)handSide, VrHapticPreset.Success));
+ GlobalEventDispatcher.LockPickComboFinished.AddListener((_, _, handSide) => Vibrate((VrHandSide)handSide, VrHapticPreset.Success));
}
- private void AttackVibration(NpcContainer combatant, VibrationType vibrationType)
+ private void AttackVibration(NpcContainer combatant, VrHapticPreset preset)
{
// Resolve which hand holds the weapon for this combatant.
// For NPCs attacking the player, we don't vibrate — only when it's the player's own attack.
var handSide = _vrWeaponService.GetHandSideForCombatant(combatant);
- switch (handSide)
+ if (handSide == GlobalEventDispatcher.HandSide.Both)
+ {
+ Vibrate(VrHandSide.Left, preset);
+ Vibrate(VrHandSide.Right, preset);
+ }
+ else if (handSide.TryToVrHandSide(out var vrHandSide))
{
- case GlobalEventDispatcher.HandSide.Both:
- Vibrate(HVRHandSide.Left, vibrationType);
- Vibrate(HVRHandSide.Right, vibrationType);
- break;
- case GlobalEventDispatcher.HandSide.Left:
- Vibrate(HVRHandSide.Left, vibrationType);
- break;
- case GlobalEventDispatcher.HandSide.Right:
- Vibrate(HVRHandSide.Right, vibrationType);
- break;
+ Vibrate(vrHandSide, preset);
}
}
- public void Vibrate(HVRHandSide handSide, VibrationType type)
+ public void Vibrate(VrHandSide handSide, VrHapticPreset preset)
{
- _vrPlayerService.GetHand(handSide).Vibrate(_vibrationData[(int)type]);
+ _vrPlayerService.GetHand(handSide.ToHvr()).Vibrate(_vibrationData[(int)preset]);
}
}
}
diff --git a/Docs/HVR-replacement/phase-0-decouple.md b/Docs/HVR-replacement/phase-0-decouple.md
index db972aea8..b698aa597 100644
--- a/Docs/HVR-replacement/phase-0-decouple.md
+++ b/Docs/HVR-replacement/phase-0-decouple.md
@@ -119,11 +119,15 @@ Split into four PRs so each one stays reviewable.
### PR 0a - Models and hand side
-- [ ] Add `Interaction/Models/*`.
-- [ ] Replace `HVRHandSide` in `VrWeaponAttackDomain`, `VRWeaponService`, `VRPlayerWeaponInteraction`,
- `VRContainerDoorPickingInteraction`, `VrHapticsService`, `VRCinema`, `VRPlayerInputs`.
-- [ ] `VRContextMenuService.cs:115` and `VRPlayerController.SetNormalControls`: replace `HVRSitStand`,
- `PlayerDirectionMode` and `RotationType` with the new enums, converting at the HVR boundary.
+- [x] Add `Interaction/Models/*` (`VrGrabArgs` waits for PR 0c, it needs `VrInteractable`). HVR mapping lives in
+ `Backends/Hvr/HvrEnumExtensions.cs` (`ToHvr()` / `ToVr()`).
+- [x] Replace `HVRHandSide` in `VrWeaponAttackDomain`, `VRWeaponService`, `VRPlayerWeaponInteraction`,
+ `VRContainerDoorPickingInteraction`, `VrHapticsService` (`VibrationType` → `VrHapticPreset`).
+ `VRCinema` and `VRPlayerInputs` only pass it to `HVRController.GetButtonState`, so they move with `IVrInput`
+ in PR 0b.
+- [x] `VRContextMenuService.cs:115` and `VRPlayerController.SetNormalControls`: replace `HVRSitStand`,
+ `PlayerDirectionMode` and `RotationType` with the new enums, converting at the HVR boundary
+ (`VRPlayerController.ApplyComfortSettings`, the later `IVrRig` method).
### PR 0b - Rig, input, haptics, UI ports
@@ -142,6 +146,9 @@ Split into four PRs so each one stays reviewable.
- [ ] `IVrUiPointers` ← `HvrUiPointers` (`HVRInputModule.UICanvases`, `AddCanvas`, `RemoveCanvas`, `Pointers`).
Callers: `VRContextInteractionService.InitUIInteraction`, `OnMarvinLogoPoked`, `VirtualKeyboard`.
- [ ] `VRSeat`: replace the `HVRCanvasFade` lookup with `IVrRig.Fade`.
+- [ ] `SFXPlayer` (HVR's one-shot audio pool, not covered above): `VRWeaponService`, `VrWeaponAttackDomain`,
+ `VRSwimDive` play positional SFX through it. Needs an own replacement (e.g. via `AudioService`) - it's the
+ only reason these files still have `using HurricaneVR.Framework.Core.Utils`.
### PR 0c - Grab and socket events