Compare commits

..

11 Commits

Author SHA1 Message Date
gorbit99
61065eba7f Apply round of suggestions 2025-09-30 22:48:51 +02:00
gorbit99
0e750fd1de Merge branch 'main' into tracker-graph 2025-09-30 01:30:32 +02:00
gorbit99
7aabdbe724 Add tracker graph to tracker settings page 2025-09-30 01:25:44 +02:00
Eiren Rain
de16acbcf4 New Pontoon translations (#1512) 2025-09-30 00:24:22 +03:00
Erimel
486cb295ac Pontoon: Update French (fr) localization of GUI
Co-Authored-By: Erimel <loukalemire@gmail.com>
Co-Authored-By: SlimePuppy <minouviolet2007+github@gmail.com>
2025-09-23 21:00:09 +00:00
nekomona
dd3fe24294 Pontoon: Update Simplified Chinese (zh-Hans) localization of GUI
Co-authored-by: nekomona <nekomona@163.com>
2025-09-23 21:00:09 +00:00
Alejandro
59bdedecbb Pontoon: Update Latinamerican Spanish (es-419) localization of GUI
Co-authored-by: Alejandro <moctezumaalejandro25@gmail.com>
2025-09-23 21:00:09 +00:00
YumeTomo
fc3d049019 Pontoon: Update Thai (th) localization of GUI
Co-Authored-By: YumeTomo <Sodnoobe@gmail.com>
Co-Authored-By: Cusmo84 <saopob@gmail.com>
Co-Authored-By: Kaiera huzu <patsakorn9090@gmail.com>
2025-09-23 21:00:09 +00:00
ReDoX
de150e7349 Pontoon: Update Polish (pl) localization of GUI
Co-authored-by: ReDoX <redox01@o2.pl>
2025-09-23 21:00:09 +00:00
Meow Wei
06b3f61d37 Pontoon: Update Traditional Chinese (zh-Hant) localization of GUI
Co-authored-by: Meow Wei <medicalwei@gmail.com>
2025-09-23 21:00:09 +00:00
Bader
82b96d5ebe Pontoon: Update Arabic (ar) localization of GUI
Co-Authored-By: Bader <baq100@gmail.com>
Co-Authored-By: FennT <0094falcon@gmail.com>
2025-09-23 21:00:09 +00:00
31 changed files with 1746 additions and 5252 deletions

View File

@@ -26,6 +26,7 @@
"@tweenjs/tween.js": "^25.0.0",
"@twemoji/svg": "^15.0.0",
"browser-fs-access": "^0.35.0",
"chart.js": "^4.5.0",
"classnames": "^2.5.1",
"flatbuffers": "22.10.26",
"intl-pluralrules": "^2.0.1",
@@ -33,6 +34,7 @@
"jotai": "^2.12.2",
"prompts": "^2.4.2",
"react": "^18.3.1",
"react-chartjs-2": "^5.3.0",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.0.13",
"react-helmet": "^6.1.0",

View File

@@ -497,8 +497,6 @@ settings-general-fk_settings-leg_tweak-floor_clip-description = يمكن أن ي
settings-general-fk_settings-leg_tweak-toe_snap-description = الانجذاب إلى أصابع القدم يحاول تخمين دوران قدميك إذا لم تكن أجهزة تعقب القدم قيد الاستخدام.
settings-general-fk_settings-leg_tweak-foot_plant-description = تثبيت اصبع القدم يحاول تخمين دوران قدميك إذا لم تكن أجهزة تعقب القدم قيد الاستخدام.
settings-general-fk_settings-leg_fk = تعقب الساق
settings-general-fk_settings-leg_fk-reset_mounting_feet-description = تمكين إعادة ضبط تركيب القدمين عن طريق المشي على رؤوس الأصابع.
settings-general-fk_settings-leg_fk-reset_mounting_feet = إعادة تعيين تركيب القدمين
settings-general-fk_settings-enforce_joint_constraints = حدود الهيكل العظمي
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints = فرض القيود
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints-description = منع المفاصل من الدوران إلى ما بعد الحد الأقصى
@@ -637,6 +635,14 @@ settings-general-interface-discord_presence-message =
[many] كثيرة
*[other] أخرى
}
settings-interface-behavior-error_tracking = جمع الأخطاء عبر Sentry.io
settings-interface-behavior-error_tracking-description_v2 =
<h1>هل توافق على جمع بيانات الخطأ مجهولة المصدر؟</h1>
<b>نحن لا نجمع معلومات شخصية</b> مثل عنوان IP الخاص بك أو بيانات الاعتماد اللاسلكية. يقدر SlimeVR خصوصيتك!
لتوفير أفضل تجربة للمستخدم، نقوم بجمع تقارير الأخطاء ومقاييس الأداء ومعلومات نظام التشغيل مجهولة المصدر. يساعدنا هذا في اكتشاف الأخطاء والمشكلات المتعلقة ب SlimeVR. يتم جمع هذه المقاييس عبر Sentry.io.
settings-interface-behavior-error_tracking-label = إرسال الأخطاء إلى المطورين
## Serial settings
@@ -659,6 +665,8 @@ settings-serial-get_infos = احصل على معلومات
settings-serial-serial_select = اختر منفذ تسلسلي
settings-serial-auto_dropdown_item = تلقائي
settings-serial-get_wifi_scan = احصل على فحص WiFi
settings-serial-file_type = نص عادي
settings-serial-save_logs = حفظ في ملف
## OSC router settings
@@ -688,9 +696,21 @@ settings-osc-router-network-address-placeholder = عنوان آي بي في 4
## OSC VRChat settings
settings-osc-vrchat = أجهزة تعقب "في ار تشات أوه أس سي"
# This cares about multilines
settings-osc-vrchat-description-v1 =
تغيير الإعدادات الخاصة بمعيار أجهزة تعقب OSC المستخدم لإرسال
بيانات التعقب إلى التطبيقات التي لا تحتوي على SteamVR (مثل Quest المستقل).
تأكد من تمكين OSC في VRChat عبر قائمة الإجراءات ضمن OSC > ممكن.
settings-osc-vrchat-enable = تمكين
settings-osc-vrchat-enable-description = بتبديل إرسال واستقبال البيانات.
settings-osc-vrchat-enable-label = تمكين
settings-osc-vrchat-oscqueryEnabled = تمكين OSCQuery
settings-osc-vrchat-oscqueryEnabled-description =
يكتشف OSCQuery تلقائيا مثيلات VRChat قيد التشغيل ويرسل البيانات إليها.
يمكنه أيضا الإعلان عن نفسه لهم من أجل تلقي بيانات HMD ووحدة التحكم.
للسماح بتلقي بيانات HMD ووحدة التحكم من VRChat ، انتقل إلى إعدادات القائمة الرئيسية
ضمن "التتبع و IK (الحركة العكسية)" وتمكين "السماح بإرسال بيانات OSC لتتبع الرأس والمعصم".
settings-osc-vrchat-oscqueryEnabled-label = تمكين OSCQuery
settings-osc-vrchat-network = منافذ الشبكة
settings-osc-vrchat-network-port_in =
.label = منفذ الدخول

View File

@@ -390,6 +390,10 @@ tracker-settings-update-blocked = Update not available. No other releases availa
tracker-settings-update-available = { $versionName } is now available
tracker-settings-update = Update now
tracker-settings-update-title = Firmware version
tracker-settings-graph-acceleration-title = Tracker Acceleration
tracker-settings-graph-position-title = Tracker Position
tracker-settings-graph-show-title = Show Tracker Graph
tracker-settings-graph-hide-title = Hide Tracker Graph
## Tracker part card info
tracker-part_card-no_name = No name

View File

@@ -7,8 +7,8 @@
## Websocket (server) status
websocket-connecting = Conectando al servidor
websocket-connection_lost = Conexión al servidor perdida. Intentando reconectar...
websocket-connecting = Cargando...
websocket-connection_lost = ¡El servidor falló!
websocket-connection_lost-desc = Parece que el servidor de SlimeVR ha dejado de funcionar. Revise los registros y reinicie el programa.
websocket-timedout = No se ha podido conectar al servidor.
websocket-timedout-desc = Parece que el servidor de SlimeVR ha dejado de funcionar o se agotó el tiempo de espera de la conexión. Revise los registros y reinicie el programa
@@ -609,8 +609,6 @@ settings-general-fk_settings-leg_tweak-floor_clip-description = El clip del suel
settings-general-fk_settings-leg_tweak-toe_snap-description = El encajado de dedos intenta adivinar la rotación de los pies si sus respectivos trackers no están en uso.
settings-general-fk_settings-leg_tweak-foot_plant-description = El plantado del pie rota los pies para que sean paralelos con el suelo al entrar en contacto.
settings-general-fk_settings-leg_fk = Tracking de piernas
settings-general-fk_settings-leg_fk-reset_mounting_feet-description = Activar reinicio de montura para el pie mediante el pararse de puntillas.
settings-general-fk_settings-leg_fk-reset_mounting_feet = Reinicio de montura de pies
settings-general-fk_settings-enforce_joint_constraints = Límites esqueléticos
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints = Imponer restricciones
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints-description = Evita que las articulaciones giren más allá de su límite
@@ -1018,7 +1016,6 @@ onboarding-connect_tracker-next = He conectado todos mis sensores
onboarding-calibration_tutorial = Tutorial de calibración de IMU
onboarding-calibration_tutorial-subtitle = ¡Esto te ayudara a reducir la desviación del tracker!
onboarding-calibration_tutorial-description = Cada vez que enciendes tus trackers, van a necesitar descansar un ratito en una superficie plana para calibrarse. Tratemos de hacer lo mismo presionando el botón «{ onboarding-calibration_tutorial-calibrate }», <b>¡No los muevas!</b>
onboarding-calibration_tutorial-calibrate = Puse los sensores en una mesa.
onboarding-calibration_tutorial-status-waiting = Esperando por ti
onboarding-calibration_tutorial-status-calibrating = Calibrando

View File

@@ -244,6 +244,8 @@ reset-reset_all_warning_default-v2 =
Êtes-vous sûr de vouloir faire cela ?
reset-full = Réinitialisation complète
reset-mounting = Réinitialiser l'alignement
reset-mounting-feet = Réinitialiser l'alignement des pieds
reset-mounting-fingers = Réinitialiser l'alignement des doigts
reset-yaw = Réinitialisation horizontale
## Serial detection stuff
@@ -611,8 +613,8 @@ settings-general-fk_settings-leg_tweak-floor_clip-description = Le limitage au s
settings-general-fk_settings-leg_tweak-toe_snap-description = La correction des orteils estime l'orientation de vos pieds si vous ne portez pas de capteurs sur ses derniers.
settings-general-fk_settings-leg_tweak-foot_plant-description = La correction des pieds oriente vos pieds pour qu'ils soient parallèles au sol lorsqu'ils le touche.
settings-general-fk_settings-leg_fk = Capture des jambes
settings-general-fk_settings-leg_fk-reset_mounting_feet-description = Activer la réinitialisation de l'alignement des pieds en allant sur la pointe des pieds.
settings-general-fk_settings-leg_fk-reset_mounting_feet = Réinitialisation de l'alignement des pieds
settings-general-fk_settings-leg_fk-reset_mounting_feet-description-v1 = Forcer la réinitialisation de l'alignement des pieds pendant la réinitialisation d'alignement générale.
settings-general-fk_settings-leg_fk-reset_mounting_feet-v1 = Forcer la réinitialisation de l'alignement des pieds
settings-general-fk_settings-enforce_joint_constraints = Limites squelettiques
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints = Appliquer les contraintes
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints-description = Empêche les articulations de tourner au-delà de leur limite

View File

@@ -243,6 +243,8 @@ reset-reset_all_warning_default-v2 =
Czy na pewno chcesz to zrobić?
reset-full = Pełny Reset
reset-mounting = Zresetuj położenie
reset-mounting-feet = Zresetuj mocowanie stóp
reset-mounting-fingers = Zresetuj mocowanie palców
reset-yaw = Reset odchylenia
## Serial detection stuff
@@ -610,8 +612,6 @@ settings-general-fk_settings-leg_tweak-floor_clip-description = Floor-clip może
settings-general-fk_settings-leg_tweak-toe_snap-description = Toe-snap próbuje odgadnąć obrót twoich stóp, jeśli trackery stóp nie są używane.
settings-general-fk_settings-leg_tweak-foot_plant-description = Foot-plant obraca stopy, aby były równoległe do podłoża podczas kontaktu.
settings-general-fk_settings-leg_fk = Śledzenie nóg
settings-general-fk_settings-leg_fk-reset_mounting_feet-description = Włącz resetowanie montażu stóp, chodząc na palcach.
settings-general-fk_settings-leg_fk-reset_mounting_feet = Reset mocowania stóp
settings-general-fk_settings-enforce_joint_constraints = Limity szkieletowe
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints = Wymuszanie ograniczeń
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints-description = Zapobiega obracaniu się stawów poza ich limit

View File

