Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing head tracker status #962

Merged
merged 12 commits into from
Jul 11, 2024
1 change: 1 addition & 0 deletions gui/public/i18n/en/translation.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,7 @@ status_system-StatusSteamVRDisconnected = { $type ->
[steamvr_feeder] Currently not connected to the SlimeVR Feeder App.
}
status_system-StatusTrackerError = The { $trackerName } tracker has an error.
status_system-StatusUnassignedHMD = The VR headset should be assigned as a head tracker.

## Tray Menu
tray_menu-show = Show
Expand Down
11 changes: 9 additions & 2 deletions gui/src/hooks/status-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
StatusSystemUpdateT,
StatusTrackerErrorT,
StatusTrackerResetT,
StatusUnassignedHMDT,
TrackerDataT,
} from 'solarxr-protocol';
import { useWebsocketAPI } from './websocket-api';
Expand Down Expand Up @@ -122,6 +123,7 @@ export function parseStatusToLocale(
switch (status.dataType) {
case StatusData.NONE:
case StatusData.StatusTrackerReset:
case StatusData.StatusUnassignedHMD:
return {};
case StatusData.StatusSteamVRDisconnected: {
const data = status.data as StatusSteamVRDisconnectedT;
Expand Down Expand Up @@ -157,8 +159,6 @@ export function parseStatusToLocale(
}
return { trackerName: name };
}
case StatusData.StatusUnassignedHMD:
return { trackerName: 'Not implemented.' }; // TODO
}
}

Expand Down Expand Up @@ -186,6 +186,13 @@ export function trackerStatusRelated(
data.trackerId?.deviceId?.id === tracker.trackerId?.deviceId?.id
);
}
case StatusData.StatusUnassignedHMD: {
const data = status.data as StatusUnassignedHMDT;
return (
data.trackerId?.trackerNum == tracker.trackerId?.trackerNum &&
data.trackerId?.deviceId?.id === tracker.trackerId?.deviceId?.id
);
}
default:
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ class VRCOSCHandler(
userEditable = false,
isComputed = true,
usesTimeout = true,
isHmd = true,
)
vrcDevice.trackers[0] = vrcHmd!!
server.registerTracker(vrcHmd!!)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ public static int createTrackerInfos(
TrackerInfo.addMountingResetOrientation(fbb, createQuat(fbb, mountResetFix));
}

TrackerInfo.addIsHmd(fbb, tracker.isHmd());

return TrackerInfo.endTrackerInfo(fbb);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ import io.github.axisangles.ktmath.Quaternion.Companion.IDENTITY
import io.github.axisangles.ktmath.Vector3
import io.github.axisangles.ktmath.Vector3.Companion.POS_Y
import org.apache.commons.math3.util.Precision
import solarxr_protocol.datatypes.DeviceIdT
import solarxr_protocol.datatypes.TrackerIdT
import solarxr_protocol.rpc.StatusData
import solarxr_protocol.rpc.StatusDataUnion
import solarxr_protocol.rpc.StatusUnassignedHMD
import solarxr_protocol.rpc.StatusUnassignedHMDT
import java.util.function.Consumer
import kotlin.math.*

Expand Down Expand Up @@ -696,5 +702,64 @@ class HumanPoseManager(val server: VRServer?) {
skeleton.setPauseTracking(pauseTracking, sourceName)
}

fun togglePauseTracking(sourceName: String?): Boolean = skeleton.togglePauseTracking(sourceName) // #endregion
fun togglePauseTracking(sourceName: String?): Boolean = skeleton.togglePauseTracking(sourceName)

// This should be executed when the head tracker is changed
fun checkTrackersRequiringReset() {
// Checks if this is main human pose manager (having server) or
// skeleton doesn't have a head tracker or not an HMD one
if (server == null ||
skeleton.headTracker?.isComputed != true
) {
return
}
server.allTrackers
.filter { !it.isInternal && it.trackerPosition != null }
.forEach {
it.checkReportRequireReset()
}
}

