200Tigersbloxed / UnityMods

A collection of my mods for games that run on the Unity Engine.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[HRtoVRChat] Add support for generic Bluetooth LE/GATT devices on Windows 10

Naraenda opened this issue Β· comments

commented

Windows 10 allows Bluetooth GATT/LE heart rate monitors to be connected.
It would be great if this mod also could use these kinds of connections instead of doing it via 3rd party services.

image

I've implemented a small library which you could use or use as a reference for implementing it yourself.

Looks amazing! I'll add it as soon as I can! Unfortunately, it may be a couple of days as I'm currently sick and will have makeup work to finish when I get to feeling better... D: Thanks a lot though!

EDIT: Also verify that it doesn't already work with https://github.com/jlennox/HeartRate as the mod supports grabbing HR data from a text file

commented

Looks amazing! I'll add it as soon as I can! Unfortunately, it may be a couple of days as I'm currently sick and will have makeup work to finish when I get to feeling better... D: Thanks a lot though!

Thanks! No rush. I might try to add it myself if I find some spare time. Hope you get well soon!

EDIT: Also verify that it doesn't already work with https://github.com/jlennox/HeartRate as the mod supports grabbing HR data from a text file

I think it would work (maybe with a bit of modification).
But it would definitely be nice to have everything be standalone in the mod so you wouldn't need to start another program to run in the background.

The standalone feature is nice, but if you do the text file approach, then the HR data app you made can support multiple things too, such as OBS.

Back again, for your library, would you like me to build it myself, or do you want to provide your own build and publish it as a release? @Naraenda

Because this relies on the Windows SDK, and not many people having that installed (I don't blame them, I didn't even have if, nor do I know which SDK all the Contracts are apart of), I decided to implement this using Reflection. Because of choosing Reflection over just adding a Reference, I no longer require every client to have the Windows SDK installed.

Here's what happens when someone without the Windows SDK tries to run the mod using Assembly References, rather than Reflection:

Then their game proceeds to crash. Keep in mind, this person had Pulsoid selected as their HRManager, so the interface which initializes the HRManager didn't even get invoked.

I'd like to be able to test the reflection, so if you happen to know which Windows SDK I need to install, that would speed up the debugging process by a lot!

commented

Hai.
The required Windows Runtime APIs should work from Windows 10 build 10240 (10.0.10240) and later.
You can find those in C:\Program Files (x86)\Windows Kits\10\References\<sdkversion>\Windows.Foundation.UniversalApiContract\10.0.0.0\Windows.Foundation.UniversalApiContract.winmd or via nuget in %USERPROFILE%\.nuget\packages\microsoft.windows.sdk.contracts\<sdkversion>\ref\netstandard2.0\Windows.Foundation.UniversalApiContract.winmd.
I think reflection should be able to handle those kinds of files.

Ps. Does marking those dependencies as optional not work?

Thank you much for the info!

Ps. Does marking those dependencies as optional not work?

No clue, haven't tried it. I would assume not since they're SDK contracts, but who knows. I can try that, but I don't think it would stop the crashing from happening.

Added to v1.4.0 Pre-Release, I highly doubt this will work and will probably cause a crash, but that's what Pre-Releases are for...

Re-open issue if you notice any issues or errors.

commented

Starting the mod with the WinBLEGATTManager gives an error on my end:

[17:30:15.142] [HRtoVRChat] [HRtoVRChat/MainMod] (LOG): Starting HRtoVRChat!
[17:30:15.144] [HRtoVRChat] [HRtoVRChat/ConfigHelper] (LOG): Created Config!
[17:30:15.145] [HRtoVRChat] [HRtoVRChat/ConfigHelper] (LOG): Loaded Config!
[17:30:15.151] [HRtoVRChat] [HRtoVRChat/AssetManager] (LOG): Loaded AssetBudle!
[17:30:15.153] [HRtoVRChat] [HRtoVRChat/ModSupport.UIX] (DEBUG): Found UIX!
[17:30:15.154] [HRtoVRChat] [HRtoVRChat/MainMod] (LOG): UI Expansion Kit loaded!
[17:30:15.156] [HRtoVRChat] [HRtoVRChat/ModSupport.AMAPI] (DEBUG): Found ActionMenuApi!
[17:30:15.157] [HRtoVRChat] [HRtoVRChat/MainMod] (LOG): ActionMenuApi loaded!
[17:30:15.158] [HRtoVRChat] [HRtoVRChat/WinBLEGATTManager] (DEBUG): Loaded GenericHRLib Assembly!
[17:30:15.160] [HRtoVRChat] [HRtoVRChat/WinBLEGATTManager] (DEBUG): Loaded GenericHRLib Assembly Symbols!
[17:30:15.163] [HRtoVRChat] [HRtoVRChat/ParamsManager] (DEBUG): IntParameter with ParameterName: onesHR, has been created!
[17:30:15.165] [HRtoVRChat] [HRtoVRChat/ParamsManager] (DEBUG): IntParameter with ParameterName: tensHR, has been created!
[17:30:15.166] [HRtoVRChat] [HRtoVRChat/ParamsManager] (DEBUG): IntParameter with ParameterName: hundredsHR, has been created![
17:30:15.168] [HRtoVRChat] [ERROR] [HRtoVRChat/WinBLEGATTManager] (LOG): GenericHR Assembly is null!

It happened because generichr_assembly wasn't never set in the code. I assume it need to be loaded in load_generichr_resource. However, after fixing that, it started complaining about missing Windows.Foundation.FoundationContract and Windows.Foundation.UniversalApiContract. Loading in those assemblies allowed the mod to initialize GenericHRDevice, but it throws an error while calling FindAndConnect(). (Stuff I tried here)

