1+ using System . Reflection ;
2+ using ABI_RC . Core . Player ;
3+ using ABI_RC . Core . Savior ;
4+ using ABI_RC . Systems . ChatBox ;
5+ using ABI_RC . Systems . GameEventSystem ;
6+ using ABI_RC . Systems . IK ;
7+ using ABI . CCK . Components ;
8+ using HarmonyLib ;
9+ using MelonLoader ;
10+ using RootMotion . FinalIK ;
11+ using UnityEngine ;
12+
13+ namespace NAK . DesktopInteractions ;
14+
15+ public class DesktopInteractionsMod : MelonMod
16+ {
17+ private static readonly MelonPreferences_Category Category =
18+ MelonPreferences . CreateCategory ( nameof ( DesktopInteractions ) ) ;
19+
20+ private static readonly MelonPreferences_Entry < bool > EntryTypingGesture =
21+ Category . CreateEntry ( "enable_typing_gesture" , true ,
22+ "Typing Gesture" , description : "When enabled you will place your arm up to your ear when typing in ChatBox." ) ;
23+
24+ private static readonly MelonPreferences_Entry < bool > EntryZoomGesture =
25+ Category . CreateEntry ( "enable_zoom_gesture" , false ,
26+ "Zoom Gesture" , description : "When enabled you will cup your hands around your eyes while zooming." ) ;
27+
28+ public override void OnInitializeMelon ( )
29+ {
30+ CVRGameEventSystem . Initialization . OnPlayerSetupStart . AddListener ( OnPlayerSetupStart ) ;
31+ CVRGameEventSystem . Avatar . OnLocalAvatarLoad . AddListener ( OnLocalAvatarLoad ) ;
32+ CVRGameEventSystem . Avatar . OnLocalAvatarHeightScale . AddListener ( OnLocalAvatarHeightScale ) ;
33+
34+ HarmonyInstance . Patch (
35+ typeof ( IKSystem ) . GetMethod ( nameof ( IKSystem . OnPreSolverUpdateGeneral ) ,
36+ BindingFlags . NonPublic | BindingFlags . Instance ) ,
37+ prefix : new HarmonyMethod ( typeof ( DesktopInteractionsMod ) . GetMethod ( nameof ( OnPreSolverUpdateGeneral ) ,
38+ BindingFlags . NonPublic | BindingFlags . Static ) )
39+ ) ;
40+ }
41+
42+ private static Transform _cameraTargetContainerTransform ;
43+ private static Transform _earIKTargetTransform ;
44+ private static Transform _leftEyeIKTargetTransform ;
45+ private static Transform _rightEyeIKTargetTransform ;
46+ private static Transform _calibratedEarIKTargetTransform ;
47+ private static Transform _calibratedLeftEyeIKTargetTransform ;
48+ private static Transform _calibratedRightEyeIKTargetTransform ;
49+
50+ private static IKLimbController _leftArmController ;
51+ private static IKLimbController _rightArmController ;
52+
53+ private static void OnPlayerSetupStart ( )
54+ {
55+ Transform cameraTransform = PlayerSetup . Instance . desktopCamera . transform ;
56+
57+ _cameraTargetContainerTransform = new GameObject ( "ScaledTargetsContainer" ) . transform ;
58+ _cameraTargetContainerTransform . SetParent ( cameraTransform , false ) ;
59+ _cameraTargetContainerTransform . localScale = Vector3 . one * PlayerSetup . Instance . GetPlaySpaceScale ( ) * 1.8f ;
60+
61+ _earIKTargetTransform = new GameObject ( "LeftEarIKTarget" ) . transform ;
62+ _earIKTargetTransform . SetParent ( _cameraTargetContainerTransform ) ;
63+ _earIKTargetTransform . localPosition = new Vector3 ( - 0.1141031f , - 0.05610896f , 0.01008159f ) ;
64+ _earIKTargetTransform . localRotation = Quaternion . Euler ( new Vector3 ( - 63.037f , - 108.763f , 141.237f ) ) ;
65+ _calibratedEarIKTargetTransform = new GameObject ( "CalibratedOffset" ) . transform ;
66+ _calibratedEarIKTargetTransform . SetParent ( _earIKTargetTransform , false ) ;
67+
68+ _leftEyeIKTargetTransform = new GameObject ( "LeftEyeIKTarget" ) . transform ;
69+ _leftEyeIKTargetTransform . SetParent ( _cameraTargetContainerTransform ) ;
70+ _leftEyeIKTargetTransform . localPosition = new Vector3 ( - 0.0768f , - 0.0551f , 0.0278f ) ;
71+ _leftEyeIKTargetTransform . localRotation = Quaternion . Euler ( new Vector3 ( - 47.436f , - 34.336f , 84.604f ) ) ;
72+ _calibratedLeftEyeIKTargetTransform = new GameObject ( "CalibratedOffset" ) . transform ;
73+ _calibratedLeftEyeIKTargetTransform . SetParent ( _leftEyeIKTargetTransform , false ) ;
74+
75+ _rightEyeIKTargetTransform = new GameObject ( "RightEyeIKTarget" ) . transform ;
76+ _rightEyeIKTargetTransform . SetParent ( _cameraTargetContainerTransform ) ;
77+ _rightEyeIKTargetTransform . localPosition = new Vector3 ( 0.0768f , - 0.0551f , 0.0278f ) ;
78+ _rightEyeIKTargetTransform . localRotation = Quaternion . Euler ( new Vector3 ( - 132.564f , - 145.664f , 95.396f ) ) ;
79+ _calibratedRightEyeIKTargetTransform = new GameObject ( "CalibratedOffset" ) . transform ;
80+ _calibratedRightEyeIKTargetTransform . SetParent ( _rightEyeIKTargetTransform , false ) ;
81+
82+ _leftArmController = new IKLimbController ( 8f ) ;
83+ _rightArmController = new IKLimbController ( 8f ) ;
84+ }
85+
86+ private static void OnLocalAvatarLoad ( CVRAvatar _ )
87+ {
88+ if ( ! IKSystem . Instance . IsAvatarCalibrated ( ) ) return ; // IKSystem did not consider for setup
89+
90+ IKSystem . Instance . SetAvatarPose ( IKSystem . AvatarPose . Default ) ;
91+
92+ VRIK vrik = IKSystem . vrik ;
93+ Quaternion localHandRotationLeft = IKCalibrator . CalculateLocalRotation ( vrik . references . root , vrik . references . leftHand ) ;
94+ _calibratedEarIKTargetTransform . localRotation = localHandRotationLeft ;
95+ _calibratedLeftEyeIKTargetTransform . localRotation = localHandRotationLeft ;
96+
97+ Quaternion localHandRotationRight = IKCalibrator . CalculateLocalRotation ( vrik . references . root , vrik . references . rightHand ) ;
98+ _calibratedRightEyeIKTargetTransform . localRotation = localHandRotationRight ;
99+
100+ IKSystem . Instance . SetAvatarPose ( IKSystem . AvatarPose . LastSaved ) ;
101+ }
102+
103+ // I fucked the offsets and didn't account for scale until now, so we have to adjust it
104+ private static void OnLocalAvatarHeightScale ( float height , float scale )
105+ => _cameraTargetContainerTransform . localScale = Vector3 . one * scale * 1.8f ;
106+
107+ private static void OnPreSolverUpdateGeneral ( )
108+ {
109+ if ( MetaPort . Instance . isUsingVr ) return ;
110+
111+ bool isTyping = EntryTypingGesture . Value && ChatBoxManager . Instance . LocalPlayerBubble . IsTypingIndicatorActive ;
112+ bool isZooming = EntryZoomGesture . Value && CVR_DesktopCameraController . GetCurrentZoomModifier ( ) > 0.25f ;
113+
114+ _leftArmController . SetInfluence ( 10 , isTyping , _calibratedEarIKTargetTransform ) ;
115+ _leftArmController . SetInfluence ( 5 , isZooming , _calibratedLeftEyeIKTargetTransform ) ;
116+ _leftArmController . Update ( Time . deltaTime ) ;
117+
118+ IKSolverVR solver = IKSystem . vrik . solver ;
119+
120+ IKSolverVR . Arm leftArm = solver . leftArm ;
121+ leftArm . positionWeight = _leftArmController . Weight ;
122+ leftArm . rotationWeight = _leftArmController . Weight ;
123+ leftArm . IKPosition = _leftArmController . Position ;
124+ leftArm . IKRotation = _leftArmController . Rotation ;
125+
126+ _rightArmController . SetInfluence ( 5 , isZooming , _calibratedRightEyeIKTargetTransform ) ;
127+ _rightArmController . Update ( Time . deltaTime ) ;
128+
129+ IKSolverVR . Arm rightArm = solver . rightArm ;
130+ rightArm . positionWeight = _rightArmController . Weight ;
131+ rightArm . rotationWeight = _rightArmController . Weight ;
132+ rightArm . IKPosition = _rightArmController . Position ;
133+ rightArm . IKRotation = _rightArmController . Rotation ;
134+ }
135+ }
136+
137+ public class IKLimbController ( float blendSpeed )
138+ {
139+ private struct Influence
140+ {
141+ public int Priority ;
142+ public bool IsActive ;
143+ public Transform Target ;
144+ }
145+
146+ private readonly Influence [ ] _influences = new Influence [ 8 ] ;
147+ private int _count ;
148+
149+ private Vector3 _position ;
150+ private Quaternion _rotation = Quaternion . identity ;
151+ private float _weight ;
152+
153+ private Transform _fromTarget ;
154+ private Transform _toTarget ;
155+ /*private Vector3 _fromPosition;
156+ private Quaternion _fromRotation;*/
157+ private float _blendT ;
158+
159+ public Vector3 Position => _position ;
160+ public Quaternion Rotation => _rotation ;
161+ public float Weight => _weight ;
162+
163+ public void SetInfluence ( int priority , bool isActive , Transform target )
164+ {
165+ int index = - 1 ;
166+ for ( int i = 0 ; i < _count ; i ++ )
167+ {
168+ if ( _influences [ i ] . Priority == priority )
169+ {
170+ index = i ;
171+ break ;
172+ }
173+ if ( _influences [ i ] . Priority < priority )
174+ {
175+ index = i ;
176+ for ( int j = _count ; j > i ; j -- ) _influences [ j ] = _influences [ j - 1 ] ;
177+ _count ++ ;
178+ break ;
179+ }
180+ }
181+
182+ if ( index == - 1 )
183+ {
184+ if ( _count >= _influences . Length ) return ;
185+ index = _count ++ ;
186+ }
187+
188+ _influences [ index ] = new Influence { Priority = priority , IsActive = isActive , Target = target } ;
189+ }
190+
191+ public void Update ( float deltaTime )
192+ {
193+ Transform target = null ;
194+ for ( int i = 0 ; i < _count ; i ++ )
195+ {
196+ if ( ! _influences [ i ] . IsActive ) continue ;
197+ target = _influences [ i ] . Target ;
198+ break ;
199+ }
200+
201+ float targetWeight ;
202+ if ( target != null )
203+ {
204+ targetWeight = 1f ;
205+
206+ if ( _toTarget != target )
207+ {
208+ /*if (_toTarget != null)
209+ {
210+ _fromPosition = _toTarget.position;
211+ _fromRotation = _toTarget.rotation;
212+ }
213+ else
214+ {
215+ _fromPosition = target.position;
216+ _fromRotation = target.rotation;
217+ }*/
218+ _fromTarget = _toTarget ?? target ;
219+ _toTarget = target ;
220+ _blendT = 0f ;
221+ }
222+
223+ _blendT = Mathf . Min ( _blendT + blendSpeed * deltaTime , 1f ) ;
224+ _position = Vector3 . Lerp ( _fromTarget . position , _toTarget . position , _blendT ) ;
225+ _rotation = Quaternion . Slerp ( _fromTarget . rotation , _toTarget . rotation , _blendT ) ;
226+ }
227+ else
228+ {
229+ targetWeight = 0f ;
230+ _toTarget = null ;
231+ }
232+
233+ _weight = Mathf . MoveTowards ( _weight , targetWeight , blendSpeed * deltaTime ) ;
234+ }
235+ }
0 commit comments