private var lastMissingHmdStatus = 0u
fun checkReportMissingHmd() {
// Check if this is main skeleton, there is no head tracker currently,
// and there is an available HMD one
if (server == null) return
val tracker = VRServer.instance.allTrackers.firstOrNull { it.isHmd && !it.isInternal && it.status.sendData }
if (skeleton.headTracker == null &&
lastMissingHmdStatus == 0u &&
tracker != null
) {
reportMissingHmd(tracker)
} else if (lastMissingHmdStatus != 0u &&
(skeleton.headTracker != null || tracker == null)
) {
server.statusSystem.removeStatus(lastMissingHmdStatus)
lastMissingHmdStatus = 0u
}
}

private fun reportMissingHmd(tracker: Tracker) {
require(lastMissingHmdStatus == 0u) {
"${::lastMissingHmdStatus.name} must be 0u, but was $lastMissingHmdStatus"
}
require(server != null) {
"${::server.name} must not be null"
}

val status = StatusDataUnion().apply {
type = StatusData.StatusUnassignedHMD
value = StatusUnassignedHMDT().apply {
trackerId = TrackerIdT().apply {
if (tracker.device != null) {
deviceId = DeviceIdT().apply { id = tracker.device.id }
}
trackerNum = tracker.trackerNum
}
}
}
lastMissingHmdStatus = server.statusSystem.addStatus(status, true)
}

// #endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import io.github.axisangles.ktmath.Vector3.Companion.NEG_Y
import io.github.axisangles.ktmath.Vector3.Companion.NULL
import io.github.axisangles.ktmath.Vector3.Companion.POS_Y
import java.lang.IllegalArgumentException
import kotlin.properties.Delegates

class HumanSkeleton(
val humanPoseManager: HumanPoseManager,
Expand Down Expand Up @@ -83,7 +84,12 @@ class HumanSkeleton(
var hasRightArmTracker = false

// Input trackers
var headTracker: Tracker? = null
var headTracker: Tracker? by Delegates.observable(null) { _, old, new ->
if (old == new) return@observable

humanPoseManager.checkReportMissingHmd()
humanPoseManager.checkTrackersRequiringReset()
}
var neckTracker: Tracker? = null
var upperChestTracker: Tracker? = null
var chestTracker: Tracker? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class Tracker @JvmOverloads constructor(
val allowFiltering: Boolean = false,
val needsReset: Boolean = false,
val needsMounting: Boolean = false,
val isHmd: Boolean = false,
) {
private val timer = BufferedTimer(1f)
private var timeAtLastUpdate: Long = System.currentTimeMillis()
Expand Down Expand Up @@ -100,6 +101,9 @@ class Tracker @JvmOverloads constructor(
VRServer.instance.updateSkeletonModel()
VRServer.instance.refreshTrackersDriftCompensationEnabled()

if (isHmd) {
VRServer.instance.humanPoseManager.checkReportMissingHmd()
}
checkReportErrorStatus()
checkReportRequireReset()
}
Expand Down Expand Up @@ -132,12 +136,15 @@ class Tracker @JvmOverloads constructor(
require(!needsMounting || (needsReset && needsMounting)) {
"If ${::needsMounting.name} is true, then ${::needsReset.name} must also be true"
}
require(!isHmd || (hasPosition && isHmd)) {
"If ${::isHmd.name} is true, then ${::hasPosition.name} must also be true"
}
// require(device != null && _trackerNum == null) {
// "If ${::device.name} exists, then ${::trackerNum.name} must not be null"
// }
}

private fun checkReportRequireReset() {
fun checkReportRequireReset() {
if (needsReset && trackerPosition != null && lastResetStatus == 0u &&
!status.reset && (isImu() || !statusResetRecently)
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,17 @@ abstract class SteamVRBridge(
)

val displayName: String
val needsReset: Boolean
if (trackerAdded.trackerId == 0) {
val (needsReset, isHmd) = if (trackerAdded.trackerId == 0) {
displayName = if (trackerAdded.trackerName == "HMD") {
"SteamVR Driver HMD"
} else {
"Feeder App HMD"
}
// TODO support needsReset = true for VTubing (GUI toggle?)
needsReset = false
false to true
} else {
displayName = trackerAdded.trackerName
needsReset = true
true to false
}

val tracker = Tracker(
Expand All @@ -180,6 +179,7 @@ abstract class SteamVRBridge(
userEditable = true,
isComputed = true,
needsReset = needsReset,
isHmd = isHmd,
)

device.trackers[0] = tracker
Expand Down