diff --git a/gui/public/i18n/en/translation.ftl b/gui/public/i18n/en/translation.ftl index e91247bac8..e34e7dd0a8 100644 --- a/gui/public/i18n/en/translation.ftl +++ b/gui/public/i18n/en/translation.ftl @@ -635,6 +635,9 @@ settings-general-fk_settings-enforce_joint_constraints-correct_constraints-descr settings-general-fk_settings-ik = Position data settings-general-fk_settings-ik-use_position = Use Position data settings-general-fk_settings-ik-use_position-description = Enables the use of position data from trackers that provide it. When enabling this make sure to full reset and recalibrate in game. +settings-general-fk_settings-velocity_settings = Velocity Settings +settings-general-fk_settings-velocity_settings-description = Send derived velocity data to SteamVR. Required for Natural Locomotion support. May cause jitter in FBT. +settings-general-fk_settings-velocity_settings-send_derived_velocity = Send derived velocity to driver settings-general-fk_settings-arm_fk = Arm tracking settings-general-fk_settings-arm_fk-description = Force arms to be tracked from the headset (HMD) even if positional hand data is available. settings-general-fk_settings-arm_fk-force_arms = Force arms from HMD diff --git a/gui/src/components/settings/pages/GeneralSettings.tsx b/gui/src/components/settings/pages/GeneralSettings.tsx index 56b8adcbb0..570ccca823 100644 --- a/gui/src/components/settings/pages/GeneralSettings.tsx +++ b/gui/src/components/settings/pages/GeneralSettings.tsx @@ -15,6 +15,7 @@ import { SteamVRTrackersSettingT, TapDetectionSettingsT, HIDSettingsT, + VelocitySettingsT, } from 'solarxr-protocol'; import { useConfig } from '@/hooks/config'; import { useWebsocketAPI } from '@/hooks/websocket-api'; @@ -108,6 +109,9 @@ export type SettingsForm = { hidSettings: { trackersOverHID: boolean; }; + velocitySettings: { + sendDerivedVelocity: boolean; + }; }; const defaultValues: SettingsForm = { @@ -164,6 +168,7 @@ const defaultValues: SettingsForm = { resetsSettings: defaultResetSettings, stayAligned: defaultStayAlignedSettings, hidSettings: { trackersOverHID: false }, + velocitySettings: { sendDerivedVelocity: false }, }; const settingsAtom = atom(new SettingsResponseT()); @@ -325,6 +330,11 @@ export function GeneralSettings() { hidSettings.trackersOverHid = values.hidSettings.trackersOverHID; settingsReq.hidSettings = hidSettings; + const velocitySettings = new VelocitySettingsT(); + velocitySettings.sendDerivedVelocity = + values.velocitySettings.sendDerivedVelocity; + settingsReq.velocitySettings = velocitySettings; + if (values.resetsSettings) { settingsReq.resetsSettings = loadResetSettings(values.resetsSettings); } @@ -446,6 +456,12 @@ export function GeneralSettings() { }; } + if (settings.velocitySettings) { + formData.velocitySettings = { + sendDerivedVelocity: settings.velocitySettings.sendDerivedVelocity, + }; + } + reset({ ...getValues(), ...formData }); }, [settings]); @@ -1016,6 +1032,32 @@ export function GeneralSettings() { /> +
+ + {l10n.getString( + 'settings-general-fk_settings-velocity_settings' + )} + +
+ + {l10n.getString( + 'settings-general-fk_settings-velocity_settings-description' + )} + +
+
+
+ +
+ {config?.debug && ( <>
diff --git a/server/core/src/main/java/dev/slimevr/config/VRConfig.kt b/server/core/src/main/java/dev/slimevr/config/VRConfig.kt index 9ef33f5e00..903750aa8a 100644 --- a/server/core/src/main/java/dev/slimevr/config/VRConfig.kt +++ b/server/core/src/main/java/dev/slimevr/config/VRConfig.kt @@ -58,6 +58,8 @@ class VRConfig { val trackingChecklist: TrackingChecklistConfig = TrackingChecklistConfig() + val velocityConfig: VelocityConfig = VelocityConfig() + val vrcConfig: VRCConfig = VRCConfig() init { @@ -119,6 +121,7 @@ class VRConfig { .readFilteringConfig(filters, tracker.getRotation()) } } + tracker.allowVelocity = velocityConfig.sendDerivedVelocity } fun writeTrackerConfig(tracker: Tracker?) { diff --git a/server/core/src/main/java/dev/slimevr/config/VelocityConfig.kt b/server/core/src/main/java/dev/slimevr/config/VelocityConfig.kt new file mode 100644 index 0000000000..82a6d1f673 --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/config/VelocityConfig.kt @@ -0,0 +1,19 @@ +package dev.slimevr.config + +import dev.slimevr.VRServer + +/** + * Allows to enable/disable sending of optional derived velocity data via Protobuf. + * Enables Natural Locomotion Support + * May create overprediction in certain titles causing excessive jitter when moving upper body. + */ +class VelocityConfig { + // Disables derived velocity for all trackers. Driver zeroes out velocity if nothing is returned in protobuf message. + var sendDerivedVelocity: Boolean = false + + fun updateTrackersVelocitySettings() { + for (t in VRServer.instance.allTrackers) { + t.allowVelocity = sendDerivedVelocity + } + } +} diff --git a/server/core/src/main/java/dev/slimevr/protocol/rpc/settings/RPCSettingsBuilder.kt b/server/core/src/main/java/dev/slimevr/protocol/rpc/settings/RPCSettingsBuilder.kt index 0735c1831f..dcd0551903 100644 --- a/server/core/src/main/java/dev/slimevr/protocol/rpc/settings/RPCSettingsBuilder.kt +++ b/server/core/src/main/java/dev/slimevr/protocol/rpc/settings/RPCSettingsBuilder.kt @@ -15,6 +15,7 @@ import dev.slimevr.config.StayAlignedConfig import dev.slimevr.config.TapDetectionConfig import dev.slimevr.config.VMCConfig import dev.slimevr.config.VRCOSCConfig +import dev.slimevr.config.VelocityConfig import dev.slimevr.filtering.TrackerFilters.Companion.getByConfigkey import dev.slimevr.tracking.processor.HumanPoseManager import dev.slimevr.tracking.processor.config.SkeletonConfigToggles @@ -34,6 +35,7 @@ import solarxr_protocol.rpc.SteamVRTrackersSetting import solarxr_protocol.rpc.TapDetectionSettings import solarxr_protocol.rpc.VMCOSCSettings import solarxr_protocol.rpc.VRCOSCSettings +import solarxr_protocol.rpc.VelocitySettings import solarxr_protocol.rpc.settings.LegTweaksSettings import solarxr_protocol.rpc.settings.ModelRatios import solarxr_protocol.rpc.settings.ModelSettings @@ -427,6 +429,7 @@ fun createSettingsResponse(fbb: FlatBufferBuilder, server: VRServer): Int { ), createHIDSettings(fbb, server.configManager.vrConfig.hidConfig), 0, + createVelocitySettings(fbb, server.configManager.vrConfig.velocityConfig), ) } @@ -462,3 +465,12 @@ fun createHIDSettings( fbb, config.trackersOverHID, ) + +fun createVelocitySettings( + fbb: FlatBufferBuilder, + config: VelocityConfig, +): Int = VelocitySettings + .createVelocitySettings( + fbb, + config.sendDerivedVelocity, + ) diff --git a/server/core/src/main/java/dev/slimevr/protocol/rpc/settings/RPCSettingsHandler.kt b/server/core/src/main/java/dev/slimevr/protocol/rpc/settings/RPCSettingsHandler.kt index 713b70e989..12e1784c28 100644 --- a/server/core/src/main/java/dev/slimevr/protocol/rpc/settings/RPCSettingsHandler.kt +++ b/server/core/src/main/java/dev/slimevr/protocol/rpc/settings/RPCSettingsHandler.kt @@ -362,6 +362,12 @@ class RPCSettingsHandler(var rpcHandler: RPCHandler, var api: ProtocolAPI) { config.trackersOverHID = requestConfig.trackersOverHid() } + if (req.velocitySettings() != null) { + val velocityConfig = api.server.configManager.vrConfig.velocityConfig + velocityConfig.sendDerivedVelocity = req.velocitySettings().sendDerivedVelocity() + velocityConfig.updateTrackersVelocitySettings() + } + api.server.configManager.saveConfig() } @@ -379,7 +385,7 @@ class RPCSettingsHandler(var rpcHandler: RPCHandler, var api: ProtocolAPI) { val settings = SettingsResponse .createSettingsResponse( fbb, - createSteamVRSettings(fbb, bridge), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + createSteamVRSettings(fbb, bridge), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ) val outbound = rpcHandler.createRPCMessage(fbb, RpcMessage.SettingsResponse, settings) diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/HumanSkeleton.kt b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/HumanSkeleton.kt index 2baef0bcd5..da16526691 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/HumanSkeleton.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/HumanSkeleton.kt @@ -1171,6 +1171,7 @@ class HumanSkeleton( it.position = trackerBone.getTailPosition() it.setRotation(trackerBone.getGlobalRotation() * trackerBone.rotationOffset.inv()) it.dataTick() + it.updateDerivedVelocity() } } diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt index a3d03ea10b..4262b2abe9 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt @@ -12,6 +12,10 @@ import io.eiren.util.BufferedTimer import io.github.axisangles.ktmath.Quaternion import io.github.axisangles.ktmath.Vector3 import kotlin.properties.Delegates +import kotlin.time.Duration.Companion.microseconds +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.DurationUnit +import kotlin.time.TimeSource const val TIMEOUT_MS = 2_000L const val DISCONNECT_MS = 3_000L + TIMEOUT_MS @@ -75,6 +79,11 @@ class Tracker @JvmOverloads constructor( */ val allowMounting: Boolean = false, + /** + * If true, the tracker will send Derived Velocity. + */ + var allowVelocity: Boolean = false, + val isHmd: Boolean = false, /** @@ -111,7 +120,19 @@ class Tracker @JvmOverloads constructor( // IMU: +z forward, +x left, +y up // SlimeVR: +z backward, +x right, +y up private var _acceleration = Vector3.NULL + private var _velocity = Vector3.NULL private var _magVector = Vector3.NULL + + /** + * Velocity state server-side differentiation based on sent poses + */ + private data class VelocityState( + var prevMark: TimeSource.Monotonic.ValueTimeMark? = null, + var prevPos: Vector3 = Vector3(0f, 0f, 0f), + ) + + private val velocityState = VelocityState() + var position = Vector3.NULL val resetsHandler: TrackerResetsHandler = TrackerResetsHandler(this) val filteringHandler: TrackerFilteringHandler = TrackerFilteringHandler() @@ -345,6 +366,39 @@ class Tracker @JvmOverloads constructor( } } + /** + * If derived velocity is enabled, updates the derived velocity of the tracker, + * calculating it based on the position displacement since the last update, + * applying a sanity check on the time delta to filter out noise and ensure data stability. + */ + fun updateDerivedVelocity() { + if (!allowVelocity || !hasPosition) { + velocityState.prevMark = null + _velocity = Vector3.NULL + return + } + + val pos = position + val now = TimeSource.Monotonic.markNow() + + val prevMark = velocityState.prevMark + if (prevMark != null) { + val dt = now - prevMark + if (dt in 100.microseconds..250.milliseconds) { + val dtSeconds = dt.toDouble(DurationUnit.SECONDS) + _velocity = Vector3( + ((pos.x - velocityState.prevPos.x) / dtSeconds).toFloat(), + ((pos.y - velocityState.prevPos.y) / dtSeconds).toFloat(), + ((pos.z - velocityState.prevPos.z) / dtSeconds).toFloat(), + ) + } else { + _velocity = Vector3.NULL + } + } + velocityState.prevMark = now + velocityState.prevPos = pos + } + /** * Gets the identity-adjusted tracker rotation after the resetsHandler's corrections * (identity reset, drift and identity mounting). @@ -421,6 +475,24 @@ class Tracker @JvmOverloads constructor( this._acceleration = vec } + /** + * Sets the derived velocity of the tracker. + */ + fun setVelocity(vec: Vector3) { + this._velocity = if (allowVelocity) vec else Vector3.NULL + } + + /** + * Gets the derived velocity of the tracker. + */ + fun getVelocity(): Vector3 = _velocity + + /** + * True if the tracker has valid velocity data. + */ + val hasVelocity: Boolean + get() = allowVelocity && _velocity != Vector3.NULL + /** * True if the raw rotation is coming directly from an IMU (no cameras or lighthouses) * For example, flex sensor trackers are not considered as IMU trackers (see TrackerDataType) diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/platform/ProtobufBridge.kt b/server/desktop/src/main/java/dev/slimevr/desktop/platform/ProtobufBridge.kt index e6b60aaf52..5cc8a33603 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/platform/ProtobufBridge.kt +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/ProtobufBridge.kt @@ -82,6 +82,7 @@ abstract class ProtobufBridge(@JvmField protected val bridgeName: String) : ISte target.position = source.position target.setRotation(source.getRotation()) target.status = source.status + target.setVelocity(source.getVelocity()) target.batteryLevel = source.batteryLevel target.batteryVoltage = source.batteryVoltage target.dataTick() @@ -102,16 +103,17 @@ abstract class ProtobufBridge(@JvmField protected val bridgeName: String) : ISte } @VRServerThread - protected fun writeTrackerUpdate(localTracker: Tracker?) { - val builder = ProtobufMessages.Position.newBuilder().setTrackerId( - localTracker!!.id, - ) + protected fun writeTrackerUpdate(localTracker: Tracker) { + val builder = ProtobufMessages.Position.newBuilder() + .setTrackerId(localTracker.id) + if (localTracker.hasPosition) { val pos = localTracker.position builder.setX(pos.x) builder.setY(pos.y) builder.setZ(pos.z) } + if (localTracker.hasRotation) { val rot = localTracker.getRotation() builder.setQx(rot.x) @@ -119,7 +121,19 @@ abstract class ProtobufBridge(@JvmField protected val bridgeName: String) : ISte builder.setQz(rot.z) builder.setQw(rot.w) } - sendMessage(ProtobufMessage.newBuilder().setPosition(builder).build()) + + if (localTracker.hasVelocity) { + val vel = localTracker.getVelocity() + builder.setVx(vel.x) + builder.setVy(vel.y) + builder.setVz(vel.z) + } + + sendMessage( + ProtobufMessage.newBuilder() + .setPosition(builder) + .build(), + ) } @VRServerThread @@ -169,6 +183,16 @@ abstract class ProtobufBridge(@JvmField protected val bridgeName: String) : ISte ), ) + if (positionMessage.hasVx()) { + tracker + .setVelocity( + Vector3( + positionMessage.vx, + positionMessage.vy, + positionMessage.vz, + ), + ) + } tracker.dataTick() } } diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/platform/ProtobufMessages.java b/server/desktop/src/main/java/dev/slimevr/desktop/platform/ProtobufMessages.java index ebb8e0f03c..703938ad6d 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/platform/ProtobufMessages.java +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/ProtobufMessages.java @@ -1052,6 +1052,48 @@ public interface PositionOrBuilder extends * @return The dataSource. */ dev.slimevr.desktop.platform.ProtobufMessages.Position.DataSource getDataSource(); + + /** + * optional float vx = 10; + * + * @return Whether the vx field is set. + */ + boolean hasVx(); + + /** + * optional float vx = 10; + * + * @return The vx. + */ + float getVx(); + + /** + * optional float vy = 11; + * + * @return Whether the vy field is set. + */ + boolean hasVy(); + + /** + * optional float vy = 11; + * + * @return The vy. + */ + float getVy(); + + /** + * optional float vz = 12; + * + * @return Whether the vz field is set. + */ + boolean hasVz(); + + /** + * optional float vz = 12; + * + * @return The vz. + */ + float getVz(); } /** @@ -1416,6 +1458,75 @@ public dev.slimevr.desktop.platform.ProtobufMessages.Position.DataSource getData : result; } + public static final int VX_FIELD_NUMBER = 10; + private float vx_ = 0F; + + /** + * optional float vx = 10; + * + * @return Whether the vx field is set. + */ + @java.lang.Override + public boolean hasVx() { + return ((bitField0_ & 0x00000010) != 0); + } + + /** + * optional float vx = 10; + * + * @return The vx. + */ + @java.lang.Override + public float getVx() { + return vx_; + } + + public static final int VY_FIELD_NUMBER = 11; + private float vy_ = 0F; + + /** + * optional float vy = 11; + * + * @return Whether the vy field is set. + */ + @java.lang.Override + public boolean hasVy() { + return ((bitField0_ & 0x00000020) != 0); + } + + /** + * optional float vy = 11; + * + * @return The vy. + */ + @java.lang.Override + public float getVy() { + return vy_; + } + + public static final int VZ_FIELD_NUMBER = 12; + private float vz_ = 0F; + + /** + * optional float vz = 12; + * + * @return Whether the vz field is set. + */ + @java.lang.Override + public boolean hasVz() { + return ((bitField0_ & 0x00000040) != 0); + } + + /** + * optional float vz = 12; + * + * @return The vz. + */ + @java.lang.Override + public float getVz() { + return vz_; + } + private byte memoizedIsInitialized = -1; @java.lang.Override @@ -1460,6 +1571,15 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) if (((bitField0_ & 0x00000008) != 0)) { output.writeEnum(9, dataSource_); } + if (((bitField0_ & 0x00000010) != 0)) { + output.writeFloat(10, vx_); + } + if (((bitField0_ & 0x00000020) != 0)) { + output.writeFloat(11, vy_); + } + if (((bitField0_ & 0x00000040) != 0)) { + output.writeFloat(12, vz_); + } getUnknownFields().writeTo(output); } @@ -1506,6 +1626,18 @@ public int getSerializedSize() { size += com.google.protobuf.CodedOutputStream .computeEnumSize(9, dataSource_); } + if (((bitField0_ & 0x00000010) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeFloatSize(10, vx_); + } + if (((bitField0_ & 0x00000020) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeFloatSize(11, vy_); + } + if (((bitField0_ & 0x00000040) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeFloatSize(12, vz_); + } size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; @@ -1600,6 +1732,42 @@ public boolean equals(final java.lang.Object obj) { if (dataSource_ != other.dataSource_) return false; } + if (hasVx() != other.hasVx()) + return false; + if (hasVx()) { + if ( + java.lang.Float.floatToIntBits(getVx()) + != java.lang.Float + .floatToIntBits( + other.getVx() + ) + ) + return false; + } + if (hasVy() != other.hasVy()) + return false; + if (hasVy()) { + if ( + java.lang.Float.floatToIntBits(getVy()) + != java.lang.Float + .floatToIntBits( + other.getVy() + ) + ) + return false; + } + if (hasVz() != other.hasVz()) + return false; + if (hasVz()) { + if ( + java.lang.Float.floatToIntBits(getVz()) + != java.lang.Float + .floatToIntBits( + other.getVz() + ) + ) + return false; + } if (!getUnknownFields().equals(other.getUnknownFields())) return false; return true; @@ -1666,6 +1834,30 @@ public int hashCode() { hash = (37 * hash) + DATA_SOURCE_FIELD_NUMBER; hash = (53 * hash) + dataSource_; } + if (hasVx()) { + hash = (37 * hash) + VX_FIELD_NUMBER; + hash = (53 * hash) + + java.lang.Float + .floatToIntBits( + getVx() + ); + } + if (hasVy()) { + hash = (37 * hash) + VY_FIELD_NUMBER; + hash = (53 * hash) + + java.lang.Float + .floatToIntBits( + getVy() + ); + } + if (hasVz()) { + hash = (37 * hash) + VZ_FIELD_NUMBER; + hash = (53 * hash) + + java.lang.Float + .floatToIntBits( + getVz() + ); + } hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; @@ -1841,6 +2033,9 @@ public Builder clear() { qz_ = 0F; qw_ = 0F; dataSource_ = 0; + vx_ = 0F; + vy_ = 0F; + vz_ = 0F; return this; } @@ -1911,6 +2106,18 @@ private void buildPartial0( result.dataSource_ = dataSource_; to_bitField0_ |= 0x00000008; } + if (((from_bitField0_ & 0x00000200) != 0)) { + result.vx_ = vx_; + to_bitField0_ |= 0x00000010; + } + if (((from_bitField0_ & 0x00000400) != 0)) { + result.vy_ = vy_; + to_bitField0_ |= 0x00000020; + } + if (((from_bitField0_ & 0x00000800) != 0)) { + result.vz_ = vz_; + to_bitField0_ |= 0x00000040; + } result.bitField0_ |= to_bitField0_; } @@ -1960,6 +2167,15 @@ public Builder mergeFrom(dev.slimevr.desktop.platform.ProtobufMessages.Position if (other.hasDataSource()) { setDataSourceValue(other.getDataSourceValue()); } + if (other.hasVx()) { + setVx(other.getVx()); + } + if (other.hasVy()) { + setVy(other.getVy()); + } + if (other.hasVz()) { + setVz(other.getVz()); + } this.mergeUnknownFields(other.getUnknownFields()); onChanged(); return this; @@ -2032,6 +2248,21 @@ public Builder mergeFrom( bitField0_ |= 0x00000100; break; } // case 72 + case 85: { + vx_ = input.readFloat(); + bitField0_ |= 0x00000200; + break; + } // case 85 + case 93: { + vy_ = input.readFloat(); + bitField0_ |= 0x00000400; + break; + } // case 93 + case 101: { + vz_ = input.readFloat(); + bitField0_ |= 0x00000800; + break; + } // case 101 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { done = true; // was an endgroup tag @@ -2464,6 +2695,150 @@ public Builder clearDataSource() { return this; } + private float vx_; + + /** + * optional float vx = 10; + * + * @return Whether the vx field is set. + */ + @java.lang.Override + public boolean hasVx() { + return ((bitField0_ & 0x00000200) != 0); + } + + /** + * optional float vx = 10; + * + * @return The vx. + */ + @java.lang.Override + public float getVx() { + return vx_; + } + + /** + * optional float vx = 10; + * + * @param value The vx to set. + * @return This builder for chaining. + */ + public Builder setVx(float value) { + + vx_ = value; + bitField0_ |= 0x00000200; + onChanged(); + return this; + } + + /** + * optional float vx = 10; + * + * @return This builder for chaining. + */ + public Builder clearVx() { + bitField0_ = (bitField0_ & ~0x00000200); + vx_ = 0F; + onChanged(); + return this; + } + + private float vy_; + + /** + * optional float vy = 11; + * + * @return Whether the vy field is set. + */ + @java.lang.Override + public boolean hasVy() { + return ((bitField0_ & 0x00000400) != 0); + } + + /** + * optional float vy = 11; + * + * @return The vy. + */ + @java.lang.Override + public float getVy() { + return vy_; + } + + /** + * optional float vy = 11; + * + * @param value The vy to set. + * @return This builder for chaining. + */ + public Builder setVy(float value) { + + vy_ = value; + bitField0_ |= 0x00000400; + onChanged(); + return this; + } + + /** + * optional float vy = 11; + * + * @return This builder for chaining. + */ + public Builder clearVy() { + bitField0_ = (bitField0_ & ~0x00000400); + vy_ = 0F; + onChanged(); + return this; + } + + private float vz_; + + /** + * optional float vz = 12; + * + * @return Whether the vz field is set. + */ + @java.lang.Override + public boolean hasVz() { + return ((bitField0_ & 0x00000800) != 0); + } + + /** + * optional float vz = 12; + * + * @return The vz. + */ + @java.lang.Override + public float getVz() { + return vz_; + } + + /** + * optional float vz = 12; + * + * @param value The vz to set. + * @return This builder for chaining. + */ + public Builder setVz(float value) { + + vz_ = value; + bitField0_ |= 0x00000800; + onChanged(); + return this; + } + + /** + * optional float vz = 12; + * + * @return This builder for chaining. + */ + public Builder clearVz() { + bitField0_ = (bitField0_ & ~0x00000800); + vz_ = 0F; + onChanged(); + return this; + } + // @@protoc_insertion_point(builder_scope:messages.Position) } @@ -9023,7 +9398,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "ngPong\"#\n\007Version\022\030\n\020protocol_version\030\001 " + - "\001(\005\"\223\002\n\010Position\022\022\n\ntracker_id\030\001 \001(\005\022\016\n\001" + "\001(\005\"\333\002\n\010Position\022\022\n\ntracker_id\030\001 \001(\005\022\016\n\001" + "x\030\002 \001(\002H\000\210\001\001\022\016\n\001y\030\003 \001(\002H\001\210\001\001\022\016\n\001z\030\004 \001(\002H" + @@ -9031,67 +9406,71 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "\022\n\n\002qw\030\010 \001(\002\0227\n\013data_source\030\t \001(\0162\035.mess" + - "ages.Position.DataSourceH\003\210\001\001\"8\n\nDataSou" + "ages.Position.DataSourceH\003\210\001\001\022\017\n\002vx\030\n \001(" + + + "\002H\004\210\001\001\022\017\n\002vy\030\013 \001(\002H\005\210\001\001\022\017\n\002vz\030\014 \001(\002H\006\210\001\001" + + + "\"8\n\nDataSource\022\010\n\004NONE\020\000\022\007\n\003IMU\020\001\022\r\n\tPRE" + - "rce\022\010\n\004NONE\020\000\022\007\n\003IMU\020\001\022\r\n\tPRECISION\020\002\022\010\n" + "CISION\020\002\022\010\n\004FULL\020\003B\004\n\002_xB\004\n\002_yB\004\n\002_zB\016\n\014" + - "\004FULL\020\003B\004\n\002_xB\004\n\002_yB\004\n\002_zB\016\n\014_data_sourc" + "_data_sourceB\005\n\003_vxB\005\n\003_vyB\005\n\003_vz\"\227\001\n\nUs" + - "e\"\227\001\n\nUserAction\022\014\n\004name\030\001 \001(\t\022C\n\020action" + "erAction\022\014\n\004name\030\001 \001(\t\022C\n\020action_argumen" + - "_arguments\030\002 \003(\0132).messages.UserAction.A" + "ts\030\002 \003(\0132).messages.UserAction.ActionArg" + - "ctionArgumentsEntry\0326\n\024ActionArgumentsEn" + "umentsEntry\0326\n\024ActionArgumentsEntry\022\013\n\003k" + - "try\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"|\n\014T" + "ey\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"|\n\014TrackerAd" + - "rackerAdded\022\022\n\ntracker_id\030\001 \001(\005\022\026\n\016track" + "ded\022\022\n\ntracker_id\030\001 \001(\005\022\026\n\016tracker_seria" + - "er_serial\030\002 \001(\t\022\024\n\014tracker_name\030\003 \001(\t\022\024\n" + "l\030\002 \001(\t\022\024\n\014tracker_name\030\003 \001(\t\022\024\n\014tracker" + - "\014tracker_role\030\004 \001(\005\022\024\n\014manufacturer\030\005 \001(" + "_role\030\004 \001(\005\022\024\n\014manufacturer\030\005 \001(\t\"\374\002\n\rTr" + - "\t\"\374\002\n\rTrackerStatus\022\022\n\ntracker_id\030\001 \001(\005\022" + "ackerStatus\022\022\n\ntracker_id\030\001 \001(\005\022.\n\006statu" + - ".\n\006status\030\002 \001(\0162\036.messages.TrackerStatus" + "s\030\002 \001(\0162\036.messages.TrackerStatus.Status\022" + - ".Status\0221\n\005extra\030\003 \003(\0132\".messages.Tracke" + "1\n\005extra\030\003 \003(\0132\".messages.TrackerStatus." + - "rStatus.ExtraEntry\022;\n\nconfidence\030\004 \001(\0162\"" + "ExtraEntry\022;\n\nconfidence\030\004 \001(\0162\".message" + - ".messages.TrackerStatus.ConfidenceH\000\210\001\001\032" + "s.TrackerStatus.ConfidenceH\000\210\001\001\032,\n\nExtra" + - ",\n\nExtraEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(" + "Entry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"E\n" + - "\t:\0028\001\"E\n\006Status\022\020\n\014DISCONNECTED\020\000\022\006\n\002OK\020" + "\006Status\022\020\n\014DISCONNECTED\020\000\022\006\n\002OK\020\001\022\010\n\004BUS" + - "\001\022\010\n\004BUSY\020\002\022\t\n\005ERROR\020\003\022\014\n\010OCCLUDED\020\004\"3\n\n" + "Y\020\002\022\t\n\005ERROR\020\003\022\014\n\010OCCLUDED\020\004\"3\n\nConfiden" + - "Confidence\022\006\n\002NO\020\000\022\007\n\003LOW\020\001\022\n\n\006MEDIUM\020\005\022" + "ce\022\006\n\002NO\020\000\022\007\n\003LOW\020\001\022\n\n\006MEDIUM\020\005\022\010\n\004HIGH\020" + - "\010\n\004HIGH\020\nB\r\n\013_confidence\"I\n\007Battery\022\022\n\nt" + "\nB\r\n\013_confidence\"I\n\007Battery\022\022\n\ntracker_i" + - "racker_id\030\001 \001(\005\022\025\n\rbattery_level\030\002 \001(\002\022\023" + "d\030\001 \001(\005\022\025\n\rbattery_level\030\002 \001(\002\022\023\n\013is_cha" + - "\n\013is_charging\030\003 \001(\010\"\241\002\n\017ProtobufMessage\022" + "rging\030\003 \001(\010\"\241\002\n\017ProtobufMessage\022&\n\010posit" + - "&\n\010position\030\001 \001(\0132\022.messages.PositionH\000\022" + "ion\030\001 \001(\0132\022.messages.PositionH\000\022+\n\013user_" + - "+\n\013user_action\030\002 \001(\0132\024.messages.UserActi" + "action\030\002 \001(\0132\024.messages.UserActionH\000\022/\n\r" + - "onH\000\022/\n\rtracker_added\030\003 \001(\0132\026.messages.T" + "tracker_added\030\003 \001(\0132\026.messages.TrackerAd" + - "rackerAddedH\000\0221\n\016tracker_status\030\004 \001(\0132\027." + "dedH\000\0221\n\016tracker_status\030\004 \001(\0132\027.messages" + - "messages.TrackerStatusH\000\022$\n\007battery\030\005 \001(" + ".TrackerStatusH\000\022$\n\007battery\030\005 \001(\0132\021.mess" + - "\0132\021.messages.BatteryH\000\022$\n\007version\030\006 \001(\0132" + "ages.BatteryH\000\022$\n\007version\030\006 \001(\0132\021.messag" + - "\021.messages.VersionH\000B\t\n\007messageB2\n\034dev.s" + "es.VersionH\000B\t\n\007messageB2\n\034dev.slimevr.d" + - "limevr.desktop.platformB\020ProtobufMessage" + "esktop.platformB\020ProtobufMessagesH\003b\006pro" + - "sH\003b\006proto3" + "to3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom( @@ -9113,7 +9492,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { internal_static_messages_Position_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_messages_Position_descriptor, new java.lang.String[] { "TrackerId", "X", "Y", "Z", "Qx", "Qy", "Qz", "Qw", - "DataSource", } + "DataSource", "Vx", "Vy", "Vz", } ); internal_static_messages_UserAction_descriptor = getDescriptor().getMessageTypes().get(3); internal_static_messages_UserAction_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( diff --git a/solarxr-protocol b/solarxr-protocol index 5d572629c9..aa384c0f8b 160000 --- a/solarxr-protocol +++ b/solarxr-protocol @@ -1 +1 @@ -Subproject commit 5d572629c94f895574162225ec69443705ce35af +Subproject commit aa384c0f8b0c1c8c8146295ff595ea034d348399