[22:24:02.082] [HRtoVRChat] [ERROR] [HRtoVRChat/WinBLEGATTManager] (LOG): Failed to FindAndConnect() devices! Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.MissingMethodException: void Windows.Devices.Bluetooth.GenericAttributeProfile.GattDeviceService.Dispose()
  at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod,object,object[],System.Exception&)
  at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00032] in <e1319b7195c343e79b385cd3aa43f5dc>:0
   --- End of inner exception stack trace ---
  at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00048] in <e1319b7195c343e79b385cd3aa43f5dc>:0
  at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in <e1319b7195c343e79b385cd3aa43f5dc>:0
  at HRtoVRChat.HRManagers.WinBLEGATTManager.generichrdevice_findandconnect (System.Object reference) [0x00017] in <194774867b8c4b03bb99bd844939c690>:0

MissingMethodException during the Dispose... I feel there is some funky things going on with the reflection, but I'm honestly a bit at a loss here how to fix it πŸ€·β€β™€οΈ. At the bright side, it doesn't crash the client πŸ˜„

If it seems too much to get working feel free to drop this. πŸ˜…

Starting the mod with the WinBLEGATTManager gives an error on my end:

Probably failed to load the Assembly with the PDB bytes. I shouldn't have added that lol.

I assume it need to be loaded in load_generichr_resource

The tree looks like load_generichr_resource() -> create_generichr_resource() -> generichrdevice_register_events() -> generichrdevice_findandconnect() -> generichrdevice_dispose()

MissingMethodException during the Dispose...

If you look closer at the exception, it's coming from Windows.Devices.Bluetooth.GenericAttributeProfile.GattDeviceService.Dispose(), not an IDisposable (from System) or something else in the GenericHRLib. I think that Windows.Devices.Bluetooth is a totally different library that is missing, which is why it's throwing a missing method exception.

I'm going to try and switch back to Assembly References and use ILRepack to just merge the Windows Foundation Contratcs, and hope it's not against some licensing or something like that.

If it seems too much to get working feel free to drop this.

The point of the pre-release was to get this tested with clients who do and don't have the BLE/GATT stuff to make sure it works, plus I'm not letting good code go to waste!

EDIT: Maybe these winmd files shouldn't be merged, and should just have their Assembly loaded instead. I'll just have to do some path finding for it lol.

EDIT2: A little while later and I get this exception
System.TypeInitializationException: The type initializer for 'GenericHRLib.GenericHRDevice' threw an exception. ---> System.InvalidProgramException: Unrecognizable runtime implemented method 'Windows.Devices.Bluetooth.BluetoothUuidHelper:FromShortId (uint)'

Kinda clueless here from this point, so anymore help would be appreciated. All I've done is Load the two Contract SDKs from File (Assembly.LoadFile()) and merged System.Runtime.WindowsRuntime with ILRepack

EDIT3: Here's where I stopped
https://gist.github.com/200Tigersbloxed/7dde1fdf72e506ed681c867ece6ff464

commented

If you look closer at the exception, it's coming from Windows.Devices.Bluetooth.GenericAttributeProfile.GattDeviceService.Dispose(), not an IDisposable (from System) or something else in the GenericHRLib.

I think the .Dispose() is triggered here. Which is really weird since during first start that value should be null and the .Dispose call should be skipped.

I think that Windows.Devices.Bluetooth is a totally different library that is missing, which is why it's throwing a missing method exception.

I was thinking something similar but I haven't found it yet. Some people said including Windows.Foundation.winmd and Windows.Services.winmd from C:\Windows\System32\WinMetadata\ but that didn't change anything.

A little while later and I get this exception
System.TypeInitializationException: The type initializer for 'GenericHRLib.GenericHRDevice' threw an exception. ---> System.InvalidProgramException: Unrecognizable runtime implemented method 'Windows.Devices.Bluetooth.BluetoothUuidHelper:FromShortId (uint)'

I think Reflection doesn't like that? I moved it from a static readonly to just inline it and that avoids that exception... πŸ˜• I've pushed this to GenericHRLib.

I think Reflection doesn't like that? I moved it from a static readonly to just inline it and that avoids that exception... πŸ˜• I've pushed this to GenericHRLib.

No no, this one was without the reflection, see the gist like I posted on Edit 3.

I've pushed this to GenericHRLib.

When using the new build, I now get this error
[16:46:37.308] [ERROR] System.MissingMethodException: void Windows.Devices.Bluetooth.GenericAttributeProfile.GattDeviceService.Dispose()

I've pushed this to GenericHRLib.

When using the new build, I now get this error [16:46:37.308] [ERROR] System.MissingMethodException: void Windows.Devices.Bluetooth.GenericAttributeProfile.GattDeviceService.Dispose()

Hi, I'm back in this issue. I've been trying to get this going, and I'm still unaware of the error, and at this point, I have no clue why.

The Windows.Devices.Bluetooth.GenericAttributeProfile lies in the Windows.winmd assembly in the WIndows Kits' UnionMetadata folder, so with this Dispose error prompting from the namespace, I decided to Assembly.LoadFile that winmd file, yet with no success. I then realized that the MissingMethodException is missing the method Dispose(), which is from the IDisposable base... what? How is it possible that that method is missing? This seems near impossible to implement.

Maybe instead I could initiate some sort of communication on the mod's end for other programs to communicate with the mod and tell it the HR values. Now there is already the textfile method, which you could implement into the GenericHRLibProgram, then reference that file in the mod, but that can be inefficient sometimes.

Regardless, I'm closing this issue for good. There seems to be no good solutions for implementing this library properly, without referencing a thousand Windows only SDKs. Please feel free to re-open this issue or discuss on the discussions board or the discord server if you have any comments, questions, or concerns. Thank you very much for the support given.