mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
@@ -13,6 +13,7 @@ websocket-connection_lost = Connection lost to the server. Trying to reconnect..
|
||||
tips-find_tracker = Not sure which tracker is which? Shake a tracker and it will highlight the corresponding item.
|
||||
tips-do_not_move_heels = Ensure your heels do not move during recording!
|
||||
tips-file_select = Drag & drop files to use, or <u>browse</u>.
|
||||
tips-tap_setup = You can slowly tap 2 times your tracker to choose it instead of selecting it from the menu.
|
||||
|
||||
## Body parts
|
||||
body_part-NONE = Unassigned
|
||||
@@ -208,7 +209,7 @@ tracker_selection_menu-LEFT_CONTROLLER = { -tracker_selection-part } left contro
|
||||
|
||||
tracker_selection_menu-unassigned = Unassigned Trackers
|
||||
tracker_selection_menu-assigned = Assigned Trackers
|
||||
tracker_selection_menu-dont_assign = Do not assign
|
||||
tracker_selection_menu-dont_assign = Unassign
|
||||
|
||||
# This line cares about multilines.
|
||||
# <b>text</b> means that the text should be bold.
|
||||
|
||||
BIN
gui/public/sounds/end-tap.mp3
Normal file
BIN
gui/public/sounds/end-tap.mp3
Normal file
Binary file not shown.
BIN
gui/public/sounds/fifth-tap.mp3
Normal file
BIN
gui/public/sounds/fifth-tap.mp3
Normal file
Binary file not shown.
BIN
gui/public/sounds/first-tap.mp3
Normal file
BIN
gui/public/sounds/first-tap.mp3
Normal file
Binary file not shown.
BIN
gui/public/sounds/fourth-tap.mp3
Normal file
BIN
gui/public/sounds/fourth-tap.mp3
Normal file
Binary file not shown.
BIN
gui/public/sounds/second-tap.mp3
Normal file
BIN
gui/public/sounds/second-tap.mp3
Normal file
Binary file not shown.
BIN
gui/public/sounds/tapextrasetup.mp3
Normal file
BIN
gui/public/sounds/tapextrasetup.mp3
Normal file
Binary file not shown.
BIN
gui/public/sounds/third-tap.mp3
Normal file
BIN
gui/public/sounds/third-tap.mp3
Normal file
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
import { useLocalization } from '@fluent/react';
|
||||
import classNames from 'classnames';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useMemo, useState, useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import {
|
||||
AssignTrackerRequestT,
|
||||
@@ -8,6 +8,11 @@ import {
|
||||
QuatT,
|
||||
RpcMessage,
|
||||
TrackerIdT,
|
||||
SettingsRequestT,
|
||||
SettingsResponseT,
|
||||
TapDetectionSettingsT,
|
||||
ChangeSettingsRequestT,
|
||||
TapDetectionSetupNotificationT,
|
||||
} from 'solarxr-protocol';
|
||||
import { FlatDeviceTracker } from '../../../../hooks/app';
|
||||
import { useChokerWarning } from '../../../../hooks/choker-warning';
|
||||
@@ -23,17 +28,26 @@ import { NeckWarningModal } from '../../NeckWarningModal';
|
||||
import { TrackerSelectionMenu } from './TrackerSelectionMenu';
|
||||
import { SkipSetupWarningModal } from '../../SkipSetupWarningModal';
|
||||
import { SkipSetupButton } from '../../SkipSetupButton';
|
||||
import { useConfig } from '../../../../hooks/config';
|
||||
import { playTapSetupSound } from '../../../../sounds/sounds';
|
||||
|
||||
export type BodyPartError = {
|
||||
label: string | undefined;
|
||||
affectedRoles: BodyPart[];
|
||||
};
|
||||
|
||||
interface FlatDeviceTrackerDummy {
|
||||
tracker: {
|
||||
trackerId: TrackerIdT;
|
||||
info: undefined;
|
||||
};
|
||||
}
|
||||
|
||||
export function TrackersAssignPage() {
|
||||
const { l10n } = useLocalization();
|
||||
const { useAssignedTrackers, trackers } = useTrackers();
|
||||
const { applyProgress, skipSetup, state } = useOnboarding();
|
||||
const { sendRPCPacket } = useWebsocketAPI();
|
||||
const { sendRPCPacket, useRPCPacket } = useWebsocketAPI();
|
||||
|
||||
const { control, watch } = useForm<{ advanced: boolean }>({
|
||||
defaultValues: { advanced: false },
|
||||
@@ -42,6 +56,66 @@ export function TrackersAssignPage() {
|
||||
const [selectedRole, setSelectRole] = useState<BodyPart>(BodyPart.NONE);
|
||||
const assignedTrackers = useAssignedTrackers();
|
||||
const [skipWarning, setSkipWarning] = useState(false);
|
||||
const { config } = useConfig();
|
||||
const [tapDetectionSettings, setTapDetectionSettings] = useState<Omit<
|
||||
TapDetectionSettingsT,
|
||||
'pack'
|
||||
> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
sendRPCPacket(RpcMessage.SettingsRequest, new SettingsRequestT());
|
||||
}, []);
|
||||
|
||||
useRPCPacket(RpcMessage.SettingsResponse, (settings: SettingsResponseT) => {
|
||||
setTapDetectionSettings(settings.tapDetectionSettings);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!tapDetectionSettings) return;
|
||||
const newTapSettings = new TapDetectionSettingsT(
|
||||
tapDetectionSettings.fullResetDelay,
|
||||
tapDetectionSettings.fullResetEnabled,
|
||||
tapDetectionSettings.fullResetTaps,
|
||||
tapDetectionSettings.yawResetDelay,
|
||||
tapDetectionSettings.yawResetEnabled,
|
||||
tapDetectionSettings.yawResetTaps,
|
||||
tapDetectionSettings.mountingResetDelay,
|
||||
tapDetectionSettings.mountingResetEnabled,
|
||||
tapDetectionSettings.mountingResetTaps,
|
||||
true
|
||||
);
|
||||
|
||||
sendRPCPacket(
|
||||
RpcMessage.ChangeSettingsRequest,
|
||||
new ChangeSettingsRequestT(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
newTapSettings
|
||||
)
|
||||
);
|
||||
|
||||
return () => {
|
||||
newTapSettings.setupMode = false;
|
||||
sendRPCPacket(
|
||||
RpcMessage.ChangeSettingsRequest,
|
||||
new ChangeSettingsRequestT(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
newTapSettings
|
||||
)
|
||||
);
|
||||
};
|
||||
}, [tapDetectionSettings]);
|
||||
|
||||
const trackerPartGrouped = useMemo(
|
||||
() =>
|
||||
@@ -103,7 +177,9 @@ export function TrackersAssignPage() {
|
||||
}, {} as any);
|
||||
}, [trackers]);
|
||||
|
||||
const onTrackerSelected = (tracker: FlatDeviceTracker | null) => {
|
||||
const onTrackerSelected = (
|
||||
tracker: FlatDeviceTracker | FlatDeviceTrackerDummy | null
|
||||
) => {
|
||||
const assign = (
|
||||
role: BodyPart,
|
||||
rotation: QuatT | null,
|
||||
@@ -129,7 +205,6 @@ export function TrackersAssignPage() {
|
||||
setSelectRole(BodyPart.NONE);
|
||||
return;
|
||||
}
|
||||
|
||||
assign(
|
||||
selectedRole,
|
||||
tracker.tracker.info?.mountingOrientation || null,
|
||||
@@ -138,6 +213,17 @@ export function TrackersAssignPage() {
|
||||
setSelectRole(BodyPart.NONE);
|
||||
};
|
||||
|
||||
useRPCPacket(
|
||||
RpcMessage.TapDetectionSetupNotification,
|
||||
(tapSetup: TapDetectionSetupNotificationT) => {
|
||||
if (selectedRole === BodyPart.NONE || !tapSetup.trackerId) return;
|
||||
onTrackerSelected({
|
||||
tracker: { trackerId: tapSetup.trackerId, info: undefined },
|
||||
});
|
||||
playTapSetupSound(config?.feedbackSoundVolume);
|
||||
}
|
||||
);
|
||||
|
||||
applyProgress(0.5);
|
||||
|
||||
const { closeChokerWarning, tryOpenChokerWarning, shouldShowChokerWarn } =
|
||||
|
||||
@@ -52,9 +52,12 @@ export function TrackerSelectionMenu({
|
||||
<Typography variant="main-title" bold>
|
||||
{l10n.getString('tracker_selection_menu-' + BodyPart[bodyPart])}
|
||||
</Typography>
|
||||
<div className="w-full max-w-sm">
|
||||
<TipBox>{l10n.getString('tips-tap_setup')}</TipBox>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div
|
||||
className="w-full h-full min-w-[700px] overflow-y-auto p-2 flex flex-col gap-6"
|
||||
className="w-full h-full min-w-[700px] overflow-y-auto p-2 pt-0 flex flex-col gap-6"
|
||||
ref={refTrackers}
|
||||
style={{ height: trackersHeight - optionsHeight }}
|
||||
>
|
||||
@@ -115,7 +118,7 @@ export function TrackerSelectionMenu({
|
||||
ref={refOptions}
|
||||
>
|
||||
<div className="w-full max-w-sm">
|
||||
<TipBox>{l10n.getString('tips-find_tracker')}</TipBox>
|
||||
{/* <TipBox>{l10n.getString('tips-find_tracker')}</TipBox> */}
|
||||
</div>
|
||||
<div className="flex flex-col justify-end pointer-events-auto">
|
||||
<Button variant="primary" onClick={() => onTrackerSelected(null)}>
|
||||
|
||||
@@ -190,6 +190,7 @@ export function GeneralSettings() {
|
||||
values.tapDetection.mountingResetEnabled;
|
||||
tapDetection.mountingResetDelay = values.tapDetection.mountingResetDelay;
|
||||
tapDetection.mountingResetTaps = values.tapDetection.mountingResetTaps;
|
||||
tapDetection.setupMode = false;
|
||||
settings.tapDetectionSettings = tapDetection;
|
||||
|
||||
const filtering = new FilteringSettingsT();
|
||||
|
||||
@@ -57,6 +57,10 @@ export function TrackerPartCard({
|
||||
setVelocities(velocities);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!td) setVelocities([0, 0, 0]);
|
||||
}, [td]);
|
||||
|
||||
const globalVelocity = useMemo(
|
||||
() =>
|
||||
Math.floor(
|
||||
|
||||
@@ -7,6 +7,31 @@ const fullResetStartedSound = new Audio('/sounds/full-reset-started-sound.mp3');
|
||||
const mountingResetStartedSound = new Audio(
|
||||
'/sounds/mounting-reset-started-sound.mp3'
|
||||
);
|
||||
const tapSetupSound1 = new Audio('/sounds/first-tap.mp3');
|
||||
const tapSetupSound2 = new Audio('/sounds/second-tap.mp3');
|
||||
const tapSetupSound3 = new Audio('/sounds/third-tap.mp3');
|
||||
const tapSetupSound4 = new Audio('/sounds/fourth-tap.mp3');
|
||||
const tapSetupSound5 = new Audio('/sounds/fifth-tap.mp3');
|
||||
const tapSetupSoundEnd = new Audio('/sounds/end-tap.mp3');
|
||||
const tapSetupExtraSound = new Audio('/sounds/tapextrasetup.mp3');
|
||||
|
||||
const sounds = [
|
||||
quickResetStartedSound,
|
||||
fullResetStartedSound,
|
||||
mountingResetStartedSound,
|
||||
tapSetupSound1,
|
||||
tapSetupSound2,
|
||||
tapSetupSound3,
|
||||
tapSetupSound4,
|
||||
tapSetupSound5,
|
||||
tapSetupSoundEnd,
|
||||
tapSetupExtraSound,
|
||||
];
|
||||
|
||||
sounds.forEach((s) => {
|
||||
s.play();
|
||||
setTimeout(() => s.pause(), 10);
|
||||
});
|
||||
|
||||
function restartAndPlay(audio: HTMLAudioElement, volume: number) {
|
||||
audio.volume = Math.min(1, Math.pow(volume, Math.E) + 0.05);
|
||||
@@ -33,3 +58,29 @@ export function playSoundOnResetStarted(resetType: ResetType, volume = 1) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let lastKnownVolume = 1;
|
||||
/* Easter egg */
|
||||
tapSetupSoundEnd.onended = () => {
|
||||
if (Math.floor(Math.random() * 12000) !== 0) return;
|
||||
restartAndPlay(tapSetupExtraSound, lastKnownVolume);
|
||||
};
|
||||
|
||||
const order = [
|
||||
tapSetupSound1,
|
||||
tapSetupSound2,
|
||||
tapSetupSound3,
|
||||
tapSetupSound4,
|
||||
tapSetupSound5,
|
||||
tapSetupSoundEnd,
|
||||
tapSetupSoundEnd,
|
||||
tapSetupSoundEnd,
|
||||
];
|
||||
let lastTap = 0;
|
||||
export function playTapSetupSound(volume = 1) {
|
||||
lastKnownVolume = volume;
|
||||
restartAndPlay(order[lastTap++], volume);
|
||||
if (lastTap >= order.length) {
|
||||
lastTap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,8 @@ dependencies {
|
||||
implementation("com.melloware:jintellitype:1.+")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0-RC")
|
||||
|
||||
implementation("it.unimi.dsi:fastutil:8.5.12")
|
||||
|
||||
testImplementation(kotlin("test"))
|
||||
// Use JUnit test framework
|
||||
testImplementation(platform("org.junit:junit-bom:5.9.0"))
|
||||
|
||||
@@ -16,6 +16,7 @@ import dev.slimevr.protocol.ProtocolAPI;
|
||||
import dev.slimevr.reset.ResetHandler;
|
||||
import dev.slimevr.serial.ProvisioningHandler;
|
||||
import dev.slimevr.serial.SerialHandler;
|
||||
import dev.slimevr.setup.TapSetupHandler;
|
||||
import dev.slimevr.tracking.processor.HumanPoseManager;
|
||||
import dev.slimevr.tracking.processor.skeleton.HumanSkeleton;
|
||||
import dev.slimevr.tracking.trackers.DeviceManager;
|
||||
@@ -58,6 +59,7 @@ public class VRServer extends Thread {
|
||||
private final BVHRecorder bvhRecorder;
|
||||
private final SerialHandler serialHandler;
|
||||
private final AutoBoneHandler autoBoneHandler;
|
||||
private final TapSetupHandler tapSetupHandler;
|
||||
private final ProtocolAPI protocolAPI;
|
||||
private final ConfigManager configManager;
|
||||
private final Timer timer = new Timer();
|
||||
@@ -87,6 +89,7 @@ public class VRServer extends Thread {
|
||||
provisioningHandler = new ProvisioningHandler(this);
|
||||
|
||||
resetHandler = new ResetHandler();
|
||||
tapSetupHandler = new TapSetupHandler();
|
||||
|
||||
autoBoneHandler = new AutoBoneHandler(this);
|
||||
protocolAPI = new ProtocolAPI(this);
|
||||
@@ -446,6 +449,10 @@ public class VRServer extends Thread {
|
||||
return this.resetHandler;
|
||||
}
|
||||
|
||||
public TapSetupHandler getTapSetupHandler() {
|
||||
return this.tapSetupHandler;
|
||||
}
|
||||
|
||||
public AutoBoneHandler getAutoBoneHandler() {
|
||||
return this.autoBoneHandler;
|
||||
}
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
package dev.slimevr.config;
|
||||
|
||||
import com.jme3.math.FastMath;
|
||||
|
||||
|
||||
// handles the tap detection config
|
||||
// this involves the number of taps, the delay, and whether or not the feature is enabled
|
||||
// for each reset type
|
||||
public class TapDetectionConfig {
|
||||
|
||||
private float yawResetDelay = 0.2f;
|
||||
private float fullResetDelay = 1.0f;
|
||||
private float mountingResetDelay = 1.0f;
|
||||
private boolean yawResetEnabled = true;
|
||||
private boolean fullResetEnabled = true;
|
||||
private boolean mountingResetEnabled = true;
|
||||
private int yawResetTaps = 2;
|
||||
private int fullResetTaps = 3;
|
||||
private int mountingResetTaps = 3;
|
||||
private int numberTrackersOverThreshold = 1;
|
||||
|
||||
public float getYawResetDelay() {
|
||||
return yawResetDelay;
|
||||
}
|
||||
|
||||
public void setYawResetDelay(float yawResetDelay) {
|
||||
this.yawResetDelay = yawResetDelay;
|
||||
}
|
||||
|
||||
public float getFullResetDelay() {
|
||||
return fullResetDelay;
|
||||
}
|
||||
|
||||
public void setFullResetDelay(float fullResetDelay) {
|
||||
this.fullResetDelay = fullResetDelay;
|
||||
}
|
||||
|
||||
public float getMountingResetDelay() {
|
||||
return mountingResetDelay;
|
||||
}
|
||||
|
||||
public void setMountingResetDelay(float mountingResetDelay) {
|
||||
this.mountingResetDelay = mountingResetDelay;
|
||||
}
|
||||
|
||||
public boolean getYawResetEnabled() {
|
||||
return yawResetEnabled;
|
||||
}
|
||||
|
||||
public void setYawResetEnabled(boolean yawResetEnabled) {
|
||||
this.yawResetEnabled = yawResetEnabled;
|
||||
}
|
||||
|
||||
public boolean getFullResetEnabled() {
|
||||
return fullResetEnabled;
|
||||
}
|
||||
|
||||
public void setFullResetEnabled(boolean fullResetEnabled) {
|
||||
this.fullResetEnabled = fullResetEnabled;
|
||||
}
|
||||
|
||||
public boolean getMountingResetEnabled() {
|
||||
return mountingResetEnabled;
|
||||
}
|
||||
|
||||
public void setMountingResetEnabled(boolean mountingResetEnabled) {
|
||||
this.mountingResetEnabled = mountingResetEnabled;
|
||||
}
|
||||
|
||||
public int getYawResetTaps() {
|
||||
return yawResetTaps;
|
||||
}
|
||||
|
||||
// clamp to 2-3 to prevent errors
|
||||
public void setYawResetTaps(int yawResetTaps) {
|
||||
this.yawResetTaps = (int) FastMath.clamp(yawResetTaps, 2, 10);
|
||||
this.yawResetTaps = yawResetTaps;
|
||||
}
|
||||
|
||||
public int getFullResetTaps() {
|
||||
return fullResetTaps;
|
||||
}
|
||||
|
||||
public void setFullResetTaps(int fullResetTaps) {
|
||||
this.fullResetTaps = (int) FastMath.clamp(fullResetTaps, 2, 10);
|
||||
this.fullResetTaps = fullResetTaps;
|
||||
}
|
||||
|
||||
public int getMountingResetTaps() {
|
||||
return mountingResetTaps;
|
||||
}
|
||||
|
||||
public void setMountingResetTaps(int mountingResetTaps) {
|
||||
this.mountingResetTaps = (int) FastMath.clamp(mountingResetTaps, 2, 10);
|
||||
this.mountingResetTaps = mountingResetTaps;
|
||||
}
|
||||
|
||||
public int getNumberTrackersOverThreshold() {
|
||||
return numberTrackersOverThreshold;
|
||||
}
|
||||
|
||||
public void setNumberTrackersOverThreshold(int numberTrackersOverThreshold) {
|
||||
this.numberTrackersOverThreshold = numberTrackersOverThreshold;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package dev.slimevr.config
|
||||
|
||||
import com.jme3.math.FastMath
|
||||
|
||||
// handles the tap detection config
|
||||
// this involves the number of taps, the delay, and whether or not the feature is enabled
|
||||
// for each reset type
|
||||
class TapDetectionConfig {
|
||||
var yawResetDelay = 0.2f
|
||||
var fullResetDelay = 1.0f
|
||||
var mountingResetDelay = 1.0f
|
||||
var yawResetEnabled = true
|
||||
var fullResetEnabled = true
|
||||
var mountingResetEnabled = true
|
||||
var setupMode = false
|
||||
var yawResetTaps = 2
|
||||
// clamp to 2-3 to prevent errors
|
||||
set(yawResetTaps) {
|
||||
field = FastMath.clamp(yawResetTaps.toFloat(), 2f, 10f).toInt()
|
||||
field = yawResetTaps
|
||||
}
|
||||
var fullResetTaps = 3
|
||||
set(fullResetTaps) {
|
||||
field = FastMath.clamp(fullResetTaps.toFloat(), 2f, 10f).toInt()
|
||||
field = fullResetTaps
|
||||
}
|
||||
var mountingResetTaps = 3
|
||||
set(mountingResetTaps) {
|
||||
field = FastMath.clamp(mountingResetTaps.toFloat(), 2f, 10f).toInt()
|
||||
field = mountingResetTaps
|
||||
}
|
||||
var numberTrackersOverThreshold = 1
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import dev.slimevr.protocol.rpc.reset.RPCResetHandler;
|
||||
import dev.slimevr.protocol.rpc.serial.RPCProvisioningHandler;
|
||||
import dev.slimevr.protocol.rpc.serial.RPCSerialHandler;
|
||||
import dev.slimevr.protocol.rpc.settings.RPCSettingsHandler;
|
||||
import dev.slimevr.protocol.rpc.setup.RPCTapSetupHandler;
|
||||
import dev.slimevr.tracking.processor.config.SkeletonConfigOffsets;
|
||||
import dev.slimevr.tracking.trackers.Tracker;
|
||||
import dev.slimevr.tracking.trackers.TrackerPosition;
|
||||
@@ -46,6 +47,7 @@ public class RPCHandler extends ProtocolHandler<RpcMessageHeader>
|
||||
new RPCSerialHandler(this, api);
|
||||
new RPCProvisioningHandler(this, api);
|
||||
new RPCSettingsHandler(this, api);
|
||||
new RPCTapSetupHandler(this, api);
|
||||
|
||||
registerPacketListener(RpcMessage.ResetRequest, this::onResetRequest);
|
||||
registerPacketListener(RpcMessage.AssignTrackerRequest, this::onAssignTrackerRequest);
|
||||
|
||||
@@ -141,7 +141,8 @@ public class RPCSettingsBuilder {
|
||||
tapDetectionConfig.getYawResetTaps(),
|
||||
tapDetectionConfig.getMountingResetDelay(),
|
||||
tapDetectionConfig.getMountingResetEnabled(),
|
||||
tapDetectionConfig.getMountingResetTaps()
|
||||
tapDetectionConfig.getMountingResetTaps(),
|
||||
tapDetectionConfig.getSetupMode()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -218,21 +218,18 @@ public record RPCSettingsHandler(RPCHandler rpcHandler, ProtocolAPI api) {
|
||||
|
||||
if (tapDetectionSettings != null) {
|
||||
// enable/disable tap detection
|
||||
tapDetectionConfig
|
||||
.setYawResetEnabled(tapDetectionSettings.yawResetEnabled());
|
||||
tapDetectionConfig
|
||||
.setFullResetEnabled(tapDetectionSettings.fullResetEnabled());
|
||||
tapDetectionConfig.setYawResetEnabled(tapDetectionSettings.yawResetEnabled());
|
||||
tapDetectionConfig.setFullResetEnabled(tapDetectionSettings.fullResetEnabled());
|
||||
tapDetectionConfig
|
||||
.setMountingResetEnabled(tapDetectionSettings.mountingResetEnabled());
|
||||
tapDetectionConfig.setSetupMode(tapDetectionSettings.setupMode());
|
||||
|
||||
// set tap detection delays
|
||||
if (tapDetectionSettings.hasYawResetDelay()) {
|
||||
tapDetectionConfig
|
||||
.setYawResetDelay(tapDetectionSettings.yawResetDelay());
|
||||
tapDetectionConfig.setYawResetDelay(tapDetectionSettings.yawResetDelay());
|
||||
}
|
||||
if (tapDetectionSettings.hasFullResetDelay()) {
|
||||
tapDetectionConfig
|
||||
.setFullResetDelay(tapDetectionSettings.fullResetDelay());
|
||||
tapDetectionConfig.setFullResetDelay(tapDetectionSettings.fullResetDelay());
|
||||
}
|
||||
if (tapDetectionSettings.hasMountingResetDelay()) {
|
||||
tapDetectionConfig
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package dev.slimevr.protocol.rpc.setup
|
||||
|
||||
import com.google.flatbuffers.FlatBufferBuilder
|
||||
import dev.slimevr.protocol.GenericConnection
|
||||
import dev.slimevr.protocol.ProtocolAPI
|
||||
import dev.slimevr.protocol.datafeed.DataFeedBuilder
|
||||
import dev.slimevr.protocol.rpc.RPCHandler
|
||||
import dev.slimevr.setup.TapSetupListener
|
||||
import dev.slimevr.tracking.trackers.Tracker
|
||||
import solarxr_protocol.rpc.RpcMessage
|
||||
import solarxr_protocol.rpc.TapDetectionSetupNotification
|
||||
|
||||
class RPCTapSetupHandler(
|
||||
private val rpcHandler: RPCHandler,
|
||||
val api: ProtocolAPI,
|
||||
) :
|
||||
TapSetupListener {
|
||||
init {
|
||||
this.api.server.tapSetupHandler.addListener(this)
|
||||
}
|
||||
|
||||
override fun onStarted(tracker: Tracker) {
|
||||
val fbb = FlatBufferBuilder(32)
|
||||
val idOffset = DataFeedBuilder.createTrackerId(fbb, tracker)
|
||||
val update = TapDetectionSetupNotification.createTapDetectionSetupNotification(fbb, idOffset)
|
||||
val outbound =
|
||||
rpcHandler.createRPCMessage(fbb, RpcMessage.TapDetectionSetupNotification, update)
|
||||
fbb.finish(outbound)
|
||||
|
||||
forAllListeners {
|
||||
it.send(
|
||||
fbb.dataBuffer()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun forAllListeners(action: (GenericConnection) -> Unit) {
|
||||
api
|
||||
.apiServers
|
||||
.forEach {
|
||||
it
|
||||
.apiConnections
|
||||
.forEach(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
24
server/src/main/java/dev/slimevr/setup/TapSetupHandler.kt
Normal file
24
server/src/main/java/dev/slimevr/setup/TapSetupHandler.kt
Normal file
@@ -0,0 +1,24 @@
|
||||
package dev.slimevr.setup
|
||||
|
||||
import dev.slimevr.tracking.trackers.Tracker
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
class TapSetupHandler {
|
||||
private val listeners: MutableList<TapSetupListener> = CopyOnWriteArrayList()
|
||||
|
||||
fun addListener(listener: TapSetupListener) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
fun removeListener(listener: TapSetupListener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
fun sendTap(tracker: Tracker) {
|
||||
listeners.forEach { it.onStarted(tracker) }
|
||||
}
|
||||
}
|
||||
|
||||
interface TapSetupListener {
|
||||
fun onStarted(tracker: Tracker)
|
||||
}
|
||||
@@ -177,7 +177,9 @@ public class HumanSkeleton {
|
||||
this,
|
||||
humanPoseManager,
|
||||
server.getConfigManager().getVrConfig().getTapDetection(),
|
||||
server.getResetHandler()
|
||||
server.getResetHandler(),
|
||||
server.getTapSetupHandler(),
|
||||
server.getAllTrackers()
|
||||
);
|
||||
legTweaks.setConfig(server.getConfigManager().getVrConfig().getLegTweaks());
|
||||
}
|
||||
|
||||
@@ -58,6 +58,10 @@ public class TapDetection {
|
||||
trackerToWatch = tracker;
|
||||
}
|
||||
|
||||
public Tracker getTracker() {
|
||||
return trackerToWatch;
|
||||
}
|
||||
|
||||
public int getTaps() {
|
||||
return taps;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package dev.slimevr.tracking.processor.skeleton;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import dev.slimevr.config.TapDetectionConfig;
|
||||
import dev.slimevr.reset.ResetHandler;
|
||||
import dev.slimevr.setup.TapSetupHandler;
|
||||
import dev.slimevr.tracking.processor.HumanPoseManager;
|
||||
import dev.slimevr.tracking.trackers.Tracker;
|
||||
import solarxr_protocol.rpc.ResetType;
|
||||
@@ -13,6 +17,7 @@ import solarxr_protocol.rpc.ResetType;
|
||||
*/
|
||||
public class TapDetectionManager {
|
||||
private static final String resetSourceName = "TapDetection";
|
||||
private static final int tapsForSetupMode = 2;
|
||||
|
||||
// server and related classes
|
||||
private final HumanSkeleton skeleton;
|
||||
@@ -24,6 +29,8 @@ public class TapDetectionManager {
|
||||
private TapDetection fullResetDetector;
|
||||
private TapDetection mountingResetDetector;
|
||||
|
||||
private ArrayList<TapDetection> tapDetectors;
|
||||
|
||||
// number of taps to detect
|
||||
private int yawResetTaps = 2;
|
||||
private int fullResetTaps = 3;
|
||||
@@ -41,6 +48,7 @@ public class TapDetectionManager {
|
||||
private boolean mountingResetAllowPlaySound = true;
|
||||
|
||||
private ResetHandler resetHandler;
|
||||
private TapSetupHandler tapSetupHandler;
|
||||
|
||||
public TapDetectionManager(HumanSkeleton skeleton) {
|
||||
this.skeleton = skeleton;
|
||||
@@ -50,17 +58,28 @@ public class TapDetectionManager {
|
||||
HumanSkeleton skeleton,
|
||||
HumanPoseManager humanPoseManager,
|
||||
TapDetectionConfig config,
|
||||
ResetHandler resetHandler
|
||||
ResetHandler resetHandler,
|
||||
TapSetupHandler tapSetupHandler,
|
||||
List<Tracker> trackers
|
||||
) {
|
||||
this.skeleton = skeleton;
|
||||
this.humanPoseManager = humanPoseManager;
|
||||
this.config = config;
|
||||
this.resetHandler = resetHandler;
|
||||
this.tapSetupHandler = tapSetupHandler;
|
||||
|
||||
yawResetDetector = new TapDetection(skeleton, getTrackerToWatchYawReset());
|
||||
fullResetDetector = new TapDetection(skeleton, getTrackerToWatchFullReset());
|
||||
mountingResetDetector = new TapDetection(skeleton, getTrackerToWatchMountingReset());
|
||||
|
||||
// a list of tap detectors for each tracker
|
||||
tapDetectors = new ArrayList<>();
|
||||
for (Tracker tracker : trackers) {
|
||||
TapDetection tapDetector = new TapDetection(skeleton, tracker);
|
||||
tapDetector.setEnabled(true);
|
||||
tapDetectors.add(tapDetector);
|
||||
}
|
||||
|
||||
// since this config value is only modified by editing the config file,
|
||||
// we can set it here
|
||||
yawResetDetector
|
||||
@@ -95,17 +114,35 @@ public class TapDetectionManager {
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (yawResetDetector == null || fullResetDetector == null || mountingResetDetector == null)
|
||||
if (
|
||||
yawResetDetector == null
|
||||
|| fullResetDetector == null
|
||||
|| mountingResetDetector == null
|
||||
|| tapDetectors == null
|
||||
)
|
||||
return;
|
||||
// update the tap detectors
|
||||
yawResetDetector.update();
|
||||
fullResetDetector.update();
|
||||
mountingResetDetector.update();
|
||||
|
||||
// check if any tap detectors have detected taps
|
||||
checkYawReset();
|
||||
checkFullReset();
|
||||
checkMountingReset();
|
||||
// if setup mode is enabled, update the tap detectors for each tracker
|
||||
if (config.getSetupMode()) {
|
||||
for (TapDetection tapDetector : tapDetectors) {
|
||||
tapDetector.update();
|
||||
|
||||
if (tapDetector.getTaps() >= tapsForSetupMode) {
|
||||
tapSetupHandler.sendTap(tapDetector.getTracker());
|
||||
tapDetector.resetDetector();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// update the tap detectors
|
||||
yawResetDetector.update();
|
||||
fullResetDetector.update();
|
||||
mountingResetDetector.update();
|
||||
|
||||
// check if any tap detectors have detected taps
|
||||
checkYawReset();
|
||||
checkFullReset();
|
||||
checkMountingReset();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkYawReset() {
|
||||
|
||||
Submodule solarxr-protocol updated: c49a2ac9e0...fd88c26942
Reference in New Issue
Block a user