@@ -89,7 +89,7 @@ body_part-RIGHT_LITTLE_DISTAL = ปลายนิ้วก้อยขวา
board_type-UNKNOWN = ไม่ทราบ
board_type-NODEMCU = NodeMCU
board_type-CUSTOM = บอร์ดคัสตอม
board_type-CUSTOM = บอร์ดสั่งทำ
board_type-WROOM32 = WROOM32
board_type-WEMOSD1MINI = Wemos D1 Mini
board_type-TTGO_TBASE = TTGO T-Base
@@ -187,7 +187,7 @@ skeleton_bone-SKELETON_OFFSET-desc =
ปรับค่านี้เพื่อเลื่อนตำแหน่งแทร็กเกอร์ทั้งหมดไปด้านหน้าหรือด้านหลัง
เพื่อช่วยในการปรับเทียบสำหรับเกมหรือแอปพลิเคชันบางตัว
ที่อาจต้องการให้แทร็กเกอร์อยู่ด้านหน้ามากกว่าปกติ
skeleton_bone-SHOULDERS_DISTANCE = ระยะไหล่
skeleton_bone-SHOULDERS_DISTANCE = ระยะความกว้างไหล่
skeleton_bone-SHOULDERS_DISTANCE-desc =
นี่คือระยะทางในแนวตั้งจากฐานคอถึงไหล่ของคุณ
ปรับโดยเริ่มจากตั้งความยาวแขนส่วนบนเป็น 0 และปรับค่านี้จนกว่าแทร็กเกอร์ข้อศอกเสมือน
@@ -243,7 +243,9 @@ reset-reset_all_warning_default-v2 =
คุณต้องการดำเนินการต่อหรือไม่?
reset-full = รีเซ็ตแทร็กเกอร์ทั้งหมด
reset-mounting = รีเซ็ตการติดตั้ง
reset-yaw = รีเซ็ตแกนแนวตั้ง
reset-mounting-feet = รีเซ็ตทิศทางติดตั้งเท้า
reset-mounting-fingers = รีเซ็ตการติดตั้งนิ้วมือ
reset-yaw = รีเซ็ตแกนหมุน
## Serial detection stuff
@@ -260,25 +262,26 @@ serial_detection-close = ปิด
navbar-home = หน้าหลัก
navbar-body_proportions = สัดส่วนร่างกาย
navbar-trackers_assign = กำหนดแทร็กเกอร์
navbar-mounting = ปรับเทียบการติดตั้ง
navbar-mounting = ปรับเทียบทิศทางการติดตั้ง
navbar-onboarding = ตัวช่วยการตั้งค่า
navbar-settings = ตั้งค่า
## Biovision hierarchy recording
bvh-start_recording = อัด BVH
bvh-recording = กำลังอัดบันทึก
bvh-start_recording = บันทึก BVH
bvh-recording = กำลังบันทึก...
bvh-save_title = บันทึก การบันทึก BVH
## Tracking pause
tracking-unpaused = หยุดการติดตามชั่วคราว
tracking-paused = ยกเลิกการหยุดการติดตาม
tracking-paused = ยกเลิกหยุดการติดตาม
## Widget: Overlay settings
widget-overlay = โอเวอร์เลย์
widget-overlay-is_visible_label = แสดงโอเวอร์เลย์ ใน SteamVR
widget-overlay-is_mirrored_label = แสดงโอเวอร์เลย์เป็นกระจก
widget-overlay-is_mirrored_label = สะท้อนการแสดงโอเวอร์เลย์
## Widget: Drift compensation
@@ -286,7 +289,7 @@ widget-drift_compensation-clear = ล้างการชดเชยค่า
## Widget: Clear Reset Mounting
widget-clear_mounting = คืนค่าการติดตั้ง
widget-clear_mounting = ล้างค้าการติดตั้ง
## Widget: Developer settings
@@ -321,9 +324,9 @@ tracker-status-none = ไม่มีสถานะ
tracker-status-busy = ไม่ว่าง
tracker-status-error = มีปัญหา
tracker-status-disconnected = ขาดการเชื่อมต่อ
tracker-status-occluded = มีการติดขัด
tracker-status-occluded = ติดขัด
tracker-status-ok = OK
tracker-status-timed_out = หมดเวลาการเชื่อมต่อ
tracker-status-timed_out = หมดเวลาเชื่อมต่อ
## Tracker status columns
@@ -350,7 +353,7 @@ tracker-rotation-back = หลัง
tracker-rotation-back_left = หลังซ้าย
tracker-rotation-back_right = หลังขวา
tracker-rotation-custom = กำหนดเอง
tracker-rotation-overriden = (ถูกแทนที่ด้วยการ รีเซ็ตการติดตั้ง)
tracker-rotation-overriden = (ถูกแทนที่ด้วยการรีเซ็ตการติดตั้ง)
## Tracker information
@@ -403,7 +406,8 @@ tracker-settings-forget-description = ลบตัวแทร็กเกอร
tracker-settings-forget-label = ลืมแทร็กเกอร์นี้
tracker-settings-update-unavailable = ไม่สามารถอัพเดทได้ (DIY)
tracker-settings-update-low-battery = ไม่สามารถอัพเดทได้ แบตเตอรรี่ต่ำกว่า 50%
tracker-settings-update-up_to_date = อัพเดทล่าสุด
tracker-settings-update-up_to_date = อัพเดทล่าสุดแล้ว
tracker-settings-update-blocked = ไม่สามารถอัพเดทได้ ไม่มีเวอร์ชั่นอื่นที่พร้อมอัพเดท
tracker-settings-update-available = { $versionName } พร้อมใช้งานแล้ว
tracker-settings-update = อัพเดตเดี๋ยวนี้
tracker-settings-update-title = เวอร์ชั่นเฟิร์มแวร์
@@ -471,7 +475,7 @@ mounting_selection_menu-close = ปิด
## Sidebar settings
settings-sidebar-title = การตั้งค่า
settings-sidebar-general = ทั่วไป
settings-sidebar-general = การตั้งค่าทั่วไป
settings-sidebar-tracker_mechanics = การทำงานแทร็กเกอร์
settings-sidebar-stay_aligned = Stay Aligned
settings-sidebar-fk_settings = ตั้งค่าการจับตำแหน่ง
@@ -560,9 +564,9 @@ settings-general-tracker_mechanics-drift_compensation-amount-label = เปอ
settings-general-tracker_mechanics-drift_compensation-max_resets-label = ใช้ค่าจากการรีเซ็ต X ครั้ง
settings-general-tracker_mechanics-save_mounting_reset = บันทึกค่าการปรับเทียบตำแหน่งแบบอัตโนมัติ
settings-general-tracker_mechanics-save_mounting_reset-description =
บันทึกการปรับเทียบตำแหน่งแทร็กเกอร์ระหว่างการรีสตาร์ท มีประโยชน์กับ
ผู้ที่สวมชุดที่แทร็กเกอร์ไม่เคลื่อนในการใช้แต่ละครั้ง <b>ไม่แนะนำสำหรับผู้ใช้ทั่วไป!</b>
settings-general-tracker_mechanics-save_mounting_reset-enabled-label = บันทึกการรีเซ็ตตำแหน่
บันทึกการปรับเทียบการติดตั้งแทร็กเกอร์ระหว่างการรีสตาร์ท มีประโยชน์กับ
ผู้ที่แทร็กเกอร์ไม่เคลื่อนในการใช้แต่ละครั้ง <b>ไม่แนะนำสำหรับผู้ใช้ทั่วไป!</b>
settings-general-tracker_mechanics-save_mounting_reset-enabled-label = บันทึกการรีเซ็ตการติดตั้
settings-general-tracker_mechanics-use_mag_on_all_trackers = ใช้ตัววัดสนามแม่เหล็กบนแทร็กเกอร์ที่ IMU รองรับ
settings-general-tracker_mechanics-use_mag_on_all_trackers-description =
ใช้ตัววัดสนามแม่เหล็กกับแทร็กเกอร์ทุกตัวที่เฟิร์มแวร์รองรับ ลดค่าดริฟท์ในพื้นที่เล่นที่สนามแม่เหล็กเสถียร์
@@ -573,6 +577,7 @@ settings-stay_aligned-description = Stay Aligned ลดอัตตาค่า
settings-stay_aligned-setup-label = ตั้งค่า Stay Aligned
settings-stay_aligned-setup-description = คุณต้องทำการ "ตั้งค่า Stay Aligned" ถึงจะเปิดใช้งาน Stay Aligned ได้
settings-stay_aligned-warnings-drift_compensation = ⚠ กรุณาปิดใช้งาน การชดเชยค่าดริฟท์!! เพราะมันจะขัดกับการตั้งค่า Stay Aligned
settings-stay_aligned-enabled-label = ปรับแทร็กเกอร์ของคุณ
settings-stay_aligned-hide_yaw_correction-label = ซ่อนการปรับแต่ง(เพื่อเปรียบเทียบกับไม่ได้เปิดใช้ Stay Aligned)
settings-stay_aligned-general-label = การตั้งค่าทั่วไป
settings-stay_aligned-relaxed_poses-label = ท่าผ่อนคลาย
@@ -609,21 +614,28 @@ settings-general-fk_settings-leg_tweak-floor_clip-description = เปิดก
settings-general-fk_settings-leg_tweak-toe_snap-description = เปิดเดาการหมุนของเท้าเพื่อคาดเดาการหมุนของเท้าในกรณีที่คุณไม่ได้ใส่แทร็กเกอร์ที่เท้า
settings-general-fk_settings-leg_tweak-foot_plant-description = เปิดปรับสมดุลเท้าเพื่อให้เท้าคุณอยู่ในระนาบเดียวกับพื้นเมื่อเท้าอยู่บนพื้น
settings-general-fk_settings-leg_fk = การจับตำแหน่งขา
settings-general-fk_settings-leg_fk-reset_mounting_feet-description = เปิดให้รีเซ็ตตำแหน่งแทร็กเกอร์เท้าเมื่อเขย่งได้
settings-general-fk_settings-leg_fk-reset_mounting_feet = รีเซ็ตตำแหน่งแทร็กเกอร์เท้า
settings-general-fk_settings-leg_fk-reset_mounting_feet-description-v1 = บังคับใช้การรีเซ็ตการติดตั้งของแทร็กเกอร์เท้าเมื่อทำการรีเซ็ตการติดตั้ง
settings-general-fk_settings-leg_fk-reset_mounting_feet-v1 = บังคับใช้รีเซ็ตตำแหน่งที่เท้า
settings-general-fk_settings-enforce_joint_constraints = จำกัดองศากระดูก
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints = จำกัดองศาที่จะหมุนได้
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints-description = ป้องกันไม่ให้ข้อต่อหมุนเกินขีดจำกัด
settings-general-fk_settings-enforce_joint_constraints-correct_constraints = แก้ไขด้วยข้อจำกัด
settings-general-fk_settings-enforce_joint_constraints-correct_constraints-description = แก้การหมุนของข้อต่อเมื่อหมุนเกินขีดจำกัด
settings-general-fk_settings-arm_fk = การจับตำแหน่งแขน
settings-general-fk_settings-arm_fk-description = บังคับให้ใช้การจับตำแหน่งแขนจากแว่น VR แม้ว่าจะมีตำแหน่งแขนอยู่แล้ว
settings-general-fk_settings-arm_fk-force_arms = บังคับใช้ตำแหน่งแขนจากแว่น
settings-general-fk_settings-reset_settings = ตั้งค่าการรีเซ็ต
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = รีเซ็ตแกนตั้งของแว่น(HMD) เมื่อใช้การรีเซ็ตแทร็กเกอร์ทั้งหมด เหมาะกับผู้ที่ใส่แว่นบนหน้าผากสำหรับ Vtubing หรือ mocap ไม่ควรใช้สำหรับเล่น VR
settings-general-fk_settings-reset_settings-reset_hmd_pitch = รีเซ็ตแกนตั้งแว่น HMD
settings-general-fk_settings-arm_fk-reset_mode-description = เปลี่ยนท่าทางการไว้แขนในการรีเซ็ตตำแหน่งแทร็กเกอร์
settings-general-fk_settings-arm_fk-reset_mode-description = เปลี่ยนท่าทางการไว้แขนเมื่อทำการรีเซ็ตการติดตั้งแทร็กเกอร์
settings-general-fk_settings-arm_fk-back = หลัง
settings-general-fk_settings-arm_fk-back-description = เป็นท่าเริ่มต้น โดยแขนส่วนบนไปด้านหลัง และแขนส่วนล่างไปด้านหน้า
settings-general-fk_settings-arm_fk-tpose_up = ที-โพส (ขึ้น)
settings-general-fk_settings-arm_fk-tpose_up-description = ให้แขนอยู๋ข้างลำตัวเมื่อทำการรีเซ็ตทั้งหมด และอยู่ในมุม 90 องศา เมื่อทำการรีเซ็ตการติดตั้ง
settings-general-fk_settings-arm_fk-tpose_down = ที-โพส (ล่าง)
settings-general-fk_settings-arm_fk-tpose_down-description = ให้แขนอยู๋ในมุม 90 องศาข้างลำตัวเมื่อทำการรีเซ็ตทั้งหมด และอยู่แนบลำตัวเมื่อทำการรีเซ็ตการติดตั้ง
settings-general-fk_settings-arm_fk-forward = ไปข้างหน้า
settings-general-fk_settings-arm_fk-forward-description = ให้ยกแขนคุณ 90 องศาในด้านหน้า เหมาะสำหรับผู้ที่ Vtubing
settings-general-fk_settings-skeleton_settings-toggles = ตั้งค่าโครงกระดูก
settings-general-fk_settings-skeleton_settings-description = ตั้งค่าให้แสดงหรือไม่แสดงโครงกระดูก เราแนะนำเปิดไว้
settings-general-fk_settings-skeleton_settings-extended_spine_model = โมเดลกระดูกสันหลังขั้นสูง
@@ -645,7 +657,7 @@ settings-general-fk_settings-self_localization-description = โหมด Mocap
settings-general-gesture_control = ควบคุมผ่านท่าทาง
settings-general-gesture_control-subtitle = การรีเซ็ตตามการแตะ
settings-general-gesture_control-description = ใช้การแตะเพื่อรีเซ็ตแทรกเกอร์โดย แทร็กเกอร์ที่อยู่บนสุดบนตัวจะใช้เพื่อรีเซ็ตแกนตั้ง แทร็กเกอร์ที่อยู่บนสุดของเท้าซ้ายจะใช้เพื่อรีเซ็ทแทร็กเกอร์ทั้งหมด และแทร็กเกอร์ที่อยู่บนสุดของขาขวาจะใช้เพื่อรีเซ็ตตำแหน่งแทร็กเกอร์ โดยการแตะจะต้องทำในระยะเวลา 0.3 วินาทีเพื่อให้โปรแกรมรับทราบ
settings-general-gesture_control-description = ใช้งานการแตะเพื่อรีเซ็ตแทรกเกอร์ โดยให้แทร็กเกอร์ที่อยู่บนสุดบนตัวในการรีเซ็ตแกนหมุน แทร็กเกอร์ที่อยู่บนสุดของเท้าซ้ายจะใช้เพื่อรีเซ็ทแทร็กเกอร์ทั้งหมด และแทร็กเกอร์ที่อยู่บนสุดของขาขวาจะใช้เพื่อรีเซ็ตตำแหน่งแทร็กเกอร์ โดยการแตะจะต้องทำในระยะเวลา 0.3 วินาทีเพื่อให้โปรแกรมรับทราบ
# This is a unit: 3 taps, 2 taps, 1 tap
# $amount (Number) - Amount of taps (touches to the tracker's case)
settings-general-gesture_control-taps = แตะ{ $amount }ครั้ง
@@ -729,6 +741,9 @@ settings-interface-behavior-error_tracking-description_v2 =
เพื่อมอบประสบการณ์การใช้งานที่ดีที่สุด เรานั้นเก็บรายงานข้อผิดพลาดแบบไม่ระบุตัวตน เมตริกประสิทธิภาพ และข้อมูลระบบปฏิบัติการเพื่อให้เราตรวจพบข้อบกพร่องและปัญหาใน SlimeVR โดยข้อมูลเหล่านี้ถูกเก็บผ่าน Sentry.io
settings-interface-behavior-error_tracking-label = อนุญาติการส่งข้อมูลให้นักพัฒนา
settings-interface-behavior-bvh_directory = ตำแหน่งที่คุณจะบันทึกค่า BVH
settings-interface-behavior-bvh_directory-description = เลือกตำแหน่งที่คุณต้องการบันทึกค่า BVH แทนที่จะต้องกำหนดเองทุกครั้งเมื่อบันทึก
settings-interface-behavior-bvh_directory-label = เปิดโฟลเดอร์ไปยังไฟล์ BVH
## Serial settings
@@ -992,6 +1007,7 @@ onboarding-connect_tracker-next = ฉันเชื่อมต่อแทร
onboarding-calibration_tutorial = บทเรียนการปรับเทียบ IMU
onboarding-calibration_tutorial-subtitle = นี่จะเป็นการช่วยลดค่าดริฟท์ของแทร็กเกอร์
onboarding-calibration_tutorial-description-v1 = หลังจากเปิดแทร็กเกอร์ของคุณแล้ว วางมันลงบนพื้นที่เรียบสักครู่ แล้วให้แทร็กเกอร์ปรับเทียบตัวเอง การปรับเทียบสามารถทำได้ตลอดเวลาหลังจากเปิดแทร็กเกอร์ขึ้นมา — หน้านี้เป็นเพียงแค่ให้คำแนะนำเท่านั้น หากจะเริ่มต้น คลิกที่ปุ่ม "{ onboarding-calibration_tutorial-calibrate }" แล้ว <b>อย่าขยับแทร็กเกอร์ของคุณ!</b>
onboarding-calibration_tutorial-calibrate = ฉันได้วางแทร็กเกอร์ไว้บนโต๊ะแล้ว
onboarding-calibration_tutorial-status-waiting = เรารอคุณอยู่
onboarding-calibration_tutorial-status-calibrating = กำลังปรับเทียบ
@@ -1074,6 +1090,38 @@ onboarding-assign_trackers-warning-LEFT_LOWER_LEG =
[2] ข้อเท้าซ้าย ถูกกำหนดแล้ว แต่คุณต้องกำหนด ต้นขาซ้าย ด้วย
*[unknown] ข้อเท้าซ้าย ถูกกำหนดแล้ว แต่คุณต้องกำหนด ??? ???? ของร่างกายด้วย
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-RIGHT_LOWER_LEG =
{ $unassigned ->
[0] ข้อเท้าขวา ถูกกำหนดแล้ว แต่คุณต้องกำหนด ต้นขาขวา และอย่างใดอย่างหนึ่งระหว่าง ส่วนอก สะโพก หรือ เอว ด้วย
[1] ข้อเท้าขวา ถูกกำหนดแล้ว แต่คุณต้องกำหนด อย่างใดอย่างหนึ่งระหว่าง ส่วนอก สะโพก หรือ เอว ด้วย
[2] ข้อเท้าขวา ถูกกำหนดแล้ว แต่คุณต้องกำหนด ต้นขาขวา ด้วย
*[unknown] ข้อเท้าขวา ถูกกำหนดแล้ว แต่คุณต้องกำหนด ??? ของร่างกายด้วย
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-LEFT_UPPER_LEG =
{ $unassigned ->
[0] ต้นขาซ้าย ถูกกำหนดแล้ว แต่คุณต้องกำหนด อย่างใดอย่างหนึ่งระหว่าง ส่วนอก สะโพก หรือ เอว ด้วย
*[unknown] ต้าขาซ้าย ถูกกำหนดแล้ว แแต่คุณต้องกำหนด ??? ??? ของร่างกายด้วย
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-RIGHT_UPPER_LEG =
{ $unassigned ->
[0] ต้นขาขวา ถูกกำหนดแล้ว แต่คุณต้องกำหนด อย่างใดอย่างหนึ่งระหว่าง ส่วนอก สะโพก หรือ เอว ด้วย
*[unknown] ต้าขาขวา ถูกกำหนดแล้ว แแต่คุณต้องกำหนด ??? ??? ของร่างกายด้วย
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-HIP =
{ $unassigned ->
[0] สะโพก ถูกกำหนดแล้ว แต่คุณต้องกำหนด ส่วนอกด้วย
*[unknown] สะโพก ถูกกำหนดแล้ว แต่คุณต้องกำหนด ??? ??? ของร่างกาย ด้วย
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-WAIST =
{ $unassigned ->
[0] เอว ถูกกำหนดแล้ว แต่คุณต้องกำหนด ส่วนอกด้วย
*[unknown] เอว ถูกกำหนดแล้ว แต่คุณต้องกำหนด ??? ??? ของร่างกาย ด้วย
}
## Tracker mounting method choose
@@ -1100,12 +1148,15 @@ onboarding-choose_mounting-manual_modal-cancel = ยกเลิก
onboarding-manual_mounting-back = กลับไปยังเข้าสู่ VR
onboarding-manual_mounting = ปรับเทียบตำแหน่งแบบกำหนดเอง
onboarding-manual_mounting-description = คลิกบนแทร็กเกอร์ทุกตัว และดูทิศทางของแทร็กเกอร์ที่ถูกติดตั้ง
onboarding-manual_mounting-auto_mounting = ปรับเทียบตำแหน่งแบบอัตโนมัติ
onboarding-manual_mounting-next = ขั้นตอนถัดไป
## Tracker automatic mounting setup
onboarding-automatic_mounting-back = กลับไปยังเข้าสู่ VR
onboarding-automatic_mounting-title = ปรับเทียบตำแหน่งแทร็กเกอร์
onboarding-automatic_mounting-description = เพื่อให้ SlimeVR ทำงานได้ เราจะต้องทำการตั้งค่าการติดตั้งของแทร็กเกอร์ของคุณให้ตรงกับการติดตั้งบนร่างกายจริง
onboarding-automatic_mounting-manual_mounting = ปรับเทียบตำแหน่งแบบกำหนดเอง
onboarding-automatic_mounting-next = ขั้นตอนถัดไป
onboarding-automatic_mounting-prev_step = ขั้นตอนก่อนหน้า
@@ -1113,6 +1164,7 @@ onboarding-automatic_mounting-done-title = ตำแหน่งแทร็ก
onboarding-automatic_mounting-done-description = ปรับเทียบตำแหน่งแทร็กเกอร์ของคุณสำเร็จแล้ว!
onboarding-automatic_mounting-done-restart = ลองอีกครั้ง
onboarding-automatic_mounting-mounting_reset-title = รีเซ็ตตำแหน่งแทร็กเกอร์
onboarding-automatic_mounting-mounting_reset-step-0 = 1. ก้มตัวลงอยู่ในท่าที่ "กำลังเล่นสกี" โดยให้ขางอ ลำตัวด้านบนเอียงไปด้านหน้า และงอแขนของคุณ
onboarding-automatic_mounting-mounting_reset-step-1 = 2. กดไปที่ปุ่ม "รีเซ็ตำตำแหน่งแทร็กเกอร์" แล้วรอประมาณ 3 วินาที ก่อนที่ตำแหน่งของแทร็กเกอร์จะถูกรีเซ็ต
onboarding-automatic_mounting-preparation-title = จัดเตรียมพร้อม
onboarding-automatic_mounting-preparation-v2-step-0 = 1. กดที่ปุ่ม "รีเซ็ตทั้งหมด"
@@ -1141,7 +1193,7 @@ onboarding-manual_proportions-estimated_height = ความสูงของ
onboarding-automatic_proportions-back = กลับไปยังการปรับสัดส่วนด้วยตัวเอง
onboarding-automatic_proportions-title = วัดสัดส่วนร่างกายของคุณ
onboarding-automatic_proportions-description = เพื่อให้ SlimeVR แทร็กเกอร์ทำงานได้ เราจะต้องรู้ความยาวของกระดูกของคุณ การ Calibration อย่างไวนี้จะวัดค่ามันให้คุณ
onboarding-automatic_proportions-description = เพื่อให้ SlimeVR แทร็กเกอร์ทำงานได้ เราจะต้องรู้ความยาวของกระดูกของคุณ การปรับเทียบอย่างไวนี้จะวัดค่ามันให้คุณ
onboarding-automatic_proportions-manual = ปรับสัดส่วนด้วยตัวเอง
onboarding-automatic_proportions-prev_step = ขั้นตอนก่อนหน้า
onboarding-automatic_proportions-put_trackers_on-title = ใส่แทร็กเกอร์ของคุณ
@@ -1150,10 +1202,10 @@ onboarding-automatic_proportions-put_trackers_on-next = ฉันใส่แท
onboarding-automatic_proportions-requirements-title = สิ่งที่ต้องการ
# Each line of text is a different list item
onboarding-automatic_proportions-requirements-descriptionv2 =
คุณมีแทร็เกอร์ พอที่จะจับการเคลื่อนไหวเท้าของคุณ (โดยทั่วไป 5 ตัว)
คุณมีแทร็เกอร์พอที่จะจับการเคลื่อนไหวเท้าของคุณ (โดยทั่วไป 5 ตัว)
คุณกำลังใส่แว่น และแทร็กเกอร์อยู่
แทร็กเกอร์ของคุณได้เชื่อมต่อเข้ากับ SlimeVR Server และทำงานเป็นปรกติ (เช่น ไม่มีการกระตุก หลุดการเชื่อมต่อ หรืออื่นๆ)
แว่นของคุณได้ส่งข้อมูลตำแหน่งของคุณเข้ากับ SlimeVR server (ปรกติแล้วหมายถึงว่า SlimeVR ทำงานอยู่ และเชื่อมต่อเข้ากับ SlimeVR ด้วย SlimeVR's SteamVR driver)
แว่นของคุณได้ส่งข้อมูลตำแหน่งของคุณเข้ากับ SlimeVR server (ปรกติแล้วหมายถึงว่า SlimeVR ทำงานอยู่ และเชื่อมต่อเข้ากับ SlimeVR ด้วย ไดร์เวอร์ของ SteamVR ผ่าน SlimeVR
แทร็กเกอร์ของคุณนั้นทำงานปรกติ และแสดงการเคลื่อนไหวของคุณถูกต้อง (ตัวอย่างเช่น คุณได้ทำการ Full reset และตัวแทร็กเกอร์ขยับไปในทิศทางที่ถูกเมื่อขยับตัว ก้มลง นั่งลง หรือขยับขา เป็นต้น)
onboarding-automatic_proportions-requirements-next = ฉันได้อ่านสิ่งที่ต้องการแล้ว
onboarding-automatic_proportions-check_height-title-v3 = วัดความสูงของแว่นของคุณ
@@ -1266,9 +1318,12 @@ onboarding-stay_aligned-relaxed_poses-sitting-title = ท่าผ่อนค
onboarding-stay_aligned-relaxed_poses-sitting-step-0 = 1. นั่งในท่าที่สบายๆ
onboarding-stay_aligned-relaxed_poses-sitting-step-1-v2 = 2. กดไปที่ "บันทึกท่าโพส"
onboarding-stay_aligned-relaxed_poses-flat-title = ท่าผ่อนคลายในขณะที่นั่งบนพื้น
onboarding-stay_aligned-relaxed_poses-flat-step-0 = 1. นั่งลงบนพื้นและยื่นขาไปทางด้านหน้า ไม่ต้องเกร็งนะ
onboarding-stay_aligned-relaxed_poses-flat-step-1-v2 = 2. กดไปที่ "บันทึกท่าโพส"
onboarding-stay_aligned-relaxed_poses-skip_step = ข้าม
onboarding-stay_aligned-done-title = เปิดใช้งาน Stay Aligned แล้ว!
onboarding-stay_aligned-done-description = การตั้งค่า Stay Aligned ของคุณสำเร็จแล้ว!
onboarding-stay_aligned-done-description-2 = การตั้งค่าเสร็จสิ้นแล้ว คุณสามารถจะเริ่มต้นการตั้งค่าใหม่หากคุณต้องการจะปรับค่าของท่าโพสคุณ
onboarding-stay_aligned-previous_step = ก่อนหน้า
onboarding-stay_aligned-next_step = ต่อไป
onboarding-stay_aligned-restart = เริ่มใหม่
@@ -1276,6 +1331,7 @@ onboarding-stay_aligned-done = เสร็จแล้ว
## Home
home-no_trackers = ไม่พบแทร็กเกอร์หรือยังไม่ได้ถูกกำหนด
## Trackers Still On notification
@@ -1284,10 +1340,19 @@ trackers_still_on-modal-description =
มีแทร็กเกอร์เปิดค้างไว้อยู่
คุณแน่ใจที่จะปิด SlimeVR?
trackers_still_on-modal-confirm = ออกจาก SlimeVR
trackers_still_on-modal-cancel = ใจเย็นๆก่อน....
## Status system
status_system-StatusTrackerReset = เราแนะนำให้คุณทำการรีเซ็ตทั้งหมดเพราะว่าแทร็กเกอร์หนึ่งตัวหรือมากกว่านั้นยังไม่ได้ถูกปรับ
status_system-StatusSteamVRDisconnected =
{ $type ->
[steamvr_feeder] ขณะนี้ยังไม่มีการเชื่อมต่อกับแอป SlimeVR Feeder
*[steamvr] ขณะนี้ยังไม่มีการเชื่อมต่อกับ SteamVR ผ่านไดรเวอร์ SlimeVR
}
status_system-StatusTrackerError = แทร็กเกอร์ { $trackerName } เกิดข้อผิดพลาด
status_system-StatusUnassignedHMD = แว่น VR ของคุณควรจะถูกกำหนดเป็นแทร็กเกอร์ส่วนหัว
status_system-StatusPublicNetwork = โปรไฟล์เครือข่ายของคุณตอนนี้ถูกตั้งค่าเป็นสาธารณะ ({ $adapters }) ซึ่งไม่แนะนำสำหรับการทำงานของ SlimeVR <PublicFixLink>ดูวิธีการแก้ไขให้เหมาะสมที่นี่</PublicFixLink>
## Firmware tool globals
@@ -1299,7 +1364,16 @@ firmware_tool-loading = กำลังโหลด...
## Firmware tool Steps
firmware_tool = เครื่องมือเฟิร์มแวร์ DIY
firmware_tool-description = ให้คุณตั้งค่าและแฟลชเฟิร์มแวร์แทร็กเกอร์ DIY ของคุณ
firmware_tool-not_available = ไอ่หย๊า เครื่องมือเฟิร์มแวร์ยังไม่พร้อมใช้งานในขณะนี้ โปรดกลับมาใหม่ทีหลัง!
firmware_tool-not_compatible = Firmware นี้เข้ากันไม่ได้กับเซิร์ฟเวอร์เวอร์ชั่นนี้ โปรดอัปเดตเซิร์ฟเวอร์ของคุณ!
firmware_tool-board_step = เลือกบอร์ดของคุณ
firmware_tool-board_step-description = เลือกบอร์ดหนึ่งตัวที่แสดงอยู่ด้านล่าง
firmware_tool-board_pins_step = ตรวจสอบ Pin ของคุณ
firmware_tool-board_pins_step-description =
โปรดตรวจสอบว่า Pin ที่คุณเลือกนั้นถูกต้อง
ค่าเริ่มต้นมักจะถูกแล้วหากคุณทำตามเอกสารประกอบของ SlimeVR
firmware_tool-board_pins_step-enable_led = เปิดใช้งาน LED
firmware_tool-board_pins_step-led_pin =
.label = พิน LED
@@ -1315,6 +1389,16 @@ firmware_tool-board_pins_step-battery_sensor_pin =
firmware_tool-board_pins_step-battery_resistor =
.label = ตัวต้านทานของแบตเตอรี่ (โอห์ม)
.placeholder = ใส่ค่าต้านทานของตัวต้านทานแบตเตอรี่
firmware_tool-board_pins_step-battery_shield_resistor-0 =
.label = ค่าความต้านทาน R1 ของ Battery Shield (โอห์ม)
.placeholder = กรุณากรอกค่าความต้านทาน R1 ของ Battery Shield
firmware_tool-board_pins_step-battery_shield_resistor-1 =
.label = ค่าความต้านทาน R1 ของ Battery Shield (โอห์ม)
.placeholder = กรุณากรอกค่าความต้านทาน R1 ของ Battery Shield
firmware_tool-add_imus_step = เลือก IMU ที่คุณใช้
firmware_tool-add_imus_step-description =
กรุณาใส่ชนิดและจำนวนของ IMU ที่แทร็กเกอร์ของคุณใช้
ค่าเริ่มต้นมักจะถูกแล้วหากคุณทำตามเอกสารประกอบของ SlimeVR
firmware_tool-add_imus_step-imu_type-label = ประเภท IMU
firmware_tool-add_imus_step-imu_type-placeholder = เลือกประเภทของ IMU
firmware_tool-add_imus_step-imu_rotation =
@@ -1458,14 +1542,25 @@ vrc_config-mute-btn = ปิดคำเตือน
vrc_config-unmute-btn = เลิกแจ้งเตือน
vrc_config-legacy_mode = การตั้งศูนย์แบบเก่า
vrc_config-disable_shoulder_tracking = ปิดใช้งานการจับตำแหน่งไหล
vrc_config-shoulder_width_compensation = การชดเชยความกว้างของไหล่
vrc_config-spine_mode = โหมดกระดูกสันหลัง FBT
vrc_config-tracker_model = โมเดลตัวติดตาม FBT
vrc_config-avatar_measurement_type = การวัดของอวาตาร์
vrc_config-calibration_range = ช่วงการตั้งศูนย์
vrc_config-calibration_visuals = แสดงภาพการตั้งศูนย์
vrc_config-user_height = ความสูงจริงของผู้ใช้
vrc_config-spine_mode-UNKNOWN = ไม่ทราบ
vrc_config-spine_mode-LOCK_BOTH = ล็อคทั้งคู่
vrc_config-spine_mode-LOCK_HEAD = ล็อคศีรษะ
vrc_config-spine_mode-LOCK_HIP = ล็อคสะโพก
vrc_config-tracker_model-UNKNOWN = ไม่ทราบ
vrc_config-tracker_model-AXIS = แกนหมุน
vrc_config-tracker_model-BOX = กล่อง
vrc_config-tracker_model-SPHERE = ทรงกลม
vrc_config-tracker_model-SYSTEM = ระบบ
vrc_config-avatar_measurement_type-UNKNOWN = ไม่ทราบ
vrc_config-avatar_measurement_type-HEIGHT = ความสูง:
vrc_config-avatar_measurement_type-ARM_SPAN = ช่วงแขน
## Error collection consent modal

View File

@@ -602,8 +602,8 @@ settings-general-fk_settings-leg_tweak-floor_clip-description = 地板限制可
settings-general-fk_settings-leg_tweak-toe_snap-description = 脚趾着地可以在没有脚部追踪器的情况下尝试猜测脚部的俯仰。
settings-general-fk_settings-leg_tweak-foot_plant-description = 脚掌着地会在脚与地面接触时保持脚掌与地板平行。
settings-general-fk_settings-leg_fk = 腿部追踪
settings-general-fk_settings-leg_fk-reset_mounting_feet-description = 开启脚部佩戴重置。(佩戴重置时需要踮起脚尖)
settings-general-fk_settings-leg_fk-reset_mounting_feet = 脚部佩戴重置
settings-general-fk_settings-leg_fk-reset_mounting_feet-description-v1 = 在进行普通佩戴重置时强制进行脚部佩戴重置。
settings-general-fk_settings-leg_fk-reset_mounting_feet-v1 = 强制脚部佩戴重置
settings-general-fk_settings-enforce_joint_constraints = 骨骼限制
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints = 强制约束
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints-description = 避免关节旋转超过人体骨骼角度限制

View File

@@ -239,6 +239,8 @@ reset-reset_all_warning_default-v2 =
確定要繼續嗎?
reset-full = 完整重置
reset-mounting = 配戴重置
reset-mounting-feet = 重置腳部配戴
reset-mounting-fingers = 重置手指配戴
reset-yaw = 左右偏擺重置
## Serial detection stuff
@@ -264,6 +266,7 @@ navbar-settings = 詳細設定
bvh-start_recording = 錄製 BVH 檔案
bvh-recording = 錄製中…
bvh-save_title = 儲存 BVH 紀錄
## Tracking pause
@@ -401,6 +404,7 @@ tracker-settings-forget-label = 忘記追蹤器
tracker-settings-update-unavailable = 無法更新 (DIY)
tracker-settings-update-low-battery = 無法更新,電池電量低於 50%
tracker-settings-update-up_to_date = 已為最新版本
tracker-settings-update-blocked = 無法更新,沒有其他可用版本。
tracker-settings-update-available = 版本 { $versionName } 可供更新
tracker-settings-update = 立即更新
tracker-settings-update-title = 韌體版本
@@ -604,8 +608,8 @@ settings-general-fk_settings-leg_tweak-floor_clip-description = 地板限制功
settings-general-fk_settings-leg_tweak-toe_snap-description = 腳趾跟地功能在沒有腳部的追蹤器時,會嘗試猜測腳掌的旋轉角度。
settings-general-fk_settings-leg_tweak-foot_plant-description = 腳底貼地功能會在腳底與地面接觸時,將腳部旋轉成與地板平行。
settings-general-fk_settings-leg_fk = 腿部追蹤
settings-general-fk_settings-leg_fk-reset_mounting_feet-description = 開啟腳部配戴重置,進行配戴重置時需要踮起腳尖
settings-general-fk_settings-leg_fk-reset_mounting_feet = 腳部配戴重置
settings-general-fk_settings-leg_fk-reset_mounting_feet-description-v1 = 使用普通的重置配戴時,一併重置腳部配戴
settings-general-fk_settings-leg_fk-reset_mounting_feet-v1 = 強制重置腳部配戴
settings-general-fk_settings-enforce_joint_constraints = 骨架限制
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints = 約束關節旋轉
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints-description = 避免關節旋轉超出極限
@@ -734,6 +738,9 @@ settings-interface-behavior-error_tracking-description_v2 =
為了提供最佳的使用者體驗,我們會蒐集匿名化的錯誤報告、性能指標和作業系統資訊,這會對我們檢測 SlimeVR 的錯誤和問題有所幫助。我們會透過 Sentry.io 來蒐集這些指標。
settings-interface-behavior-error_tracking-label = 向開發者傳送錯誤資訊
settings-interface-behavior-bvh_directory = BVH 紀錄儲存目錄
settings-interface-behavior-bvh_directory-description = 選擇儲存 BVH 紀錄文件的目錄,如此每次錄製 BVH 時不需要選擇儲存位置。
settings-interface-behavior-bvh_directory-label = 存放 BVH 紀錄的目錄
## Serial settings
@@ -879,8 +886,8 @@ settings-utils-advanced-reset_warning-cancel = 取消
settings-utils-advanced-open_data-v1 = 設定資料夾
settings-utils-advanced-open_data-description-v1 = 在檔案管理器中開啟 SlimeVR 的設定資料夾,該資料夾包含程式的設定。
settings-utils-advanced-open_data-label = 打開資料夾
settings-utils-advanced-open_logs = 錄檔資料夾
settings-utils-advanced-open_logs-description = 在檔案管理器中開啟 SlimeVR 的錄檔資料夾,該資料夾包含程式的錄檔。
settings-utils-advanced-open_logs = 錄檔資料夾
settings-utils-advanced-open_logs-description = 在檔案管理器中開啟 SlimeVR 的錄檔資料夾,該資料夾包含程式的錄檔。
settings-utils-advanced-open_logs-label = 打開資料夾
## Setup/onboarding menu
@@ -1000,7 +1007,7 @@ onboarding-connect_tracker-next = 所有的追蹤器都連接好了
onboarding-calibration_tutorial = IMU 校正教學
onboarding-calibration_tutorial-subtitle = 進行這項操作可以有效減少追蹤器發生飄移的機會
onboarding-calibration_tutorial-description = 每次在打開追蹤器開關時,需要將追蹤器平置一下來進行自動校正。你也可以透過按下「{ onboarding-calibration_tutorial-calibrate }」按鈕來進行手動校正,<b>校正過程中請勿移動追蹤器</b>
onboarding-calibration_tutorial-description-v1 = 開啟追蹤器開關後,將其放置在穩定的平面上一段時間以便進行校正。本頁僅提供操作教學——追蹤器電源開啟後即可隨時進行校正,無須回到本頁進行。首先請點選「{ onboarding-calibration_tutorial-calibrate }」按鈕,然後<b>不要移動追蹤器</b>
onboarding-calibration_tutorial-calibrate = 追蹤器已經放置在桌上了
onboarding-calibration_tutorial-status-waiting = 正在等待你完成動作
onboarding-calibration_tutorial-status-calibrating = 校正中

View File

@@ -61,6 +61,16 @@ import { FirmwareUpdate } from './components/firmware-update/FirmwareUpdate';
import { ConnectionLost } from './components/onboarding/pages/ConnectionLost';
import { VRCWarningsPage } from './components/vrc/VRCWarningsPage';
import { StayAlignedSetup } from './components/onboarding/pages/stay-aligned/StayAlignedSetup';
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
CategoryScale,
LinearScale,
PointElement,
LineElement,
} from 'chart.js';
export const GH_REPO = 'SlimeVR/SlimeVR-Server';
export const VersionContext = createContext('');
@@ -73,6 +83,16 @@ function Layout() {
const { isMobile } = useBreakpoint('mobile');
useDiscordPresence();
ChartJS.register(
Title,
Tooltip,
Legend,
CategoryScale,
LinearScale,
PointElement,
LineElement
);
return (
<>
<SerialDetectionModal></SerialDetectionModal>

View File

@@ -0,0 +1,177 @@
import { useLocalization } from '@fluent/react';
import { useEffect, useState } from 'react';
import { Line } from 'react-chartjs-2';
import { TrackerDataT } from 'solarxr-protocol';
import { Button } from '@/components/commons/Button';
import { useConfig } from '@/hooks/config';
export function TrackerGraph({ tracker }: { tracker: TrackerDataT }) {
const { l10n } = useLocalization();
const { config } = useConfig();
type AxisData = {
x: number;
y: number;
time: number;
};
type ChartData = {
x: AxisData[];
y: AxisData[];
z: AxisData[];
};
const [chartData, setChartData] = useState<ChartData>({
x: [],
y: [],
z: [],
});
const [showTrackerGraph, setShowTrackerGraph] = useState(false);
const secondDuration = 60;
useEffect(() => {
if (!showTrackerGraph) {
return;
}
const newValue = tracker.info?.isImu
? tracker.linearAcceleration
: tracker.position;
if (!newValue) {
return;
}
const currentTime = new Date().getTime() / 1000;
const startTime = currentTime - secondDuration;
const updateData = (data: AxisData[], newSample: number) => {
const remapped = data
.filter((value) => value.time >= startTime)
.map((value) => ({ ...value, x: value.time - startTime }));
remapped.push({
time: currentTime,
x: secondDuration,
y: newSample,
});
return remapped;
};
const newData = {
x: updateData(chartData.x, newValue.x),
y: updateData(chartData.y, newValue.y),
z: updateData(chartData.z, newValue.z),
};
setChartData(newData);
}, [tracker]);
useEffect(() => {
if (!showTrackerGraph) {
setChartData({ x: [], y: [], z: [] });
}
}, [showTrackerGraph]);
return (
<>
<Button
variant="tertiary"
className="self-start"
onClick={() => setShowTrackerGraph(!showTrackerGraph)}
>
{l10n.getString(
showTrackerGraph
? 'tracker-settings-graph-hide-title'
: 'tracker-settings-graph-show-title'
)}
</Button>
{showTrackerGraph && (
<div className="h-96">
<Line
options={{
responsive: true,
animation: false,
font: {
family: config?.fonts.map((font) => `"${font}"`).join(','),
size: config?.textSize,
},
plugins: {
title: {
display: true,
text: l10n.getString(
tracker?.info?.isImu
? 'tracker-settings-graph-acceleration-title'
: 'tracker-settings-graph-position-title'
),
color: 'white',
},
tooltip: {
mode: 'index',
intersect: false,
animation: false,
callbacks: {
title: () => '',
},
},
legend: {
labels: {
color: 'white',
},
},
},
scales: {
x: {
type: 'linear',
min: 0,
max: secondDuration,
ticks: {
color: 'white',
},
},
y: {
min: -4,
max: 4,
ticks: {
color: 'white',
},
},
},
elements: {
point: {
radius: 0,
},
},
parsing: false,
normalized: true,
maintainAspectRatio: false,
}}
data={{
labels: ['X', 'Y', 'Z'],
datasets: [
{
label: 'X',
data: chartData.x,
borderColor: 'rgb(200, 50, 50)',
backgroundColor: 'rgb(200, 100, 100)',
},
{
label: 'Y',
data: chartData.y,
borderColor: 'rgb(50, 200, 50)',
backgroundColor: 'rgb(100, 200, 100)',
},
{
label: 'Z',
data: chartData.z,
borderColor: 'rgb(50, 50, 200)',
backgroundColor: 'rgb(100, 100, 200)',
},
],
}}
id="tracker-graph"
/>
</div>
)}
</>
);
}

View File

@@ -40,6 +40,7 @@ import semver from 'semver';
import { useSetAtom } from 'jotai';
import { ignoredTrackersAtom } from '@/store/app-store';
import { checkForUpdate } from '@/hooks/firmware-update';
import { TrackerGraph } from './TrackerGraph';
const rotationsLabels: [Quaternion, string][] = [
[rotationToQuatMap.BACK, 'tracker-rotation-back'],
@@ -505,6 +506,7 @@ export function TrackerSettingsPage() {
</Button>
</div>
)}
{tracker && <TrackerGraph tracker={tracker.tracker} />}
</div>
</div>
</form>

31
pnpm-lock.yaml generated
View File

@@ -83,6 +83,9 @@ importers:
browser-fs-access:
specifier: ^0.35.0
version: 0.35.0
chart.js:
specifier: ^4.5.0
version: 4.5.0
classnames:
specifier: ^2.5.1
version: 2.5.1
@@ -104,6 +107,9 @@ importers:
react:
specifier: ^18.3.1
version: 18.3.1
react-chartjs-2:
specifier: ^5.3.0
version: 5.3.0(chart.js@4.5.0)(react@18.3.1)
react-dom:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
@@ -720,6 +726,9 @@ packages:
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
'@kurkle/color@0.3.4':
resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==}
'@mediapipe/tasks-vision@0.10.8':
resolution: {integrity: sha512-Rp7ll8BHrKB3wXaRFKhrltwZl1CiXGdibPxuWXvqGnKTnv8fqa/nvftYNuSbf+pbJWKYCXdBtYTITdAUTGGh0Q==}
@@ -1780,6 +1789,10 @@ packages:
character-reference-invalid@2.0.1:
resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==}
chart.js@4.5.0:
resolution: {integrity: sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==}
engines: {pnpm: '>=8'}
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
@@ -2470,6 +2483,7 @@ packages:
got-fetch@5.1.10:
resolution: {integrity: sha512-Gwj/A2htjvLEcY07PKDItv0WCPEs3dV2vWeZ+9TVBSKSTuWEZ4oXaMD0ZAOsajwx2orahQWN4HI0MfRyWSZsbg==}
engines: {node: '>=14.0.0'}
deprecated: please use built-in fetch in nodejs
peerDependencies:
got: ^12.0.0
@@ -3542,6 +3556,12 @@ packages:
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
engines: {node: '>=10'}
react-chartjs-2@5.3.0:
resolution: {integrity: sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==}
peerDependencies:
chart.js: ^4.1.1
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-composer@5.0.3:
resolution: {integrity: sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==}
peerDependencies:
@@ -4959,6 +4979,8 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.4.15
'@kurkle/color@0.3.4': {}
'@mediapipe/tasks-vision@0.10.8': {}
'@mgit-at/typescript-flatbuffers-codegen@0.1.3':
@@ -6072,6 +6094,10 @@ snapshots:
character-reference-invalid@2.0.1: {}
chart.js@4.5.0:
dependencies:
'@kurkle/color': 0.3.4
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
@@ -8159,6 +8185,11 @@ snapshots:
quick-lru@5.1.1: {}
react-chartjs-2@5.3.0(chart.js@4.5.0)(react@18.3.1):
dependencies:
chart.js: 4.5.0
react: 18.3.1
react-composer@5.0.3(react@18.3.1):
dependencies:
prop-types: 15.8.1

View File

@@ -0,0 +1 @@
protoc --proto_path=../SlimeVR-OpenVR-Driver/src/bridge --java_out=./src/main/java ProtobufMessages.proto

View File

@@ -10,8 +10,6 @@ import dev.slimevr.firmware.SerialFlashingHandler
import dev.slimevr.games.vrchat.VRCConfigHandler
import dev.slimevr.games.vrchat.VRCConfigHandlerStub
import dev.slimevr.games.vrchat.VRChatConfigManager
import dev.slimevr.inputs.Input
import dev.slimevr.inputs.TapInputManager
import dev.slimevr.osc.OSCHandler
import dev.slimevr.osc.OSCRouter
import dev.slimevr.osc.VMCHandler
@@ -119,9 +117,6 @@ class VRServer @JvmOverloads constructor(
@JvmField
val handshakeHandler = HandshakeHandler()
val tapInputManager: TapInputManager
val inputs: MutableList<Input> = FastList()
init {
// UwU
configManager = ConfigManager(configPath)
@@ -152,9 +147,7 @@ class VRServer @JvmOverloads constructor(
for (bridge in bridgeProvider(this, computedTrackers) + sequenceOf(WebSocketVRBridge(computedTrackers, this))) {
tasks.add(Runnable { bridge.startBridge() })
bridges.add(bridge)
bridge.addFingerBones(humanPoseManager.shareableFingerBones)
}
tapInputManager = TapInputManager(humanPoseManager.skeleton, this)
// Initialize OSC handlers
vrcOSCHandler = VRCOSCHandler(
@@ -252,23 +245,11 @@ class VRServer @JvmOverloads constructor(
tracker.tick(fpsTimer.timePerFrame)
}
humanPoseManager.update()
// Check for tap inputs
tapInputManager.update()
// Update bridges
for (bridge in bridges) {
// Send inputs to each bridge
for (input in inputs) {
bridge.sendInput(input)
}
bridge.dataWrite()
}
// Don't forget to clear inputs so that we don't send the same ones again
inputs.clear()
vrcOSCHandler.update()
vMCHandler.update()
// final long time = System.currentTimeMillis() - start;
try {
sleep(1) // 1000Hz

View File

@@ -1,7 +1,5 @@
package dev.slimevr.bridge
import dev.slimevr.inputs.Input
import dev.slimevr.tracking.processor.ShareableBone
import dev.slimevr.tracking.trackers.Tracker
import dev.slimevr.tracking.trackers.TrackerRole
import dev.slimevr.util.ann.VRServerThread
@@ -40,24 +38,6 @@ interface Bridge {
@VRServerThread
fun removeSharedTracker(tracker: Tracker?)
/**
* Adds a list of finger bones to the bridge. This should only be set
* once the skeleton has initialized. Bridge will send finger data for
* the hand trackers if it serves them.
*
* @param bones
*/
@VRServerThread
fun addFingerBones(bones: List<ShareableBone>)
/**
* Reports a virtual controller input to the driver.
*
* @param input the object containing the data about the input
*/
@VRServerThread
fun sendInput(input: Input)
@VRServerThread
fun startBridge()

View File

@@ -1,8 +0,0 @@
package dev.slimevr.inputs
class Input(val rightHand: Boolean, val type: InputType)
enum class InputType {
DOUBLE_TAP,
TRIPLE_TAP,
}

View File

@@ -1,98 +0,0 @@
package dev.slimevr.inputs
import dev.slimevr.VRServer
import dev.slimevr.tracking.processor.skeleton.HumanSkeleton
import dev.slimevr.tracking.processor.skeleton.TapDetection
import dev.slimevr.tracking.trackers.Tracker
import dev.slimevr.util.ann.VRServerThread
/**
* Handles tap detection for SteamVR virtual controller input
*/
class TapInputManager(
private val skeleton: HumanSkeleton,
private val vrServer: VRServer,
) {
// tap detectors
private lateinit var leftDoubleDetector: TapDetection
private lateinit var leftTripleDetector: TapDetection
private lateinit var rightDoubleDetector: TapDetection
private lateinit var rightTripleDetector: TapDetection
val NS_CONVERTER: Float = 1.0e9f
private var doubleTapDelay = 0.25f * NS_CONVERTER
init {
reinit()
}
fun reinit() {
// Create tap detectors for both hands
leftDoubleDetector = TapDetection(skeleton, trackerToWatchLeftHand)
leftDoubleDetector.enabled = true
leftDoubleDetector.setMaxTaps(2)
leftTripleDetector = TapDetection(skeleton, trackerToWatchLeftHand)
leftTripleDetector.enabled = true
leftTripleDetector.setMaxTaps(3)
rightDoubleDetector = TapDetection(skeleton, trackerToWatchRightHand)
rightDoubleDetector.enabled = true
rightDoubleDetector.setMaxTaps(2)
rightTripleDetector = TapDetection(skeleton, trackerToWatchRightHand)
rightTripleDetector.enabled = true
rightTripleDetector.setMaxTaps(3)
}
@VRServerThread
fun update() {
// update the tap detectors
leftDoubleDetector.update()
leftTripleDetector.update()
rightDoubleDetector.update()
rightTripleDetector.update()
// check if any tap detectors have detected taps
if (3 <= leftTripleDetector.taps) {
leftTripleDetector.resetDetector()
leftDoubleDetector.resetDetector()
vrServer.inputs.add(Input(false, InputType.TRIPLE_TAP))
} else if (2 <= leftDoubleDetector.taps && System.nanoTime() - rightDoubleDetector.detectionTime > doubleTapDelay) {
leftTripleDetector.resetDetector()
leftDoubleDetector.resetDetector()
vrServer.inputs.add(Input(false, InputType.DOUBLE_TAP))
}
if (3 <= rightTripleDetector.taps) {
rightTripleDetector.resetDetector()
rightDoubleDetector.resetDetector()
vrServer.inputs.add(Input(true, InputType.TRIPLE_TAP))
} else if (2 <= rightDoubleDetector.taps && System.nanoTime() - rightDoubleDetector.detectionTime > doubleTapDelay) {
rightTripleDetector.resetDetector()
rightDoubleDetector.resetDetector()
vrServer.inputs.add(Input(true, InputType.DOUBLE_TAP))
}
}
private val trackerToWatchLeftHand: Tracker?
get() = listOfNotNull(
skeleton.leftHandTracker,
skeleton.leftLowerArmTracker,
skeleton.leftUpperArmTracker,
skeleton.leftThumbDistalTracker,
skeleton.leftThumbProximalTracker,
skeleton.leftThumbMetacarpalTracker,
).firstOrNull()
private val trackerToWatchRightHand: Tracker?
get() = listOfNotNull(
skeleton.rightHandTracker,
skeleton.rightLowerArmTracker,
skeleton.rightUpperArmTracker,
skeleton.rightThumbDistalTracker,
skeleton.rightThumbProximalTracker,
skeleton.rightThumbMetacarpalTracker,
).firstOrNull()
}

View File

@@ -61,8 +61,8 @@ public class RPCSettingsBuilder {
&& config.getOSCTrackerRole(TrackerRole.RIGHT_FOOT, false),
config.getOSCTrackerRole(TrackerRole.LEFT_ELBOW, false)
&& config.getOSCTrackerRole(TrackerRole.RIGHT_ELBOW, false),
config.getOSCTrackerRole(TrackerRole.LEFT_CONTROLLER, false)
&& config.getOSCTrackerRole(TrackerRole.RIGHT_CONTROLLER, false)
config.getOSCTrackerRole(TrackerRole.LEFT_HAND, false)
&& config.getOSCTrackerRole(TrackerRole.RIGHT_HAND, false)
);
VRCOSCSettings.startVRCOSCSettings(fbb);
VRCOSCSettings.addOscSettings(fbb, generalSettingOffset);
@@ -164,8 +164,8 @@ public class RPCSettingsBuilder {
bridge.getShareSetting(TrackerRole.RIGHT_KNEE),
bridge.getShareSetting(TrackerRole.LEFT_ELBOW),
bridge.getShareSetting(TrackerRole.RIGHT_ELBOW),
bridge.getShareSetting(TrackerRole.LEFT_CONTROLLER),
bridge.getShareSetting(TrackerRole.RIGHT_CONTROLLER)
bridge.getShareSetting(TrackerRole.LEFT_HAND),
bridge.getShareSetting(TrackerRole.RIGHT_HAND)
);
}
return steamvrTrackerSettings;

View File

@@ -59,8 +59,8 @@ class RPCSettingsHandler(var rpcHandler: RPCHandler, var api: ProtocolAPI) {
bridge.changeShareSettings(TrackerRole.RIGHT_KNEE, req.steamVrTrackers().rightKnee())
bridge.changeShareSettings(TrackerRole.LEFT_ELBOW, req.steamVrTrackers().leftElbow())
bridge.changeShareSettings(TrackerRole.RIGHT_ELBOW, req.steamVrTrackers().rightElbow())
bridge.changeShareSettings(TrackerRole.LEFT_CONTROLLER, req.steamVrTrackers().leftHand())
bridge.changeShareSettings(TrackerRole.RIGHT_CONTROLLER, req.steamVrTrackers().rightHand())
bridge.changeShareSettings(TrackerRole.LEFT_HAND, req.steamVrTrackers().leftHand())
bridge.changeShareSettings(TrackerRole.RIGHT_HAND, req.steamVrTrackers().rightHand())
bridge.setAutomaticSharedTrackers(req.steamVrTrackers().automaticTrackerToggle())
}
}
@@ -128,8 +128,8 @@ class RPCSettingsHandler(var rpcHandler: RPCHandler, var api: ProtocolAPI) {
vrcOSCConfig.setOSCTrackerRole(TrackerRole.RIGHT_FOOT, trackers.feet())
vrcOSCConfig.setOSCTrackerRole(TrackerRole.LEFT_ELBOW, trackers.elbows())
vrcOSCConfig.setOSCTrackerRole(TrackerRole.RIGHT_ELBOW, trackers.elbows())
vrcOSCConfig.setOSCTrackerRole(TrackerRole.LEFT_CONTROLLER, trackers.hands())
vrcOSCConfig.setOSCTrackerRole(TrackerRole.RIGHT_CONTROLLER, trackers.hands())
vrcOSCConfig.setOSCTrackerRole(TrackerRole.LEFT_HAND, trackers.hands())
vrcOSCConfig.setOSCTrackerRole(TrackerRole.RIGHT_HAND, trackers.hands())
}
vrcOSCConfig.oscqueryEnabled = req.vrcOsc().oscqueryEnabled()

View File

@@ -1,58 +1,14 @@
@file:Suppress("ktlint:standard:no-wildcard-imports")
package dev.slimevr.tracking.processor;
package dev.slimevr.tracking.processor
import solarxr_protocol.datatypes.BodyPart;
import dev.slimevr.tracking.processor.BoneType.*
import solarxr_protocol.datatypes.BodyPart
fun BoneType?.isLeftFinger(): Boolean {
this?.let {
return it == LEFT_THUMB_METACARPAL ||
it == LEFT_THUMB_PROXIMAL ||
it == LEFT_THUMB_DISTAL ||
it == LEFT_INDEX_PROXIMAL ||
it == LEFT_INDEX_INTERMEDIATE ||
it == LEFT_INDEX_DISTAL ||
it == LEFT_MIDDLE_PROXIMAL ||
it == LEFT_MIDDLE_INTERMEDIATE ||
it == LEFT_MIDDLE_DISTAL ||
it == LEFT_RING_PROXIMAL ||
it == LEFT_RING_INTERMEDIATE ||
it == LEFT_RING_DISTAL ||
it == LEFT_LITTLE_PROXIMAL ||
it == LEFT_LITTLE_INTERMEDIATE ||
it == LEFT_LITTLE_DISTAL
}
return false
}
fun BoneType?.isRightFinger(): Boolean {
this?.let {
return it == RIGHT_THUMB_METACARPAL ||
it == RIGHT_THUMB_PROXIMAL ||
it == RIGHT_THUMB_DISTAL ||
it == RIGHT_INDEX_PROXIMAL ||
it == RIGHT_INDEX_INTERMEDIATE ||
it == RIGHT_INDEX_DISTAL ||
it == RIGHT_MIDDLE_PROXIMAL ||
it == RIGHT_MIDDLE_INTERMEDIATE ||
it == RIGHT_MIDDLE_DISTAL ||
it == RIGHT_RING_PROXIMAL ||
it == RIGHT_RING_INTERMEDIATE ||
it == RIGHT_RING_DISTAL ||
it == RIGHT_LITTLE_PROXIMAL ||
it == RIGHT_LITTLE_INTERMEDIATE ||
it == RIGHT_LITTLE_DISTAL
}
return false
}
/**
* Keys for all the bones in the skeleton.
*/
enum class BoneType {
public enum BoneType {
HEAD(BodyPart.HEAD),
HEAD_TRACKER,
HEAD_TRACKER(),
NECK(BodyPart.NECK),
UPPER_CHEST(BodyPart.UPPER_CHEST),
CHEST_TRACKER,
@@ -115,21 +71,17 @@ enum class BoneType {
RIGHT_RING_DISTAL(BodyPart.RIGHT_RING_DISTAL),
RIGHT_LITTLE_PROXIMAL(BodyPart.RIGHT_LITTLE_PROXIMAL),
RIGHT_LITTLE_INTERMEDIATE(BodyPart.RIGHT_LITTLE_INTERMEDIATE),
RIGHT_LITTLE_DISTAL(BodyPart.RIGHT_LITTLE_DISTAL),
;
RIGHT_LITTLE_DISTAL(BodyPart.RIGHT_LITTLE_DISTAL);
@JvmField
val bodyPart: Int
public static final BoneType[] values = values();
constructor() {
this.bodyPart = BodyPart.NONE
public final int bodyPart;
BoneType() {
this.bodyPart = BodyPart.NONE;
}
constructor(associatedBodyPart: Int) {
this.bodyPart = associatedBodyPart
}
companion object {
val values: Array<BoneType> = entries.toTypedArray()
BoneType(int associatedBodyPart) {
this.bodyPart = associatedBodyPart;
}
}

View File

@@ -34,7 +34,6 @@ import kotlin.math.*
*/
class HumanPoseManager(val server: VRServer?) {
val computedTrackers: MutableList<Tracker> = FastList()
val shareableFingerBones: MutableList<ShareableBone> = FastList()
private val onSkeletonUpdated: MutableList<Consumer<HumanSkeleton>> = FastList()
private val skeletonConfigManager = SkeletonConfigManager(true, this)
@@ -46,7 +45,6 @@ class HumanPoseManager(val server: VRServer?) {
// #region Constructors
init {
initializeComputedHumanPoseTracker()
initializeShareableFingerBones()
}
init {
@@ -232,39 +230,6 @@ class HumanPoseManager(val server: VRServer?) {
connectComputedHumanPoseTrackers()
}
private fun initializeShareableFingerBones() {
shareableFingerBones.add(ShareableBone(BoneType.LEFT_THUMB_METACARPAL))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_THUMB_PROXIMAL))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_THUMB_DISTAL))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_INDEX_PROXIMAL))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_INDEX_INTERMEDIATE))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_INDEX_DISTAL))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_MIDDLE_PROXIMAL))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_MIDDLE_INTERMEDIATE))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_MIDDLE_DISTAL))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_RING_PROXIMAL))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_RING_INTERMEDIATE))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_RING_DISTAL))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_LITTLE_PROXIMAL))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_LITTLE_INTERMEDIATE))
shareableFingerBones.add(ShareableBone(BoneType.LEFT_LITTLE_DISTAL))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_THUMB_METACARPAL))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_THUMB_PROXIMAL))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_THUMB_DISTAL))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_INDEX_PROXIMAL))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_INDEX_INTERMEDIATE))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_INDEX_DISTAL))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_MIDDLE_PROXIMAL))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_MIDDLE_INTERMEDIATE))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_MIDDLE_DISTAL))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_RING_PROXIMAL))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_RING_INTERMEDIATE))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_RING_DISTAL))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_LITTLE_PROXIMAL))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_LITTLE_INTERMEDIATE))
shareableFingerBones.add(ShareableBone(BoneType.RIGHT_LITTLE_DISTAL))
}
fun loadFromConfig(configManager: ConfigManager) {
skeletonConfigManager.loadFromConfig(configManager)
}

View File

@@ -1,11 +0,0 @@
package dev.slimevr.tracking.processor
import io.github.axisangles.ktmath.Quaternion
class ShareableBone(val boneType: BoneType) {
/**
* Returns the rotation of the bone relative to its parent
*/
var localRotation: Quaternion = Quaternion.IDENTITY
}

View File

@@ -7,7 +7,6 @@ import dev.slimevr.tracking.processor.BoneType
import dev.slimevr.tracking.processor.Constraint
import dev.slimevr.tracking.processor.Constraint.Companion.ConstraintType
import dev.slimevr.tracking.processor.HumanPoseManager
import dev.slimevr.tracking.processor.ShareableBone
import dev.slimevr.tracking.processor.config.SkeletonConfigToggles
import dev.slimevr.tracking.processor.config.SkeletonConfigValues
import dev.slimevr.tracking.processor.stayaligned.StayAligned
@@ -191,38 +190,6 @@ class HumanSkeleton(
var computedLeftHandTracker: Tracker? = null
var computedRightHandTracker: Tracker? = null
// Output bones
var shareableLeftThumbMetacarpalBone: ShareableBone? = null
var shareableLeftThumbProximalBone: ShareableBone? = null
var shareableLeftThumbDistalBone: ShareableBone? = null
var shareableLeftIndexProximalBone: ShareableBone? = null
var shareableLeftIndexIntermediateBone: ShareableBone? = null
var shareableLeftIndexDistalBone: ShareableBone? = null
var shareableLeftMiddleProximalBone: ShareableBone? = null
var shareableLeftMiddleIntermediateBone: ShareableBone? = null
var shareableLeftMiddleDistalBone: ShareableBone? = null
var shareableLeftRingProximalBone: ShareableBone? = null
var shareableLeftRingIntermediateBone: ShareableBone? = null
var shareableLeftRingDistalBone: ShareableBone? = null
var shareableLeftLittleProximalBone: ShareableBone? = null
var shareableLeftLittleIntermediateBone: ShareableBone? = null
var shareableLeftLittleDistalBone: ShareableBone? = null
var shareableRightThumbMetacarpalBone: ShareableBone? = null
var shareableRightThumbProximalBone: ShareableBone? = null
var shareableRightThumbDistalBone: ShareableBone? = null
var shareableRightIndexProximalBone: ShareableBone? = null
var shareableRightIndexIntermediateBone: ShareableBone? = null
var shareableRightIndexDistalBone: ShareableBone? = null
var shareableRightMiddleProximalBone: ShareableBone? = null
var shareableRightMiddleIntermediateBone: ShareableBone? = null
var shareableRightMiddleDistalBone: ShareableBone? = null
var shareableRightRingProximalBone: ShareableBone? = null
var shareableRightRingIntermediateBone: ShareableBone? = null
var shareableRightRingDistalBone: ShareableBone? = null
var shareableRightLittleProximalBone: ShareableBone? = null
var shareableRightLittleIntermediateBone: ShareableBone? = null
var shareableRightLittleDistalBone: ShareableBone? = null
// Toggles
private var extendedSpineModel = false
private var extendedPelvisModel = false
@@ -256,7 +223,6 @@ class HumanSkeleton(
init {
assembleSkeleton()
setComputedTrackers(humanPoseManager.computedTrackers)
setShareableBones(humanPoseManager.shareableFingerBones)
}
constructor(
@@ -489,7 +455,6 @@ class HumanSkeleton(
// Update tap detection's trackers
tapDetectionManager.updateConfig(trackers)
humanPoseManager.server?.tapInputManager?.reinit()
// Update bones tracker field
refreshBoneTracker()
@@ -527,54 +492,6 @@ class HumanSkeleton(
}
}
/**
* Set shareable bones from list
*/
private fun setShareableBones(bones: List<ShareableBone>) {
for (b in bones) {
setShareableBone(b)
}
}
/**
* Set shareable bone
*/
private fun setShareableBone(bone: ShareableBone) {
when (bone.boneType) {
BoneType.LEFT_THUMB_METACARPAL -> shareableLeftThumbMetacarpalBone = bone
BoneType.LEFT_THUMB_PROXIMAL -> shareableLeftThumbProximalBone = bone
BoneType.LEFT_THUMB_DISTAL -> shareableLeftThumbDistalBone = bone
BoneType.LEFT_INDEX_PROXIMAL -> shareableLeftIndexProximalBone = bone
BoneType.LEFT_INDEX_INTERMEDIATE -> shareableLeftIndexIntermediateBone = bone
BoneType.LEFT_INDEX_DISTAL -> shareableLeftIndexDistalBone = bone
BoneType.LEFT_MIDDLE_PROXIMAL -> shareableLeftMiddleProximalBone = bone
BoneType.LEFT_MIDDLE_INTERMEDIATE -> shareableLeftMiddleIntermediateBone = bone
BoneType.LEFT_MIDDLE_DISTAL -> shareableLeftMiddleDistalBone = bone
BoneType.LEFT_RING_PROXIMAL -> shareableLeftRingProximalBone = bone
BoneType.LEFT_RING_INTERMEDIATE -> shareableLeftRingIntermediateBone = bone
BoneType.LEFT_RING_DISTAL -> shareableLeftRingDistalBone = bone
BoneType.LEFT_LITTLE_PROXIMAL -> shareableLeftLittleProximalBone = bone
BoneType.LEFT_LITTLE_INTERMEDIATE -> shareableLeftLittleIntermediateBone = bone
BoneType.LEFT_LITTLE_DISTAL -> shareableLeftLittleDistalBone = bone
BoneType.RIGHT_THUMB_METACARPAL -> shareableRightThumbMetacarpalBone = bone
BoneType.RIGHT_THUMB_PROXIMAL -> shareableRightThumbProximalBone = bone
BoneType.RIGHT_THUMB_DISTAL -> shareableRightThumbDistalBone = bone
BoneType.RIGHT_INDEX_PROXIMAL -> shareableRightIndexProximalBone = bone
BoneType.RIGHT_INDEX_INTERMEDIATE -> shareableRightIndexIntermediateBone = bone
BoneType.RIGHT_INDEX_DISTAL -> shareableRightIndexDistalBone = bone
BoneType.RIGHT_MIDDLE_PROXIMAL -> shareableRightMiddleProximalBone = bone
BoneType.RIGHT_MIDDLE_INTERMEDIATE -> shareableRightMiddleIntermediateBone = bone
BoneType.RIGHT_MIDDLE_DISTAL -> shareableRightMiddleDistalBone = bone
BoneType.RIGHT_RING_PROXIMAL -> shareableRightRingProximalBone = bone
BoneType.RIGHT_RING_INTERMEDIATE -> shareableRightRingIntermediateBone = bone
BoneType.RIGHT_RING_DISTAL -> shareableRightRingDistalBone = bone
BoneType.RIGHT_LITTLE_PROXIMAL -> shareableRightLittleProximalBone = bone
BoneType.RIGHT_LITTLE_INTERMEDIATE -> shareableRightLittleIntermediateBone = bone
BoneType.RIGHT_LITTLE_DISTAL -> shareableRightLittleDistalBone = bone
else -> {}
}
}
/**
* Get output tracker from TrackerRole
*/
@@ -588,8 +505,8 @@ class HumanSkeleton(
TrackerRole.RIGHT_FOOT -> computedRightFootTracker!!
TrackerRole.LEFT_ELBOW -> computedLeftElbowTracker!!
TrackerRole.RIGHT_ELBOW -> computedRightElbowTracker!!
TrackerRole.LEFT_CONTROLLER -> computedLeftHandTracker!!
TrackerRole.RIGHT_CONTROLLER -> computedRightHandTracker!!
TrackerRole.LEFT_HAND -> computedLeftHandTracker!!
TrackerRole.RIGHT_HAND -> computedRightHandTracker!!
else -> throw IllegalArgumentException("Unsupported computed tracker's TrackerRole in HumanSkeleton")
}
@@ -610,7 +527,6 @@ class HumanSkeleton(
headBone.updateWithConstraints(false)
}
updateComputedTrackers()
updateShareableBones()
// Don't run post-processing if the tracking is paused
if (pauseTracking) return
@@ -1232,45 +1148,6 @@ class HumanSkeleton(
}
}
private fun updateShareableBones() {
this.updateShareableBone(shareableLeftThumbMetacarpalBone, leftThumbMetacarpalBone)
this.updateShareableBone(shareableLeftThumbProximalBone, leftThumbProximalBone)
this.updateShareableBone(shareableLeftThumbDistalBone, leftThumbDistalBone)
this.updateShareableBone(shareableLeftIndexProximalBone, leftIndexProximalBone)
this.updateShareableBone(shareableLeftIndexIntermediateBone, leftIndexIntermediateBone)
this.updateShareableBone(shareableLeftIndexDistalBone, leftIndexDistalBone)
this.updateShareableBone(shareableLeftMiddleProximalBone, leftMiddleProximalBone)
this.updateShareableBone(shareableLeftMiddleIntermediateBone, leftMiddleIntermediateBone)
this.updateShareableBone(shareableLeftMiddleDistalBone, leftMiddleDistalBone)
this.updateShareableBone(shareableLeftRingProximalBone, leftRingProximalBone)
this.updateShareableBone(shareableLeftRingIntermediateBone, leftRingIntermediateBone)
this.updateShareableBone(shareableLeftRingDistalBone, leftRingDistalBone)
this.updateShareableBone(shareableLeftLittleProximalBone, leftLittleProximalBone)
this.updateShareableBone(shareableLeftLittleIntermediateBone, leftLittleIntermediateBone)
this.updateShareableBone(shareableLeftLittleDistalBone, leftLittleDistalBone)
this.updateShareableBone(shareableRightThumbMetacarpalBone, rightThumbMetacarpalBone)
this.updateShareableBone(shareableRightThumbProximalBone, rightThumbProximalBone)
this.updateShareableBone(shareableRightThumbDistalBone, rightThumbDistalBone)
this.updateShareableBone(shareableRightIndexProximalBone, rightIndexProximalBone)
this.updateShareableBone(shareableRightIndexIntermediateBone, rightIndexIntermediateBone)
this.updateShareableBone(shareableRightIndexDistalBone, rightIndexDistalBone)
this.updateShareableBone(shareableRightMiddleProximalBone, rightMiddleProximalBone)
this.updateShareableBone(shareableRightMiddleIntermediateBone, rightMiddleIntermediateBone)
this.updateShareableBone(shareableRightMiddleDistalBone, rightMiddleDistalBone)
this.updateShareableBone(shareableRightRingProximalBone, rightRingProximalBone)
this.updateShareableBone(shareableRightRingIntermediateBone, rightRingIntermediateBone)
this.updateShareableBone(shareableRightRingDistalBone, rightRingDistalBone)
this.updateShareableBone(shareableRightLittleProximalBone, rightLittleProximalBone)
this.updateShareableBone(shareableRightLittleIntermediateBone, rightLittleIntermediateBone)
this.updateShareableBone(shareableRightLittleDistalBone, rightLittleDistalBone)
}
private fun updateShareableBone(shareableBone: ShareableBone?, bone: Bone) {
shareableBone?.let {
it.localRotation = bone.getLocalRotation()
}
}
// Skeleton Config toggles
fun updateToggleState(configToggle: SkeletonConfigToggles, newValue: Boolean) {
when (configToggle) {

View File

@@ -130,8 +130,8 @@ enum class TrackerPosition(
RIGHT_LOWER_ARM("body:right_lower_arm", null, BodyPart.RIGHT_LOWER_ARM, 14),
LEFT_UPPER_ARM("body:left_upper_arm", TrackerRole.LEFT_ELBOW, BodyPart.LEFT_UPPER_ARM, 15),
RIGHT_UPPER_ARM("body:right_upper_arm", TrackerRole.RIGHT_ELBOW, BodyPart.RIGHT_UPPER_ARM, 16),
LEFT_HAND("body:left_hand", TrackerRole.LEFT_CONTROLLER, BodyPart.LEFT_HAND, 17),
RIGHT_HAND("body:right_hand", TrackerRole.RIGHT_CONTROLLER, BodyPart.RIGHT_HAND, 18),
LEFT_HAND("body:left_hand", TrackerRole.LEFT_HAND, BodyPart.LEFT_HAND, 17),
RIGHT_HAND("body:right_hand", TrackerRole.RIGHT_HAND, BodyPart.RIGHT_HAND, 18),
LEFT_SHOULDER("body:left_shoulder", TrackerRole.LEFT_SHOULDER, BodyPart.LEFT_SHOULDER, 19),
RIGHT_SHOULDER("body:right_shoulder", TrackerRole.RIGHT_SHOULDER, BodyPart.RIGHT_SHOULDER, 20),
LEFT_THUMB_METACARPAL("body:left_thumb_metacarpal", null, BodyPart.LEFT_THUMB_METACARPAL, 21),
@@ -216,10 +216,12 @@ enum class TrackerPosition(
@JvmStatic
fun getByTrackerRole(role: TrackerRole): TrackerPosition? {
// Hands TrackerPositions are bound to the controllers TrackerRoles so we hardcode that case.
if (role == TrackerRole.LEFT_HAND) {
// Hands TrackerPositions are bound to the hands TrackerRoles,
// so we hardcode getting those.
if (role == TrackerRole.LEFT_CONTROLLER) {
return LEFT_HAND
} else if (role == TrackerRole.RIGHT_HAND) {
}
if (role == TrackerRole.RIGHT_CONTROLLER) {
return RIGHT_HAND
}
return byTrackerRole[role]

View File

@@ -6,8 +6,6 @@ import dev.slimevr.VRServer
import dev.slimevr.VRServer.Companion.getNextLocalTrackerId
import dev.slimevr.VRServer.Companion.instance
import dev.slimevr.bridge.Bridge
import dev.slimevr.inputs.Input
import dev.slimevr.tracking.processor.ShareableBone
import dev.slimevr.tracking.trackers.Tracker
import dev.slimevr.tracking.trackers.TrackerPosition
import dev.slimevr.tracking.trackers.TrackerStatus
@@ -229,14 +227,6 @@ class WebSocketVRBridge(
// TODO Auto-generated method stub
}
override fun addFingerBones(bones: List<ShareableBone>) {
// TODO Auto-generated method stub
}
override fun sendInput(input: Input) {
// TODO Auto-generated method stub
}
override fun startBridge() {
start()
}

View File

@@ -60,7 +60,7 @@ dependencies {
implementation("commons-cli:commons-cli:1.8.0")
implementation("org.apache.commons:commons-lang3:3.15.0")
implementation("com.google.protobuf:protobuf-java:4.31.1")
implementation("com.google.protobuf:protobuf-java:3.21.12")
implementation("net.java.dev.jna:jna:5.+")
implementation("net.java.dev.jna:jna-platform:5.+")
implementation("com.fazecast:jSerialComm:2.11.2")

View File

@@ -1 +0,0 @@
protoc --proto_path=../../../SlimeVR-OpenVR-Driver/src/bridge --java_out=./src/main/java ProtobufMessages.proto

View File

@@ -4,34 +4,24 @@ import dev.slimevr.VRServer.Companion.instance
import dev.slimevr.bridge.BridgeThread
import dev.slimevr.bridge.ISteamVRBridge
import dev.slimevr.desktop.platform.ProtobufMessages.*
import dev.slimevr.inputs.InputType
import dev.slimevr.tracking.processor.BoneType
import dev.slimevr.tracking.processor.ShareableBone
import dev.slimevr.tracking.processor.isLeftFinger
import dev.slimevr.tracking.processor.isRightFinger
import dev.slimevr.tracking.trackers.Tracker
import dev.slimevr.tracking.trackers.TrackerPosition
import dev.slimevr.tracking.trackers.TrackerStatus
import dev.slimevr.tracking.trackers.TrackerStatus.Companion.getById
import dev.slimevr.util.ann.VRServerThread
import io.eiren.util.ann.Synchronize
import io.eiren.util.ann.ThreadSafe
import io.eiren.util.collections.FastList
import io.eiren.util.logging.LogManager
import io.github.axisangles.ktmath.Quaternion
import io.github.axisangles.ktmath.Vector3
import java.util.*
import java.util.Queue
import java.util.concurrent.LinkedBlockingQueue
import kotlin.collections.HashMap
abstract class ProtobufBridge(@JvmField protected val bridgeName: String) : ISteamVRBridge {
@JvmField
@VRServerThread
protected val sharedTrackers: MutableList<Tracker> = FastList()
@JvmField
@VRServerThread
protected val fingerBones: MutableList<ShareableBone> = FastList()
@ThreadSafe
private val inputQueue: Queue<ProtobufMessage> = LinkedBlockingQueue()
@@ -45,10 +35,6 @@ abstract class ProtobufBridge(@JvmField protected val bridgeName: String) : ISte
private val remoteTrackersByTrackerId: MutableMap<Int, Tracker> = HashMap()
private var hadNewData = false
private var remoteProtocolVersion: Int = 0
private val inputs: MutableList<dev.slimevr.inputs.Input> = FastList()
/**
* Wakes the bridge thread, implementation is platform-specific.
*/
@@ -113,19 +99,15 @@ abstract class ProtobufBridge(@JvmField protected val bridgeName: String) : ISte
@VRServerThread
protected fun writeTrackerUpdate(localTracker: Tracker?) {
val builder = Position.newBuilder().setTrackerId(
val builder = ProtobufMessages.Position.newBuilder().setTrackerId(
localTracker!!.id,
)
// localTracker position
if (localTracker.hasPosition) {
val pos = localTracker.position
builder.setX(pos.x)
builder.setY(pos.y)
builder.setZ(pos.z)
}
// localTracker rotation
if (localTracker.hasRotation) {
val rot = localTracker.getRotation()
builder.setQx(rot.x)
@@ -133,66 +115,9 @@ abstract class ProtobufBridge(@JvmField protected val bridgeName: String) : ISte
builder.setQz(rot.z)
builder.setQw(rot.w)
}
// localTracker's associated fingers' rotations
if (remoteProtocolVersion >= 1) {
val trackerIsLeftHand = localTracker.trackerPosition == TrackerPosition.LEFT_HAND
val trackerIsRightHand = localTracker.trackerPosition == TrackerPosition.RIGHT_HAND
if (trackerIsLeftHand || trackerIsRightHand) {
for (fingerBone in fingerBones) {
// Only send finger data if the finger bone matches the hand tracker side
if ((trackerIsLeftHand && fingerBone.boneType.isLeftFinger()) ||
(trackerIsRightHand && fingerBone.boneType.isRightFinger())
) {
val fingerBuilder = FingerBoneRotation.newBuilder()
.setName(boneTypeToFingerBoneName(fingerBone.boneType))
.setX(fingerBone.localRotation.x)
.setY(fingerBone.localRotation.y)
.setZ(fingerBone.localRotation.z)
.setW(fingerBone.localRotation.w)
builder.addFingerBoneRotations(fingerBuilder.build())
}
}
}
}
// Double and triple tap inputs
if (remoteProtocolVersion >= 1) {
val trackerIsLeftHand = localTracker.trackerPosition == TrackerPosition.LEFT_HAND
val trackerIsRightHand = localTracker.trackerPosition == TrackerPosition.RIGHT_HAND
if (trackerIsLeftHand || trackerIsRightHand) {
val iterator = inputs.iterator()
while (iterator.hasNext()) {
val input = iterator.next()
if ((input.rightHand && trackerIsRightHand) || (!input.rightHand && trackerIsLeftHand)) {
val inputBuilder = Input.newBuilder()
if (input.type == InputType.DOUBLE_TAP) {
inputBuilder.setType(Input.InputType.DOUBLE_TAP)
} else if (input.type == InputType.TRIPLE_TAP) {
inputBuilder.setType(Input.InputType.TRIPLE_TAP)
} else {
LogManager.debug("[ProtobufBridge] Unsupported Input, skipping: " + input.type)
iterator.remove()
continue
}
builder.addInput(inputBuilder.build())
iterator.remove()
}
}
}
}
sendMessage(ProtobufMessage.newBuilder().setPosition(builder).build())
}
@VRServerThread
override fun sendInput(input: dev.slimevr.inputs.Input) {
inputs.add(input)
}
@VRServerThread
protected open fun writeBatteryUpdate(localTracker: Tracker) {
return
@@ -212,8 +137,6 @@ abstract class ProtobufBridge(@JvmField protected val bridgeName: String) : ISte
trackerAddedReceived(message.trackerAdded)
} else if (message.hasBattery()) {
batteryReceived(message.battery)
} else if (message.hasVersion()) {
versionReceived(message.version)
}
}
@@ -249,15 +172,6 @@ abstract class ProtobufBridge(@JvmField protected val bridgeName: String) : ISte
return
}
@VRServerThread
protected open fun versionReceived(versionMessage: Version) {
remoteProtocolVersion = versionMessage.protocolVersion
LogManager.info("[ProtobufBridge] Received driver protocol version: $remoteProtocolVersion")
if (remoteProtocolVersion != PROTOCOL_VERSION) {
LogManager.warning("[ProtobufBridge] Driver protocol version ($remoteProtocolVersion) doesn't match server protocol version ($PROTOCOL_VERSION)")
}
}
@VRServerThread
protected abstract fun createNewTracker(trackerAdded: TrackerAdded): Tracker
@@ -358,50 +272,7 @@ abstract class ProtobufBridge(@JvmField protected val bridgeName: String) : ISte
sendMessage(ProtobufMessage.newBuilder().setTrackerStatus(statusBuilder).build())
}
@VRServerThread
override fun addFingerBones(bones: List<ShareableBone>) {
fingerBones.addAll(bones)
}
private fun boneTypeToFingerBoneName(boneType: BoneType): FingerBoneRotation.FingerBoneName = when (boneType) {
BoneType.LEFT_THUMB_METACARPAL, BoneType.RIGHT_THUMB_METACARPAL -> FingerBoneRotation.FingerBoneName.THUMB_METACARPAL
BoneType.LEFT_THUMB_PROXIMAL, BoneType.RIGHT_THUMB_PROXIMAL -> FingerBoneRotation.FingerBoneName.THUMB_PROXIMAL
BoneType.LEFT_THUMB_DISTAL, BoneType.RIGHT_THUMB_DISTAL -> FingerBoneRotation.FingerBoneName.THUMB_DISTAL
BoneType.LEFT_INDEX_PROXIMAL, BoneType.RIGHT_INDEX_PROXIMAL -> FingerBoneRotation.FingerBoneName.INDEX_PROXIMAL
BoneType.LEFT_INDEX_INTERMEDIATE, BoneType.RIGHT_INDEX_INTERMEDIATE -> FingerBoneRotation.FingerBoneName.INDEX_INTERMEDIATE
BoneType.LEFT_INDEX_DISTAL, BoneType.RIGHT_INDEX_DISTAL -> FingerBoneRotation.FingerBoneName.INDEX_DISTAL
BoneType.LEFT_MIDDLE_PROXIMAL, BoneType.RIGHT_MIDDLE_PROXIMAL -> FingerBoneRotation.FingerBoneName.MIDDLE_PROXIMAL
BoneType.LEFT_MIDDLE_INTERMEDIATE, BoneType.RIGHT_MIDDLE_INTERMEDIATE -> FingerBoneRotation.FingerBoneName.MIDDLE_INTERMEDIATE
BoneType.LEFT_MIDDLE_DISTAL, BoneType.RIGHT_MIDDLE_DISTAL -> FingerBoneRotation.FingerBoneName.MIDDLE_DISTAL
BoneType.LEFT_RING_PROXIMAL, BoneType.RIGHT_RING_PROXIMAL -> FingerBoneRotation.FingerBoneName.RING_PROXIMAL
BoneType.LEFT_RING_INTERMEDIATE, BoneType.RIGHT_RING_INTERMEDIATE -> FingerBoneRotation.FingerBoneName.RING_INTERMEDIATE
BoneType.LEFT_RING_DISTAL, BoneType.RIGHT_RING_DISTAL -> FingerBoneRotation.FingerBoneName.RING_DISTAL
BoneType.LEFT_LITTLE_PROXIMAL, BoneType.RIGHT_LITTLE_PROXIMAL -> FingerBoneRotation.FingerBoneName.LITTLE_PROXIMAL
BoneType.LEFT_LITTLE_INTERMEDIATE, BoneType.RIGHT_LITTLE_INTERMEDIATE -> FingerBoneRotation.FingerBoneName.LITTLE_INTERMEDIATE
BoneType.LEFT_LITTLE_DISTAL, BoneType.RIGHT_LITTLE_DISTAL -> FingerBoneRotation.FingerBoneName.LITTLE_DISTAL
else -> {
LogManager.severe("[ProtobufBridge] Tried to get FingerBoneName from invalid BoneType " + boneType.name)
FingerBoneRotation.FingerBoneName.UNRECOGNIZED
}
}
companion object {
private const val resetSourceNamePrefix = "ProtobufBridge"
private const val PROTOCOL_VERSION = 1
}
}

View File

@@ -1,15 +1,12 @@
package dev.slimevr.desktop.platform.linux;
import dev.slimevr.bridge.BridgeThread;
import dev.slimevr.inputs.Input;
import dev.slimevr.protocol.GenericConnection;
import dev.slimevr.protocol.ProtocolAPI;
import dev.slimevr.tracking.processor.ShareableBone;
import dev.slimevr.tracking.trackers.Tracker;
import dev.slimevr.util.ann.VRServerThread;
import dev.slimevr.VRServer;
import io.eiren.util.logging.LogManager;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
@@ -77,10 +74,6 @@ public class UnixSocketRpcBridge implements dev.slimevr.bridge.Bridge,
public void removeSharedTracker(Tracker tracker) {
}
@Override
public void addFingerBones(@NotNull List<ShareableBone> bones) {
}
@Override
@VRServerThread
public void startBridge() {
@@ -143,9 +136,4 @@ public class UnixSocketRpcBridge implements dev.slimevr.bridge.Bridge,
.map(key -> (GenericConnection) key.attachment())
.filter(conn -> conn != null);
}
@Override
public void sendInput(@NotNull Input input) {
}
}