mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2026-02-04 00:56:11 +00:00
Compare commits
2 commits
bf58de493a
...
e14bec132e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e14bec132e | ||
|
|
b4b392d20d |
6 changed files with 315 additions and 1 deletions
9
DesktopInteractions/DesktopInteractions.csproj
Normal file
9
DesktopInteractions/DesktopInteractions.csproj
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>PlayerCloneAttachment</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\playercloneattachment.assets" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
235
DesktopInteractions/Main.cs
Normal file
235
DesktopInteractions/Main.cs
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
using System.Reflection;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Systems.ChatBox;
|
||||
using ABI_RC.Systems.GameEventSystem;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI.CCK.Components;
|
||||
using HarmonyLib;
|
||||
using MelonLoader;
|
||||
using RootMotion.FinalIK;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.DesktopInteractions;
|
||||
|
||||
public class DesktopInteractionsMod : MelonMod
|
||||
{
|
||||
private static readonly MelonPreferences_Category Category =
|
||||
MelonPreferences.CreateCategory(nameof(DesktopInteractions));
|
||||
|
||||
private static readonly MelonPreferences_Entry<bool> EntryTypingGesture =
|
||||
Category.CreateEntry("enable_typing_gesture", true,
|
||||
"Typing Gesture", description: "When enabled you will place your arm up to your ear when typing in ChatBox.");
|
||||
|
||||
private static readonly MelonPreferences_Entry<bool> EntryZoomGesture =
|
||||
Category.CreateEntry("enable_zoom_gesture", false,
|
||||
"Zoom Gesture", description: "When enabled you will cup your hands around your eyes while zooming.");
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
CVRGameEventSystem.Initialization.OnPlayerSetupStart.AddListener(OnPlayerSetupStart);
|
||||
CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(OnLocalAvatarLoad);
|
||||
CVRGameEventSystem.Avatar.OnLocalAvatarHeightScale.AddListener(OnLocalAvatarHeightScale);
|
||||
|
||||
HarmonyInstance.Patch(
|
||||
typeof(IKSystem).GetMethod(nameof(IKSystem.OnPreSolverUpdateGeneral),
|
||||
BindingFlags.NonPublic | BindingFlags.Instance),
|
||||
prefix: new HarmonyMethod(typeof(DesktopInteractionsMod).GetMethod(nameof(OnPreSolverUpdateGeneral),
|
||||
BindingFlags.NonPublic | BindingFlags.Static))
|
||||
);
|
||||
}
|
||||
|
||||
private static Transform _cameraTargetContainerTransform;
|
||||
private static Transform _earIKTargetTransform;
|
||||
private static Transform _leftEyeIKTargetTransform;
|
||||
private static Transform _rightEyeIKTargetTransform;
|
||||
private static Transform _calibratedEarIKTargetTransform;
|
||||
private static Transform _calibratedLeftEyeIKTargetTransform;
|
||||
private static Transform _calibratedRightEyeIKTargetTransform;
|
||||
|
||||
private static IKLimbController _leftArmController;
|
||||
private static IKLimbController _rightArmController;
|
||||
|
||||
private static void OnPlayerSetupStart()
|
||||
{
|
||||
Transform cameraTransform = PlayerSetup.Instance.desktopCamera.transform;
|
||||
|
||||
_cameraTargetContainerTransform = new GameObject("ScaledTargetsContainer").transform;
|
||||
_cameraTargetContainerTransform.SetParent(cameraTransform, false);
|
||||
_cameraTargetContainerTransform.localScale = Vector3.one * PlayerSetup.Instance.GetPlaySpaceScale() * 1.8f;
|
||||
|
||||
_earIKTargetTransform = new GameObject("LeftEarIKTarget").transform;
|
||||
_earIKTargetTransform.SetParent(_cameraTargetContainerTransform);
|
||||
_earIKTargetTransform.localPosition = new Vector3(-0.1141031f, -0.05610896f, 0.01008159f);
|
||||
_earIKTargetTransform.localRotation = Quaternion.Euler(new Vector3(-63.037f, -108.763f, 141.237f));
|
||||
_calibratedEarIKTargetTransform = new GameObject("CalibratedOffset").transform;
|
||||
_calibratedEarIKTargetTransform.SetParent(_earIKTargetTransform, false);
|
||||
|
||||
_leftEyeIKTargetTransform = new GameObject("LeftEyeIKTarget").transform;
|
||||
_leftEyeIKTargetTransform.SetParent(_cameraTargetContainerTransform);
|
||||
_leftEyeIKTargetTransform.localPosition = new Vector3(-0.0768f, -0.0551f, 0.0278f);
|
||||
_leftEyeIKTargetTransform.localRotation = Quaternion.Euler(new Vector3(-47.436f, -34.336f, 84.604f));
|
||||
_calibratedLeftEyeIKTargetTransform = new GameObject("CalibratedOffset").transform;
|
||||
_calibratedLeftEyeIKTargetTransform.SetParent(_leftEyeIKTargetTransform, false);
|
||||
|
||||
_rightEyeIKTargetTransform = new GameObject("RightEyeIKTarget").transform;
|
||||
_rightEyeIKTargetTransform.SetParent(_cameraTargetContainerTransform);
|
||||
_rightEyeIKTargetTransform.localPosition = new Vector3(0.0768f, -0.0551f, 0.0278f);
|
||||
_rightEyeIKTargetTransform.localRotation = Quaternion.Euler(new Vector3(-132.564f, -145.664f, 95.396f));
|
||||
_calibratedRightEyeIKTargetTransform = new GameObject("CalibratedOffset").transform;
|
||||
_calibratedRightEyeIKTargetTransform.SetParent(_rightEyeIKTargetTransform, false);
|
||||
|
||||
_leftArmController = new IKLimbController(8f);
|
||||
_rightArmController = new IKLimbController(8f);
|
||||
}
|
||||
|
||||
private static void OnLocalAvatarLoad(CVRAvatar _)
|
||||
{
|
||||
if (!IKSystem.Instance.IsAvatarCalibrated()) return; // IKSystem did not consider for setup
|
||||
|
||||
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.Default);
|
||||
|
||||
VRIK vrik = IKSystem.vrik;
|
||||
Quaternion localHandRotationLeft = IKCalibrator.CalculateLocalRotation(vrik.references.root, vrik.references.leftHand);
|
||||
_calibratedEarIKTargetTransform.localRotation = localHandRotationLeft;
|
||||
_calibratedLeftEyeIKTargetTransform.localRotation = localHandRotationLeft;
|
||||
|
||||
Quaternion localHandRotationRight = IKCalibrator.CalculateLocalRotation(vrik.references.root, vrik.references.rightHand);
|
||||
_calibratedRightEyeIKTargetTransform.localRotation = localHandRotationRight;
|
||||
|
||||
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.LastSaved);
|
||||
}
|
||||
|
||||
// I fucked the offsets and didn't account for scale until now, so we have to adjust it
|
||||
private static void OnLocalAvatarHeightScale(float height, float scale)
|
||||
=> _cameraTargetContainerTransform.localScale = Vector3.one * scale * 1.8f;
|
||||
|
||||
private static void OnPreSolverUpdateGeneral()
|
||||
{
|
||||
if (MetaPort.Instance.isUsingVr) return;
|
||||
|
||||
bool isTyping = EntryTypingGesture.Value && ChatBoxManager.Instance.LocalPlayerBubble.IsTypingIndicatorActive;
|
||||
bool isZooming = EntryZoomGesture.Value && CVR_DesktopCameraController.GetCurrentZoomModifier() > 0.25f;
|
||||
|
||||
_leftArmController.SetInfluence(10, isTyping, _calibratedEarIKTargetTransform);
|
||||
_leftArmController.SetInfluence(5, isZooming, _calibratedLeftEyeIKTargetTransform);
|
||||
_leftArmController.Update(Time.deltaTime);
|
||||
|
||||
IKSolverVR solver = IKSystem.vrik.solver;
|
||||
|
||||
IKSolverVR.Arm leftArm = solver.leftArm;
|
||||
leftArm.positionWeight = _leftArmController.Weight;
|
||||
leftArm.rotationWeight = _leftArmController.Weight;
|
||||
leftArm.IKPosition = _leftArmController.Position;
|
||||
leftArm.IKRotation = _leftArmController.Rotation;
|
||||
|
||||
_rightArmController.SetInfluence(5, isZooming, _calibratedRightEyeIKTargetTransform);
|
||||
_rightArmController.Update(Time.deltaTime);
|
||||
|
||||
IKSolverVR.Arm rightArm = solver.rightArm;
|
||||
rightArm.positionWeight = _rightArmController.Weight;
|
||||
rightArm.rotationWeight = _rightArmController.Weight;
|
||||
rightArm.IKPosition = _rightArmController.Position;
|
||||
rightArm.IKRotation = _rightArmController.Rotation;
|
||||
}
|
||||
}
|
||||
|
||||
public class IKLimbController(float blendSpeed)
|
||||
{
|
||||
private struct Influence
|
||||
{
|
||||
public int Priority;
|
||||
public bool IsActive;
|
||||
public Transform Target;
|
||||
}
|
||||
|
||||
private readonly Influence[] _influences = new Influence[8];
|
||||
private int _count;
|
||||
|
||||
private Vector3 _position;
|
||||
private Quaternion _rotation = Quaternion.identity;
|
||||
private float _weight;
|
||||
|
||||
private Transform _fromTarget;
|
||||
private Transform _toTarget;
|
||||
/*private Vector3 _fromPosition;
|
||||
private Quaternion _fromRotation;*/
|
||||
private float _blendT;
|
||||
|
||||
public Vector3 Position => _position;
|
||||
public Quaternion Rotation => _rotation;
|
||||
public float Weight => _weight;
|
||||
|
||||
public void SetInfluence(int priority, bool isActive, Transform target)
|
||||
{
|
||||
int index = -1;
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
if (_influences[i].Priority == priority)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
if (_influences[i].Priority < priority)
|
||||
{
|
||||
index = i;
|
||||
for (int j = _count; j > i; j--) _influences[j] = _influences[j - 1];
|
||||
_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
if (_count >= _influences.Length) return;
|
||||
index = _count++;
|
||||
}
|
||||
|
||||
_influences[index] = new Influence { Priority = priority, IsActive = isActive, Target = target };
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
Transform target = null;
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
if (!_influences[i].IsActive) continue;
|
||||
target = _influences[i].Target;
|
||||
break;
|
||||
}
|
||||
|
||||
float targetWeight;
|
||||
if (target != null)
|
||||
{
|
||||
targetWeight = 1f;
|
||||
|
||||
if (_toTarget != target)
|
||||
{
|
||||
/*if (_toTarget != null)
|
||||
{
|
||||
_fromPosition = _toTarget.position;
|
||||
_fromRotation = _toTarget.rotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
_fromPosition = target.position;
|
||||
_fromRotation = target.rotation;
|
||||
}*/
|
||||
_fromTarget = _toTarget ?? target;
|
||||
_toTarget = target;
|
||||
_blendT = 0f;
|
||||
}
|
||||
|
||||
_blendT = Mathf.Min(_blendT + blendSpeed * deltaTime, 1f);
|
||||
_position = Vector3.Lerp(_fromTarget.position, _toTarget.position, _blendT);
|
||||
_rotation = Quaternion.Slerp(_fromTarget.rotation, _toTarget.rotation, _blendT);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetWeight = 0f;
|
||||
_toTarget = null;
|
||||
}
|
||||
|
||||
_weight = Mathf.MoveTowards(_weight, targetWeight, blendSpeed * deltaTime);
|
||||
}
|
||||
}
|
||||
32
DesktopInteractions/Properties/AssemblyInfo.cs
Normal file
32
DesktopInteractions/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
using MelonLoader;
|
||||
using NAK.DesktopInteractions.Properties;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyTitle(nameof(NAK.DesktopInteractions))]
|
||||
[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
|
||||
[assembly: AssemblyProduct(nameof(NAK.DesktopInteractions))]
|
||||
|
||||
[assembly: MelonInfo(
|
||||
typeof(NAK.DesktopInteractions.DesktopInteractionsMod),
|
||||
nameof(NAK.DesktopInteractions),
|
||||
AssemblyInfoParams.Version,
|
||||
AssemblyInfoParams.Author,
|
||||
downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/DesktopInteractions"
|
||||
)]
|
||||
|
||||
[assembly: MelonGame("ChilloutVR", "ChilloutVR")]
|
||||
[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
[assembly: MelonColor(255, 246, 25, 99)] // red-pink
|
||||
[assembly: MelonAuthorColor(255, 158, 21, 32)] // red
|
||||
[assembly: HarmonyDontPatchAll]
|
||||
|
||||
namespace NAK.DesktopInteractions.Properties;
|
||||
internal static class AssemblyInfoParams
|
||||
{
|
||||
public const string Version = "1.0.0";
|
||||
public const string Author = "NotAKidoS";
|
||||
}
|
||||
14
DesktopInteractions/README.md
Normal file
14
DesktopInteractions/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# DesktopInteractions
|
||||
|
||||
Adds IK-driven hand gestures to your avatar in Desktop: earpiece grab (GMOD-style) when typing in ChatBox, and binocular cupping when zooming. Both gestures are toggleable in settings.
|
||||
|
||||
---
|
||||
|
||||
Here is the block of text where I tell you this mod is not affiliated with or endorsed by ABI.
|
||||
https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games
|
||||
|
||||
> This mod is an independent creation not affiliated with, supported by, or approved by Alpha Blend Interactive.
|
||||
|
||||
> Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use.
|
||||
|
||||
> To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive.
|
||||
23
DesktopInteractions/format.json
Normal file
23
DesktopInteractions/format.json
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"_id": -1,
|
||||
"name": "DesktopInteractions",
|
||||
"modversion": "1.0.0",
|
||||
"gameversion": "2025r181",
|
||||
"loaderversion": "0.7.2",
|
||||
"modtype": "Mod",
|
||||
"author": "NotAKidoS",
|
||||
"description": "Adds IK-driven hand gestures to your avatar in Desktop: earpiece grab (GMOD-style) when typing in ChatBox, and binocular cupping when zooming. Both gestures are toggleable in settings.",
|
||||
"searchtags": [
|
||||
"gmod",
|
||||
"typing",
|
||||
"zooming",
|
||||
"desktop"
|
||||
],
|
||||
"requirements": [
|
||||
"None"
|
||||
],
|
||||
"downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/DesktopInteractions.dll",
|
||||
"sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/DesktopInteractions/",
|
||||
"changelog": "- Initial release",
|
||||
"embedcolor": "#f61963"
|
||||
}
|
||||
|
|
@ -9,9 +9,10 @@
|
|||
| [ASTExtension](ASTExtension/README.md) | Extension mod for [Avatar Scale Tool](https://github.com/NotAKidoS/AvatarScaleTool): | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/ASTExtension.dll) |
|
||||
| [ConfigureCalibrationPose](ConfigureCalibrationPose/README.md) | Select FBT calibration pose. | No Download |
|
||||
| [CustomSpawnPoint](CustomSpawnPoint/README.md) | Replaces the unused Images button in the World Details page with a button to set a custom spawn point. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/CustomSpawnPoint.dll) |
|
||||
| [DesktopInteractions](DesktopInteractions/README.md) | Adds IK-driven hand gestures to your avatar in Desktop: earpiece grab (GMOD-style) when typing in ChatBox, and binocular cupping when zooming. Both gestures are toggleable in settings. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/DesktopInteractions.dll) |
|
||||
| [DoubleTapJumpToExitSeat](DoubleTapJumpToExitSeat/README.md) | Replaces seat exit controls with a double-tap of the jump button, avoiding accidental exits from joystick drift or opening the menu. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/DoubleTapJumpToExitSeat.dll) |
|
||||
| [FuckToes](FuckToes/README.md) | Prevents VRIK from autodetecting toes in Halfbody or Fullbody. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/FuckToes.dll) |
|
||||
| [PlapPlapForAll](PlapPlapForAll/README.md) | Penetrator SFX mod which adds Noach's PlapPlap prefab to any detected DPS setup on avatars that do not already have it. | No Download |
|
||||
| [PlapPlapForAll](PlapPlapForAll/README.md) | Penetrator SFX mod which adds Noach's PlapPlap prefab to any detected DPS setup on avatars that do not already have it. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/PlapPlapForAll.dll) |
|
||||
| [PropLoadingHexagon](PropLoadingHexagon/README.md) | https://github.com/NotAKidoS/NAK_CVR_Mods/assets/37721153/a892c765-71c1-47f3-a781-bdb9b60ba117 | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/PropLoadingHexagon.dll) |
|
||||
| [RCCVirtualSteeringWheel](RCCVirtualSteeringWheel/README.md) | Allows you to physically grab rigged RCC steering wheels in VR to provide steering input. No explicit setup required other than defining the Steering Wheel transform within the RCC component. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/RCCVirtualSteeringWheel.dll) |
|
||||
| [RelativeSyncJitterFix](RelativeSyncJitterFix/README.md) | Relative sync jitter fix is the single harmony patch that could not make it into the native release of RelativeSync. | [Download](https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r48/RelativeSyncJitterFix.dll) |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue