-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMyBhapticsTactsuit.cs
193 lines (169 loc) · 7.36 KB
/
MyBhapticsTactsuit.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using MelonLoader;
namespace MyBhapticsTactsuit
{
public class TactsuitVR
{
/* A class that contains the basic functions for the bhaptics Tactsuit, like:
* - A Heartbeat function that can be turned on/off
* - A function to read in and register all .tact patterns in the bHaptics subfolder
* - A logging hook to output to the Melonloader log
* -
* */
public bool suitDisabled = true;
public bool systemInitialized = false;
// Event to start and stop the heartbeat thread
private static ManualResetEvent HeartBeat_mrse = new ManualResetEvent(false);
// dictionary of all feedback patterns found in the bHaptics directory
public Dictionary<String, FileInfo> FeedbackMap = new Dictionary<String, FileInfo>();
private static bHaptics.RotationOption defaultRotationOption = new bHaptics.RotationOption(0.0f, 0.0f);
public void HeartBeatFunc()
{
while (true)
{
// Check if reset event is active
HeartBeat_mrse.WaitOne();
bHaptics.SubmitRegistered("HeartBeat");
Thread.Sleep(600);
}
}
public TactsuitVR()
{
LOG("Initializing suit");
if (!bHaptics.WasError)
{
suitDisabled = false;
}
RegisterAllTactFiles();
LOG("Starting HeartBeat thread...");
Thread HeartBeatThread = new Thread(HeartBeatFunc);
HeartBeatThread.Start();
}
public void LOG(string logStr)
{
#pragma warning disable CS0618 // remove warning that the logger is deprecated
MelonLogger.Msg(logStr);
#pragma warning restore CS0618
}
void RegisterAllTactFiles()
{
// Get location of the compiled assembly and search through "bHaptics" directory and contained patterns
string configPath = Directory.GetCurrentDirectory() + "\\Mods\\bHaptics";
DirectoryInfo d = new DirectoryInfo(configPath);
FileInfo[] Files = d.GetFiles("*.tact", SearchOption.AllDirectories);
for (int i = 0; i < Files.Length; i++)
{
string filename = Files[i].Name;
string fullName = Files[i].FullName;
string prefix = Path.GetFileNameWithoutExtension(filename);
// LOG("Trying to register: " + prefix + " " + fullName);
if (filename == "." || filename == "..")
continue;
string tactFileStr = File.ReadAllText(fullName);
try
{
bHaptics.RegisterFeedbackFromTactFile(prefix, tactFileStr);
LOG("Pattern registered: " + prefix);
}
catch (Exception e) { LOG(e.ToString()); }
FeedbackMap.Add(prefix, Files[i]);
}
systemInitialized = true;
}
public void PlaybackHaptics(String key, float intensity = 1.0f, float duration = 1.0f)
{
//LOG("Trying to play");
if (FeedbackMap.ContainsKey(key))
{
//LOG("ScaleOption");
bHaptics.ScaleOption scaleOption = new bHaptics.ScaleOption(intensity, duration);
//LOG("Submit");
bHaptics.SubmitRegistered(key, key, scaleOption, defaultRotationOption);
// LOG("Playing back: " + key);
}
else
{
LOG("Feedback not registered: " + key);
}
}
public void PlayBackHit(String key, float xzAngle, float yShift)
{
// two parameters can be given to the pattern to move it on the vest:
// 1. An angle in degrees [0, 360] to turn the pattern to the left
// 2. A shift [-0.5, 0.5] in y-direction (up and down) to move it up or down
bHaptics.ScaleOption scaleOption = new bHaptics.ScaleOption(1f, 1f);
bHaptics.RotationOption rotationOption = new bHaptics.RotationOption(xzAngle, yShift);
bHaptics.SubmitRegistered(key, key, scaleOption, rotationOption);
}
public void Recoil(string weaponName, bool isRightHand, float intensity = 1.0f)
{
// weaponName is a parameter that will go into the vest feedback pattern name
// isRightHand is just which side the feedback is on
// intensity should usually be between 0 and 1
float duration = 1.0f;
var scaleOption = new bHaptics.ScaleOption(intensity, duration);
// the function needs some rotation if you want to give the scale option as well
var rotationFront = new bHaptics.RotationOption(0f, 0f);
// make postfix according to parameter
string postfix = "_L";
if (isRightHand) { postfix = "_R"; }
// stitch together pattern names for Arm and Hand recoil
string keyHands = "RecoilHands" + postfix;
string keyArm = "Recoil" + postfix;
// vest pattern name contains the weapon name. This way, you can quickly switch
// between swords, pistols, shotguns, ... by just changing the shoulder feedback
// and scaling via the intensity for arms and hands
string keyVest = "Recoil" + weaponName + "Vest" + postfix;
bHaptics.SubmitRegistered(keyHands, keyHands, scaleOption, rotationFront);
bHaptics.SubmitRegistered(keyArm, keyArm, scaleOption, rotationFront);
bHaptics.SubmitRegistered(keyVest, keyVest, scaleOption, rotationFront);
}
public void HeadShot(String key, float hitAngle)
{
// I made 4 patterns in the Tactal for fron/back/left/right headshots
if (bHaptics.IsDeviceConnected(bHaptics.DeviceType.Tactal))
{
if ((hitAngle < 45f) | (hitAngle > 315f)) { PlaybackHaptics("Headshot_F"); }
if ((hitAngle > 45f) && (hitAngle < 135f)) { PlaybackHaptics("Headshot_L"); }
if ((hitAngle > 135f) && (hitAngle < 225f)) { PlaybackHaptics("Headshot_B"); }
if ((hitAngle > 225f) && (hitAngle < 315f)) { PlaybackHaptics("Headshot_R"); }
}
// If there is no Tactal, just forward to the vest with angle and at the very top (0.5)
else { PlayBackHit(key, hitAngle, 0.5f); }
}
public void StartHeartBeat()
{
HeartBeat_mrse.Set();
}
public void StopHeartBeat()
{
HeartBeat_mrse.Reset();
}
public bool IsPlaying(String effect)
{
return bHaptics.IsPlaying(effect);
}
public void StopHapticFeedback(String effect)
{
bHaptics.TurnOff(effect);
}
public void StopAllHapticFeedback()
{
StopThreads();
foreach (String key in FeedbackMap.Keys)
{
bHaptics.TurnOff(key);
}
}
public void StopThreads()
{
// Yes, looks silly here, but if you have several threads like this, this is
// very useful when the player dies or starts a new level
StopHeartBeat();
}
}
}