mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2026-01-01 06:07:30 +00:00
169 lines
No EOL
6 KiB
C#
169 lines
No EOL
6 KiB
C#
using ABI_RC.Core;
|
|
using ABI_RC.Core.InteractionSystem;
|
|
using ABI_RC.Core.Player;
|
|
using ABI_RC.Core.Savior;
|
|
using ABI_RC.Systems.FaceTracking;
|
|
using ABI_RC.Systems.InputManagement;
|
|
using MelonLoader;
|
|
using UnityEngine;
|
|
|
|
namespace NAK.ControlToUnlockEyes;
|
|
|
|
public class ControlToUnlockEyesMod : MelonMod
|
|
{
|
|
public override void OnInitializeMelon()
|
|
{
|
|
HarmonyInstance.Patch(
|
|
typeof(FaceTrackingManager).GetMethod(nameof(FaceTrackingManager.RegisterBuiltinModules),
|
|
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance),
|
|
postfix: new HarmonyLib.HarmonyMethod(typeof(ControlToUnlockEyesMod).GetMethod(nameof(OnPostFaceTrackingManagerRegisterBuiltinModules),
|
|
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static))
|
|
);
|
|
}
|
|
|
|
private static void OnPostFaceTrackingManagerRegisterBuiltinModules(FaceTrackingManager __instance)
|
|
=> __instance.RegisterEyeModule(new DefaultEyeModule());
|
|
|
|
public class DefaultEyeModule : IEyeTrackingModule
|
|
{
|
|
private const float FixedDistance = 10f;
|
|
private bool _useFixedDistance = true;
|
|
|
|
private readonly EyeTrackingData _eyeTrackingData = new();
|
|
private bool _dataAvailable;
|
|
private bool _running;
|
|
|
|
private ControllerRay _activeRay;
|
|
private Transform _rayDirectionTransform;
|
|
|
|
private CVRHand lastInteractHand = CVRHand.Right;
|
|
|
|
public bool Start(bool vr)
|
|
{
|
|
_running = true;
|
|
return true;
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
_running = false;
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
if (!PlayerSetup.Instance)
|
|
return;
|
|
|
|
UpdateLastInteractHand();
|
|
UpdateFakedEyeTrackingData();
|
|
}
|
|
|
|
private void UpdateLastInteractHand()
|
|
{
|
|
ControllerRay leftRay = PlayerSetup.Instance.vrRayLeft;
|
|
ControllerRay rightRay = PlayerSetup.Instance.vrRayRight;
|
|
|
|
if (!MetaPort.Instance.isUsingVr)
|
|
{
|
|
_activeRay = PlayerSetup.Instance.desktopRay;
|
|
_rayDirectionTransform = _activeRay.rayDirectionTransform;
|
|
return;
|
|
}
|
|
|
|
bool leftAvailable = IsHandAvailable(leftRay, CVRHand.Left);
|
|
bool rightAvailable = IsHandAvailable(rightRay, CVRHand.Right);
|
|
|
|
if (CVRInputManager.Instance.interactLeftDown && leftAvailable)
|
|
lastInteractHand = CVRHand.Left;
|
|
else if (CVRInputManager.Instance.interactRightDown && rightAvailable)
|
|
lastInteractHand = CVRHand.Right;
|
|
|
|
_activeRay = GetLastInteractRay();
|
|
_rayDirectionTransform = _activeRay.rayDirectionTransform;
|
|
}
|
|
|
|
private void UpdateFakedEyeTrackingData()
|
|
{
|
|
_dataAvailable = _activeRay.CanSelectPlayersAndProps();
|
|
if (!_dataAvailable)
|
|
return;
|
|
|
|
_eyeTrackingData.blinking = false;
|
|
|
|
Transform ourCameraTransform = PlayerSetup.Instance.activeCam.transform;
|
|
|
|
Vector3 rayForward = _rayDirectionTransform.forward;
|
|
float rayDistance = _useFixedDistance ? FixedDistance : _activeRay.Hit.distance;
|
|
|
|
// TODO: dot product check to flip direction if behind camera
|
|
|
|
// Convert to camera-local *direction* (normalized) and multiply by selected distance so the gazePoint
|
|
// is on a sphere around the camera rather than mapped to a "square".
|
|
Vector3 localDir = ourCameraTransform.InverseTransformDirection(rayForward).normalized;
|
|
Vector3 localGazePoint = localDir * rayDistance;
|
|
|
|
_eyeTrackingData.gazePoint = localGazePoint;
|
|
}
|
|
|
|
private ControllerRay GetLastInteractRay()
|
|
{
|
|
if (!MetaPort.Instance.isUsingVr)
|
|
return PlayerSetup.Instance.desktopRay;
|
|
|
|
ControllerRay leftRay = PlayerSetup.Instance.vrRayLeft;
|
|
ControllerRay rightRay = PlayerSetup.Instance.vrRayRight;
|
|
|
|
if (lastInteractHand == CVRHand.Left && IsHandAvailable(leftRay, CVRHand.Left))
|
|
return leftRay;
|
|
if (lastInteractHand == CVRHand.Right && IsHandAvailable(rightRay, CVRHand.Right))
|
|
return rightRay;
|
|
|
|
return GetBestAvailableHand();
|
|
}
|
|
|
|
private ControllerRay GetBestAvailableHand()
|
|
{
|
|
if (!MetaPort.Instance.isUsingVr)
|
|
return PlayerSetup.Instance.desktopRay;
|
|
|
|
ControllerRay leftRay = PlayerSetup.Instance.vrRayLeft;
|
|
ControllerRay rightRay = PlayerSetup.Instance.vrRayRight;
|
|
|
|
bool leftAvailable = IsHandAvailable(leftRay, CVRHand.Left);
|
|
bool rightAvailable = IsHandAvailable(rightRay, CVRHand.Right);
|
|
|
|
if (CVRInputManager.Instance.interactLeftDown && leftAvailable)
|
|
return leftRay;
|
|
if (CVRInputManager.Instance.interactRightDown && rightAvailable)
|
|
return rightRay;
|
|
|
|
if (lastInteractHand == CVRHand.Left && leftAvailable)
|
|
return leftRay;
|
|
if (lastInteractHand == CVRHand.Right && rightAvailable)
|
|
return rightRay;
|
|
|
|
if (rightAvailable) return rightRay;
|
|
if (leftAvailable) return leftRay;
|
|
|
|
return rightRay;
|
|
}
|
|
|
|
private static bool IsHandAvailable(ControllerRay ray, CVRHand hand)
|
|
{
|
|
if (ray.grabbedObject)
|
|
return false;
|
|
|
|
if (CVR_MenuManager.Instance.IsViewShown &&
|
|
CVR_MenuManager.Instance.SelectedQuickMenuHand == hand)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool IsRunning() => _running;
|
|
public bool IsDataAvailable() => _dataAvailable;
|
|
public EyeTrackingData GetTrackingData() => _eyeTrackingData;
|
|
public string GetModuleName() => "None";
|
|
public string GetModuleShortName() => "None";
|
|
}
|
|
} |