Truegear_player provides a WebSocket server address,"ws://127.0.0.1:18233/v1/tact/" to connect to TrueGear suit. After connecting to this WebSocket link, the suit will produce a vibration or EMS effect based on corresponding request from Truegear_player. The request message transmitted by this link is in JSON format as following:
-
The main parameters of the method is: "play_no_registered".
-
The Body and Result data in the request body must be base64 encoded Json Object.
{ 'Method': "play_effect_by_content', 'Body': Body }{ 'Method': 'play_effect_by_content', 'Result': Body }
EffectObject contains two member variables: eventName and trackList. These two member variables represent the trigger event name and the action, respectively.
- An eff_asset belongs to an EffectObject.
- An EffectObject is a collection of multiple TrackObjects
struct EffectObject { string eventName; vector<TrackObject> trackList; };
- eventName: A member variable of type string that is used to trigger the event name. In practical applications, we can perform corresponding operations according to different trigger event names.
- trackList: An array of type TrackObject that stores a collection of actions.
- TrackObject objects have the same action mode.
- The TrackObject class is used to describe objects with the same action pattern and contains the following properties:
#Action type enum ActionType { Shake, // vibration Electrical, // electrical stimulation }; - action_type: Used to represent the class of action of an object, such as vibration, electrical, etc.
enum IntensityMode { // Intensity mode Const, // constant Fade, // fade in or fade out FadeInAndOut // fade in and out, or fade out and in };
- intensity_mode: which is used to represent how the intensity of an object changes, such as gradient, mutation, etc.
struct TrackObject { ActionType action_type; // Action type IntensityMode intensity_mode; // Intensity mode bool once; // Is it once only for electrical stimulation int interval; // Interval (only for electrical stimulation) int start_time; // Start time int end_time; // End time int start_intensity; // Start intensity int end_intensity; // End intensity (For FadeInAndOut, it's peak or trough) vector index; // IDs for the motors or electrical stimulations }
- once: Boolean type, which indicates whether the object performs an action only once and is effective only when EMS is used.
- interval: Integer type, that represents the interval between the actions of an object and is valid only when electrical stimulation is used.
- start_time: Integer type, indicating the start time of an object action.
- end_time:Integer type,indicating the end time of an object action.
- start_intensity:Integer type,Represents the initial intensity of the object's action.
- end_intensity:Integer type,Represents the termination intensity of the object's action, and when the intensity mode is FadeInAndOut, this value represents the peak or trough intensity.
- index:A vector of type integer that represents the relevant ID of the object's action, such as the ID of a motor or EMS.
The procedure for connecting to the WebSocket server is as follows:
- First, install a client library that supports the WebSocket protocol on the device.
- JavaScript: you can use the browser's built-in WebSocket object;
- Python: you can use websocket libraries such as websockets or websocket-client.
- After importing the client library, create a WebSocket object and pass the server address as a parameter.
- JavaScript: you can create a WebSocket object like this:
const ws = new WebSocket('ws://127.0.0.1:18233/v1/tact/');
- When the WebSocket object successfully connects to the server, the 'open' event is triggered. When the connection is established, a request can be sent to control the vibration or electrical stimulation effect of the garment.
An example of sending a vibration and electrical stimulation
- The body of the json sent is:
After unraveling base64, the specific data of the body can be obtained{"Method":"play_no_registered","Body":"eyJuYW1lIjoiTGVmdEhhbmRQaWNrdXBJdGVtIiwidXVpZCI6IkxlZnRIYW5kUGlja3VwSXRlbSIsImtlZXAiOiJGYWxzZSIsInByaW9yaXR5IjowLCJ0cmFja3MiOlt7InN0YXJ0X3RpbWUiOjAsImVuZF90aW1lIjoxMDAsInN0b3BfbmFtZSI6IiIsInN0YXJ0X2ludGVuc2l0eSI6MzAsImVuZF9pbnRlbnNpdHkiOjUsImludGVuc2l0eV9tb2RlIjoiQ29uc3QiLCJhY3Rpb25fdHlwZSI6IlNoYWtlIiwib25jZSI6IkZhbHNlIiwiaW50ZXJ2YWwiOjAsImluZGV4IjpbMCw0XX0seyJzdGFydF90aW1lIjowLCJlbmRfdGltZSI6MjAwLCJzdG9wX25hbWUiOiIiLCJzdGFydF9pbnRlbnNpdHkiOjEwLCJlbmRfaW50ZW5zaXR5Ijo1LCJpbnRlbnNpdHlfbW9kZSI6IkNvbnN0IiwiYWN0aW9uX3R5cGUiOiJFbGVjdHJpY2FsIiwib25jZSI6IkZhbHNlIiwiaW50ZXJ2YWwiOjEwLCJpbmRleCI6WzAsMTAwXX1dfQ=="}{ "name": "LeftHandPickupItem", "uuid": "LeftHandPickupItem", "keep": "False", "priority": 0, "tracks": [ { "start_time": 0, "end_time": 100, "stop_name": "", "start_intensity": 30, "end_intensity": 5, "intensity_mode": "Const", "action_type": "Shake", "once": "False", "interval": 0, "index": [ 0, 4 ] }, { "start_time": 0, "end_time": 200, "stop_name": "", "start_intensity": 10, "end_intensity": 5, "intensity_mode": "Const", "action_type": "Electrical", "once": "False", "interval": 10, "index": [ 0, 100 ] } ] } - You can close the WebSocket connection when you no longer need to control the suit.
Test code:
// To install the ws module, run: npm install ws const WebSocket = require('ws'); const ws = new WebSocket('ws://127.0.0.1:18233/v1/tact'); ws.on('error', console.error); ws.on('open', function open() { console.log('ws open'); ws.send('{"Method":"play_no_registered","Body":"eyJuYW1lIjoiTGVmdEhhbmRQaWNrdXBJdGVtIiwidXVpZCI6IkxlZnRIYW5kUGlja3VwSXRlbSIsImtlZXAiOiJGYWxzZSIsInByaW9yaXR5IjowLCJ0cmFja3MiOlt7InN0YXJ0X3RpbWUiOjAsImVuZF90aW1lIjoxMDAsInN0b3BfbmFtZSI6IiIsInN0YXJ0X2ludGVuc2l0eSI6MzAsImVuZF9pbnRlbnNpdHkiOjUsImludGVuc2l0eV9tb2RlIjoiQ29uc3QiLCJhY3Rpb25fdHlwZSI6IlNoYWtlIiwib25jZSI6IkZhbHNlIiwiaW50ZXJ2YWwiOjAsImluZGV4IjpbMCw0XX0seyJzdGFydF90aW1lIjowLCJlbmRfdGltZSI6MjAwLCJzdG9wX25hbWUiOiIiLCJzdGFydF9pbnRlbnNpdHkiOjEwLCJlbmRfaW50ZW5zaXR5Ijo1LCJpbnRlbnNpdHlfbW9kZSI6IkNvbnN0IiwiYWN0aW9uX3R5cGUiOiJFbGVjdHJpY2FsIiwib25jZSI6IkZhbHNlIiwiaW50ZXJ2YWwiOjEwLCJpbmRleCI6WzAsMTAwXX1dfQ=="} '); }); ws.on('message', function message(data) { console.log('received: %s', data); });
- if UPL_Android.xml exist, add the aar file to the project
- if UPL_Android.xml does not exist, create
Build.csand add corresponding codes:if (Target.Platform == UnrealTargetPlatform.Android){ var manifestFile = Path.Combine(ModuleDirectory, "UPL.xml"); AdditionalPropertiesForReceipt.Add("AndroidPlugin", manifestFile); }
- Under
Project Settings-Platform-Android-Advanced APK Packaging-Extra Permissions, add following:android.permission.WRITE EXTERNAL STORAGE android.permission.READ_EXTERNAL_STORAGE android.permission.BLUETOOTH_CONNECT android.permission.BLUETOOTH_SCAN android.permission.BLUETOOTH_PRIVILEGED android.permission.BLUETOOTH android.permission.BLUETOOTH_ADMIN android.permission.BLUETOOTH_ADVERTISE android.permission.BLUETOOTH_CONNECT

-
Initialize SDK Configuration
unrealInitialized(Context context);
-
Register Effect,and export eff file:
registeEffect_Eff(eventName, textFile_bytes);Parameter Description Required eventNameEffect Name Required textFile_bytesBytes data of the file Required -
Customized Json Data
private string jsonStr = @"{""name"":""MindDeathWave"",""uuid"":""MindDeathWave"",""keep"":""False"",""tracks"":[{""start_time"":0,""end_time"":100,""stop_name"":"""",""start_intensity"":20,""end_intensity"":40,""intensity_mode"":""Const"",""action_type"":""Shake"",""once"":""False"",""interval"":0,""index"":[5,6,3,2,7,1,0,4,8,9,10,11,15,14,13,12,16,17,19,18,116,117,118,119,115,114,113,112,108,109,110,111,107,106,104,105,100,101,102,103]},{""start_time"":0,""end_time"":0,""stop_name"":"""",""start_intensity"":30,""end_intensity"":20,""intensity_mode"":""Const"",""action_type"":""Electrical"",""once"":""True"",""interval"":1,""index"":[0,100]}]}";
registeEffect(eventName, jsonStr);
Parameter Description Required eventNameEffect Name Required jsonStrEffect Data Required -
Bluetooth Availability Detection:
isAvailable() // Returns 1 if available, -1 if not available // -1 is not bluetooth privilege
-
Avaliable Device Scan:
startScanning(); -
Get Avaliable Device:
getDeviceList() -
Connect to Device:
connectToDevice(macAddress);
Parameter Description Required macAddressDevice's macAddress Required -
Disconnect Device(java)
disconnectFromDevice(); -
Send Event message to Trigger Effect:
sendPlayByEventName(eventName );
Parameter Description Required eventNameRegistered Effect Name Required -
Send Customized Json Data to Trigger Effect:
string jsonStr = @"{""name"":""MindDeathWave"",""uuid"":""MindDeathWave"",""keep"":""False"",""tracks"":[{""start_time"":0,""end_time"":100,""stop_name"":"""",""start_intensity"":20,""end_intensity"":40,""intensity_mode"":""Const"",""action_type"":""Shake"",""once"":""False"",""interval"":0,""index"":[5,6,3,2,7,1,0,4,8,9,10,11,15,14,13,12,16,17,19,18,116,117,118,119,115,114,113,112,108,109,110,111,107,106,104,105,100,101,102,103]},{""start_time"":0,""end_time"":0,""stop_name"":"""",""start_intensity"":30,""end_intensity"":20,""intensity_mode"":""Const"",""action_type"":""Electrical"",""once"":""True"",""interval"":1,""index"":[0,100]}]}"; sendPlayByContent( jsonStr );
Parameter Description Required jsonStrEffect Json Data Required
- Add the aar file to the project
android.permission.WRITE EXTERNAL STORAGE
android.permission.READ_EXTERNAL_STORAGE
android.permission.BLUETOOTH_CONNECT
android.permission.BLUETOOTH_SCAN
android.permission.BLUETOOTH_PRIVILEGED
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BLUETOOTH_ADVERTISE
android.permission.BLUETOOTH_CONNECT dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.google.code.gson:gson:2.11.0'
implementation 'com.google.flatbuffers:flatbuffers-java:24.3.25'**DEPS**}-
Initialize SDK Config load Script to the senario
TruegearAndroidConnector androidConnector = new TruegearAndroidConnector();
-
Register Effect,and export eff file:
byte[] textFile_bytes = File.ReadAllBytes(filePath); TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance; androidConnector.RegisterEffect_Eff(eventName, textFile_bytes);
Parameter Description Required eventNameEffect Name Required textFile_bytesBytes data of the file Required -
Customized Json Data
private string jsonStr = @"{""name"":""MindDeathWave"",""uuid"":""MindDeathWave"",""keep"":""False"",""tracks"":[{""start_time"":0,""end_time"":100,""stop_name"":"""",""start_intensity"":20,""end_intensity"":40,""intensity_mode"":""Const"",""action_type"":""Shake"",""once"":""False"",""interval"":0,""index"":[5,6,3,2,7,1,0,4,8,9,10,11,15,14,13,12,16,17,19,18,116,117,118,119,115,114,113,112,108,109,110,111,107,106,104,105,100,101,102,103]},{""start_time"":0,""end_time"":0,""stop_name"":"""",""start_intensity"":30,""end_intensity"":20,""intensity_mode"":""Const"",""action_type"":""Electrical"",""once"":""True"",""interval"":1,""index"":[0,100]}]}"; TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance; androidConnector.RegisterEffect(eventName, jsonStr);
Parameter Description Required eventNameEffect Name Required jsonStrEffect Data Required -
Bluetooth Availability Detection:
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance; Int res = androidConnector.IsAvailable() // Returns 1 if available, -1 if not available // -1 is not bluetooth privilege
-
Avaliable Device Scan:
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance; androidConnector.StartScan();
-
Get Avaliable Device:
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance; public List<DeviceData> res = androidConnector.GetScanedDevices()
-
Connect to Device:
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance; androidConnector.ConnectToDevice(macAddress);
Parameter Description Required macAddressDevice's macAddress Required -
Disconnect Device
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance; androidConnector.DisconnectFromDevice();
-
Send Event message to Trigger Effect:
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance; androidConnector.SendPlayByEventName(eventName );
Parameter Description Required eventNameRegistered Effect Name Required -
Send Customized Json Data to Trigger Effect:
string jsonStr = @"{""name"":""MindDeathWave"",""uuid"":""MindDeathWave"",""keep"":""False"",""tracks"":[{""start_time"":0,""end_time"":100,""stop_name"":"""",""start_intensity"":20,""end_intensity"":40,""intensity_mode"":""Const"",""action_type"":""Shake"",""once"":""False"",""interval"":0,""index"":[5,6,3,2,7,1,0,4,8,9,10,11,15,14,13,12,16,17,19,18,116,117,118,119,115,114,113,112,108,109,110,111,107,106,104,105,100,101,102,103]},{""start_time"":0,""end_time"":0,""stop_name"":"""",""start_intensity"":30,""end_intensity"":20,""intensity_mode"":""Const"",""action_type"":""Electrical"",""once"":""True"",""interval"":1,""index"":[0,100]}]}"; TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance; androidConnector.SendPlayEffectByContent( jsonStr );
Parameter Description Required jsonStrEffect Json Data Required


