diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..673e162aa --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +* text=auto + +*.png binary +*.webp binary +*.gif binary diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6f3095381..1c112d9f5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,38 +1,38 @@ -# Global code owner -* @Eirenliel - -# Make everyone be able to approve SolarXR submodule changes -/solarxr-protocol @ButterscotchV @Erimelowo @ImUrX @loucass003 - -# Make Loucas and Uriel the owners of all GUI stuff -/gui/ @ImUrX @loucass003 -/pnpm-lock.yaml @ImUrX @loucass003 -/pnpm-workspace.yaml @ImUrX @loucass003 - -# Uriel and Erimel responsible for i18n -/gui/public/i18n/ @ImUrX @Erimelowo -/gui/src/i18n/ @ImUrX @Erimelowo -/l10n.toml @ImUrX @Erimelowo - -/gui/src/components/settings/ @Erimelowo @ImUrX - -# Rust part of the GUI -/gui/src-tauri/ @ImUrX -/Cargo.lock @ImUrX - -# Some server code~ -/server/ @ButterscotchV @Eirenliel @Erimelowo - -/server/src/main/java/dev/slimevr/autobone/ @ButterscotchV -/server/src/main/java/dev/slimevr/poserecorder/ @ButterscotchV -/server/src/main/java/dev/slimevr/posestreamer/ @ButterscotchV - -/server/src/main/java/dev/slimevr/osc/ @Erimelowo -/server/src/main/java/dev/slimevr/tracking/processor/ @Erimelowo -/server/src/main/java/dev/slimevr/filtering/ @Erimelowo - -# Linux files -*.nix @ImUrX -/flake.lock @ImUrX -/dev.slimevr.SlimeVR.metainfo.xml @ImUrX -/.envrc @ImUrX +# Global code owner +* @Eirenliel + +# Make everyone be able to approve SolarXR submodule changes +/solarxr-protocol @ButterscotchV @Erimelowo @ImUrX @loucass003 + +# Make Loucas and Uriel the owners of all GUI stuff +/gui/ @ImUrX @loucass003 +/pnpm-lock.yaml @ImUrX @loucass003 +/pnpm-workspace.yaml @ImUrX @loucass003 + +# Uriel and Erimel responsible for i18n +/gui/public/i18n/ @ImUrX @Erimelowo +/gui/src/i18n/ @ImUrX @Erimelowo +/l10n.toml @ImUrX @Erimelowo + +/gui/src/components/settings/ @Erimelowo @ImUrX + +# Rust part of the GUI +/gui/src-tauri/ @ImUrX +/Cargo.lock @ImUrX + +# Some server code~ +/server/ @ButterscotchV @Eirenliel @Erimelowo + +/server/src/main/java/dev/slimevr/autobone/ @ButterscotchV +/server/src/main/java/dev/slimevr/poserecorder/ @ButterscotchV +/server/src/main/java/dev/slimevr/posestreamer/ @ButterscotchV + +/server/src/main/java/dev/slimevr/osc/ @Erimelowo +/server/src/main/java/dev/slimevr/tracking/processor/ @Erimelowo +/server/src/main/java/dev/slimevr/filtering/ @Erimelowo + +# Linux files +*.nix @ImUrX +/flake.lock @ImUrX +/dev.slimevr.SlimeVR.metainfo.xml @ImUrX +/.envrc @ImUrX diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..548d31009 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,37 @@ +"Area: Continuous Integration": +- changed-files: + - any-glob-to-any-file: ".github/**" +"Area: Application Protocol": +- changed-files: + - any-glob-to-any-file: ["solarxr-protocol"] +"Area: AutoBone": +- changed-files: + - any-glob-to-any-file: "server/core/src/main/java/dev/slimevr/autobone/**" +"Area: Documentation": +- changed-files: + - any-glob-to-any-file: "**/*.md" +"Area: GUI": +- all: + - changed-files: + - all-globs-to-any-file: ["gui/**/*", "!gui/public/i18n/**/*"] +"Area: Hardware Protocol": +- changed-files: + - any-glob-to-any-file: "server/core/src/main/java/dev/slimevr/tracking/trackers/udp/**" +"Area: Server": +- changed-files: + - any-glob-to-any-file: ["server/**", "*gradle*", "gradle/**"] +"Area: Skeletal Model": +- changed-files: + - any-glob-to-any-file: "server/core/src/main/java/dev/slimevr/tracking/processor/**" +"Area: SteamVR Driver": +- changed-files: + - any-glob-to-any-file: "server/desktop/src/main/java/dev/slimevr/desktop/platform/**" +"Area: Translation": +- changed-files: + - any-glob-to-any-file: "gui/public/i18n/**" +"Area: VMC": +- changed-files: + - any-glob-to-any-file: ["server/core/src/main/java/dev/slimevr/osc/Unity*", "server/core/src/main/java/dev/slimevr/osc/VMC*", "server/core/src/main/java/dev/slimevr/osc/VRM*"] +"Area: VRCOSC": +- changed-files: + - any-glob-to-any-file: ["server/core/src/main/java/dev/slimevr/osc/VRC*"] diff --git a/.github/workflows/gradle.yaml b/.github/workflows/gradle.yaml index a224da2c8..d47666444 100644 --- a/.github/workflows/gradle.yaml +++ b/.github/workflows/gradle.yaml @@ -74,7 +74,7 @@ jobs: # Artifact name name: "SlimeVR-Server" # optional, default is artifact # A file, directory or wildcard pattern that describes what to upload - path: server/desktop/build/libs/* + path: server/desktop/build/libs/slimevr.jar - name: Upload to draft release uses: softprops/action-gh-release@v2 @@ -83,7 +83,7 @@ jobs: draft: true generate_release_notes: true files: | - server/desktop/build/libs/* + server/desktop/build/libs/slimevr.jar bundle-android: @@ -147,7 +147,7 @@ jobs: bundle-linux: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: [build, test] if: contains(fromJSON('["workflow_dispatch", "create"]'), github.event_name) steps: @@ -163,14 +163,25 @@ jobs: - name: Set up Linux dependencies uses: awalsh128/cache-apt-pkgs-action@latest with: - packages: libgtk-3-dev webkit2gtk-4.1 libappindicator3-dev librsvg2-dev patchelf libfuse2 + packages: | + build-essential curl wget file libssl-dev libgtk-3-dev libappindicator3-dev librsvg2-dev # Increment to invalidate the cache - version: 1.0 + version: 2.0 # Enables a workaround to attempt to run pre and post install scripts execute_install_scripts: true # Disables uploading logs as a build artifact debug: false + - name: Set up specific Linux versioned dependencies + run: | + sudo apt-get update && sudo apt-get install -y \ + libwebkit2gtk-4.1-0=2.44.0-2 \ + libwebkit2gtk-4.1-dev=2.44.0-2 \ + libjavascriptcoregtk-4.1-0=2.44.0-2 \ + libjavascriptcoregtk-4.1-dev=2.44.0-2 \ + gir1.2-javascriptcoregtk-4.1=2.44.0-2 \ + gir1.2-webkit2-4.1=2.44.0-2; + - name: Cache cargo dependencies uses: Swatinem/rust-cache@v2 with: diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml new file mode 100644 index 000000000..d23c4d403 --- /dev/null +++ b/.github/workflows/label.yml @@ -0,0 +1,22 @@ +# This workflow will triage pull requests and apply a label based on the +# paths that are modified in the pull request. +# +# To use this workflow, you will need to set up a .github/labeler.yml +# file with configuration. For more information, see: +# https://github.com/actions/labeler + +name: Labeler +on: [pull_request_target] + +jobs: + label: + + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + + steps: + - uses: actions/labeler@v5 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.gitignore b/.gitignore index aaa77a285..1f6767f08 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,8 @@ /node_modules .husky +# kotlin stuff +/.kotlin # ignore gradle build folder build/ @@ -41,3 +43,6 @@ build/ # Ignore Android local properties local.properties + +# Ignore temporary config +vrconfig.yml.tmp diff --git a/.husky/pre-commit b/.husky/pre-commit index d24eda90e..e333e04c1 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,6 +1,3 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - YELLOW="\033[1;33m" GREEN="\033[1;32m" RESET="\033[0m" diff --git a/Cargo.lock b/Cargo.lock index dfd317a07..23fc1864d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -58,9 +64,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -73,33 +79,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -107,9 +113,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "app_dirs2" @@ -125,18 +131,22 @@ dependencies = [ [[package]] name = "ashpd" -version = "0.8.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd884d7c72877a94102c3715f3b1cd09ff4fac28221add3e57cfbe25c236d093" +checksum = "4d43c03d9e36dd40cab48435be0b09646da362c278223ca535493877b2c1dee9" dependencies = [ "enumflags2", "futures-channel", "futures-util", "rand 0.8.5", + "raw-window-handle", "serde", "serde_repr", "tokio", "url", + "wayland-backend", + "wayland-client", + "wayland-protocols", "zbus", ] @@ -166,9 +176,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ "async-lock", "cfg-if", @@ -180,7 +190,7 @@ dependencies = [ "rustix", "slab", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -196,9 +206,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.2.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ "async-channel", "async-io", @@ -211,7 +221,6 @@ dependencies = [ "futures-lite", "rustix", "tracing", - "windows-sys 0.52.0", ] [[package]] @@ -222,14 +231,14 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] name = "async-signal" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ "async-io", "async-lock", @@ -240,7 +249,7 @@ dependencies = [ "rustix", "signal-hook-registry", "slab", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -251,13 +260,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -291,9 +300,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" @@ -305,7 +314,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -376,9 +385,9 @@ dependencies = [ [[package]] name = "brotli" -version = "3.5.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -387,9 +396,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.5.1" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -403,9 +412,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.16.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" [[package]] name = "byteorder" @@ -414,10 +423,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "bytes" -version = "1.6.0" +name = "byteorder-lite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" dependencies = [ "serde", ] @@ -449,9 +464,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -491,13 +506,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.104" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -549,14 +564,14 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] name = "clap" -version = "4.5.8" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -564,9 +579,9 @@ dependencies = [ [[package]] name = "clap-verbosity-flag" -version = "2.2.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb9b20c0dd58e4c2e991c8d203bbeb76c11304d1011659686b5b644bc29aa478" +checksum = "e099138e1807662ff75e2cebe4ae2287add879245574489f9b1588eb5e5564ed" dependencies = [ "clap", "log", @@ -574,9 +589,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.8" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -586,29 +601,29 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.8" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "cocoa" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" +checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "block", "cocoa-foundation", "core-foundation", @@ -620,11 +635,11 @@ dependencies = [ [[package]] name = "cocoa-foundation" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "block", "core-foundation", "core-graphics-types", @@ -659,17 +674,11 @@ dependencies = [ "tracing-error", ] -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "combine" @@ -698,18 +707,18 @@ checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" [[package]] name = "const_format" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" dependencies = [ "proc-macro2", "quote", @@ -724,9 +733,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation" -version = "0.9.4" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" dependencies = [ "core-foundation-sys", "libc", @@ -734,17 +743,17 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core-graphics" -version = "0.23.2" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "core-foundation", "core-graphics-types", "foreign-types", @@ -753,20 +762,20 @@ dependencies = [ [[package]] name = "core-graphics-types" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "core-foundation", "libc", ] [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -829,7 +838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -839,14 +848,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] name = "darling" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -854,27 +863,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] name = "darling_macro" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -914,7 +923,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -971,9 +980,9 @@ dependencies = [ [[package]] name = "discord-sdk" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc3d7a4f9bc39006b732a01d63b34ff1518313313d707cb18cf6187d2124f7f4" +checksum = "2f1d6193792828a1f83d8edbbbce2602cc07ad35ca0d5a9d5c6195e311d85d4e" dependencies = [ "anyhow", "app_dirs2", @@ -1000,6 +1009,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.5", +] + [[package]] name = "dlopen2" version = "0.7.0" @@ -1020,9 +1038,15 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "dpi" version = "0.1.1" @@ -1049,9 +1073,9 @@ dependencies = [ [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" @@ -1067,9 +1091,9 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "embed-resource" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6985554d0688b687c5cb73898a34fbe3ad6c24c58c238a4d91d5e840670ee9d" +checksum = "f4e24052d7be71f0efb50c201557f6fe7d237cfd5a64fd5bcd7fd8fe32dbbffa" dependencies = [ "cc", "memchr", @@ -1118,7 +1142,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -1180,15 +1204,15 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fdeflate" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +checksum = "d8090f921a24b04994d9929e204f50b498a33ea6ba559ffaa05e04f7ee7fb5ab" dependencies = [ "simd-adler32", ] @@ -1205,28 +1229,36 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] name = "flexi_logger" -version = "0.28.5" +version = "0.29.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca927478b3747ba47f98af6ba0ac0daea4f12d12f55e9104071b3dc00276310" +checksum = "719236bdbcf6033a3395165f797076b31056018e6723ccff616eb25fc9c99de1" dependencies = [ "chrono", - "glob", "log", - "nu-ansi-term 0.50.0", + "nu-ansi-term", "regex", "thiserror", ] +[[package]] +name = "fluent-uri" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1251,7 +1283,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -1281,24 +1313,24 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1307,9 +1339,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" @@ -1326,32 +1358,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-io", @@ -1472,19 +1504,6 @@ dependencies = [ "x11", ] -[[package]] -name = "generator" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows 0.48.0", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -1497,12 +1516,12 @@ dependencies = [ [[package]] name = "gethostname" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +checksum = "dc3655aa6818d65bc620d6911f05aa7b6aeb596291e1e9f79e52df85583d1e30" dependencies = [ - "libc", - "windows-targets 0.48.5", + "rustix", + "windows-targets 0.52.6", ] [[package]] @@ -1567,9 +1586,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.18.3" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70" +checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" dependencies = [ "bitflags 2.6.0", "libc", @@ -1612,7 +1631,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -1691,7 +1710,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -1702,9 +1721,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] name = "heck" @@ -1772,9 +1791,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", @@ -1795,15 +1814,15 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "hyper" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4fe55fb7a772d59a5ff1dfbff4fe0258d19b89fec4b233e75d35d5d2316badc" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", @@ -1819,10 +1838,28 @@ dependencies = [ ] [[package]] -name = "hyper-util" -version = "0.1.6" +name = "hyper-rustls" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-channel", @@ -1833,16 +1870,15 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1889,13 +1925,12 @@ dependencies = [ [[package]] name = "image" -version = "0.24.9" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" dependencies = [ "bytemuck", - "byteorder", - "color_quant", + "byteorder-lite", "num-traits", "png", ] @@ -1919,20 +1954,20 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", "serde", ] [[package]] name = "infer" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199" +checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" dependencies = [ "cfb", ] @@ -1948,9 +1983,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is-docker" @@ -1979,9 +2014,9 @@ checksum = "06d198e9919d9822d5f7083ba8530e04de87841eaf21ead9af8f2304efd57c89" [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" @@ -2042,33 +2077,45 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] [[package]] name = "json-patch" -version = "1.4.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9ad60d674508f3ca8f380a928cfe7b096bc729c4e2dbfe3852bc45da3ab30b" +checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc" dependencies = [ + "jsonptr", "serde", "serde_json", "thiserror", ] +[[package]] +name = "jsonptr" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c6e529149475ca0b2820835d3dce8fcc41c6b943ca608d32f35b449255e4627" +dependencies = [ + "fluent-uri", + "serde", + "serde_json", +] + [[package]] name = "keyboard-types" version = "0.7.0" @@ -2119,21 +2166,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" dependencies = [ "gtk-sys", - "libloading", + "libloading 0.7.4", "once_cell", ] [[package]] name = "libc" -version = "0.2.155" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libgit2-sys" -version = "0.16.2+1.7.2" +version = "0.17.0+1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" +checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" dependencies = [ "cc", "libc", @@ -2151,6 +2198,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + [[package]] name = "libredox" version = "0.1.3" @@ -2163,9 +2220,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.18" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "libc", @@ -2205,21 +2262,6 @@ dependencies = [ "log", ] -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] - [[package]] name = "mac" version = "0.1.1" @@ -2249,15 +2291,6 @@ dependencies = [ "tendril", ] -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - [[package]] name = "matches" version = "0.1.10" @@ -2292,50 +2325,62 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", "simd-adler32", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi 0.3.9", "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - -[[package]] -name = "muda" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b959f97c97044e4c96e32e1db292a7d594449546a3c6b77ae613dc3a5b5145" -dependencies = [ - "cocoa", - "crossbeam-channel", - "dpi", - "gtk", - "keyboard-types", - "objc", - "once_cell", - "png", - "serde", - "thiserror", "windows-sys 0.52.0", ] [[package]] -name = "ndk" -version = "0.7.0" +name = "muda" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +checksum = "b8123dfd4996055ac9b15a60ad263b44b01e539007523ad7a4a533a3d93b0591" dependencies = [ - "bitflags 1.3.2", + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", + "png", + "serde", + "thiserror", + "windows-sys 0.59.0", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.6.0", "jni-sys", + "log", "ndk-sys", "num_enum", - "raw-window-handle 0.5.2", + "raw-window-handle", "thiserror", ] @@ -2347,9 +2392,9 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-sys" -version = "0.4.1+23.1.7779620" +version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ "jni-sys", ] @@ -2380,21 +2425,11 @@ checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "nu-ansi-term" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14" -dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2412,35 +2447,25 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.9", - "libc", -] - [[package]] name = "num_enum" -version = "0.5.11" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.11" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 2.0.2", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.79", ] [[package]] @@ -2459,18 +2484,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ "malloc_buf", - "objc_exception", -] - -[[package]] -name = "objc-foundation" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", ] [[package]] @@ -2478,6 +2491,9 @@ name = "objc-sys" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" +dependencies = [ + "cc", +] [[package]] name = "objc2" @@ -2505,6 +2521,30 @@ dependencies = [ "objc2-quartz-core", ] +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + [[package]] name = "objc2-core-data" version = "0.2.2" @@ -2529,6 +2569,18 @@ dependencies = [ "objc2-metal", ] +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", +] + [[package]] name = "objc2-encode" version = "4.0.3" @@ -2548,6 +2600,18 @@ dependencies = [ "objc2", ] +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + [[package]] name = "objc2-metal" version = "0.2.2" @@ -2574,21 +2638,71 @@ dependencies = [ ] [[package]] -name = "objc_exception" -version = "0.1.2" +name = "objc2-symbols" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ - "cc", + "objc2", + "objc2-foundation", ] [[package]] -name = "objc_id" -version = "0.1.1" +name = "objc2-ui-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "objc", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-web-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", ] [[package]] @@ -2602,15 +2716,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "open" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2c909a3fce3bd80efef4cd1c6c056bd9376a8fe06fcfdbebaf32cb485a7e37" +checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3" dependencies = [ "is-wsl", "libc", @@ -2646,20 +2760,14 @@ dependencies = [ [[package]] name = "os_pipe" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d73ba8daf8fac13b0501d1abeddcfe21ba7401ada61a819144b6c2a4f32209" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "owo-colors" version = "3.5.0" @@ -2693,9 +2801,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -2717,14 +2825,14 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" [[package]] name = "percent-encoding" @@ -2836,7 +2944,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -2866,26 +2974,6 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.68", -] - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -2900,9 +2988,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", "fastrand", @@ -2911,9 +2999,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plist" @@ -2922,30 +3010,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", - "indexmap 2.2.6", - "quick-xml", + "indexmap 2.6.0", + "quick-xml 0.32.0", "serde", "time", ] [[package]] name = "png" -version = "0.17.13" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" dependencies = [ "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] name = "polling" -version = "3.7.2" +version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ "cfg-if", "concurrent-queue", @@ -2953,7 +3041,7 @@ dependencies = [ "pin-project-lite", "rustix", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2964,9 +3052,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "precomputed-hash" @@ -3026,9 +3117,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -3043,10 +3134,68 @@ dependencies = [ ] [[package]] -name = "quote" -version = "1.0.36" +name = "quick-xml" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "quinn" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +dependencies = [ + "bytes", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -3132,12 +3281,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - [[package]] name = "raw-window-handle" version = "0.6.2" @@ -3146,18 +3289,18 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", @@ -3166,53 +3309,38 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata", + "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.1.10" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64 0.22.1", "bytes", @@ -3222,6 +3350,7 @@ dependencies = [ "http-body", "http-body-util", "hyper", + "hyper-rustls", "hyper-util", "ipnet", "js-sys", @@ -3230,11 +3359,16 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", + "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", + "tokio-rustls", "tokio-util", "tower-service", "url", @@ -3242,33 +3376,48 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "winreg", + "webpki-roots", + "windows-registry", ] [[package]] name = "rfd" -version = "0.14.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a73a7337fc24366edfca76ec521f51877b114e42dab584008209cca6719251" +checksum = "8af382a047821a08aa6bfc09ab0d80ff48d45d8726f7cd8e44891f7cb4a4278e" dependencies = [ "ashpd", - "block", - "dispatch", + "block2", "glib-sys", "gobject-sys", "gtk-sys", "js-sys", "log", - "objc", - "objc-foundation", - "objc_id", - "raw-window-handle 0.6.2", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "raw-window-handle", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "windows-sys 0.48.0", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -3276,19 +3425,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] -name = "rustc_version" -version = "0.4.0" +name = "rustc-hash" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -3298,10 +3453,44 @@ dependencies = [ ] [[package]] -name = "rustversion" -version = "1.0.17" +name = "rustls" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] [[package]] name = "ryu" @@ -3330,6 +3519,7 @@ dependencies = [ "serde", "serde_json", "url", + "uuid", ] [[package]] @@ -3341,7 +3531,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -3387,9 +3577,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -3407,13 +3597,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -3424,16 +3614,17 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa 1.0.11", + "memchr", "ryu", "serde", ] @@ -3446,14 +3637,14 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -3472,15 +3663,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.2" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "079f3a42cd87588d924ed95b533f8d30a483388c4e400ab736a7058e34f16169" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -3490,14 +3681,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.2" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc03aad67c1d26b7de277d51c86892e7d9a0110a2fe44bf6b26cc569fba302d6" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -3556,9 +3747,9 @@ dependencies = [ [[package]] name = "shadow-rs" -version = "0.27.1" +version = "0.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7960cbd6ba74691bb15e7ebf97f7136bd02d1115f5695a58c1f31d5645750128" +checksum = "2311e39772c00391875f40e34d43efef247b23930143a70ca5fbec9505937420" dependencies = [ "const_format", "git2", @@ -3578,14 +3769,20 @@ dependencies = [ [[package]] name = "shared_child" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef" +checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" dependencies = [ "libc", - "winapi", + "windows-sys 0.59.0", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -3630,6 +3827,7 @@ dependencies = [ "discord-sdk", "flexi_logger", "glob", + "libloading 0.8.5", "log", "log-panics", "open", @@ -3671,9 +3869,9 @@ dependencies = [ [[package]] name = "softbuffer" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d623bff5d06f60d738990980d782c8c866997d9194cfe79ecad00aa2f76826dd" +checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" dependencies = [ "bytemuck", "cfg_aliases", @@ -3682,14 +3880,13 @@ dependencies = [ "js-sys", "log", "objc2", - "objc2-app-kit", "objc2-foundation", "objc2-quartz-core", - "raw-window-handle 0.6.2", + "raw-window-handle", "redox_syscall", "wasm-bindgen", "web-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3718,21 +3915,18 @@ dependencies = [ "system-deps", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "state" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" -dependencies = [ - "loom", -] - [[package]] name = "static_assertions" version = "1.1.0" @@ -3772,10 +3966,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] -name = "swift-rs" -version = "1.0.6" +name = "subtle" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bbdb58577b6301f8d17ae2561f32002a5bae056d444e0f69e611e504a276204" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" dependencies = [ "base64 0.21.7", "serde", @@ -3795,9 +3995,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.68" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -3809,6 +4009,9 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "sys-locale" @@ -3834,9 +4037,9 @@ dependencies = [ [[package]] name = "tao" -version = "0.28.1" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea538df05fbc2dcbbd740ba0cfe8607688535f4798d213cbbfa13ce494f3451f" +checksum = "a0dbbebe82d02044dfa481adca1550d6dd7bd16e086bc34fa0fbecceb5a63751" dependencies = [ "bitflags 2.6.0", "cocoa", @@ -3860,43 +4063,42 @@ dependencies = [ "objc", "once_cell", "parking_lot", - "raw-window-handle 0.6.2", + "raw-window-handle", "scopeguard", "tao-macros", "unicode-segmentation", "url", - "windows 0.57.0", - "windows-core 0.57.0", + "windows", + "windows-core 0.58.0", "windows-version", "x11-dl", ] [[package]] name = "tao-macros" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec114582505d158b669b136e6851f85840c109819d77c42bb7c0709f727d18c2" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.79", ] [[package]] name = "target-lexicon" -version = "0.12.14" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.0.0-beta.23" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68725c4f17f62f0fb1fa2eecaf391200bf00a9414c84f30783ddca10570690c3" +checksum = "fd96d46534b10765ce0c6208f9451d98ea38636364a41b272d3610c70dd0e4c3" dependencies = [ "anyhow", "bytes", - "cocoa", "dirs", "dunce", "embed_plist", @@ -3912,15 +4114,17 @@ dependencies = [ "log", "mime", "muda", - "objc", + "objc2", + "objc2-app-kit", + "objc2-foundation", "percent-encoding", - "raw-window-handle 0.6.2", + "plist", + "raw-window-handle", "reqwest", "serde", "serde_json", "serde_repr", "serialize-to-javascript", - "state", "swift-rs", "tauri-build", "tauri-macros", @@ -3935,14 +4139,14 @@ dependencies = [ "webkit2gtk", "webview2-com", "window-vibrancy", - "windows 0.57.0", + "windows", ] [[package]] name = "tauri-build" -version = "2.0.0-beta.18" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1822847744f663babbfc8b7532a104734e9cf99e3408bba7109018bf9177917" +checksum = "935f9b3c49b22b3e2e485a57f46d61cd1ae07b1cbb2ba87387a387caf2d8c4e7" dependencies = [ "anyhow", "cargo_toml", @@ -3962,9 +4166,9 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.0.0-beta.18" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e36fa3c2e3bd935827fef1eed459885414fb27c82f687d8b9a15112c8a5c8f0" +checksum = "95d7443dd4f0b597704b6a14b964ee2ed16e99928d8e6292ae9825f09fbcd30e" dependencies = [ "base64 0.22.1", "brotli", @@ -3978,7 +4182,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "syn 2.0.68", + "syn 2.0.79", "tauri-utils", "thiserror", "time", @@ -3989,23 +4193,23 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.0.0-beta.18" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34aba4bed4648c3cb17d421af5783c7c29a033a94ab8597ef3791dadea69289d" +checksum = "4d2c0963ccfc3f5194415f2cce7acc975942a8797fbabfb0aa1ed6f59326ae7f" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", "tauri-codegen", "tauri-utils", ] [[package]] name = "tauri-plugin" -version = "2.0.0-beta.18" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "431ac9636bf81e7a04042399918ffa6b9d2413926dabc9366a24f6b487f64653" +checksum = "b2e6660a409963e4d57b9bfab4addd141eeff41bd3a7fb14e13004a832cf7ef6" dependencies = [ "anyhow", "glob", @@ -4020,13 +4224,12 @@ dependencies = [ [[package]] name = "tauri-plugin-dialog" -version = "2.0.0-beta.10" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736fee091e918a46abd1431325a5ff7de78bc9ca1182f91618945173d1532bf3" +checksum = "ddb2fe88b602461c118722c574e2775ab26a4e68886680583874b2f6520608b7" dependencies = [ - "dunce", "log", - "raw-window-handle 0.6.2", + "raw-window-handle", "rfd", "serde", "serde_json", @@ -4034,16 +4237,19 @@ dependencies = [ "tauri-plugin", "tauri-plugin-fs", "thiserror", + "url", ] [[package]] name = "tauri-plugin-fs" -version = "2.0.0-beta.10" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e1f9fb6054cbc48c9e0fda7e8c8aeaccddb4fe880163473555beeed580010e" +checksum = "ab300488ebec3487ca5f56289692e7e45feb07eea8d5e1dba497f7dc9dd9c407" dependencies = [ "anyhow", + "dunce", "glob", + "percent-encoding", "schemars", "serde", "serde_json", @@ -4057,9 +4263,9 @@ dependencies = [ [[package]] name = "tauri-plugin-os" -version = "2.0.0-beta.7" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2946635d31de19ed4191f1c556da20d1257f4667a1bac03852d9bb4be9fa8ffa" +checksum = "fbc5f23a86f37687c7f4fecfdc706b279087bc44f7a46702f7307ff1551ee03a" dependencies = [ "gethostname", "log", @@ -4075,9 +4281,9 @@ dependencies = [ [[package]] name = "tauri-plugin-shell" -version = "2.0.0-beta.8" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85f0347c4d056cca543b5f2dd74c33b64182553e03d1dba2738fe2a95f0ec9ef" +checksum = "371fb9aca2823990a2d0db7970573be5fdf07881fcaa2b835b29631feb84aec1" dependencies = [ "encoding_rs", "log", @@ -4096,9 +4302,9 @@ dependencies = [ [[package]] name = "tauri-plugin-store" -version = "2.0.0-beta.9" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb57852aad7c36bb367ec95e67d1b9fd2b3e6b8365c70122f8b3688937c12fc8" +checksum = "5058f179f7215390fc5a68eeffcb805b7e2681d6e817a5d08094fae7ab649e68" dependencies = [ "dunce", "log", @@ -4107,40 +4313,43 @@ dependencies = [ "tauri", "tauri-plugin", "thiserror", + "tokio", ] [[package]] name = "tauri-runtime" -version = "2.0.0-beta.19" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5fa872242a432195b814e87f91ce10f293ae5b01fbd1eb139455496260aa7c9" +checksum = "c8f437293d6f5e5dce829250f4dbdce4e0b52905e297a6689cc2963eb53ac728" dependencies = [ "dpi", "gtk", "http", "jni", - "raw-window-handle 0.6.2", + "raw-window-handle", "serde", "serde_json", "tauri-utils", "thiserror", "url", - "windows 0.57.0", + "windows", ] [[package]] name = "tauri-runtime-wry" -version = "2.0.0-beta.19" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ad6d5ef3c05d1c4b6cf97b9eac1ca1ad8ff2a7057ad0a92b3e4c476f009341e" +checksum = "aaac63b65df8e85570993eaf93ae1dd73a6fb66d8bd99674ce65f41dc3c63e7d" dependencies = [ - "cocoa", "gtk", "http", "jni", "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", "percent-encoding", - "raw-window-handle 0.6.2", + "raw-window-handle", "softbuffer", "tao", "tauri-runtime", @@ -4148,15 +4357,15 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows 0.57.0", + "windows", "wry", ] [[package]] name = "tauri-utils" -version = "2.0.0-beta.18" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f81a672883c9a67eb24727c99cce583625c919a5fb696c661603b426c463c72" +checksum = "c38b0230d6880cf6dd07b6d7dd7789a0869f98ac12146e0d18d1c1049215a045" dependencies = [ "brotli", "cargo_metadata", @@ -4184,6 +4393,7 @@ dependencies = [ "toml 0.8.2", "url", "urlpattern", + "uuid", "walkdir", ] @@ -4199,14 +4409,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4228,22 +4439,22 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -4291,9 +4502,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -4306,27 +4517,49 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "signal-hook-registry", "socket2", + "tokio-macros", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", ] [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -4374,7 +4607,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", @@ -4387,39 +4620,18 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", "winnow", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -4440,7 +4652,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] @@ -4463,53 +4675,36 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - [[package]] name = "tracing-subscriber" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ - "matchers", - "nu-ansi-term 0.46.0", - "once_cell", - "regex", "sharded-slab", - "smallvec", "thread_local", - "tracing", "tracing-core", - "tracing-log", ] [[package]] name = "tray-icon" -version = "0.14.3" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ad8319cca93189ea9ab1b290de0595960529750b6b8b501a399ed1ec3775d60" +checksum = "7c92af36a182b46206723bdf8a7942e20838cde1cf062e5b97854d57eb01763b" dependencies = [ - "cocoa", "core-graphics", "crossbeam-channel", "dirs", "libappindicator", "muda", - "objc", + "objc2", + "objc2-app-kit", + "objc2-foundation", "once_cell", "png", "serde", "thiserror", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4520,9 +4715,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typeid" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" [[package]] name = "typenum" @@ -4552,9 +4747,9 @@ dependencies = [ [[package]] name = "tzdb_data" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1889fdffac09d65c1d95c42d5202e9b21ad8c758f426e9fe09088817ea998d6" +checksum = "654c1ec546942ce0594e8d220e6b8e3899e0a0a8fe70ddd54d32a376dfefe3f8" dependencies = [ "tz-rs", ] @@ -4613,36 +4808,42 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" @@ -4658,11 +4859,10 @@ dependencies = [ [[package]] name = "urlpattern" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9bd5ff03aea02fa45b13a7980151fe45009af1980ba69f651ec367121a31609" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" dependencies = [ - "derive_more", "regex", "serde", "unic-ucd-ident", @@ -4683,11 +4883,12 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.9.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom 0.2.15", + "serde", ] [[package]] @@ -4710,9 +4911,9 @@ checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vswhom" @@ -4767,34 +4968,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -4804,9 +5006,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4814,28 +5016,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" dependencies = [ "futures-util", "js-sys", @@ -4845,10 +5047,70 @@ dependencies = [ ] [[package]] -name = "web-sys" -version = "0.3.69" +name = "wayland-backend" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3f45d1222915ef1fd2057220c1d9d9624b7654443ea35c3877f7a52bd0a5a2d" +dependencies = [ + "bitflags 2.6.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b5755d77ae9040bb872a25026555ce4cb0ae75fd923e90d25fba07d81057de0" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" +dependencies = [ + "proc-macro2", + "quick-xml 0.36.2", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" +dependencies = [ + "dlib", + "log", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -4899,46 +5161,55 @@ dependencies = [ ] [[package]] -name = "webview2-com" -version = "0.31.0" +name = "webpki-roots" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6516cfa64c6b3212686080eeec378e662c2af54bb2a5b2a22749673f5cb2226f" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webview2-com" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61ff3d9d0ee4efcb461b14eb3acfda2702d10dc329f339303fc3e57215ae2c" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows 0.57.0", - "windows-core 0.57.0", + "windows", + "windows-core 0.58.0", "windows-implement", "windows-interface", ] [[package]] name = "webview2-com-macros" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc" +checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] name = "webview2-com-sys" -version = "0.31.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c76d5b77320ff155660be1df3e6588bc85c75f1a9feef938cc4dc4dd60d1d7cf" +checksum = "a3a3e2eeb58f82361c93f9777014668eb3d07e7d174ee4c819575a9208011886" dependencies = [ "thiserror", - "windows 0.57.0", - "windows-core 0.57.0", + "windows", + "windows-core 0.58.0", ] [[package]] name = "which" -version = "6.0.1" +version = "6.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" dependencies = [ "either", "home", @@ -4974,11 +5245,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4989,34 +5260,26 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window-vibrancy" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33082acd404763b315866e14a0d5193f3422c81086657583937a750cdd3ec340" +checksum = "3ea403deff7b51fff19e261330f71608ff2cdef5721d72b64180bb95be7c4150" dependencies = [ - "cocoa", - "objc", - "raw-window-handle 0.6.2", - "windows-sys 0.52.0", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "raw-window-handle", + "windows-sys 0.59.0", "windows-version", ] [[package]] name = "windows" -version = "0.48.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" -dependencies = [ - "windows-core 0.57.0", - "windows-targets 0.52.5", + "windows-core 0.58.0", + "windows-targets 0.52.6", ] [[package]] @@ -5025,50 +5288,72 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] name = "windows-core" -version = "0.57.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ "windows-implement", "windows-interface", "windows-result", - "windows-targets 0.52.5", + "windows-strings", + "windows-targets 0.52.6", ] [[package]] name = "windows-implement" -version = "0.57.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", ] [[package]] name = "windows-interface" -version = "0.57.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.79", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", ] [[package]] name = "windows-result" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", ] [[package]] @@ -5095,7 +5380,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -5130,18 +5424,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -5150,7 +5444,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -5167,9 +5461,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -5185,9 +5479,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -5203,15 +5497,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -5227,9 +5521,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -5245,9 +5539,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -5263,9 +5557,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -5281,9 +5575,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -5312,14 +5606,12 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "wry" -version = "0.41.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b00c945786b02d7805d09a969fa36d0eee4e0bd4fb3ec2a79d2bf45a1b44cd" +checksum = "469a3765ecc3e8aa9ccdf3c5a52c82697ec03037cd60494488763880d31a1b3a" dependencies = [ "base64 0.22.1", - "block", - "cocoa", - "core-graphics", + "block2", "crossbeam-channel", "dpi", "dunce", @@ -5332,13 +5624,14 @@ dependencies = [ "kuchikiki", "libc", "ndk", - "ndk-context", - "ndk-sys", - "objc", - "objc_id", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", "once_cell", "percent-encoding", - "raw-window-handle 0.6.2", + "raw-window-handle", "sha2", "soup3", "tao-macros", @@ -5346,8 +5639,8 @@ dependencies = [ "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows 0.57.0", - "windows-core 0.57.0", + "windows", + "windows-core 0.58.0", "windows-version", "x11-dl", ] @@ -5381,12 +5674,12 @@ checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" [[package]] name = "xdg-home" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca91dcf8f93db085f3a0a29358cd0b9d670915468f4290e8b85d118a34211ab8" +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5448,6 +5741,33 @@ dependencies = [ "zvariant", ] +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + [[package]] name = "zvariant" version = "4.0.0" diff --git a/dev.slimevr.SlimeVR.metainfo.xml b/dev.slimevr.SlimeVR.metainfo.xml index b6b45a8e7..141ea2040 100644 --- a/dev.slimevr.SlimeVR.metainfo.xml +++ b/dev.slimevr.SlimeVR.metainfo.xml @@ -65,6 +65,15 @@ work. If not, see . + https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.13.1 + https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.13.1-rc.3 + https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.13.1-rc.2 + https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.13.1-rc.1 + https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.13.0 + https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.13.0-rc.4 + https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.13.0-rc.3 + https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.13.0-rc.2 + https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.13.0-rc.1 https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.12.1 https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.12.0 https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.12.0-rc.4 diff --git a/flake.lock b/flake.lock index baf9f177b..af78cdf72 100644 --- a/flake.lock +++ b/flake.lock @@ -1,22 +1,160 @@ { "nodes": { - "devenv": { + "cachix": { "inputs": { - "flake-compat": "flake-compat", - "nix": "nix", - "nixpkgs": "nixpkgs", - "pre-commit-hooks": "pre-commit-hooks" + "devenv": "devenv_2", + "flake-compat": [ + "devenv", + "flake-compat" + ], + "git-hooks": [ + "devenv", + "pre-commit-hooks" + ], + "nixpkgs": [ + "devenv", + "nixpkgs" + ] }, "locked": { - "lastModified": 1699541523, - "narHash": "sha256-Rv0ryuBC5KtA/3YqwIEe58Tabu71qSGnGcGRd67mMUY=", + "lastModified": 1726520618, + "narHash": "sha256-jOsaBmJ/EtX5t/vbylCdS7pWYcKGmWOKg4QKUzKr6dA=", "owner": "cachix", - "repo": "devenv", - "rev": "14fdefc0bb80c3d6f3a18a491e33429b4064c371", + "repo": "cachix", + "rev": "695525f9086542dfb09fde0871dbf4174abbf634", "type": "github" }, "original": { "owner": "cachix", + "repo": "cachix", + "type": "github" + } + }, + "cachix_2": { + "inputs": { + "devenv": "devenv_3", + "flake-compat": [ + "devenv", + "cachix", + "devenv", + "flake-compat" + ], + "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "nixpkgs" + ], + "pre-commit-hooks": [ + "devenv", + "cachix", + "devenv", + "pre-commit-hooks" + ] + }, + "locked": { + "lastModified": 1712055811, + "narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=", + "owner": "cachix", + "repo": "cachix", + "rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "cachix", + "type": "github" + } + }, + "devenv": { + "inputs": { + "cachix": "cachix", + "flake-compat": "flake-compat_2", + "nix": "nix_3", + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit-hooks": "pre-commit-hooks_2" + }, + "locked": { + "lastModified": 1730213537, + "narHash": "sha256-bWoeNdFISbGK8M0Xw4edmManGCkJ1oNqbfNY0Hlv9Vc=", + "owner": "cachix", + "repo": "devenv", + "rev": "5c046eeafd13f7a2b9fc733f70ea17571b24410f", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "devenv_2": { + "inputs": { + "cachix": "cachix_2", + "flake-compat": [ + "devenv", + "cachix", + "flake-compat" + ], + "nix": "nix_2", + "nixpkgs": [ + "devenv", + "cachix", + "nixpkgs" + ], + "pre-commit-hooks": [ + "devenv", + "cachix", + "git-hooks" + ] + }, + "locked": { + "lastModified": 1723156315, + "narHash": "sha256-0JrfahRMJ37Rf1i0iOOn+8Z4CLvbcGNwa2ChOAVrp/8=", + "owner": "cachix", + "repo": "devenv", + "rev": "ff5eb4f2accbcda963af67f1a1159e3f6c7f5f91", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "devenv_3": { + "inputs": { + "flake-compat": [ + "devenv", + "cachix", + "devenv", + "cachix", + "flake-compat" + ], + "nix": "nix", + "nixpkgs": "nixpkgs", + "poetry2nix": "poetry2nix", + "pre-commit-hooks": [ + "devenv", + "cachix", + "devenv", + "cachix", + "pre-commit-hooks" + ] + }, + "locked": { + "lastModified": 1708704632, + "narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=", + "owner": "cachix", + "repo": "devenv", + "rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "python-rewrite", "repo": "devenv", "type": "github" } @@ -29,11 +167,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1699683614, - "narHash": "sha256-XT2tIoIiiv0AxRs9g76nuRhfQf7KU1dE3ho8BL5CYM4=", + "lastModified": 1730270567, + "narHash": "sha256-ZTBMwsY0i5zTT6rejotc9wqcSGkEgAeejXktJBo9Z5M=", "owner": "nix-community", "repo": "fenix", - "rev": "ca6415d87d2e1b5975d59b2a68ae19029de1759c", + "rev": "6535bb2a77a3bec73cc5b2d2ff63da8a479e32bd", "type": "github" }, "original": { @@ -58,16 +196,54 @@ "type": "github" } }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "devenv", + "nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712014858, + "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { "inputs": { "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1698882062, - "narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=", + "lastModified": 1727826117, + "narHash": "sha256-K5ZLCyfO/Zj9mPFldf3iwS6oZStJcU4tSpiXTMYaaL0=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "8c9fa2545007b49a5db5f650ae91f227672c3877", + "rev": "3d04084d54bedc3d6b8b736c70ef449225c361b1", "type": "github" }, "original": { @@ -80,11 +256,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1685518550, - "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", + "lastModified": 1689068808, + "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", "owner": "numtide", "repo": "flake-utils", - "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", "type": "github" }, "original": { @@ -94,15 +270,12 @@ } }, "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, "locked": { - "lastModified": 1694529238, - "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", "owner": "numtide", "repo": "flake-utils", - "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", "type": "github" }, "original": { @@ -112,6 +285,24 @@ } }, "flake-utils_3": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_4": { "locked": { "lastModified": 1659877975, "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", @@ -135,11 +326,11 @@ ] }, "locked": { - "lastModified": 1660459072, - "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", "owner": "hercules-ci", "repo": "gitignore.nix", - "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", "type": "github" }, "original": { @@ -148,19 +339,19 @@ "type": "github" } }, - "lowdown-src": { + "libgit2": { "flake": false, "locked": { - "lastModified": 1633514407, - "narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=", - "owner": "kristapsdz", - "repo": "lowdown", - "rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8", + "lastModified": 1697646580, + "narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=", + "owner": "libgit2", + "repo": "libgit2", + "rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5", "type": "github" }, "original": { - "owner": "kristapsdz", - "repo": "lowdown", + "owner": "libgit2", + "repo": "libgit2", "type": "github" } }, @@ -181,50 +372,59 @@ }, "nix": { "inputs": { - "lowdown-src": "lowdown-src", + "flake-compat": "flake-compat", "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "cachix", "devenv", "nixpkgs" ], "nixpkgs-regression": "nixpkgs-regression" }, "locked": { - "lastModified": 1676545802, - "narHash": "sha256-EK4rZ+Hd5hsvXnzSzk2ikhStJnD63odF7SzsQ8CuSPU=", + "lastModified": 1712911606, + "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", "owner": "domenkozar", "repo": "nix", - "rev": "7c91803598ffbcfe4a55c44ac6d49b2cf07a527f", + "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", "type": "github" }, "original": { "owner": "domenkozar", - "ref": "relaxed-flakes", + "ref": "devenv-2.21", "repo": "nix", "type": "github" } }, - "nix2container": { + "nix-github-actions": { "inputs": { - "flake-utils": "flake-utils_2", "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "cachix", + "devenv", + "poetry2nix", "nixpkgs" ] }, "locked": { - "lastModified": 1697285352, - "narHash": "sha256-tRGLm/DO8+anGUCgLYxTF5EPqWv8EZ9MVFWRdh285HU=", - "owner": "nlewo", - "repo": "nix2container", - "rev": "9d7f33ef0058f4df4c0912025f43c758a3289d76", + "lastModified": 1688870561, + "narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=", + "owner": "nix-community", + "repo": "nix-github-actions", + "rev": "165b1650b753316aa7f1787f3005a8d2da0f5301", "type": "github" }, "original": { - "owner": "nlewo", - "repo": "nix2container", + "owner": "nix-community", + "repo": "nix-github-actions", "type": "github" } }, - "nixgl": { + "nix2container": { "inputs": { "flake-utils": "flake-utils_3", "nixpkgs": [ @@ -232,11 +432,91 @@ ] }, "locked": { - "lastModified": 1685908677, - "narHash": "sha256-E4zUPEUFyVWjVm45zICaHRpfGepfkE9Z2OECV9HXfA4=", + "lastModified": 1729339656, + "narHash": "sha256-smV7HQ/OqZeRguQxNjsb3uQDwm0p6zKDbSDbPCav/oY=", + "owner": "nlewo", + "repo": "nix2container", + "rev": "cc96df7c3747c61c584d757cfc083922b4f4b33e", + "type": "github" + }, + "original": { + "owner": "nlewo", + "repo": "nix2container", + "type": "github" + } + }, + "nix_2": { + "inputs": { + "flake-compat": [ + "devenv", + "cachix", + "devenv", + "flake-compat" + ], + "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression_2" + }, + "locked": { + "lastModified": 1712911606, + "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", + "owner": "domenkozar", + "repo": "nix", + "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "devenv-2.21", + "repo": "nix", + "type": "github" + } + }, + "nix_3": { + "inputs": { + "flake-compat": [ + "devenv", + "flake-compat" + ], + "flake-parts": "flake-parts", + "libgit2": "libgit2", + "nixpkgs": "nixpkgs_2", + "nixpkgs-23-11": "nixpkgs-23-11", + "nixpkgs-regression": "nixpkgs-regression_3", + "pre-commit-hooks": "pre-commit-hooks" + }, + "locked": { + "lastModified": 1727438425, + "narHash": "sha256-X8ES7I1cfNhR9oKp06F6ir4Np70WGZU5sfCOuNBEwMg=", + "owner": "domenkozar", + "repo": "nix", + "rev": "f6c5ae4c1b2e411e6b1e6a8181cc84363d6a7546", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "devenv-2.24", + "repo": "nix", + "type": "github" + } + }, + "nixgl": { + "inputs": { + "flake-utils": "flake-utils_4", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1713543440, + "narHash": "sha256-lnzZQYG0+EXl/6NkGpyIz+FEOc/DSEG57AP1VsdeNrM=", "owner": "guibou", "repo": "nixGL", - "rev": "489d6b095ab9d289fe11af0219a9ff00fe87c7c5", + "rev": "310f8e49a149e4c9ea52f1adf70cdc768ec53f8a", "type": "github" }, "original": { @@ -247,11 +527,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1678875422, - "narHash": "sha256-T3o6NcQPwXjxJMn2shz86Chch4ljXgZn746c2caGxd8=", + "lastModified": 1692808169, + "narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "126f49a01de5b7e35a43fd43f891ecf6d3a51459", + "rev": "9201b5ff357e781bf014d0330d18555695df7ba8", "type": "github" }, "original": { @@ -261,24 +541,34 @@ "type": "github" } }, - "nixpkgs-lib": { + "nixpkgs-23-11": { "locked": { - "dir": "lib", - "lastModified": 1698611440, - "narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=", + "lastModified": 1717159533, + "narHash": "sha256-oamiKNfr2MS6yH64rUn99mIZjc45nGJlj9eGth/3Xuw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735", + "rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446", "type": "github" }, "original": { - "dir": "lib", "owner": "NixOS", - "ref": "nixos-unstable", "repo": "nixpkgs", + "rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446", "type": "github" } }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1727825735, + "narHash": "sha256-0xHYkMkeLVQAMa7gvkddbPqpxph+hDzdu1XdGPJR+Os=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz" + } + }, "nixpkgs-regression": { "locked": { "lastModified": 1643052045, @@ -295,29 +585,77 @@ "type": "github" } }, - "nixpkgs-stable": { + "nixpkgs-regression_2": { "locked": { - "lastModified": 1685801374, - "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.05", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-regression_3": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1720386169, + "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", "repo": "nixpkgs", "type": "github" } }, "nixpkgs_2": { "locked": { - "lastModified": 1721562059, - "narHash": "sha256-Tybxt65eyOARf285hMHIJ2uul8SULjFZbT9ZaEeUnP8=", + "lastModified": 1717432640, + "narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "68c9ed8bbed9dfce253cc91560bf9043297ef2fe", + "rev": "88269ab3044128b7c2f4c7d68448b2fb50456870", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "release-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1729880355, + "narHash": "sha256-RP+OQ6koQQLX5nw0NmcDrzvGL8HDLnyXt/jHhL1jwjM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "18536bf04cd71abd345f9579158841376fdd0c5a", "type": "github" }, "original": { @@ -327,13 +665,75 @@ "type": "github" } }, + "poetry2nix": { + "inputs": { + "flake-utils": "flake-utils", + "nix-github-actions": "nix-github-actions", + "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "cachix", + "devenv", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1692876271, + "narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=", + "owner": "nix-community", + "repo": "poetry2nix", + "rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "poetry2nix", + "type": "github" + } + }, "pre-commit-hooks": { + "inputs": { + "flake-compat": [ + "devenv", + "nix" + ], + "flake-utils": "flake-utils_2", + "gitignore": [ + "devenv", + "nix" + ], + "nixpkgs": [ + "devenv", + "nix", + "nixpkgs" + ], + "nixpkgs-stable": [ + "devenv", + "nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712897695, + "narHash": "sha256-nMirxrGteNAl9sWiOhoN5tIHyjBbVi5e2tgZUgZlK3Y=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "40e6053ecb65fcbf12863338a6dcefb3f55f1bf8", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "pre-commit-hooks_2": { "inputs": { "flake-compat": [ "devenv", "flake-compat" ], - "flake-utils": "flake-utils", "gitignore": "gitignore", "nixpkgs": [ "devenv", @@ -342,11 +742,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1688056373, - "narHash": "sha256-2+SDlNRTKsgo3LBRiMUcoEUb6sDViRNQhzJquZ4koOI=", + "lastModified": 1726745158, + "narHash": "sha256-D5AegvGoEjt4rkKedmxlSEmC+nNLMBPWFxvmYnVLhjk=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "5843cf069272d92b60c3ed9e55b7a8989c01d4c7", + "rev": "4e743a6920eab45e8ba0fbe49dc459f1423a4b74", "type": "github" }, "original": { @@ -359,21 +759,21 @@ "inputs": { "devenv": "devenv", "fenix": "fenix", - "flake-parts": "flake-parts", + "flake-parts": "flake-parts_2", "mk-shell-bin": "mk-shell-bin", "nix2container": "nix2container", "nixgl": "nixgl", - "nixpkgs": "nixpkgs_2" + "nixpkgs": "nixpkgs_3" } }, "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1699629149, - "narHash": "sha256-oDxT2FTYLRnwBRgxgWMApbgvNsbsPV4EeH4TZtp70F0=", + "lastModified": 1730197931, + "narHash": "sha256-MjYc80pHGrD6TYMHHpXniCW0egVyHiDR23xAh7MN7Ww=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "11a87c917943dac5a568579f799c2d7458324103", + "rev": "468b5cd43023d9771996b06ab7215997895a6059", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 196673d8d..809182a6c 100644 --- a/flake.nix +++ b/flake.nix @@ -3,7 +3,10 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - devenv.url = "github:cachix/devenv"; + devenv = { + url = "github:cachix/devenv"; + inputs.nixpkgs.follows = "nixpkgs"; + }; nix2container = { url = "github:nlewo/nix2container"; inputs.nixpkgs.follows = "nixpkgs"; @@ -125,7 +128,7 @@ enable = true; toolchain = fenixpkgs.fromToolchainName { name = rust_toolchain.toolchain.channel; - sha256 = "sha256-Ngiz76YP4HTY75GGdH2P+APE/DEIx2R/Dn+BwwOyzZU="; + sha256 = "sha256-VZZnlyP69+Y3crrLHQyJirqlHrTtGTsyiSnZB8jEvVo="; }; components = rust_toolchain.toolchain.components; }; diff --git a/gradle.properties b/gradle.properties index 17c9dc12e..613dd4862 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,8 +13,8 @@ android.useAndroidX=true android.nonTransitiveRClass=true org.gradle.unsafe.configuration-cache=false -kotlinVersion=1.9.23 +kotlinVersion=2.0.20 spotlessVersion=6.25.0 -shadowJarVersion=8.1.1 -buildconfigVersion=5.3.5 +shadowJarVersion=8.3.2 +buildconfigVersion=5.5.0 grgitVersion=5.2.2 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bdc9a83b1..c44c2304c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gui/index.html b/gui/index.html index 3f55eac0f..8fe23023b 100644 --- a/gui/index.html +++ b/gui/index.html @@ -10,7 +10,7 @@ - React App + SlimeVR GUI diff --git a/gui/package.json b/gui/package.json index 1609e5467..aa08de84a 100644 --- a/gui/package.json +++ b/gui/package.json @@ -5,18 +5,18 @@ "dependencies": { "@fluent/bundle": "^0.18.0", "@fluent/react": "^0.15.2", - "@fontsource/poppins": "^5.0.14", + "@fontsource/poppins": "^5.1.0", "@formatjs/intl-localematcher": "^0.2.32", - "@react-three/drei": "^9.107.0", - "@react-three/fiber": "^8.16.8", - "@sentry/react": "^8.26.0", - "@sentry/vite-plugin": "^2.22.2", - "@tauri-apps/api": "2.0.0-beta.14", - "@tauri-apps/plugin-dialog": "2.0.0-beta.6", - "@tauri-apps/plugin-fs": "2.0.0-beta.6", - "@tauri-apps/plugin-os": "2.0.0-beta.6", - "@tauri-apps/plugin-shell": "2.0.0-beta.7", - "@tauri-apps/plugin-store": "2.0.0-beta.6", + "@react-three/drei": "^9.114.3", + "@react-three/fiber": "^8.17.10", + "@sentry/react": "^8.44.0", + "@sentry/vite-plugin": "^2.22.7", + "@tauri-apps/api": "^2.0.2", + "@tauri-apps/plugin-dialog": "^2.0.0", + "@tauri-apps/plugin-fs": "^2.0.0", + "@tauri-apps/plugin-os": "^2.0.0", + "@tauri-apps/plugin-shell": "^2.0.0", + "@tauri-apps/plugin-store": "^2.0.0", "browser-fs-access": "^0.35.0", "classnames": "^2.5.1", "flatbuffers": "22.10.26", @@ -27,15 +27,16 @@ "react-dom": "^18.3.1", "react-error-boundary": "^4.0.13", "react-helmet": "^6.1.0", - "react-hook-form": "^7.52.0", + "react-hook-form": "^7.53.0", "react-modal": "^3.16.1", "react-responsive": "^10.0.0", - "react-router-dom": "^6.23.1", - "semver": "^7.6.2", + "react-router-dom": "^6.26.2", + "semver": "^7.6.3", "solarxr-protocol": "file:../solarxr-protocol", "three": "^0.163.0", - "ts-pattern": "^5.2.0", - "typescript": "^5.4.5" + "ts-pattern": "^5.4.0", + "typescript": "^5.6.3", + "use-double-tap": "^1.3.6" }, "scripts": { "start": "vite --force", @@ -51,33 +52,33 @@ }, "devDependencies": { "@dword-design/eslint-plugin-import-alias": "^4.0.9", - "@tailwindcss/forms": "^0.5.7", - "@tauri-apps/cli": "2.0.0-beta.21", + "@tailwindcss/forms": "^0.5.9", + "@tauri-apps/cli": "^2.0.2", "@types/file-saver": "^2.0.7", - "@types/react": "^18.3.3", + "@types/react": "^18.3.11", "@types/react-dom": "^18.3.0", "@types/react-helmet": "^6.1.11", "@types/react-modal": "3.16.3", "@types/semver": "^7.5.8", "@types/three": "^0.163.0", - "@typescript-eslint/eslint-plugin": "^7.13.0", - "@typescript-eslint/parser": "^7.13.0", - "@vitejs/plugin-react": "^4.3.1", - "autoprefixer": "^10.4.19", + "@typescript-eslint/eslint-plugin": "^7.18.0", + "@typescript-eslint/parser": "^7.18.0", + "@vitejs/plugin-react": "^4.3.2", + "autoprefixer": "^10.4.20", "cross-env": "^7.0.3", - "eslint": "^8.57.0", + "eslint": "^8.57.1", "eslint-config-airbnb": "^19.0.4", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", - "eslint-plugin-react": "^7.34.2", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.1", "eslint-plugin-react-hooks": "^4.6.2", - "prettier": "^3.3.2", + "prettier": "^3.3.3", "rollup-plugin-visualizer": "^5.12.0", - "sass": "^1.77.5", + "sass": "^1.79.4", "spdx-satisfies": "^5.0.1", "tailwind-gradient-mask-image": "^1.2.0", - "tailwindcss": "^3.4.4", - "vite": "^5.3.1" + "tailwindcss": "^3.4.13", + "vite": "^5.4.8" } } diff --git a/gui/public/i18n/cs/translation.ftl b/gui/public/i18n/cs/translation.ftl index ffafc3b07..03723d27f 100644 --- a/gui/public/i18n/cs/translation.ftl +++ b/gui/public/i18n/cs/translation.ftl @@ -244,7 +244,7 @@ body_assignment_menu-unassign_tracker = Zrušit přiřazení trackeru -tracker_selection-part = { "Který tracker přiřadit k" } tracker_selection_menu-NONE = Který tracker chcete aby byl nezařazený? tracker_selection_menu-HEAD = { -tracker_selection-part } hlavě? -tracker_selection_menu-NECK = Který tracker přiřadit ke krku? +tracker_selection_menu-NECK = { -tracker_selection-part } krku? tracker_selection_menu-RIGHT_SHOULDER = { -tracker_selection-part } pravému rameni? tracker_selection_menu-RIGHT_UPPER_ARM = { -tracker_selection-part } pravýmu nadloktí? tracker_selection_menu-RIGHT_LOWER_ARM = { -tracker_selection-part } pravýmu podloktí? @@ -256,7 +256,7 @@ tracker_selection_menu-RIGHT_CONTROLLER = { -tracker_selection-part } pravému o tracker_selection_menu-UPPER_CHEST = { -tracker_selection-part } k horní část hrudníku? tracker_selection_menu-CHEST = { -tracker_selection-part } hrudníku? tracker_selection_menu-WAIST = { -tracker_selection-part } pasu? -tracker_selection_menu-HIP = Který tracker přiřadit ke kyčli? +tracker_selection_menu-HIP = { -tracker_selection-part } kyčle? tracker_selection_menu-LEFT_SHOULDER = { -tracker_selection-part } levému rameni? tracker_selection_menu-LEFT_UPPER_ARM = { -tracker_selection-part } levýmu nadloktí? tracker_selection_menu-LEFT_LOWER_ARM = { -tracker_selection-part } levýmu podloktí? @@ -492,15 +492,10 @@ settings-osc-router-network-address-placeholder = Adresa IPV4 ## OSC VRChat settings settings-osc-vrchat = Trackery VRChat OSC -# This cares about multilines -settings-osc-vrchat-description = - Úprava nastavení specifických pro VRChat pro příjem dat HMD a odesílání - data trackerů pro FBT (funguje na samostatném Questu). settings-osc-vrchat-enable = Zapnout settings-osc-vrchat-enable-description = Vypnutí a zapnutí odesílání a přijímání dat. settings-osc-vrchat-enable-label = Zapnout settings-osc-vrchat-network = Síťové porty -settings-osc-vrchat-network-description = Nastavení portů pro naslouchání a odesílání dat do VRChat. settings-osc-vrchat-network-port_in = .label = Vstup portu .placeholder = Vstup portu (výchozí: 9001) @@ -508,7 +503,6 @@ settings-osc-vrchat-network-port_out = .label = Výstup portu .placeholder = Výstup portu (výchozí: 9000) settings-osc-vrchat-network-address = Síťová adresa -settings-osc-vrchat-network-address-description = Zvolte adresu, ze které se mají odesílat data na VRChat (zkontrolujte nastavení Wi-Fi v zařízení). settings-osc-vrchat-network-address-placeholder = VRChat ip adresa settings-osc-vrchat-network-trackers = Trackery settings-osc-vrchat-network-trackers-description = Vypnuti a zapnutí odesílání konkrétních trackerů přes OSC. @@ -702,12 +696,8 @@ onboarding-choose_mounting = Jakou metodu nasazení trackerů použít? # Multiline text onboarding-choose_mounting-description = Správná orientace nasazení zajistí přesné sledování trackerů na těle. onboarding-choose_mounting-auto_mounting = Automatická detekce nasazení -# Italized text -onboarding-choose_mounting-auto_mounting-label = Experimentální onboarding-choose_mounting-auto_mounting-description = Orientace nasazení všech trackerů bude automaticky rozpoznána ze 2 pozic. onboarding-choose_mounting-manual_mounting = Manuální nastavení -# Italized text -onboarding-choose_mounting-manual_mounting-label = Doporučeno onboarding-choose_mounting-manual_mounting-description = Ručně zadejte orientaci nasazení každého trackeru. # Multiline text onboarding-choose_mounting-manual_modal-title = diff --git a/gui/public/i18n/de/translation.ftl b/gui/public/i18n/de/translation.ftl index b13eef199..e4a6a8ed6 100644 --- a/gui/public/i18n/de/translation.ftl +++ b/gui/public/i18n/de/translation.ftl @@ -13,7 +13,7 @@ websocket-connection_lost = Verbindung zum Server verloren. Versuche Verbindung ## Update notification version_update-title = Neue Version verfügbar: { $version } -version_update-description = Wenn Sie auf "Aktualisieren" klicken, wird der SlimeVR-Installationsassistent für dich heruntergeladen. +version_update-description = Wenn Sie auf "{ version_update-update }" klicken, wird das SlimeVR-Installationsprogramm heruntergeladen. version_update-update = Aktualisieren version_update-close = Schließen @@ -36,7 +36,7 @@ body_part-RIGHT_UPPER_ARM = Rechter Oberarm body_part-RIGHT_LOWER_ARM = Rechter Unterarm body_part-RIGHT_HAND = Rechte Hand body_part-RIGHT_UPPER_LEG = Rechter Oberschenkel -body_part-RIGHT_LOWER_LEG = Rechter Unterschenkel +body_part-RIGHT_LOWER_LEG = Rechter Knöchel body_part-RIGHT_FOOT = Rechter Fuß body_part-UPPER_CHEST = Obere Brust body_part-CHEST = Brust @@ -47,7 +47,7 @@ body_part-LEFT_UPPER_ARM = Linker Oberarm body_part-LEFT_LOWER_ARM = Linker Unterarm body_part-LEFT_HAND = Linke Hand body_part-LEFT_UPPER_LEG = Linker Oberschenkel -body_part-LEFT_LOWER_LEG = Linker Unterschenkel +body_part-LEFT_LOWER_LEG = Linker Knöchel body_part-LEFT_FOOT = Linker Fuß ## Proportions @@ -81,6 +81,11 @@ skeleton_bone-ELBOW_OFFSET = Ellbogenversatz ## Tracker reset buttons reset-reset_all = Alle Proportionen zurücksetzen +reset-reset_all_warning = + Achtung: Die Proportionen werden zurückgesetzt und auf Basis ihrer Körpergröße neu berechnet. + Sind sie sich sicher? +reset-reset_all_warning-reset = Proportionen zurücksetzen +reset-reset_all_warning-cancel = Abbrechen reset-full = Reset reset-mounting = Befestigungs-Reset reset-yaw = Horizontaler Reset @@ -142,9 +147,12 @@ widget-developer_mode-more_info = Mehr Infos ## Widget: IMU Visualizer widget-imu_visualizer = Drehung +widget-imu_visualizer-preview = Vorschau +widget-imu_visualizer-hide = Ausblenden widget-imu_visualizer-rotation_raw = Rohe Drehung widget-imu_visualizer-rotation_preview = Vorschau -widget-imu_visualizer-rotation_hide = Ausblenden +widget-imu_visualizer-acceleration = Beschleunigung +widget-imu_visualizer-position = Position ## Widget: Skeleton Visualizer @@ -199,6 +207,13 @@ tracker-infos-hardware_identifier = Hardware-ID tracker-infos-imu = IMU-Sensor tracker-infos-board_type = Platine tracker-infos-network_version = Protokoll Version +tracker-infos-magnetometer = Magnetometer +tracker-infos-magnetometer-status-v1 = + { $status -> + [DISABLED] Ausgeschalten + [ENABLED] Angeschalten + *[NOT_SUPPORTED] Nicht unterstützt + } ## Tracker settings @@ -213,11 +228,19 @@ tracker-settings-mounting_section-edit = Befestigung bearbeiten tracker-settings-drift_compensation_section = Drift-Kompensierung tracker-settings-drift_compensation_section-description = Soll dieser Tracker Drift kompensieren, wenn die Drift-Kompensierung allgemein aktiviert ist? tracker-settings-drift_compensation_section-edit = Erlaube Drift Kompensierung +tracker-settings-use_mag = Magnetometer auf diesem Tracker zulassen +# Multiline! +tracker-settings-use_mag-description = + Soll dieser Tracker das Magnetometer verwenden um Drift zu reduzieren, wenn die Verwendung von Magnetometer erlaubt ist? Bitten schalten Sie den Tracker nicht aus, während Sie diese Einstellung umschalten! + + Sie müssen zuerst die Verwendung des Magnetometers zulassen, klicken Sie hier, um zu den Einstellungen zu gelangen. +tracker-settings-use_mag-label = Magnetometer zulassen # The . means it's an attribute and it's related to the top key. # In this case that is the settings for the assignment section. tracker-settings-name_section = Trackername tracker-settings-name_section-description = Geben Sie ihm einen süßen Spitznamen :) tracker-settings-name_section-placeholder = NightyBeast's linkes Bein +tracker-settings-name_section-label = Trackername tracker-settings-forget = Tracker Vergessen tracker-settings-forget-description = Entfernt den Tracker vom SlimeVR Server und verhindert, dass er sich wieder verbindet, bis der Server neu gestartet wurde. Die Konfiguration des Trackers geht nicht verloren. tracker-settings-forget-label = Tracker Vergessen @@ -296,6 +319,7 @@ settings-sidebar-utils = Werkzeuge settings-sidebar-serial = Serielle Konsole settings-sidebar-appearance = Erscheinungsbild settings-sidebar-notifications = Benachrichtigungen +settings-sidebar-advanced = Erweitert ## SteamVR settings @@ -350,6 +374,20 @@ settings-general-tracker_mechanics-drift_compensation-description = Kompensiert IMU Drift auf der Gier-Achse durch Anwenden einer invertierten Rotation. Ändern Sie die Menge der Kompensierung und die Anzahl der Resets, welche für die Berechnung genutzt werden. settings-general-tracker_mechanics-drift_compensation-enabled-label = Drift-Kompensierung +settings-general-tracker_mechanics-drift_compensation-prediction = Prognose der Driftkompensation +# This cares about multilines +settings-general-tracker_mechanics-drift_compensation-prediction-description = + Prognostiziert die Driftkompensation basierend auf dem zuvor gemessenen Drift. + Aktivieren Sie diese Funktion, wenn sich der Tracker kontinuierlich um die gier-Achse dreht. +settings-general-tracker_mechanics-drift_compensation-prediction-label = Prognose der Driftkompensation +settings-general-tracker_mechanics-drift_compensation_warning = + Warnung: Verwenden Sie die Driftkompensation nur, wenn sie sehr oft + reseten müssen (alle ~5-10 Minuten). + + Zu den IMUs, die häufig einen Reset benötigen, gehören: + Joy-Cons, owoTrack und MPUs (ohne aktuelle Firmware). +settings-general-tracker_mechanics-drift_compensation_warning-cancel = Abbrechen +settings-general-tracker_mechanics-drift_compensation_warning-done = Ich verstehe settings-general-tracker_mechanics-drift_compensation-amount-label = Kompensierungsmenge settings-general-tracker_mechanics-drift_compensation-max_resets-label = Nutze die letzten x Resets settings-general-tracker_mechanics-save_mounting_reset = Automatische Befestigungs-Reset Kalibrierung speichern @@ -357,6 +395,11 @@ settings-general-tracker_mechanics-save_mounting_reset-description = Speichert die automatische Befestigungs-Reset Kalibrierung für die Tracker zwischen den Neustarts. Nützlich wenn Sie einen Anzug tragen, bei dem sich die Tracker zwischen den Sitzungen nicht bewegen. Für normale Benutzer nicht zu empfehlen! settings-general-tracker_mechanics-save_mounting_reset-enabled-label = Befestigungs-Reset speichern +settings-general-tracker_mechanics-use_mag_on_all_trackers = Verwende das Magnetometer auf allen IMU-Trackern, die dies unterstützen. +settings-general-tracker_mechanics-use_mag_on_all_trackers-description = + Verwendet das Magnetometer auf allen Trackern, die über eine kompatible Firmware verfügen, um den Drift in stabilen magnetischen Umgebungen zu reduzieren. + Kann pro Tracker in den Einstellungen des Trackers deaktiviert werden. Bitte schalten Sie keinen der Tracker aus, während Sie dies umschalten! +settings-general-tracker_mechanics-use_mag_on_all_trackers-label = Magnetometer auf Trackern verwenden ## FK/Tracking settings @@ -383,6 +426,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Fußausrichtung zurüc settings-general-fk_settings-arm_fk = Arm-Tracking settings-general-fk_settings-arm_fk-description = Ändern Sie die Art und Weise, wie die Arme berechnet werden. settings-general-fk_settings-arm_fk-force_arms = Arme vom VR-Headset erzwingen +settings-general-fk_settings-reset_settings = Einstellungen zurücksetzen +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Setzen Sie die Neigung (vertikale Drehung) Ihres Headsets zurück, wenn Sie einen vollständigen Reset durchführen. Nützlich, wenn Sie ein Headset auf der Stirn für VTubing oder Mocap tragen. Nicht für VR aktivieren. +settings-general-fk_settings-reset_settings-reset_hmd_pitch = Headset-Nick (vertikale Drehung) zurücksetzen settings-general-fk_settings-arm_fk-reset_mode-description = Ändern Sie, welche Armhaltung für den Befestigungs-Reset erwartet wird. settings-general-fk_settings-arm_fk-back = nach Hinten settings-general-fk_settings-arm_fk-back-description = Der Standardmodus, bei dem die Oberarme nach hinten und die Unterarme nach vorne gehen. @@ -451,6 +497,9 @@ settings-general-interface-dev_mode = Entwicklermodus settings-general-interface-dev_mode-description = Der Entwicklermodus stellt mehr Daten dar und erlaubt auch erweiterte Einstellungen, so wie erweiterte Optionen bei verbundenen Trackern. settings-general-interface-dev_mode-label = Entwicklermodus settings-general-interface-theme = Farbschema +settings-general-interface-show-navbar-onboarding = "{ navbar-onboarding }" in der Navigationsleiste anzeigen +settings-general-interface-show-navbar-onboarding-description = Dies ändert die Sichtbarkeit der Schaltfläche "{ navbar-onboarding }" in der Navigationsleiste +settings-general-interface-show-navbar-onboarding-label = Zeige "{ navbar-onboarding }" settings-general-interface-lang = Sprachauswahl settings-general-interface-lang-description = Ändern Sie die Standard-Sprache, die Sie verwenden möchten settings-general-interface-lang-placeholder = Wählen Sie die zu verwendende Sprache aus @@ -462,6 +511,9 @@ settings-interface-appearance-font-os_font = Betriebssystem-Schriftart settings-interface-appearance-font-slime_font = Standard-Schriftart settings-interface-appearance-font_size = Standard-Schriftgröße settings-interface-appearance-font_size-description = Verändert die Schriftgröße der gesamten Oberfläche außer diesem Einstellungs-Panel. +settings-interface-appearance-decorations = Verwenden Sie die systemeigenen Fensterdekorationen +settings-interface-appearance-decorations-description = Dadurch wird die obere Leiste der Benutzeroberfläche nicht gerendert, sondern die des Betriebssystems verwendet. +settings-interface-appearance-decorations-label = Verwenden der native Fensterdekorationen ## Notification settings @@ -479,6 +531,15 @@ settings-general-interface-connected_trackers_warning-label = Warnung vor verbun settings-general-interface-use_tray = In den Infobereich minimieren settings-general-interface-use_tray-description = Erlaubt Ihnen, das Fenster zu schließen, ohne den SlimeVR-Server zu beenden. Dies erlaubt Ihnen diesen weiterzuverwenden, ohne dass das Fenster stört. settings-general-interface-use_tray-label = In den Infobereich minimieren +settings-general-interface-discord_presence = Aktivität auf Discord teilen +settings-general-interface-discord_presence-description = Teilt Ihrem Discord-Client mit, dass Sie SlimeVR verwenden, zusammen mit der Anzahl der IMU-Tracker, die Sie benutzen. +settings-general-interface-discord_presence-label = Aktivität auf Discord teilen +settings-general-interface-discord_presence-message = + { $amount -> + [0] Sliming around + [one] nutzt 1 Tracker + *[other] nutzt { $amount } Tracker + } ## Serial settings @@ -501,6 +562,8 @@ settings-serial-get_infos = Informationen abrufen settings-serial-serial_select = Wählen Sie einen seriellen Anschluss settings-serial-auto_dropdown_item = Auto settings-serial-get_wifi_scan = WLAN-Scan +settings-serial-file_type = Klartext +settings-serial-save_logs = In Datei speichern ## OSC router settings @@ -531,12 +594,16 @@ settings-osc-router-network-address-placeholder = IPv4 Adresse settings-osc-vrchat = VRChat-OSC-Trackers # This cares about multilines -settings-osc-vrchat-description = Ändern Sie VRChat-spezifische Einstellungen, um Headset- und Tracker-Daten für FBT zu empfangen und zu senden (funktioniert auch im Standalone-Modus auf der Meta Quest). +settings-osc-vrchat-description-v1 = + Ändern Sie die Einstellungen, die speziell für den OSC-Trackers-Standard verwendet werden, um Tracking-Daten an Anwendungen ohne SteamVR zu senden (z. B. für Quest Standalone). + Stellen Sie sicher, dass Sie OSC in VRChat über das Aktionsmenü unter OSC > Aktiviert einschalten. + Um das Empfangen von HMD- und Controller-Daten von VRChat zu ermöglichen, gehen Sie in Ihrem Hauptmenü + zu den Einstellungen unter Tracking & IK > Erlaube das Senden von Kopf- und Handgelenk-VR-Tracking-OSC-Daten. settings-osc-vrchat-enable = Aktivieren settings-osc-vrchat-enable-description = Ein- und Ausschalten des Sendens und Empfangen von Daten settings-osc-vrchat-enable-label = Aktivieren settings-osc-vrchat-network = Netzwerk-Ports -settings-osc-vrchat-network-description = Festlegen der Ports zum Empfangen und Senden von Daten an VRChat +settings-osc-vrchat-network-description-v1 = Legt die Ports für das Empfangen und Senden von Daten fest. Kann für VRChat unverändert bleiben. settings-osc-vrchat-network-port_in = .label = Eingangsport .placeholder = Eingangsport (Standard: 9001) @@ -544,7 +611,7 @@ settings-osc-vrchat-network-port_out = .label = Ausgangsport .placeholder = Ausgangsport (Standard: 9000) settings-osc-vrchat-network-address = Netzwerkadresse -settings-osc-vrchat-network-address-description = Wählen Sie, an welche Adresse die Daten an VRChat gesendet werden sollen (überprüfen Sie Ihre WLAN-Einstellungen auf Ihrem Gerät) +settings-osc-vrchat-network-address-description-v1 = Wählen Sie die IP-Adresse, an die die Daten gesendet werden sollen. Kann für VRChat unverändert bleiben. settings-osc-vrchat-network-address-placeholder = VRChat-IP-Adresse settings-osc-vrchat-network-trackers = Tracker settings-osc-vrchat-network-trackers-description = Ein- und Ausschalten des Sendens und Empfangens von Daten @@ -585,6 +652,39 @@ settings-osc-vmc-vrm-file_select = Modell per Drag & Drop laden oder durchsuc settings-osc-vmc-anchor_hip = Hüftenverankerung settings-osc-vmc-anchor_hip-description = Die Hüften-Verankerung für das Tracking ist nützlich für VTubing im Sitzen. Beim Deaktivieren muss ein VRM-Model geladen werden. settings-osc-vmc-anchor_hip-label = Hüftenverankerung +settings-osc-vmc-mirror_tracking = Tracking spiegeln +settings-osc-vmc-mirror_tracking-description = Tracking horizontal spiegeln +settings-osc-vmc-mirror_tracking-label = Tracking spiegeln + +## Advanced settings + +settings-utils-advanced = Erweitert +settings-utils-advanced-reset-gui = Einstellungen der Benutzeroberfläche zurücksetzen +settings-utils-advanced-reset-gui-description = Stellt die Standardeinstellungen für die Benutzeroberfläche wieder her. +settings-utils-advanced-reset-gui-label = Benutzeroberfläche zurücksetzen +settings-utils-advanced-reset-server = Tracking-Einstellungen zurücksetzen +settings-utils-advanced-reset-server-description = Stellen Sie die Standardeinstellungen für das Tracking wieder her. +settings-utils-advanced-reset-server-label = Tracking zurücksetzen +settings-utils-advanced-reset-all = Alle Einstellungen zurücksetzen +settings-utils-advanced-reset-all-description = Stellt die Standardeinstellungen für die Benutzeroberfläche und das Tracking wieder her. +settings-utils-advanced-reset-all-label = Alles zurücksetzen +settings-utils-advanced-reset_warning = + { $type -> + [gui] + Warnung: Dadurch werden Ihre Benutzeroberfläche-Einstellungen auf die Standardeinstellungen zurückgesetzt. + Möchten Sie das wirklich tun? + [server] + Warnung: Dadurch werden Ihre Tracking-Einstellungen auf die Standardeinstellungen zurückgesetzt. + Möchten Sie das wirklich tun? + *[all] + Warnung: Dadurch werden alle Ihre Einstellungen auf die Standardeinstellungen zurückgesetzt. + Möchten Sie das wirklich tun? + } +settings-utils-advanced-reset_warning-reset = Einstellungen zurücksetzen +settings-utils-advanced-reset_warning-cancel = Abbrechen +settings-utils-advanced-open_data = Daten-Ordner +settings-utils-advanced-open_data-description = Öffnet den Daten-Ordner von SlimeVR im Explorer, der Konfigurations- und Protokolldateien enthält. +settings-utils-advanced-open_data-label = Ordner öffnen ## Setup/onboarding menu @@ -696,6 +796,7 @@ onboarding-calibration_tutorial-status-waiting = Wir warten auf Sie onboarding-calibration_tutorial-status-calibrating = Kalibriere onboarding-calibration_tutorial-status-success = Gut! onboarding-calibration_tutorial-status-error = Der Tracker wurde bewegt +onboarding-calibration_tutorial-skip = Tutorial überspringen ## Tracker assignment tutorial @@ -723,6 +824,27 @@ onboarding-assign_trackers-assigned = onboarding-assign_trackers-advanced = Erweiterte Zuweisungspositionen anzeigen onboarding-assign_trackers-next = Ich habe alle Tracker zugewiesen onboarding-assign_trackers-mirror_view = Ansicht spiegeln +onboarding-assign_trackers-option-amount = + { $trackersCount -> + [one] x{ $trackersCount } + *[other] x{ $trackersCount } + } +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] Lower-Body Set + [core] Core Set + [enhanced-core] Enhanced Core Set + [full-body] Full-Body Set + *[all] Alle Tracker + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] Minimum für VR Full-Body Tracking + [core] + Erweitertes Rücken-Tracking + [enhanced-core] + Fuß-Rotation + [full-body] + Ellbogen-Tracking + *[all] Alle verfügbaren Tracker-Zuweisungen + } ## Tracker assignment warnings @@ -798,12 +920,12 @@ onboarding-choose_mounting = Welche Kalibrierungsmethode ist zu verwenden? # Multiline text onboarding-choose_mounting-description = Die Montageausrichtung korrigiert die Platzierung von Trackern am Körper. onboarding-choose_mounting-auto_mounting = Befestigung automatisch ermitteln -# Italized text -onboarding-choose_mounting-auto_mounting-label = Experimentell +# Italicized text +onboarding-choose_mounting-auto_mounting-label-v2 = Empfohlen onboarding-choose_mounting-auto_mounting-description = Dadurch werden die Befestigungsausrichtungen für alle Ihrer Tracker automatisch aus 2 Posen erkannt onboarding-choose_mounting-manual_mounting = Manuelle Befestigungsposition -# Italized text -onboarding-choose_mounting-manual_mounting-label = Empfohlen +# Italicized text +onboarding-choose_mounting-manual_mounting-label-v2 = Möglicherweise nicht präzise genug onboarding-choose_mounting-manual_mounting-description = Auf diese Weise können Sie die Montagerichtung für jeden Tracker manuell auswählen # Multiline text onboarding-choose_mounting-manual_modal-title = @@ -850,14 +972,14 @@ onboarding-choose_proportions-description-v1 = Wenn die Proportionen Ihres Körpers nicht mit den Gespeicherten übereinstimmen, ist die Präzision des Trackings schlechter. Außerdem können Probleme wie Skaten oder Rutschen auftreten oder, dass die Bewegungen Ihres Avatars nicht gut mit den Bewegungen Ihres Körpers übereinstimmen. Sie müssen Ihren Körper nur einmal messen! Es sei denn, die Messwerte sind falsch oder Ihr Körper hat sich verändert, dann müssen Sie die Körperproportionen nochmal bestimmen. onboarding-choose_proportions-auto_proportions = Automatische Proportionen -# Italized text +# Italicized text onboarding-choose_proportions-auto_proportions-subtitle = Empfohlen onboarding-choose_proportions-auto_proportions-descriptionv3 = Dies wird versuchen, Ihre Proportionen mit Hilfe einer Bewegungsaufnahme zu bestimmen, welche von einem Algorithmus verarbeitet wird. Dazu muss Ihr Headset (HMD) mit SlimeVR verbunden sein und Sie müssen es an haben! onboarding-choose_proportions-manual_proportions = Manuelle Körperproportionen -# Italized text +# Italicized text onboarding-choose_proportions-manual_proportions-subtitle = Für kleine Anpassungen onboarding-choose_proportions-manual_proportions-description = Auf diese Weise können Sie Ihre Proportionen manuell anpassen, indem Sie diese direkt ändern onboarding-choose_proportions-export = Proportionen exportieren @@ -907,7 +1029,7 @@ onboarding-automatic_proportions-check_height-hmd_height1 = Ihre Headset-Höhe i onboarding-automatic_proportions-check_height-height1 = Ihre tatsächliche Körpergröße ist onboarding-automatic_proportions-check_height-next_step = Werte sind korrekt onboarding-automatic_proportions-start_recording-title = Bereiten Sie sich auf ein paar Bewegungen vor -onboarding-automatic_proportions-start_recording-description = Wir werden nun einige bestimmte Posen und Bewegungen aufnehmen. Diese werden im nächsten Bildschirm angezeigt. Bereiten Sie sicht darauf vor, wenn Sie den Knopf drücken! +onboarding-automatic_proportions-start_recording-description = Wir werden nun einige bestimmte Posen und Bewegungen aufnehmen. Diese werden im nächsten Schritt angezeigt. Sei bereit damit zu beginnen, wenn du auf den Knopf drückst! onboarding-automatic_proportions-start_recording-next = Aufnahme starten onboarding-automatic_proportions-recording-title = Aufnahme onboarding-automatic_proportions-recording-description-p0 = Aufnahme läuft... @@ -935,9 +1057,10 @@ onboarding-automatic_proportions-verify_results-redo = Aufnahme wiederholen onboarding-automatic_proportions-verify_results-confirm = Ergebnisse sind korrekt onboarding-automatic_proportions-done-title = Körper gemessen und gespeichert. onboarding-automatic_proportions-done-description = Ihre Körperproportionen-Kalibrierung ist abgeschlossen! -onboarding-automatic_proportions-error_modal = - Warnung: Beim Schätzen der Proportionen wurde ein Fehler festgestellt! - Bitte prüfen Sie die Dokumentation oder treten sie unserem Discord Server bei, um Hilfe zu bekommen. ^_^ +onboarding-automatic_proportions-error_modal-v2 = + Warnung: Bei der Schätzung der Proportionen ist ein Fehler aufgetreten! + Dies ist wahrscheinlich ein Problem mit der Tracker-Ausrichtung. Vergewissern Sie sich, dass Ihre Tracker ordnungsgemäß funktioniert, bevor Sie es erneut versuchen. + Bitte überprüfen Sie die Dokumentation oder treten Sie unserem Discord bei, um Hilfe zu erhalten ^_^ onboarding-automatic_proportions-error_modal-confirm = Verstanden! ## Home @@ -962,6 +1085,7 @@ status_system-StatusSteamVRDisconnected = *[other] Derzeit nicht über den SlimeVR-Treiber mit SteamVR verbunden. } status_system-StatusTrackerError = Der Tracker "{ $trackerName }" weist einen Fehler auf. +status_system-StatusUnassignedHMD = Das VR-Headset sollte als Kopf-Tracker zugewiesen sein. ## Tray Menu diff --git a/gui/public/i18n/en-x-owo/translation.ftl b/gui/public/i18n/en-x-owo/translation.ftl index ba39c8047..712fe0746 100644 --- a/gui/public/i18n/en-x-owo/translation.ftl +++ b/gui/public/i18n/en-x-owo/translation.ftl @@ -23,6 +23,8 @@ tips-find_tracker = nawt suwe whicsh twayckyaw is whicsh? shayke a twackaw and i tips-do_not_move_heels = ensuwe yoowr pawsies do nawt mowve duwing wecowding! ^w^ tips-file_select = dwag & dwop fiwes to use OwO, ow bwowse. tips-tap_setup = u can swowly tap youw twackew 2 times to choose it insted of sewecting it fwom the menyu. +tips-turn_on_tracker = erm.. are u using offishal SlaiemVR twackews??! rember to tuwn on yuor twackew aftwew coneccting it to teh PC! +tips-failed_webgl = oh nooooo :( faiwled to initiawizwe WebGL... ## Body parts @@ -196,6 +198,7 @@ tracker-infos-hardware_rev = hawdwawe revision tracker-infos-hardware_identifier = hawdwawe id tracker-infos-imu = imu sensow tracker-infos-board_type = mane bored +tracker-infos-network_version = pwotocol vewsiowon ## Tracker settings @@ -215,6 +218,9 @@ tracker-settings-drift_compensation_section-edit = awwow dwift compensation tracker-settings-name_section = twackaw name tracker-settings-name_section-description = owo whats dis? tracker-settings-name_section-placeholder = ewimewl's weft pawb +tracker-settings-forget = *forgors the tracker* +tracker-settings-forget-description = remooves teh twackew fwom da SwimeVR sewvew n pwevent it frum conecting to it til fhe sewvew iz westawtied. the cowonfigyuwatsin of da twackew woant b wost. +tracker-settings-forget-label = *forgors the tracker* ## Tracker part card info @@ -304,10 +310,22 @@ settings-general-steamvr-description = usefuw if yew want mowwe contwoww owew what swimevr does. settings-general-steamvr-trackers-waist = wyayst~ settings-general-steamvr-trackers-chest = chwest~ -settings-general-steamvr-trackers-feet = pweets~ -settings-general-steamvr-trackers-knees = knyees~ -settings-general-steamvr-trackers-elbows = ewbows~ -settings-general-steamvr-trackers-hands = pawbsies~ +settings-general-steamvr-trackers-left_foot = weft lower pawb +settings-general-steamvr-trackers-right_foot = wight lower pawb +settings-general-steamvr-trackers-left_knee = weft knee +settings-general-steamvr-trackers-right_knee = wight knee +settings-general-steamvr-trackers-left_elbow = weft elbow +settings-general-steamvr-trackers-right_elbow = wight elbow +settings-general-steamvr-trackers-left_hand = weft upper pawb +settings-general-steamvr-trackers-right_hand = wight upper pawb +settings-general-steamvr-trackers-tracker_toggling = awtomawtic twackaws assigwment +settings-general-steamvr-trackers-tracker_toggling-description = aUwUtomaticawwy handels tawggling SteemVR twackews on oar off depening on yoar cuwwent twackew assaingmentz +settings-general-steamvr-trackers-tracker_toggling-label = awtomawtic twackaws assigwment +settings-general-steamvr-trackers-hands-warning = + OwOarning: paw twackows wiww owovewwide youw contwowworz. + r u sure?? +settings-general-steamvr-trackers-hands-warning-cancel = cancew :o +settings-general-steamvr-trackers-hands-warning-done = yes!! ## Tracker mechanics @@ -325,6 +343,7 @@ settings-general-tracker_mechanics-filtering-type-smoothing-description = smowth settings-general-tracker_mechanics-filtering-type-prediction = pwediction~ settings-general-tracker_mechanics-filtering-type-prediction-description = wowduces wowcyancy and makes wowvements mowe wowappy, but may incwease jiwitty settings-general-tracker_mechanics-filtering-amount = amownt +settings-general-tracker_mechanics-yaw-reset-smooth-time = nyaw weset smootse taim (0s disaeblez smooting) settings-general-tracker_mechanics-drift_compensation = dwift compensation # This cares about multilines settings-general-tracker_mechanics-drift_compensation-description = @@ -333,6 +352,11 @@ settings-general-tracker_mechanics-drift_compensation-description = settings-general-tracker_mechanics-drift_compensation-enabled-label = dwift compensation settings-general-tracker_mechanics-drift_compensation-amount-label = compensation amownt settings-general-tracker_mechanics-drift_compensation-max_resets-label = nuwmbew of wesets uwsed +settings-general-tracker_mechanics-save_mounting_reset = saiv awtomatic meownting weset calibwaytion +settings-general-tracker_mechanics-save_mounting_reset-description = + saves the auwtoemyatic meownting weset cawybwationz for da twackews betwean westawts. useful + wen weawing a sUwUit whewe twackews dont move between sesshuns. nawt wecomended for noarmal UwUsews! +settings-general-tracker_mechanics-save_mounting_reset-enabled-label = save meownting weset ## FK/Tracking settings @@ -359,6 +383,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Pawb Meownting Weset settings-general-fk_settings-arm_fk = awm twacking settings-general-fk_settings-arm_fk-description = chawnge teh way teh awms awe twacked. settings-general-fk_settings-arm_fk-force_arms = fowce awms fwom hmd +settings-general-fk_settings-reset_settings = weset setings +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = weset da HMD's pitch (vewticaw wowtaytion) upawn doin a fuww weset. uwusefuw if weaewing an HMD on da foawrhed fow VTuwubing ow mocap. do nyat enaebwew fow VR. +settings-general-fk_settings-reset_settings-reset_hmd_pitch = weset HMD pitch settings-general-fk_settings-arm_fk-reset_mode-description = Change which awm pose is expected fow meownting weset. settings-general-fk_settings-arm_fk-back = bak settings-general-fk_settings-arm_fk-back-description = The defauwt mode, wit da uppew awms going back and wowew awms going fowwawd. @@ -452,6 +479,18 @@ settings-general-interface-feedback_sound-volume = feedback sownd volyume settings-general-interface-connected_trackers_warning = Connected twackews wawning settings-general-interface-connected_trackers_warning-description = This option wiww show a pop-up evewy time you twy exiting SwimeVR whiwe having one ow mowe connected twackews. It weminds you to tuwn off youw twackews when you awe done to pwesewve battewy wife. settings-general-interface-connected_trackers_warning-label = Connected twackews wawning on exit +settings-general-interface-use_tray = minimaize to systewm tway +settings-general-interface-use_tray-description = wets u cwose the wimdOwOw wifhout cwosing da SwimeVR Sewvew so uou can keep using it withowt da GUI bohtewing u. +settings-general-interface-use_tray-label = minimaize to systewm tway +settings-general-interface-discord_presence = shaer activitey on discowd +settings-general-interface-discord_presence-description = tewws ur discoard cwient dat ur using SlyimeVR awong wif teh nuhmbew of IMU twackewrz u r using. +settings-general-interface-discord_presence-label = shaer activitey on discowd +settings-general-interface-discord_presence-message = + { $amount -> + [0] slimin awaound :3 + [one] using 1 twackew + *[other] using { $amount } twackewz + } ## Serial settings @@ -473,6 +512,9 @@ settings-serial-factory_reset-warning-cancel = cancew settings-serial-get_infos = get infows settings-serial-serial_select = sewect a shewyaw pawt settings-serial-auto_dropdown_item = awto +settings-serial-get_wifi_scan = get wifi scan uwu +settings-serial-file_type = plane text +settings-serial-save_logs = saeve to file ## OSC router settings @@ -502,15 +544,11 @@ settings-osc-router-network-address-placeholder = IPV4 addwess ## OSC VRChat settings settings-osc-vrchat = VRChawt OSC Twayckaws -# This cares about multilines -settings-osc-vrchat-description = - change vwchat-specific settwings to wweceive hmd data awnd send - twayckaws data fow fbt (wawwks on quest standalone). settings-osc-vrchat-enable = enaybwe settings-osc-vrchat-enable-description = toggle teh sending awnd wweceiving of data settings-osc-vrchat-enable-label = enaybwe settings-osc-vrchat-network = newtwowk pawts -settings-osc-vrchat-network-description = set the pawts fow wistening awnd sending data to vwchawt +settings-osc-vrchat-network-description-v1 = set da powrts fow wistening and sending data. can b left untouwched fow vrawrchat settings-osc-vrchat-network-port_in = .label = pawt in .placeholder = pawt in (defawwt: 9001) @@ -518,7 +556,6 @@ settings-osc-vrchat-network-port_out = .label = pawt out .placeholder = pawt out (defawwt: 9000) settings-osc-vrchat-network-address = network addwess -settings-osc-vrchat-network-address-description = choose which addwess to send out data to vwchat (check yuw wi-fi settwings on yuw device) settings-osc-vrchat-network-address-placeholder = vwchat ip addwess settings-osc-vrchat-network-trackers = trayckawws settings-osc-vrchat-network-trackers-description = toggle teh sending of spweciwic twackers viwa OSC @@ -561,6 +598,9 @@ settings-osc-vmc-vrm-file_select = dwag & dwop a modew to use OwO, ow bwowse< settings-osc-vmc-anchor_hip = anchow at hips settings-osc-vmc-anchor_hip-description = anchow the twacking at the hips, usefuw fow seated vtubing settings-osc-vmc-anchor_hip-label = anchow at hips +settings-osc-vmc-mirror_tracking = miwwow twacking +settings-osc-vmc-mirror_tracking-description = miwwow da twacking howizawntawwy. +settings-osc-vmc-mirror_tracking-label = miwwow twacking ## Setup/onboarding menu @@ -638,8 +678,8 @@ onboarding-done-close = cwose the guide onboarding-connect_tracker-back = gaww bawwk to wi-fi cwedentials onboarding-connect_tracker-title = connect twackaws -onboarding-connect_tracker-description-p0 = now onto teh fun pawwt, connecting awe teh twackaws! -onboarding-connect_tracker-description-p1 = simply connect awe that awe nawt cownyected yet, through a usb powwt. +onboarding-connect_tracker-description-p0-v1 = now onto teh fun pawrt, connyecting twackews!1! :D +onboarding-connect_tracker-description-p1-v1 = conect each twackew wun at a taim thru a USB pawrt. onboarding-connect_tracker-issue-serial = i'm having twouble connecting! onboarding-connect_tracker-usb = usb twackew onboarding-connect_tracker-connection_status-none = wooking fow twackaws @@ -699,6 +739,28 @@ onboarding-assign_trackers-assigned = } assigned onboarding-assign_trackers-advanced = show advanced assign wocations onboarding-assign_trackers-next = i assigned awe the twackaws +onboarding-assign_trackers-mirror_view = miwwow vyew +onboarding-assign_trackers-option-amount = + { $trackersCount -> + [one] x{ $trackersCount } + *[other] x{ $trackersCount } + } +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] wower-bawdy set + [core] coar set + [enhanced-core] enhaynced coar set + [full-body] fuww-bawdy set + *[all] all twackewz + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] minimum fow VR fuww-bawdy twacking + [core] + enhanced spine twacking + [enhanced-core] + paw wowtation + [full-body] + ewbOwOw twacking + *[all] all awvaiwabule twackew assaignments + } ## Tracker assignment warnings @@ -775,11 +837,11 @@ onboarding-choose_mounting = wut meownting cawibwation mefod to use? onboarding-choose_mounting-description = meownting owientation correct fow da pwacement of twackews on u body. onboarding-choose_mounting-auto_mounting = awtomawic meownting # Italized text -onboarding-choose_mounting-auto_mounting-label = expewimentaw +onboarding-choose_mounting-auto_mounting-label-v2 = wecommended onboarding-choose_mounting-auto_mounting-description = dis will automaticawwy detec da meownting diwecshuns fow aww of ya twackews fwom 2 poses onboarding-choose_mounting-manual_mounting = manyul meownting # Italized text -onboarding-choose_mounting-manual_mounting-label = wecommended +onboarding-choose_mounting-manual_mounting-label-v2 = might nawt b pwecise enuff ;w; onboarding-choose_mounting-manual_mounting-description = dis will let u chose da meownting diwecshun manuwawwy fow eech twackew # Multiline text onboarding-choose_mounting-manual_modal-title = @@ -822,9 +884,10 @@ onboarding-automatic_mounting-put_trackers_on-next = i haff awe my twackaws on onboarding-choose_proportions = wut pwopowshun cawibwation mefod to use? # Multiline string -onboarding-choose_proportions-description = - body pawpowtions awe used to know the measuwements of uw body. dey wequiwed to cawcuwate the twackews' pawsitions. - wen pawpowtions of youw body dun mach da onyes saved, youw twacking pwecision wiwl be wowse and you wiwl nyotice tings wike skating or swiding, ow youw body nyot matching youw avataw wewl. +onboarding-choose_proportions-description-v1 = + bawdy pwopowotions r used to knwo da mehsuwementz of youw bawdy. they'we wequiewed to cawcuwate da twackews' pawsitshons. + wen pwopowotiosn of ur bawdey don match teh ones saeved, yow twacking pwecisiown wiww b wowse and u wiww nowotice tingz wike skayting ow slaiding, ow yor bodiey matching uor avataw wel. + u only need to mewhsuwe your bawdee once!! unwess dey awe rong ow yer boady haz chaenged, you dont need to do them agen. UwU onboarding-choose_proportions-auto_proportions = awtomatic pwopowtions # Italized text onboarding-choose_proportions-auto_proportions-subtitle = wecommended @@ -873,6 +936,9 @@ onboarding-automatic_proportions-check_height-title = check youw height onboarding-automatic_proportions-check_height-description = we use youw height as a basis of ouw measuwements by using da hmd's height as an appwoximashun of youw actuwaw height, but is better to check if they are right youwsewf! # All the text is in bold! onboarding-automatic_proportions-check_height-calculation_warning = pwease pwess da button while standing upwight to cawcuwate youw height. you hav 3 second aftew you pwess da button! >w< +onboarding-automatic_proportions-check_height-guardian_tip = + if u r using a standowone VR hedset, make suwe to have youw gawrdian / + bowndawy tuwned on so ur heit iz cowwect!! onboarding-automatic_proportions-check_height-fetch_height = am standing! # Context is that the height is unknown onboarding-automatic_proportions-check_height-unknown = unnown @@ -937,3 +1003,32 @@ status_system-StatusSteamVRDisconnected = *[other] cuwwentwly nawt conected to SwimeVR wiff da SwimeVR dwiver. } status_system-StatusTrackerError = da { $trackerName } twackew has ewwow. >~< +status_system-StatusUnassignedHMD = teh VR hedset shud be awssaignd as a hed twackew. + +## Tray Menu + +tray_menu-show = show +tray_menu-hide = hoide +tray_menu-quit = qwit + +## First exit modal + +tray_or_exit_modal-title = owo wat shud da cwose button do? +# Multiline text +tray_or_exit_modal-description = + dis lets u choose wether u wanna exit te sewvew ow to minimaize it to da tway wen pwessing teh cwose buttin. + + yuow can cheange dis latew in da intewfayce setings! :D +tray_or_exit_modal-radio-exit = exit on cwose +tray_or_exit_modal-radio-tray = minimaize to systehm tway +tray_or_exit_modal-submit = save :3 +tray_or_exit_modal-cancel = cancew :o + +## Unknown device modal + +unknown_device-modal-title = da twackew was find owo +unknown_device-modal-description = + therwe is a nyew twackew wif MAC addwess { $deviceId }.. + d-do u wanna conect it to SwimeVR? +unknown_device-modal-confirm = sure!! +unknown_device-modal-forget = ignowe it diff --git a/gui/public/i18n/en/translation.ftl b/gui/public/i18n/en/translation.ftl index 100d31a78..a170d1ef1 100644 --- a/gui/public/i18n/en/translation.ftl +++ b/gui/public/i18n/en/translation.ftl @@ -44,6 +44,36 @@ body_part-LEFT_HAND = Left hand body_part-LEFT_UPPER_LEG = Left thigh body_part-LEFT_LOWER_LEG = Left ankle body_part-LEFT_FOOT = Left foot +body_part-LEFT_THUMB_METACARPAL = Left thumb metacarpal +body_part-LEFT_THUMB_PROXIMAL = Left thumb proximal +body_part-LEFT_THUMB_DISTAL = Left thumb distal +body_part-LEFT_INDEX_PROXIMAL = Left index proximal +body_part-LEFT_INDEX_INTERMEDIATE = Left index intermediate +body_part-LEFT_INDEX_DISTAL = Left index distal +body_part-LEFT_MIDDLE_PROXIMAL = Left middle proximal +body_part-LEFT_MIDDLE_INTERMEDIATE = Left middle intermediate +body_part-LEFT_MIDDLE_DISTAL = Left middle distal +body_part-LEFT_RING_PROXIMAL = Left ring proximal +body_part-LEFT_RING_INTERMEDIATE = Left ring intermediate +body_part-LEFT_RING_DISTAL = Left ring distal +body_part-LEFT_LITTLE_PROXIMAL = Left little proximal +body_part-LEFT_LITTLE_INTERMEDIATE = Left little intermediate +body_part-LEFT_LITTLE_DISTAL = Left little distal +body_part-RIGHT_THUMB_METACARPAL = Right thumb metacarpal +body_part-RIGHT_THUMB_PROXIMAL = Right thumb proximal +body_part-RIGHT_THUMB_DISTAL = Right thumb distal +body_part-RIGHT_INDEX_PROXIMAL = Right index proximal +body_part-RIGHT_INDEX_INTERMEDIATE = Right index intermediate +body_part-RIGHT_INDEX_DISTAL = Right index distal +body_part-RIGHT_MIDDLE_PROXIMAL = Right middle proximal +body_part-RIGHT_MIDDLE_INTERMEDIATE = Right middle intermediate +body_part-RIGHT_MIDDLE_DISTAL = Right middle distal +body_part-RIGHT_RING_PROXIMAL = Right ring proximal +body_part-RIGHT_RING_INTERMEDIATE = Right ring intermediate +body_part-RIGHT_RING_DISTAL = Right ring distal +body_part-RIGHT_LITTLE_PROXIMAL = Right little proximal +body_part-RIGHT_LITTLE_INTERMEDIATE = Right little intermediate +body_part-RIGHT_LITTLE_DISTAL = Right little distal ## Proportions skeleton_bone-NONE = None @@ -74,6 +104,12 @@ skeleton_bone-ELBOW_OFFSET = Elbow Offset ## Tracker reset buttons reset-reset_all = Reset all proportions +reset-reset_all_warning = + Warning: This will reset your proportions to being just based on your height. + Are you sure you want to do this? +reset-reset_all_warning-reset = Reset proportions +reset-reset_all_warning-cancel = Cancel + reset-full = Full Reset reset-mounting = Reset Mounting reset-yaw = Yaw Reset @@ -125,10 +161,13 @@ widget-developer_mode-raw_slime_rotation = Raw rotation widget-developer_mode-more_info = More info ## Widget: IMU Visualizer -widget-imu_visualizer = Rotation -widget-imu_visualizer-rotation_raw = Raw -widget-imu_visualizer-rotation_preview = Preview -widget-imu_visualizer-rotation_hide = Hide +widget-imu_visualizer = Tracking data +widget-imu_visualizer-preview = Preview +widget-imu_visualizer-hide = Hide +widget-imu_visualizer-rotation_raw = Raw rotation +widget-imu_visualizer-rotation_preview = Preview rotation +widget-imu_visualizer-acceleration = Acceleration +widget-imu_visualizer-position = Position ## Widget: Skeleton Visualizer widget-skeleton_visualizer-preview = Skeleton preview @@ -175,9 +214,16 @@ tracker-infos-url = Tracker URL tracker-infos-version = Firmware Version tracker-infos-hardware_rev = Hardware Revision tracker-infos-hardware_identifier = Hardware ID +tracker-infos-data_support = Data support tracker-infos-imu = IMU Sensor tracker-infos-board_type = Main board tracker-infos-network_version = Protocol Version +tracker-infos-magnetometer = Magnetometer +tracker-infos-magnetometer-status-v1 = { $status -> + *[NOT_SUPPORTED] Not supported + [DISABLED] Disabled + [ENABLED] Enabled +} ## Tracker settings tracker-settings-back = Go back to trackers list @@ -191,11 +237,19 @@ tracker-settings-mounting_section-edit = Edit mounting tracker-settings-drift_compensation_section = Allow drift compensation tracker-settings-drift_compensation_section-description = Should this tracker compensate for its drift when drift compensation is enabled? tracker-settings-drift_compensation_section-edit = Allow drift compensation +tracker-settings-use_mag = Allow magnetometer on this tracker +# Multiline! +tracker-settings-use_mag-description = + Should this tracker use magnetometer to reduce drift when magnetometer usage is allowed? Please don't shutdown your tracker while toggling this! + + You need to allow magnetometer usage first, click here to go to the setting. +tracker-settings-use_mag-label = Allow magnetometer # The . means it's an attribute and it's related to the top key. # In this case that is the settings for the assignment section. tracker-settings-name_section = Tracker name tracker-settings-name_section-description = Give it a cute nickname :) tracker-settings-name_section-placeholder = NightyBeast's left leg +tracker-settings-name_section-label = Tracker name tracker-settings-forget = Forget tracker tracker-settings-forget-description = Removes the tracker from the SlimeVR Server and prevent it from connecting to it until the server is restarted. The configuration of the tracker won't be lost. tracker-settings-forget-label = Forget tracker @@ -272,6 +326,7 @@ settings-sidebar-serial = Serial console settings-sidebar-appearance = Appearance settings-sidebar-notifications = Notifications settings-sidebar-behavior = Behavior +settings-sidebar-advanced = Advanced ## SteamVR settings settings-general-steamvr = SteamVR @@ -322,7 +377,22 @@ settings-general-tracker_mechanics-drift_compensation = Drift compensation settings-general-tracker_mechanics-drift_compensation-description = Compensates IMU yaw drift by applying an inverse rotation. Change amount of compensation and up to how many resets are taken into account. + This should only be used if you need to reset very often! settings-general-tracker_mechanics-drift_compensation-enabled-label = Drift compensation +settings-general-tracker_mechanics-drift_compensation-prediction = Drift compensation prediction +# This cares about multilines +settings-general-tracker_mechanics-drift_compensation-prediction-description = + Predicts yaw drift compensation beyond previously measured range. + Enable this if your trackers are continuously spinning on the yaw axis. +settings-general-tracker_mechanics-drift_compensation-prediction-label = Drift compensation prediction +settings-general-tracker_mechanics-drift_compensation_warning = + Warning: Only use drift compensation if you need to reset + very often (every ~5-10 minutes). + + Some IMUs prone to frequent resets include: + Joy-Cons, owoTrack, and MPUs (without recent firmware). +settings-general-tracker_mechanics-drift_compensation_warning-cancel = Cancel +settings-general-tracker_mechanics-drift_compensation_warning-done = I understand settings-general-tracker_mechanics-drift_compensation-amount-label = Compensation amount settings-general-tracker_mechanics-drift_compensation-max_resets-label = Use up to x last resets settings-general-tracker_mechanics-save_mounting_reset = Save automatic mounting reset calibration @@ -330,6 +400,11 @@ settings-general-tracker_mechanics-save_mounting_reset-description = Saves the automatic mounting reset calibrations for the trackers between restarts. Useful when wearing a suit where trackers don't move between sessions. Not recommended for normal users! settings-general-tracker_mechanics-save_mounting_reset-enabled-label = Save mounting reset +settings-general-tracker_mechanics-use_mag_on_all_trackers = Use magnetometer on all IMU trackers that support it +settings-general-tracker_mechanics-use_mag_on_all_trackers-description = + Uses magnetometer on all trackers that have a compatible firmware for it, reducing drift in stable magnetic environments. + Can be disabled per tracker in the tracker's settings. Please don't shutdown any of the trackers while toggling this! +settings-general-tracker_mechanics-use_mag_on_all_trackers-label = Use magnetometer on trackers ## FK/Tracking settings settings-general-fk_settings = Tracking settings @@ -422,6 +497,9 @@ settings-general-gesture_control-numberTrackersOverThreshold-description = Incre ## Appearance settings settings-interface-appearance = Appearance settings-general-interface-theme = Color theme +settings-general-interface-show-navbar-onboarding = Show "{ navbar-onboarding }" on navigation bar +settings-general-interface-show-navbar-onboarding-description = This changes if the "{ navbar-onboarding }" button shows on the navigation bar. +settings-general-interface-show-navbar-onboarding-label = Show "{ navbar-onboarding }" settings-general-interface-lang = Select language settings-general-interface-lang-description = Change the default language you want to use. settings-general-interface-lang-placeholder = Select the language to use @@ -433,6 +511,9 @@ settings-interface-appearance-font-os_font = OS font settings-interface-appearance-font-slime_font = Default font settings-interface-appearance-font_size = Base font scaling settings-interface-appearance-font_size-description = This affects the font size of the whole interface except this settings panel. +settings-interface-appearance-decorations = Use the system native decorations +settings-interface-appearance-decorations-description = This will not render the top bar of the interface and will use the operating system's instead. +settings-interface-appearance-decorations-label = Use native decorations ## Notification settings settings-interface-notifications = Notifications @@ -567,11 +648,7 @@ settings-osc-vmc-network-address-description = Choose which address to send out settings-osc-vmc-network-address-placeholder = IPV4 address settings-osc-vmc-vrm = VRM Model settings-osc-vmc-vrm-description = Load a VRM model to allow head anchor and enable a higher compatibility with other applications. -settings-osc-vmc-vrm-model_unloaded = No model loaded -settings-osc-vmc-vrm-model_loaded = { $titled -> - *[false] Untitled model loaded - [true] Model loaded: { $name } -} +settings-osc-vmc-vrm-untitled_model = Untitled model settings-osc-vmc-vrm-file_select = Drag & drop a model to use, or browse settings-osc-vmc-anchor_hip = Anchor at hips settings-osc-vmc-anchor_hip-description = Anchor the tracking at the hips, useful for seated VTubing. If disabling, load a VRM model. @@ -580,6 +657,32 @@ settings-osc-vmc-mirror_tracking = Mirror tracking settings-osc-vmc-mirror_tracking-description = Mirror the tracking horizontally. settings-osc-vmc-mirror_tracking-label = Mirror tracking +## Advanced settings +settings-utils-advanced = Advanced + +settings-utils-advanced-reset-gui = Reset GUI settings +settings-utils-advanced-reset-gui-description = Restore the default settings for the interface. +settings-utils-advanced-reset-gui-label = Reset GUI +settings-utils-advanced-reset-server = Reset tracking settings +settings-utils-advanced-reset-server-description = Restore the default settings for the tracking. +settings-utils-advanced-reset-server-label = Reset tracking +settings-utils-advanced-reset-all = Reset all settings +settings-utils-advanced-reset-all-description = Restore the default settings for both the interface and tracking. +settings-utils-advanced-reset-all-label = Reset all +settings-utils-advanced-reset_warning = + Warning: This will reset { $type -> + [gui] your GUI + [server] your tracking + *[all] all your + } settings to the defaults. + Are you sure you want to do this? +settings-utils-advanced-reset_warning-reset = Reset settings +settings-utils-advanced-reset_warning-cancel = Cancel + +settings-utils-advanced-open_data = Data folder +settings-utils-advanced-open_data-description = Open SlimeVR's data folder in file explorer, containing config and log files. +settings-utils-advanced-open_data-label = Open folder + ## Setup/onboarding menu onboarding-skip = Skip setup onboarding-continue = Continue @@ -679,6 +782,7 @@ onboarding-calibration_tutorial-status-waiting = Waiting for you onboarding-calibration_tutorial-status-calibrating = Calibrating onboarding-calibration_tutorial-status-success = Nice! onboarding-calibration_tutorial-status-error = The tracker was moved +onboarding-calibration_tutorial-skip = Skip tutorial ## Tracker assignment tutorial onboarding-assignment_tutorial = How to prepare a Slime Tracker before putting it on @@ -786,11 +890,11 @@ onboarding-choose_mounting = What mounting calibration method to use? # Multiline text onboarding-choose_mounting-description = Mounting orientation corrects for the placement of trackers on your body. onboarding-choose_mounting-auto_mounting = Automatic mounting -# Italized text +# Italicized text onboarding-choose_mounting-auto_mounting-label-v2 = Recommended onboarding-choose_mounting-auto_mounting-description = This will automatically detect the mounting orientations for all of your trackers from 2 poses onboarding-choose_mounting-manual_mounting = Manual mounting -# Italized text +# Italicized text onboarding-choose_mounting-manual_mounting-label-v2 = Might not be precise enough onboarding-choose_mounting-manual_mounting-description = This will let you choose the mounting orientation manually for each tracker # Multiline text @@ -834,14 +938,14 @@ onboarding-choose_proportions-description-v1 = Body proportions are used to know When proportions of your body don't match the ones saved, your tracking precision will be worse and you will notice things like skating or sliding, or your body not matching your avatar well. You only need to measure your body once! Unless they are wrong or your body has changed, then you don't need to do them again. onboarding-choose_proportions-auto_proportions = Automatic proportions -# Italized text +# Italicized text onboarding-choose_proportions-auto_proportions-subtitle = Recommended onboarding-choose_proportions-auto_proportions-descriptionv3 = This will guess your proportions by recording a sample of your movements and passing it through an algorithm. This requires having your headset (HMD) connected to SlimeVR and on your head! onboarding-choose_proportions-manual_proportions = Manual proportions -# Italized text +# Italicized text onboarding-choose_proportions-manual_proportions-subtitle = For small touches onboarding-choose_proportions-manual_proportions-description = This will let you adjust your proportions manually by modifying them directly onboarding-choose_proportions-export = Export proportions @@ -917,8 +1021,9 @@ onboarding-automatic_proportions-verify_results-redo = Redo recording onboarding-automatic_proportions-verify_results-confirm = They're correct onboarding-automatic_proportions-done-title = Body measured and saved. onboarding-automatic_proportions-done-description = Your body proportions' calibration is complete! -onboarding-automatic_proportions-error_modal = - Warning: An error was found while estimating proportions! +onboarding-automatic_proportions-error_modal-v2 = + Warning: There was an error while estimating proportions! + This is likely a mounting calibration issue. Make sure your tracking works properly before trying again. Please check the docs or join our Discord for help ^_^ onboarding-automatic_proportions-error_modal-confirm = Understood! diff --git a/gui/public/i18n/es-419/translation.ftl b/gui/public/i18n/es-419/translation.ftl index 47982ff93..0fb12c4e7 100644 --- a/gui/public/i18n/es-419/translation.ftl +++ b/gui/public/i18n/es-419/translation.ftl @@ -22,7 +22,7 @@ version_update-close = Cerrar tips-find_tracker = ¿No estás seguro de cuál sensor es cuál? Agita un sensor y se resaltará donde está asignado. tips-do_not_move_heels = ¡Asegúrate de no mover los talones en la grabación! tips-file_select = Arrastra y suelta archivos para usarlos, o selecciónalos. -tips-tap_setup = Puedes tocar lentamente 2 veces el tracker para seleccionarlo en lugar de seleccionarlo desde el menú. +tips-tap_setup = Puedes tocar lentamente 2 veces el sensor para seleccionarlo en lugar de seleccionarlo desde el menú. tips-turn_on_tracker = ¿Estas usando trackers de SlimeVR oficiales? ¡Recuerda encender tus trackers después de conectarlos al PC! tips-failed_webgl = Fallo al inicializar WebGL. @@ -81,6 +81,11 @@ skeleton_bone-ELBOW_OFFSET = Desplazamiento del codo ## Tracker reset buttons reset-reset_all = Reiniciar todas las proporciones +reset-reset_all_warning = + Advertencia: Esto reiniciará tus proporciones para ser basadas solamente en tu altura. + ¿Estás seguro de que quieres seguir? +reset-reset_all_warning-reset = Reiniciar proporciones +reset-reset_all_warning-cancel = Cancelar reset-full = Reinicio completo reset-mounting = Reinicio de montura reset-yaw = Reinicio horizontal @@ -142,9 +147,12 @@ widget-developer_mode-more_info = More info ## Widget: IMU Visualizer widget-imu_visualizer = Rotation +widget-imu_visualizer-preview = Vista previa +widget-imu_visualizer-hide = Ocultar widget-imu_visualizer-rotation_raw = Raw widget-imu_visualizer-rotation_preview = Preview -widget-imu_visualizer-rotation_hide = Ocultar +widget-imu_visualizer-acceleration = Aceleración +widget-imu_visualizer-position = Posición ## Widget: Skeleton Visualizer @@ -199,6 +207,13 @@ tracker-infos-hardware_identifier = ID del hardware tracker-infos-imu = Sensor IMU tracker-infos-board_type = Placa principal tracker-infos-network_version = Versión del protocolo +tracker-infos-magnetometer = Magnetómetro +tracker-infos-magnetometer-status-v1 = + { $status -> + [DISABLED] Deshabilitado + [ENABLED] Habilitado + *[NOT_SUPPORTED] No soportado + } ## Tracker settings @@ -213,11 +228,19 @@ tracker-settings-mounting_section-edit = Editar montura tracker-settings-drift_compensation_section = Permitir compensación de desviación tracker-settings-drift_compensation_section-description = ¿Este sensor deberia compensar la desviación? tracker-settings-drift_compensation_section-edit = Permitir compensación de desviación +tracker-settings-use_mag = Permitir el uso del magnetómetro en este tracker +# Multiline! +tracker-settings-use_mag-description = + ¿Debería este tracker usar el magnetómetro para reducir la desviacion cuando se permite el uso del magnetómetro? ¡Por favor, no apagues tu tracker mientras alternas esto! + + Primero debes permitir el uso del magnetómetro, haga clic aquí para ir al ajuste. +tracker-settings-use_mag-label = Permitir el uso del magnetómetro # The . means it's an attribute and it's related to the top key. # In this case that is the settings for the assignment section. tracker-settings-name_section = Nombre del sensor tracker-settings-name_section-description = Dale un apodo bonito :) tracker-settings-name_section-placeholder = Pata izquierda de Manteca +tracker-settings-name_section-label = Nombre del sensor tracker-settings-forget = Olvidar tracker tracker-settings-forget-description = Remueve el tracker del servidor de SlimeVR y lo previene de conectarse hasta que el servidor se reinicie. La configuración del tracker no se perderá. tracker-settings-forget-label = Olvidar tracker @@ -296,6 +319,7 @@ settings-sidebar-utils = Utilidades settings-sidebar-serial = Consola serial settings-sidebar-appearance = Apariencia settings-sidebar-notifications = Notificaciones +settings-sidebar-advanced = Avanzado ## SteamVR settings @@ -350,6 +374,20 @@ settings-general-tracker_mechanics-drift_compensation-description = Compensa la desviación del eje vertical de los sensores aplicando una rotación inversa. Cambia la fuerza de la compensación y hasta cuantos reinicios tomar en cuenta. settings-general-tracker_mechanics-drift_compensation-enabled-label = Compensación de desviación +settings-general-tracker_mechanics-drift_compensation-prediction = Compensación mediante la predicción del desvío +# This cares about multilines +settings-general-tracker_mechanics-drift_compensation-prediction-description = + Predice la desviación horizontal y compensa cuando esta mas allá del rango previamente medido. + Activa esto si el sensor esta girando continuamente en el eje horizontal. +settings-general-tracker_mechanics-drift_compensation-prediction-label = Compensación mediante la predicción del desvío +settings-general-tracker_mechanics-drift_compensation_warning = + Advertencia: Solo usa la compensación de desviación si necesitas reiniciar + muy seguido (cada ~5-10 minutos). + + Algunos IMUs propensos a reinicios frecuentes incluyen: + Joy-Cons, owoTrack y MPU (sin un firmware reciente). +settings-general-tracker_mechanics-drift_compensation_warning-cancel = Cancelar +settings-general-tracker_mechanics-drift_compensation_warning-done = Entiendo settings-general-tracker_mechanics-drift_compensation-amount-label = Fuerza de la compensación settings-general-tracker_mechanics-drift_compensation-max_resets-label = Utilizar hasta los últimos x reinicios settings-general-tracker_mechanics-save_mounting_reset = Guardar calibración automática de reinicio de montura @@ -357,6 +395,11 @@ settings-general-tracker_mechanics-save_mounting_reset-description = Guarda las calibraciones automáticas del reinicio de montura para los trackers entre reinicios. Útil para cuando se usa un traje donde los trackers no se mueven entre sesiones. ¡No se recomienda para usuarios típicos! settings-general-tracker_mechanics-save_mounting_reset-enabled-label = Guardar reinicio de montura +settings-general-tracker_mechanics-use_mag_on_all_trackers = Usar el magnetómetro en todos los trackers IMU que lo admitan +settings-general-tracker_mechanics-use_mag_on_all_trackers-description = + Usa el magnetómetro en todos los trackers que tienen un firmware compatible, lo que reduce la desviación en entornos magnéticos estables. + Se puede desactivar por sensor en la configuración del sensor. ¡Por favor, no apagues ninguno de los trackers mientras activas esta opción! +settings-general-tracker_mechanics-use_mag_on_all_trackers-label = Usar magnetómetro en trackers ## FK/Tracking settings @@ -383,6 +426,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Reinicio de montura de settings-general-fk_settings-arm_fk = Trackeo de brazos settings-general-fk_settings-arm_fk-description = Cambia cómo el movimiento de los brazos es detectado. settings-general-fk_settings-arm_fk-force_arms = Forzar brazos desde el HMD +settings-general-fk_settings-reset_settings = Reiniciar ajustes +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Restablece la inclinación del HMD (rotación vertical) al realizar un reinicio completo. Útil si se lleva un HMD en la frente para VTubing o mocap. No habilitar para VR. +settings-general-fk_settings-reset_settings-reset_hmd_pitch = Reiniciar la inclinación del HMD settings-general-fk_settings-arm_fk-reset_mode-description = Cambiar que pose de brazos es esperada para el reinicio de montura. settings-general-fk_settings-arm_fk-back = Detrás settings-general-fk_settings-arm_fk-back-description = El modo predeterminado, con el brazo yendo por detrás y el antebrazo yendo para adelante. @@ -451,6 +497,9 @@ settings-general-interface-dev_mode = Modo desarrollador settings-general-interface-dev_mode-description = Este modo puede ser útil si es que necesitas información a fondo o para un nivel de interacción más avanzado con los sensores conectados. settings-general-interface-dev_mode-label = Modo desarrollador settings-general-interface-theme = Tema de color +settings-general-interface-show-navbar-onboarding = Mostrar "{ navbar-onboarding }" en la barra de navegación +settings-general-interface-show-navbar-onboarding-description = Esto cambia si el botón "{ navbar-onboarding }" se muestra en la barra de navegación. +settings-general-interface-show-navbar-onboarding-label = Mostrar "{ navbar-onboarding }" settings-general-interface-lang = Selecciona un idioma settings-general-interface-lang-description = Cambia el idioma que quieras usar. settings-general-interface-lang-placeholder = Selecciona el idioma a utilizar @@ -462,6 +511,9 @@ settings-interface-appearance-font-os_font = Fuente del sistema operativo settings-interface-appearance-font-slime_font = Fuente predeterminada settings-interface-appearance-font_size = Tamaño base de la fuente settings-interface-appearance-font_size-description = Esto afecta al tamaño de las letras en toda la interfaz excepto en este panel de ajustes. +settings-interface-appearance-decorations = Usar las decoraciones nativas del sistema +settings-interface-appearance-decorations-description = Esto no renderizará la barra superior de la interfaz y en cambio usará la del sistema operativo. +settings-interface-appearance-decorations-label = Usar decoraciones nativas ## Notification settings @@ -479,6 +531,16 @@ settings-general-interface-connected_trackers_warning-label = Advertencia de tra settings-general-interface-use_tray = Minimizar a la bandeja del sistema settings-general-interface-use_tray-description = Permite cerrar la ventana sin cerrar el servidor de SlimeVR para que puedas continuar usándolo sin que te moleste la interfaz. settings-general-interface-use_tray-label = Minimizar a la bandeja del sistema +settings-general-interface-discord_presence = Compartir actividad en Discord +settings-general-interface-discord_presence-description = Le dice a tu cliente de Discord que estás usando SlimeVR junto con la cantidad de sensores IMU que estás usando. +settings-general-interface-discord_presence-label = Compartir actividad en Discord +settings-general-interface-discord_presence-message = + { $amount -> + [0] Recolectando slimes + [one] Usando 1 sensor + [many] Usando { $amount } de sensores + *[other] Usando { $amount } sensores + } ## Serial settings @@ -501,6 +563,8 @@ settings-serial-get_infos = Obtener información settings-serial-serial_select = Selecciona un puerto serial settings-serial-auto_dropdown_item = Auto settings-serial-get_wifi_scan = Obtener escaneo WiFi +settings-serial-file_type = Texto sin formato +settings-serial-save_logs = Guardar en archivo ## OSC router settings @@ -531,14 +595,17 @@ settings-osc-router-network-address-placeholder = Dirección IPv4 settings-osc-vrchat = Sensores OSC de VRChat # This cares about multilines -settings-osc-vrchat-description = - Cambiar ajustes específicos de VRChat para recibir datos del HMD y enviar - datos de los sensores para seguimiento de cuerpo completo (funciona en Quest nativo). +settings-osc-vrchat-description-v1 = + Cambia los ajustes específicos de los trackers OSC utilizados para enviar + datos de seguimiento a aplicaciones sin SteamVR (ej. VRChat en Quest). + Asegúrate de activar OSC en VRChat a través del menú Acción en OSC > Activado. + Para permitir la recepción de datos del HMD y de los mandos desde VRChat, ve a los ajustes de tu menú principal + en Tracking & IK > Permitir el envío de datos OSC de seguimiento de RV de cabeza y muñeca. settings-osc-vrchat-enable = Habilitar settings-osc-vrchat-enable-description = Habilita el envio y recibo de datos. settings-osc-vrchat-enable-label = Habilitar settings-osc-vrchat-network = Puertos de conexión -settings-osc-vrchat-network-description = Establece los puertos de entrada y salida de datos a VRChat. +settings-osc-vrchat-network-description-v1 = Establece los puertos para recibir y enviar datos. Se puede dejar sin cambiar para VRChat. settings-osc-vrchat-network-port_in = .label = Puerto de entrada .placeholder = Puerto de entrada (por defecto: 9001) @@ -546,7 +613,7 @@ settings-osc-vrchat-network-port_out = .label = Puerto de salida .placeholder = Puerto de salida (por defecto: 9000) settings-osc-vrchat-network-address = Dirección de red -settings-osc-vrchat-network-address-description = Establece la dirección donde se enviarán los datos de VRChat (revisa los ajustes de Wi-Fi de tu dispositivo que tenga el juego). +settings-osc-vrchat-network-address-description-v1 = Elige a qué dirección enviar los datos. Se puede dejar sin cambiar para VRChat. settings-osc-vrchat-network-address-placeholder = Dirección IP de VRChat settings-osc-vrchat-network-trackers = Sensores settings-osc-vrchat-network-trackers-description = Habilita el envío de sensores específicos mediante OSC. @@ -589,6 +656,39 @@ settings-osc-vmc-vrm-file_select = Arrastra y suelta un modelo para usar, o s settings-osc-vmc-anchor_hip = Anclaje por cadera settings-osc-vmc-anchor_hip-description = Anclar el tracking a la cadera, útil para hacer de VTuber sentado. Si lo desactivas, carga un modelo VRM. settings-osc-vmc-anchor_hip-label = Anclaje por cadera +settings-osc-vmc-mirror_tracking = Invertir el tracking +settings-osc-vmc-mirror_tracking-description = invierte el tracking horizontalmente. +settings-osc-vmc-mirror_tracking-label = Invertir el tracking + +## Advanced settings + +settings-utils-advanced = Avanzado +settings-utils-advanced-reset-gui = Reiniciar ajustes de la interfaz de usuario +settings-utils-advanced-reset-gui-description = Restaura los ajustes por defecto de la interfaz. +settings-utils-advanced-reset-gui-label = Reiniciar interfaz de usuario +settings-utils-advanced-reset-server = Reiniciar los ajustes del tracking +settings-utils-advanced-reset-server-description = Restaura los ajustes por defecto para el tracking. +settings-utils-advanced-reset-server-label = Reiniciar tracking +settings-utils-advanced-reset-all = Reiniciar todos los ajustes +settings-utils-advanced-reset-all-description = Restaura los ajustes por defecto para la interfaz y el tracking. +settings-utils-advanced-reset-all-label = Reiniciar todo +settings-utils-advanced-reset_warning = + { $type -> + [gui] + Advertencia: Esto reiniciará tus ajustes de la interfaz de usuario a sus valores predeterminados. + ¿Estás seguro de que quieres seguir? + [server] + Advertencia: Esto reiniciará tus ajustes de seguimiento a sus valores predeterminados. + ¿Estás seguro de que quieres seguir? + *[all] + Advertencia: Esto reiniciará todos tus ajustes a sus valores predeterminados. + ¿Estás seguro de que quieres seguir? + } +settings-utils-advanced-reset_warning-reset = Reiniciar ajustes +settings-utils-advanced-reset_warning-cancel = Cancelar +settings-utils-advanced-open_data = Carpeta de datos +settings-utils-advanced-open_data-description = Abre la carpeta de datos de SlimeVR en el explorador de archivos, conteniendo archivos de configuración y registros. +settings-utils-advanced-open_data-label = Abrir carpeta ## Setup/onboarding menu @@ -701,6 +801,7 @@ onboarding-calibration_tutorial-status-waiting = Esperando por ti onboarding-calibration_tutorial-status-calibrating = Calibrando onboarding-calibration_tutorial-status-success = ¡Genial! onboarding-calibration_tutorial-status-error = El tracker fue movido +onboarding-calibration_tutorial-skip = Saltar tutorial ## Tracker assignment tutorial @@ -728,6 +829,28 @@ onboarding-assign_trackers-assigned = onboarding-assign_trackers-advanced = Mostrar ubicación de asignaciones avanzados. onboarding-assign_trackers-next = He asignado todos los sensores onboarding-assign_trackers-mirror_view = Vista espejo +onboarding-assign_trackers-option-amount = + { $trackersCount -> + [one] x{ $trackersCount } + [many] x{ $trackersCount } + *[other] x{ $trackersCount } + } +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] Conjunto para inferior del cuerpo + [core] Conjunto básico + [enhanced-core] Conjunto básico mejorado + [full-body] Conjunto para cuerpo completo + *[all] Todos los sensores + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] El mínimo para el full-body tracking en RV + [core] + Mejor seguimiento de la columna vertebral + [enhanced-core] + Rotación de pies + [full-body] + Seguimiento de codos + *[all] Todas las asignaciones de sensores disponibles + } ## Tracker assignment warnings @@ -803,12 +926,12 @@ onboarding-choose_mounting = ¿Qué método de calibración de montura quiere us # Multiline text onboarding-choose_mounting-description = La orientación de montura corrige la colocación (o orientación) de los trackers en tu cuerpo. onboarding-choose_mounting-auto_mounting = Montura automática -# Italized text -onboarding-choose_mounting-auto_mounting-label = Experimental +# Italicized text +onboarding-choose_mounting-auto_mounting-label-v2 = Recomendado onboarding-choose_mounting-auto_mounting-description = Esto detectará automáticamente las direcciones de montura para todos tus trackers a partir de 2 poses onboarding-choose_mounting-manual_mounting = Montura manual -# Italized text -onboarding-choose_mounting-manual_mounting-label = Recomendado +# Italicized text +onboarding-choose_mounting-manual_mounting-label-v2 = Puede que no sea lo suficientemente preciso onboarding-choose_mounting-manual_mounting-description = Esto te permitirá elegir la dirección de montura manualmente para cada tracker. # Multiline text onboarding-choose_mounting-manual_modal-title = @@ -856,14 +979,14 @@ onboarding-choose_proportions-description-v1 = Cuando las proporciones de tu cuerpo no encajan con las guardadas, la precisión de tu tracking será peor y notarás cosas como deslizamiento o desplazamiento, o tu cuerpo no encajando bien con tu avatar. ¡Solo necesitas medir tu cuerpo una vez! A menos que estén mal o tu cuerpo haya cambiado, no necesitas hacerlo de nuevo. onboarding-choose_proportions-auto_proportions = Proporciones automáticas -# Italized text +# Italicized text onboarding-choose_proportions-auto_proportions-subtitle = Recomendado onboarding-choose_proportions-auto_proportions-descriptionv3 = Esto estimará tus proporciones grabando una muestra de tus movimientos y pasándolos a través de un algoritmo. ¡Esto requiere tener tu visor (HMD) conectado a SlimeVR y en tu cabeza! onboarding-choose_proportions-manual_proportions = Proporciones manuales -# Italized text +# Italicized text onboarding-choose_proportions-manual_proportions-subtitle = Para toques pequeños onboarding-choose_proportions-manual_proportions-description = Esto te permitirá ajustar tus proporciones manualmente de forma directa onboarding-choose_proportions-export = Exportar proporciones @@ -943,9 +1066,10 @@ onboarding-automatic_proportions-verify_results-redo = Rehacer grabación onboarding-automatic_proportions-verify_results-confirm = Son correctos onboarding-automatic_proportions-done-title = Cuerpo medido y guardado. onboarding-automatic_proportions-done-description = ¡La calibración de tus proporciones corporales fue completada! -onboarding-automatic_proportions-error_modal = - Atención: ¡Se ha encontrado un error durante la estimación de sus proporciones! - Por favor fijate la documentación o únete a nuestro Discord para obtener ayuda ^_^ +onboarding-automatic_proportions-error_modal-v2 = + Peligro: ¡Hubo un error mientras se estimaban las proporciones! + Esto es posiblemente debido a un problema con la calibración de montura. Asegúrate de que tu tracking funcione adecuadamente antes de intentarlo nuevamente. + Por favor revisa la documentación o únete a nuestro Discord por ayuda ^_^ onboarding-automatic_proportions-error_modal-confirm = ¡Entendido! ## Home @@ -970,6 +1094,7 @@ status_system-StatusSteamVRDisconnected = *[other] Actualmente no está conectado a SteamVR a través del driver de SlimeVR. } status_system-StatusTrackerError = El tracker { $trackerName } tiene un error. +status_system-StatusUnassignedHMD = El casco de RV debe ser asignado como un sensor de cabeza. ## Tray Menu diff --git a/gui/public/i18n/es-ES/translation.ftl b/gui/public/i18n/es-ES/translation.ftl index 0607dcb61..a56284d7a 100644 --- a/gui/public/i18n/es-ES/translation.ftl +++ b/gui/public/i18n/es-ES/translation.ftl @@ -144,7 +144,6 @@ widget-developer_mode-more_info = Más información widget-imu_visualizer = Rotación widget-imu_visualizer-rotation_raw = Sin filtrar widget-imu_visualizer-rotation_preview = Previsualización -widget-imu_visualizer-rotation_hide = Ocultar ## Widget: Skeleton Visualizer @@ -348,6 +347,7 @@ settings-general-tracker_mechanics-drift_compensation-description = Compensa la desviación horizontal del IMU aplicando una rotación inversa. Cambia la cantidad de compensación y de reinicios que se tienen en cuenta. settings-general-tracker_mechanics-drift_compensation-enabled-label = Compensación en la desviación +settings-general-tracker_mechanics-drift_compensation_warning-done = Yo entiendo settings-general-tracker_mechanics-drift_compensation-amount-label = Cantidad de compensación settings-general-tracker_mechanics-drift_compensation-max_resets-label = Usar los últimos X reinicios. settings-general-tracker_mechanics-save_mounting_reset = Guardar la calibración de reajuste de montaje automático @@ -381,6 +381,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Reinicio de montura de settings-general-fk_settings-arm_fk = Tracking de brazos settings-general-fk_settings-arm_fk-description = Forzar el seguimiento de los brazos desde el HMD incluso si hay datos de posición de la mano disponibles. settings-general-fk_settings-arm_fk-force_arms = Forzar brazos desde el HMD +settings-general-fk_settings-reset_settings = Restablecer la configuración +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Restablecer la inclinación del HMD (rotación vertical) al realizar un reinicio completo. Útil si se lleva un HMD en la frente para VTubing o mocap. No habilitar para VR. +settings-general-fk_settings-reset_settings-reset_hmd_pitch = Reiniciar la inclinación del HMD settings-general-fk_settings-arm_fk-reset_mode-description = Cambia la posición por defecto para el restablecimiento de montura settings-general-fk_settings-arm_fk-back = Parte posterior del brazo settings-general-fk_settings-arm_fk-back-description = Modo predeterminado, con los brazos hacia atrás y los antebrazos hacia adelante. @@ -451,6 +454,9 @@ settings-general-interface-dev_mode = Modo de desarrollador settings-general-interface-dev_mode-description = Este modo puede ser útil si necesitas datos en profundidad o para interactuar con los trackers conectados a un nivel más avanzado settings-general-interface-dev_mode-label = Modo de desarrollador settings-general-interface-theme = Temas +settings-general-interface-show-navbar-onboarding = Enseñar ''{ navbar-onboarding }" en la barra de navegación +settings-general-interface-show-navbar-onboarding-description = Esto cambia si el botón de "{ navbar-onboarding }" enseña en la barra de navegación +settings-general-interface-show-navbar-onboarding-label = Enseña "{ navbar-onboarding }" settings-general-interface-lang = Seleccionar idioma settings-general-interface-lang-description = Cambiar el idioma predeterminado que deseas utilizar. settings-general-interface-lang-placeholder = Seleccionar el idioma que desea utilizar @@ -462,6 +468,7 @@ settings-interface-appearance-font-os_font = Fuente SO settings-interface-appearance-font-slime_font = Fuente predeterminada settings-interface-appearance-font_size = Escala de la fuente base settings-interface-appearance-font_size-description = Esto afecta al tamaño de la fuente de toda la interfaz excepto este panel de configuración +settings-interface-appearance-decorations-label = Usar decoraciones nativos. ## Notification settings @@ -479,6 +486,15 @@ settings-general-interface-connected_trackers_warning-label = Aviso de trackers settings-general-interface-use_tray = Minimizar a la bandeja settings-general-interface-use_tray-description = Te permite cerrar la ventana sin cerrar SlimeVR para que pueda seguir usándolo sin que la interfaz te moleste. settings-general-interface-use_tray-label = Minimizar en la bandeja del sistema +settings-general-interface-discord_presence = Compartir actividad en Discord +settings-general-interface-discord_presence-description = Le indica a tu cliente de Discord que estás usando SlimeVR junto con el número de rastreadores IMU que estás usando. +settings-general-interface-discord_presence-label = Compartir actividad en Discord +settings-general-interface-discord_presence-message = + { $amount -> + [0] Recolectando slimes + [one] Usando 1 tracker + *[other] Usando { $amount } trackers + } ## Serial settings @@ -501,6 +517,8 @@ settings-serial-get_infos = Obtener información settings-serial-serial_select = Selecciona un puerto serial settings-serial-auto_dropdown_item = Automático settings-serial-get_wifi_scan = Obtener escaneo WiFi +settings-serial-file_type = Texto sin formato +settings-serial-save_logs = Guardar en archivo ## OSC router settings @@ -531,12 +549,17 @@ settings-osc-router-network-address-placeholder = Dirección IPV4 settings-osc-vrchat = VRChat OSC Trackers # This cares about multilines -settings-osc-vrchat-description = Cambia la configuración específica de VRChat para recibir datos del visor (HMD) y enviar datos a los trackers para FBT sin SteamVR (ej. Quest standalone). +settings-osc-vrchat-description-v1 = + Change settings specific to the OSC Trackers standard used for sending + tracking data to applications without SteamVR (ex. Quest standalone). + Make sure to enable OSC in VRChat via the Action Menu under OSC > Enabled. + To allow receiving HMD and controller data from VRChat, go in your main menu's + settings under Tracking & IK > Allow Sending Head and Wrist VR Tracking OSC Data. settings-osc-vrchat-enable = Habilitar settings-osc-vrchat-enable-description = Alternar el envío y la recepción de datos settings-osc-vrchat-enable-label = Habilitar settings-osc-vrchat-network = Puertos de red -settings-osc-vrchat-network-description = Configura los puertos para escuchar y enviar datos a VRChat. +settings-osc-vrchat-network-description-v1 = Establece los puertos para recibir y enviar datos. Se puede dejar sin modificar para VRChat. settings-osc-vrchat-network-port_in = .label = Puerto de entrada .placeholder = Puerto de entrada (Por defecto: 9001) @@ -544,7 +567,7 @@ settings-osc-vrchat-network-port_out = .label = Puerto de salida .placeholder = Puerto de salida (Por defecto: 9000) settings-osc-vrchat-network-address = Dirección de red -settings-osc-vrchat-network-address-description = Elige a qué dirección enviar los datos a VRChat (Comprueba la configuración Wi-Fi de tu dispositivo). +settings-osc-vrchat-network-address-description-v1 = Elige a qué dirección enviar los datos. Se puede dejar sin modificar para VRChat. settings-osc-vrchat-network-address-placeholder = Dirección IP de VRChat settings-osc-vrchat-network-trackers = Trackers settings-osc-vrchat-network-trackers-description = Activar el envío de trackers específicos a través de OSC. @@ -563,12 +586,46 @@ settings-osc-vmc-enable = Habilitar settings-osc-vmc-enable-description = Alterna el envío y recepción de datos. settings-osc-vmc-enable-label = Habilitar settings-osc-vmc-network = Puertos de red +settings-osc-vmc-network-description = Establece los puertos para escuchar y enviar datos via VMC. +settings-osc-vmc-network-port_in = + .label = Puerto de entrada + .placeholder = Puerto de entrada (Por defecto: 39540) +settings-osc-vmc-network-port_out = + .label = Puerto de salida + .placeholder = Puerto de salida (Por defecto: 39539) settings-osc-vmc-network-address = Dirección de red +settings-osc-vmc-network-address-description = Elige la dirección a la que se enviarán los datos vía VMC. settings-osc-vmc-network-address-placeholder = Dirección IPV4 +settings-osc-vmc-vrm = Modelo VRM +settings-osc-vmc-vrm-description = Cargar un modelo VRM para permitir el anclaje de la cabeza y posibilitar una mayor compatibilidad con otras aplicaciones. settings-osc-vmc-vrm-model_unloaded = No hay modelo cargado +settings-osc-vmc-vrm-model_loaded = + { $titled -> + [true] Modelo cargado: { $name } + *[false] Modelo sin título cargado + } +settings-osc-vmc-vrm-file_select = Arrastre y suelte un modelo para utilizarlo, o busquelo settings-osc-vmc-anchor_hip = Anclar a la cadera settings-osc-vmc-anchor_hip-description = Ancla el tracking a la cadera, útil para VTubing sentado. Si se deshabilita, carga un modelo VRM. settings-osc-vmc-anchor_hip-label = Anclar a la cadera +settings-osc-vmc-mirror_tracking = Invertir el tracking +settings-osc-vmc-mirror_tracking-description = Invierte el tracking horizontalmente. +settings-osc-vmc-mirror_tracking-label = Invertir el tracking + +## Advanced settings + +settings-utils-advanced = Avanzado +settings-utils-advanced-reset-gui = Restablecer configucación del GUI +settings-utils-advanced-reset-gui-description = Restaurar la configuración predeterminado para el interfaz. +settings-utils-advanced-reset-gui-label = Restablecer el GUI +settings-utils-advanced-reset-server = Restablecer la configuración del tracking +settings-utils-advanced-reset-server-description = Restaurar la configuración predeterminado para el tracking, +settings-utils-advanced-reset-server-label = Restablecer el tracking, +settings-utils-advanced-reset-all = Restablecer todas las configuraciónes +settings-utils-advanced-reset-all-description = Restaurar la configuración predeterminada para el interfaz y el tracking. +settings-utils-advanced-reset_warning-cancel = Cancelar +settings-utils-advanced-open_data = Carpeta de datos +settings-utils-advanced-open_data-label = Abrir carpeta ## Setup/onboarding menu @@ -576,6 +633,9 @@ onboarding-skip = Omitir configuración onboarding-continue = Continuar onboarding-wip = Trabajo en progreso onboarding-previous_step = Paso anterior +onboarding-setup_warning = + Advertencia: La configuración inicial es necesaria para un buen tracking, + es necesaria si es la primera vez que usas SlimeVR onboarding-setup_warning-skip = Omitir configuración onboarding-setup_warning-cancel = Continuar con la configuración @@ -598,9 +658,28 @@ onboarding-wifi_creds-password = ## Mounting setup +onboarding-reset_tutorial-back = Volver a la calibración de montura onboarding-reset_tutorial = Tutorial para resetteo de trackers onboarding-reset_tutorial-explanation = Mientras usas tus trackers, es posible que se desalineen debido al balanceo de la IMU o porque es posible que se hayan movido físicamente. Tienes varias formas de solucionar este problema. onboarding-reset_tutorial-skip = Omitir paso +# Cares about multiline +onboarding-reset_tutorial-0 = + Toque { $taps } veces el rastreador resaltado para activar el restablecimiento horizontal. + + Esto hará que los trackers miren en la misma dirección que tu visor (HMD). +# Cares about multiline +onboarding-reset_tutorial-1 = + Toque { $taps } veces el rastreador resaltado para activar el reinicio completo. + + Para ello es necesario estar de pie (pose i). Hay un retraso de 3 segundos (configurable) antes de que realmente suceda. + Esto restablece completamente la posición y la rotación de todos sus trackers. Debería solucionar la mayoría de los problemas. +# Cares about multiline +onboarding-reset_tutorial-2 = + Toque { $taps } veces el tracker resaltado para activar el restablecimiento de montura. + + El restablecimiento de montura ayuda en cómo los trackers están realmente colocados en ti, así que si accidentalmente los moviste y cambiaste su orientación por una gran cantidad, esto ayudará. + + Necesitas estar en una pose como si estuvieras esquiando como se muestra en el asistente de montaje automático y tienes un retraso de 3 segundos (configurable) antes de que se active. ## Setup start @@ -624,6 +703,8 @@ onboarding-done-close = Cerrar configuración onboarding-connect_tracker-back = Volver a credenciales de Wi-Fi onboarding-connect_tracker-title = Conectar trackers +onboarding-connect_tracker-description-p0-v1 = ¡Ahora a la parte divertida, conectar los trackers! +onboarding-connect_tracker-description-p1-v1 = Conecte cada tracker de uno en uno a través de un puerto USB. onboarding-connect_tracker-issue-serial = ¡Tengo problemas para conectarme! onboarding-connect_tracker-usb = Tracker USB onboarding-connect_tracker-connection_status-none = Buscando trackers @@ -634,12 +715,24 @@ onboarding-connect_tracker-connection_status-looking_for_server = Buscando servi onboarding-connect_tracker-connection_status-connection_error = No se puede conectar al Wi-Fi onboarding-connect_tracker-connection_status-could_not_find_server = No se pudo encontrar el servidor onboarding-connect_tracker-connection_status-done = Conectado al Server +# $amount (Number) - Amount of trackers connected (this is a number, but you can use CLDR plural rules for your language) +# More info on https://www.unicode.org/cldr/cldr-aux/charts/22/supplemental/language_plural_rules.html +# English in this case only has 2 plural rules, which are "one" and "other", +# we use 0 in an explicit way because there is no plural rule in english for 0, so we directly say +# if $amount is 0 then we say "No trackers connected" +onboarding-connect_tracker-connected_trackers = + { $amount -> + [0] No hay tracker conectados + [one] 1 tracker conectado + *[other] { $amount } trackers conectados + } onboarding-connect_tracker-next = He conectado todos mis trackers ## Tracker calibration tutorial onboarding-calibration_tutorial = Tutorial de calibración de IMU onboarding-calibration_tutorial-subtitle = ¡Esto ayudará a reducir el drift de los trackers! +onboarding-calibration_tutorial-description = Cada vez que enciendas tus trackers, estos necesitan descansar sobre una superficie plana para calibrarse. Hagamos lo mismo pulsando el botón «{ onboarding-calibration_tutorial-calibrate }», ¡no los muevas! onboarding-calibration_tutorial-calibrate = Mis trackers estan en una superficie plana onboarding-calibration_tutorial-status-waiting = Esperando por ti onboarding-calibration_tutorial-status-calibrating = Calibrando @@ -661,8 +754,38 @@ onboarding-assignment_tutorial-done = ¡Le puse pegatinas y correas! onboarding-assign_trackers-back = Volver a credenciales de Wi-Fi onboarding-assign_trackers-title = Asignar trackers onboarding-assign_trackers-description = Elije qué tracker va a dónde. Haz clic en la ubicación donde deseas colocar un tracker +# Look at translation of onboarding-connect_tracker-connected_trackers on how to use plurals +# $assigned (Number) - Trackers that have been assigned a body part +# $trackers (Number) - Trackers connected to the server +onboarding-assign_trackers-assigned = + { $trackers -> + [one] { $assigned } de 1 tracker asignado + *[other] { $assigned } de { $trackers } trackers asignados + } onboarding-assign_trackers-advanced = Mostrar ubicaciones de asignación avanzadas onboarding-assign_trackers-next = He asignado todos los trackers +onboarding-assign_trackers-mirror_view = Vista en espejo +onboarding-assign_trackers-option-amount = + { $trackersCount -> + [one] x{ $trackersCount } + *[other] x{ $trackersCount } + } +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] Set de Cuerpo Inferior + [core] Set Básico + [enhanced-core] Set Básico Mejorado + [full-body] Set de Cuerpo Completo + *[all] Todos los Trackers + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] Mínimo para el seguimiento de cuerpo completo en RV + [core] + Tracking de columna mejorado + [enhanced-core] + Rotación de los pies + [full-body] + Tracking de codos + *[all] Todas las asignaciones de tracker disponibles + } ## Tracker assignment warnings @@ -691,69 +814,243 @@ onboarding-assign_trackers-warning-RIGHT_FOOT = [6] El pie derecho está asignado, pero es necesario que también se asigne el tobillo derecho! *[other] Pie derecho asignado, pero necesitas asignar Desconocido } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-LEFT_LOWER_LEG = + { $unassigned -> + [2] El tobillo izquierdo está asignado, ¡pero necesitas que el muslo izquierdo también lo esté! + [1] El tobillo izquierdo está asignado, ¡pero necesitas que el pecho, la cadera o la cintura también lo estén! + [0] El tobillo izquierdo está asignado, ¡pero necesitas que el muslo izquierdo y el pecho, la cadera o la cintura también lo estén! + *[unknown] El tobillo izquierdo está asignado, ¡pero necesitas que la parte del cuerpo desconocida no asignada también lo esté! + } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-RIGHT_LOWER_LEG = + { $unassigned -> + [2] El tobillo derecho está asignado, ¡pero necesitas que el muslo derecho también lo esté! + [1] El tobillo derecho está asignado, ¡pero necesitas que el pecho, la cadera o la cintura también lo estén! + [0] El tobillo derecho está asignado, ¡pero necesitas que el muslo derecho y el pecho, la cadera o la cintura también lo estén! + *[unknown] El tobillo derecho está asignado, ¡pero necesitas que la parte del cuerpo desconocida no asignada también lo esté! + } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-LEFT_UPPER_LEG = + { $unassigned -> + [0] El muslo izquierdo está asignado, ¡pero necesitas que el pecho, la cadera o la cintura también lo estén! + *[unknown] El muslo izquierdo está asignado, ¡pero necesitas que la parte del cuerpo desconocida no asignada también lo esté! + } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-RIGHT_UPPER_LEG = + { $unassigned -> + [0] El muslo derecho está asignado, ¡pero necesitas que el pecho, la cadera o la cintura también lo estén! + *[unknown] El muslo derecho está asignado, ¡pero necesitas que la parte del cuerpo desconocida no asignada también lo esté! + } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-HIP = + { $unassigned -> + [0] La cadera está asignada, ¡pero necesitas que el pecho también lo esté! + *[unknown] La cadera está asignada, ¡pero necesitas que la parte del cuerpo desconocida no asignada también lo esté! + } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-WAIST = + { $unassigned -> + [0] La cintura está asignada, ¡pero necesitas que el pecho también lo esté! + *[unknown] La cintura está asignada, ¡pero necesitas que la parte del cuerpo desconocida no asignada también lo esté! + } ## Tracker mounting method choose -# Italized text -onboarding-choose_mounting-auto_mounting-label = Experimental -# Italized text -onboarding-choose_mounting-manual_mounting-label = Recomendado +onboarding-choose_mounting = ¿Qué método de calibración de montura usara? +# Multiline text +onboarding-choose_mounting-description = La posición de montura corrige la colocación de los trackers en el cuerpo. +onboarding-choose_mounting-auto_mounting = Calibración de montura automatica +# Italicized text +onboarding-choose_mounting-auto_mounting-label-v2 = Recomendada +onboarding-choose_mounting-auto_mounting-description = Esto detectará automáticamente la posición de montura para todos sus trackers a partir de 2 poses +onboarding-choose_mounting-manual_mounting = Calibración de montura manual +# Italicized text +onboarding-choose_mounting-manual_mounting-label-v2 = Puede que no sea lo suficientemente precisa +onboarding-choose_mounting-manual_mounting-description = Esto te permitirá elegir la posición de montura para cada tracker de manera manual +# Multiline text +onboarding-choose_mounting-manual_modal-title = + ¿Está seguro de que desea realizar + la calibración automática de montura? +onboarding-choose_mounting-manual_modal-description = La calibración de montaje manual se recomienda para nuevos usuarios, ya que las poses de la calibración de montaje automática pueden ser difíciles de acertar a la primera y pueden requerir algo de práctica. +onboarding-choose_mounting-manual_modal-confirm = Sé lo que estoy haciendo onboarding-choose_mounting-manual_modal-cancel = Cancelar ## Tracker manual mounting setup +onboarding-manual_mounting-back = Volver atrás para entrar en VR +onboarding-manual_mounting = Calibración de montura manual +onboarding-manual_mounting-description = Haz clic en cada tracker y selecciona la forma en la que están montados +onboarding-manual_mounting-auto_mounting = Calibración de montura automatica onboarding-manual_mounting-next = Siguiente paso ## Tracker automatic mounting setup onboarding-automatic_mounting-back = Volver para entrar en VR +onboarding-automatic_mounting-title = Calibración de montura +onboarding-automatic_mounting-description = Para que los trackers de SlimeVR funcionen, necesitamos asignar una posición de montura a tus trackers para alinearlos con la posicion física del tracker. +onboarding-automatic_mounting-manual_mounting = Calibración de montura manual onboarding-automatic_mounting-next = Siguiente paso onboarding-automatic_mounting-prev_step = Paso anterior +onboarding-automatic_mounting-done-title = Posiciones de monturas calibradas. +onboarding-automatic_mounting-done-description = ¡Su calibración de montura está completa! onboarding-automatic_mounting-done-restart = Volver a intentarlo +onboarding-automatic_mounting-mounting_reset-title = Reinicio de montura +onboarding-automatic_mounting-mounting_reset-step-0 = 1. Ponte en cuclillas en postura de "esquí" con las piernas dobladas, la parte superior del cuerpo inclinada hacia adelante y los brazos doblados. +onboarding-automatic_mounting-mounting_reset-step-1 = 2. Presiona el botón "Restablecer montaje" y espera 3 segundos antes de que se restablezcan las orientaciones de montaje de los trackers. onboarding-automatic_mounting-preparation-title = Preparación +onboarding-automatic_mounting-preparation-step-0 = 1. Mantente erguido con los brazos a los lados. +onboarding-automatic_mounting-preparation-step-1 = 2. Pulse el botón "Reinicio completo" y espere 3 segundos antes de que los trackers se reinicien. +onboarding-automatic_mounting-put_trackers_on-title = Ponte los trackers +onboarding-automatic_mounting-put_trackers_on-description = Para calibrar la posiciones de montura, vamos a utilizar los trackers que acabas de asignar. Colocate todos tus trackers, puedes ver cuales son cuales en la figura de la derecha. +onboarding-automatic_mounting-put_trackers_on-next = Tengo todos mis trackers en posicion ## Tracker proportions method choose +onboarding-choose_proportions = ¿Qué método de calibración de proporciones utilizara? +# Multiline string +onboarding-choose_proportions-description-v1 = + Las proporciones corporales se utilizaran para conocer las medidas de tu cuerpo. Son necesarias para calcular las posiciones de los trackers. + Cuando las proporciones de tu cuerpo no coincidan con las guardadas, la precisión del tracking será peor y notarás cosas como que patinas o te deslizas, o que tu cuerpo no se ajusta bien a tu avatar. + ¡Sólo necesitas medir tu cuerpo una vez! A menos que estén mal o tu cuerpo haya cambiado, entonces no necesitas volver a hacerlo. onboarding-choose_proportions-auto_proportions = Proporciones automáticas -# Italized text +# Italicized text onboarding-choose_proportions-auto_proportions-subtitle = Recomendado +onboarding-choose_proportions-auto_proportions-descriptionv3 = + Adivinará tus proporciones grabando una muestra de tus movimientos y pasándola por un algoritmo. + + ¡Esto requiere tener tu visor (HMD) conectado a SlimeVR y en tu cabeza! onboarding-choose_proportions-manual_proportions = Proporciones manuales +# Italicized text +onboarding-choose_proportions-manual_proportions-subtitle = Para pequeños retoques +onboarding-choose_proportions-manual_proportions-description = Esto te permitirá ajustar tus proporciones manualmente modificándolas directamente onboarding-choose_proportions-export = Exportar proporciones +onboarding-choose_proportions-import = Importar proporciones onboarding-choose_proportions-import-success = Importado +onboarding-choose_proportions-import-failed = Fallido onboarding-choose_proportions-file_type = Archivo de proporciones físicas ## Tracker manual proportions setup +onboarding-manual_proportions-back = Volver al tutorial de reinicios onboarding-manual_proportions-title = Proporciones físicas manuales +onboarding-manual_proportions-precision = Ajuste por precisión onboarding-manual_proportions-auto = Proporciones automáticas +onboarding-manual_proportions-ratio = Ajustar por grupos de ratio ## Tracker automatic proportions setup +onboarding-automatic_proportions-back = Volver al tutorial de reinicio onboarding-automatic_proportions-title = Mide tu cuerpo +onboarding-automatic_proportions-description = Para que los trackers de SlimeVR funcionen, necesitamos saber tus proporciones corporales. Esta breve calibración lo medirá por ti. +onboarding-automatic_proportions-manual = Proporciones manuales onboarding-automatic_proportions-prev_step = Paso anterior +onboarding-automatic_proportions-put_trackers_on-title = Ponte los trackers +onboarding-automatic_proportions-put_trackers_on-description = Para calibrar tus proporciones, vamos a utilizar los trackers que acabas de asignar. Ponte todos tus trackers, puedes ver cuáles son cuáles en la figura de la derecha. +onboarding-automatic_proportions-put_trackers_on-next = Tengo todos mis trackers puestos onboarding-automatic_proportions-requirements-title = Requisitos +# Each line of text is a different list item +onboarding-automatic_proportions-requirements-descriptionv2 = + Tienes al menos suficientes trackers para trackear tus pies (generalmente 5 trackers). + Los trackers y tu visor están encendidos y los llevas puestos. + Tus trackers y visor está conectados al servidor de SlimeVR y funcionan correctamente (ej. sin cortes, sin desconexiones, etc). + Tu visor están reportando datos de posición al servidor de SlimeVR (esto generalmente significa tener SteamVR ejecutándose y conectado a SlimeVR usando el driver para SteamVR de SlimeVR). + Su tracking está funcionando y está representando con precisión sus movimientos (ej. usted ha realizado un reinicio completo y se mueven en la dirección correcta al patear, agacharse, sentarse, etc). onboarding-automatic_proportions-requirements-next = He leído los requisitos +onboarding-automatic_proportions-check_height-title = Comprueba tu altura +onboarding-automatic_proportions-check_height-description = Utilizamos tu estatura como base de nuestras mediciones utilizando la altura de tu visor (HMD) como aproximación a tu estatura real, ¡pero es mejor que compruebes tú mismo si son correctas! +# All the text is in bold! +onboarding-automatic_proportions-check_height-calculation_warning = Por favor, pulse el botón mientras esté derecho para calcular su altura. ¡Tienes 3 segundos después de pulsar el botón! +onboarding-automatic_proportions-check_height-guardian_tip = + Si usted está usando un visor VR standalone, ¡asegúrese de tener su guardián / + limite activado para que tu altura sea la correcta! +onboarding-automatic_proportions-check_height-fetch_height = ¡Estoy de pie! +# Context is that the height is unknown +onboarding-automatic_proportions-check_height-unknown = Desconocida +# Shows an element below it +onboarding-automatic_proportions-check_height-hmd_height1 = La altura de tu HMD es +# Shows an element below it +onboarding-automatic_proportions-check_height-height1 = por lo que tu altura real es +onboarding-automatic_proportions-check_height-next_step = Están bien +onboarding-automatic_proportions-start_recording-title = Prepárate para moverte +onboarding-automatic_proportions-start_recording-description = Ahora vamos a grabar algunas poses y movimientos específicos. Se le indicarán en la siguiente pantalla. ¡Prepárate para empezar cuando pulse el botón! +onboarding-automatic_proportions-start_recording-next = Iniciar grabación onboarding-automatic_proportions-recording-title = REC +onboarding-automatic_proportions-recording-description-p0 = Grabación en curso... +onboarding-automatic_proportions-recording-description-p1 = Realiza los movimientos que se muestran a continuación: +# Each line of text is a different list item +onboarding-automatic_proportions-recording-steps = + Parado derecho, gira tu cabeza en un circulo. + Dobla la espalda hacia delante y ponte en cuclillas. En cuclillas, mira a la izquierda y luego a la derecha. + Gira la parte superior de tu cuerpo hacia la izquierda (en el sentido contrario a las agujas del reloj) y luego estira los brazos hacia el suelo. + Gira la parte superior de tu cuerpo hacia la derecha (en el sentido de las agujas del reloj) y luego estira los brazos hacia el suelo. + Gira las caderas en un movimiento circular como si estuvieras usando un aro redondo. + Si queda tiempo de grabación, puedes repetir estos pasos hasta que termine. onboarding-automatic_proportions-recording-processing = Procesando los resultados +# $time (Number) - Seconds left for the automatic calibration recording to finish (max 20) +onboarding-automatic_proportions-recording-timer = + { $time -> + [one] Queda 1 segundo + *[other] Quedan { $time } segundos + } onboarding-automatic_proportions-verify_results-title = Verificar resultados +onboarding-automatic_proportions-verify_results-description = Revisa los resultados a continuación, ¿Son correctos? +onboarding-automatic_proportions-verify_results-results = Resultados de la grabación onboarding-automatic_proportions-verify_results-processing = Procesando los resultados +onboarding-automatic_proportions-verify_results-redo = Rehacer la grabación +onboarding-automatic_proportions-verify_results-confirm = Estan correctas onboarding-automatic_proportions-done-title = Proporciones medidas y guardadas. onboarding-automatic_proportions-done-description = ¡Calibración de las proporciones físicas completada! +onboarding-automatic_proportions-error_modal-confirm = ¡Entendido! ## Home +home-no_trackers = No se han detectado ni asignado trackers ## Trackers Still On notification +trackers_still_on-modal-title = Los trackers siguen encendidos +trackers_still_on-modal-description = + Uno o más trackers siguen encendidos. + Aún quieres salir de SlimeVR? +trackers_still_on-modal-confirm = Salir de SlimeVR +trackers_still_on-modal-cancel = Un momento... ## Status system +status_system-StatusTrackerReset = Se recomienda realizar un reinicio completo ya que uno o más trackers están desajustados. +status_system-StatusSteamVRDisconnected = + { $type -> + [steamvr_feeder] Actualmente no está conectado a la SlimeVR Feeder App. + *[steamvr] Actualmente no está conectado a SteamVR a través del controlador de SlimeVR. + } +status_system-StatusTrackerError = El tracker { $trackerName } tiene un error. +status_system-StatusUnassignedHMD = El casco de RV debe asignarse como tracker de cabeza. ## Tray Menu +tray_menu-show = Mostrar +tray_menu-hide = Ocultar +tray_menu-quit = Salir ## First exit modal +tray_or_exit_modal-title = ¿Qué debe hacer el botón de cierre? +# Multiline text +tray_or_exit_modal-description = + Esto te permite elegir si quieres salir de la aplicación o minimizarlo a la bandeja al pulsar el botón de cerrar. + + ¡Puedes cambiar esto más tarde en la configuración de la interfaz! +tray_or_exit_modal-radio-exit = Salir al cerrar +tray_or_exit_modal-radio-tray = Minimizar a la bandeja +tray_or_exit_modal-submit = Guardar +tray_or_exit_modal-cancel = Cancelar ## Unknown device modal +unknown_device-modal-title = ¡Se ha encontrado un nuevo tracker! +unknown_device-modal-description = + Hay un nuevo tracker con dirección MAC { $deviceId }. + ¿Quieres conectarlo a SlimeVR? +unknown_device-modal-confirm = ¡Claro! +unknown_device-modal-forget = Ignóralo diff --git a/gui/public/i18n/fi/translation.ftl b/gui/public/i18n/fi/translation.ftl index 6130f25b1..1d1d2846d 100644 --- a/gui/public/i18n/fi/translation.ftl +++ b/gui/public/i18n/fi/translation.ftl @@ -196,6 +196,7 @@ tracker-infos-hardware_rev = Laitteston Tarkistus tracker-infos-hardware_identifier = Laitteiston ID tracker-infos-imu = IMU-Sensor tracker-infos-board_type = Päälevy +tracker-infos-network_version = Protokollan versio ## Tracker settings @@ -304,10 +305,16 @@ settings-general-steamvr-description = Hyödyllinen peleille tai sovelluksille, jotka tukevat vain tiettyjä jäljittimiä. settings-general-steamvr-trackers-waist = Vyötärö settings-general-steamvr-trackers-chest = Rinta -settings-general-steamvr-trackers-feet = Jalat -settings-general-steamvr-trackers-knees = Polvet -settings-general-steamvr-trackers-elbows = Kyynärpäät -settings-general-steamvr-trackers-hands = Kädet +settings-general-steamvr-trackers-left_foot = Vasen jalkaterä +settings-general-steamvr-trackers-right_foot = Oikea jalkaterä +settings-general-steamvr-trackers-left_knee = Vasen polvi +settings-general-steamvr-trackers-right_knee = Oikea polvi +settings-general-steamvr-trackers-left_elbow = Vasen kyynärpää +settings-general-steamvr-trackers-right_elbow = Oikea kyynärpää +settings-general-steamvr-trackers-left_hand = Vasen käsi +settings-general-steamvr-trackers-right_hand = Oikea käsi +settings-general-steamvr-trackers-hands-warning-cancel = Peruuta +settings-general-steamvr-trackers-hands-warning-done = Kyllä ## Tracker mechanics @@ -359,6 +366,8 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Jalkojen asennuksen no settings-general-fk_settings-arm_fk = Käsivarsien jäljitys settings-general-fk_settings-arm_fk-description = Muuta tapaa, jolla käsivarsia jäljitetään. settings-general-fk_settings-arm_fk-force_arms = Pakota kädet HMD:ltä +settings-general-fk_settings-reset_settings = Palauta asetukset +settings-general-fk_settings-reset_settings-reset_hmd_pitch = Nollaa HMD-sävelkorkeus settings-general-fk_settings-arm_fk-reset_mode-description = Muuta, mikä käsivarren asentoa odotetaan asennuksen nollaukselle. settings-general-fk_settings-arm_fk-back = Takaisin settings-general-fk_settings-arm_fk-tpose_up = T-asento (ylös) @@ -446,6 +455,12 @@ settings-general-interface-feedback_sound-label = Palaute ääni settings-general-interface-feedback_sound-volume = Palaute äänen voimakkuus settings-general-interface-connected_trackers_warning = Yhdistettyjen jäljittimien varoitus settings-general-interface-connected_trackers_warning-description = Tämä vaihtoehto näyttää ponnahdusikkunan aina, kun yrität poistua SlimeVR:stä, kun sinulla on yksi tai useampi yhdistetty jäljitin. Se muistuttaa sinua sammuttamaan jäljittimet, kun olet valmis, akun käyttöiän säästämiseksi. +settings-general-interface-use_tray = Pienennä ilmaisinalueelle +settings-general-interface-use_tray-description = Voit sulkea ikkunan sulkematta SlimeVR-palvelinta, jotta voit jatkaa sen käyttöä ilman, että graafinen käyttöliittymä häiritsee sinua. +settings-general-interface-use_tray-label = Pienennä ilmaisinalueelle +settings-general-interface-discord_presence = Jaa toiminta Discordissa +settings-general-interface-discord_presence-description = Kertoo Discordille, että käytät SlimeVR:ää, sekä käyttämiesi IMU-seurantalaitteiden määrän. +settings-general-interface-discord_presence-label = Jaa toiminta Discordissa ## Serial settings @@ -467,6 +482,8 @@ settings-serial-factory_reset-warning-cancel = Peruuta settings-serial-get_infos = Hanki tietoja settings-serial-serial_select = Valitse sarjaportti settings-serial-auto_dropdown_item = Autom. +settings-serial-file_type = Teksti +settings-serial-save_logs = Tallenna tiedostoon ## OSC router settings @@ -496,15 +513,11 @@ settings-osc-router-network-address-placeholder = IPV4-osoite ## OSC VRChat settings settings-osc-vrchat = VRChat OSC -jäljittimet -# This cares about multilines -settings-osc-vrchat-description = - Muuta VRChat-kohtaisia asetuksia vastaanottamaan HMD-dataa ja - lähettämään jäljitindataa FBT:tä varten (toimii Quest-standalone:ssa). settings-osc-vrchat-enable = Käytä settings-osc-vrchat-enable-description = Vaihda tietojen lähettäminen ja vastaanottaminen. settings-osc-vrchat-enable-label = Käytä settings-osc-vrchat-network = Verkkoportit -settings-osc-vrchat-network-description = Aseta portit kuuntelua ja tietojen lähettämistä varten VRChatiin. +settings-osc-vrchat-network-description-v1 = Aseta portit tietojen kuuntelua ja lähettämistä varten. Voidaan jättää koskematta VRChatille. settings-osc-vrchat-network-port_in = .label = Portti sisään .placeholder = Portti sisään (oletus: 9001) @@ -512,7 +525,7 @@ settings-osc-vrchat-network-port_out = .label = Portti ulos .placeholder = Portti ulos (oletus: 9000) settings-osc-vrchat-network-address = Verkon osoite -settings-osc-vrchat-network-address-description = Valitse, mikä osoite lähettää tietoja VRChatiin (tarkista laitteesi Wi-Fi-asetukset). +settings-osc-vrchat-network-address-description-v1 = Valitse, mihin osoitteeseen tiedot lähetetään. Voidaan jättää koskematta VRChatille. settings-osc-vrchat-network-address-placeholder = VRChat IP-osoite settings-osc-vrchat-network-trackers = Jäljittimet settings-osc-vrchat-network-trackers-description = Vaihda tiettyjen jäljittimien lähettäminen OSC:n kautta. @@ -632,8 +645,6 @@ onboarding-done-close = Sulje opas onboarding-connect_tracker-back = Palaa Wi-Fi-tunnistetietoihin onboarding-connect_tracker-title = Yhdistä jäljittimet -onboarding-connect_tracker-description-p0 = Nyt hauskaan osaan, kaikkien jäljittimien yhdistämiseen! -onboarding-connect_tracker-description-p1 = Yhdistä vain kaikki, joita ei ole vielä yhdistetty, USB-portin kautta. onboarding-connect_tracker-issue-serial = Minulla on ongelmia yhteyden muodostamisessa! onboarding-connect_tracker-usb = USB-jäljitin onboarding-connect_tracker-connection_status-none = Etsitään jäljittimiä @@ -768,12 +779,8 @@ onboarding-choose_mounting = Mitä asennuskalibrointimenetelmää käytetään? # Multiline text onboarding-choose_mounting-description = Asennussuuntaus korjaa jäljittimien sijoittelun kehossasi. onboarding-choose_mounting-auto_mounting = Automaattinen asennus -# Italized text -onboarding-choose_mounting-auto_mounting-label = Kokeellinen onboarding-choose_mounting-auto_mounting-description = Tämä tunnistaa automaattisesti kaikkien jäljittimiesi asennussuunnat 2 asennosta onboarding-choose_mounting-manual_mounting = Manuaalinen asennus -# Italized text -onboarding-choose_mounting-manual_mounting-label = Suositeltu onboarding-choose_mounting-manual_mounting-description = Näin voit valita asennussuunnan manuaalisesti kullekin jäljittimelle # Multiline text onboarding-choose_mounting-manual_modal-title = @@ -895,3 +902,12 @@ status_system-StatusSteamVRDisconnected = *[other] Tällä hetkellä ei ole yhdistetty SteamVR:ään SlimeVR-ajurin kautta. } status_system-StatusTrackerError = { $trackerName } jäljittimessä on virhe + +## Tray Menu + + +## First exit modal + + +## Unknown device modal + diff --git a/gui/public/i18n/fr/translation.ftl b/gui/public/i18n/fr/translation.ftl index cce6b541c..a36f2f9fb 100644 --- a/gui/public/i18n/fr/translation.ftl +++ b/gui/public/i18n/fr/translation.ftl @@ -81,6 +81,11 @@ skeleton_bone-ELBOW_OFFSET = Décalage des coudes ## Tracker reset buttons reset-reset_all = Réinitialiser toutes les proportions +reset-reset_all_warning = + Avertissement: Cela réinitialisera vos proportions pour qu’elles soient basées sur votre taille. + Êtes-vous sûr de vouloir faire cela ? +reset-reset_all_warning-reset = Réinitialiser les proportions +reset-reset_all_warning-cancel = Annuler reset-full = Réinitialisation complète reset-mounting = Réinitialiser l'alignement reset-yaw = Réinitialisation horizontale @@ -126,7 +131,7 @@ widget-drift_compensation-clear = Réinitialiser la compensation de la dérive ## Widget: Clear Reset Mounting -widget-clear_mounting = Mettre à zéro la réinitialisation de l'alignement +widget-clear_mounting = Réinitialiser la calibration de l'alignement ## Widget: Developer settings @@ -142,9 +147,12 @@ widget-developer_mode-more_info = Plus d'informations ## Widget: IMU Visualizer widget-imu_visualizer = Rotation +widget-imu_visualizer-preview = Aperçu +widget-imu_visualizer-hide = Masquer widget-imu_visualizer-rotation_raw = Brute widget-imu_visualizer-rotation_preview = Aperçu -widget-imu_visualizer-rotation_hide = Masquer +widget-imu_visualizer-acceleration = Accélération +widget-imu_visualizer-position = Position ## Widget: Skeleton Visualizer @@ -199,6 +207,13 @@ tracker-infos-hardware_identifier = ID Matériel tracker-infos-imu = Capteur IMU tracker-infos-board_type = Carte principale tracker-infos-network_version = Version du protocole +tracker-infos-magnetometer = Magnétomètre +tracker-infos-magnetometer-status-v1 = + { $status -> + [DISABLED] Désctivé + [ENABLED] Activé + *[NOT_SUPPORTED] Non pris en charge + } ## Tracker settings @@ -213,11 +228,19 @@ tracker-settings-mounting_section-edit = Changer l'orientation tracker-settings-drift_compensation_section = Permettre la compensation de la dérive tracker-settings-drift_compensation_section-description = Ce capteur devrait-il compenser pour sa dérive quand l'option est activée ? tracker-settings-drift_compensation_section-edit = Permettre la compensation de la dérive +tracker-settings-use_mag = Autoriser l'utilisation du magnétomètre sur ce capteur +# Multiline! +tracker-settings-use_mag-description = + Est-ce que ce capteur utiliser son magnétomètre pour réduire la dérive lorsque l’utilisation du magnétomètre est autorisée ? N’éteignez pas votre capteur pendant que vous changez cette option ! + + Vous devez d’abord autoriser l’utilisation du magnétomètre dans les paramètres. Cliquez ici pour y accéder. +tracker-settings-use_mag-label = Autoriser le magnétomètre # The . means it's an attribute and it's related to the top key. # In this case that is the settings for the assignment section. tracker-settings-name_section = Nom personalisé tracker-settings-name_section-description = Donnez-lui un joli surnom :3 tracker-settings-name_section-placeholder = Patte gauche d'Erimel +tracker-settings-name_section-label = Nom personalisé tracker-settings-forget = Oublier capteur tracker-settings-forget-description = Supprime le capteur du serveur SlimeVR et l’empêche de s’y connecter jusqu’à ce que le serveur soit redémarré. La configuration du capteur ne sera pas perdue. tracker-settings-forget-label = Oublier capteur @@ -296,6 +319,7 @@ settings-sidebar-utils = Utilitaires settings-sidebar-serial = Console série settings-sidebar-appearance = Apparence settings-sidebar-notifications = Notifications +settings-sidebar-advanced = Avancé ## SteamVR settings @@ -310,10 +334,14 @@ settings-general-steamvr-description = Utile pour les jeux ou applications qui ne supportent que certains capteurs. settings-general-steamvr-trackers-waist = Taille settings-general-steamvr-trackers-chest = Poitrine -settings-general-steamvr-trackers-feet = Pieds -settings-general-steamvr-trackers-knees = Genoux -settings-general-steamvr-trackers-elbows = Coudes -settings-general-steamvr-trackers-hands = Mains +settings-general-steamvr-trackers-left_foot = Pied gauche +settings-general-steamvr-trackers-right_foot = Pied droit +settings-general-steamvr-trackers-left_knee = Genou gauche +settings-general-steamvr-trackers-right_knee = Genou droit +settings-general-steamvr-trackers-left_elbow = Coude gauche +settings-general-steamvr-trackers-right_elbow = Coude droit +settings-general-steamvr-trackers-left_hand = Main gauche +settings-general-steamvr-trackers-right_hand = Main droite settings-general-steamvr-trackers-tracker_toggling = Assignation automatique des capteurs settings-general-steamvr-trackers-tracker_toggling-description = Gère automatiquement l’activation ou la désactivation des capteurs SteamVR en fonction de vos capteurs actuellement affectés settings-general-steamvr-trackers-tracker_toggling-label = Assignation automatique des capteurs @@ -346,6 +374,20 @@ settings-general-tracker_mechanics-drift_compensation-description = Compense la dérive des gyroscopes en appliquant une rotation inverse. Modifier la force de la compensation et le nombre de réinitialisations prises en compte. settings-general-tracker_mechanics-drift_compensation-enabled-label = Compensation de la dérive +settings-general-tracker_mechanics-drift_compensation-prediction = Prédiction de la compensation de la dérive +# This cares about multilines +settings-general-tracker_mechanics-drift_compensation-prediction-description = + Prédit la compensation de la dérive au-delà de la dérive précédemment mesurée. + Activez cette option si vos capteurs tournent continuellement sur eux-mêmes horizontalement. +settings-general-tracker_mechanics-drift_compensation-prediction-label = Prédiction de la compensation de la dérive +settings-general-tracker_mechanics-drift_compensation_warning = + Avertissement: n’utilisez la compensation de la dérive que si vous devez + réinitialiser très souvent (toutes les ~5-10 minutes). + + Voici quelques IMUs sujets à des réinitialisations fréquentes : + Joy-Cons, owoTrack et MPUs (sans firmware récent). +settings-general-tracker_mechanics-drift_compensation_warning-cancel = Annuler +settings-general-tracker_mechanics-drift_compensation_warning-done = Je comprends settings-general-tracker_mechanics-drift_compensation-amount-label = Force de la compensation settings-general-tracker_mechanics-drift_compensation-max_resets-label = Nombre de réinitialisations prises en compte settings-general-tracker_mechanics-save_mounting_reset = Enregistrer la calibration de la réinitialisation automatique de l'alignement @@ -353,6 +395,11 @@ settings-general-tracker_mechanics-save_mounting_reset-description = Enregistre les calibrations des réinitialisation automatiques d'alignement pour les capteurs entre les redémarrages. Utile lorsque vous portez une combinaison où les capteurs ne bougent pas entre les sessions. Non recommandé pour les utilisateurs normaux ! settings-general-tracker_mechanics-save_mounting_reset-enabled-label = Enregistrer la réinitialisation de l'alignement +settings-general-tracker_mechanics-use_mag_on_all_trackers = Utiliser le magnétomètre sur tous les capteurs IMU qui le prennent en charge +settings-general-tracker_mechanics-use_mag_on_all_trackers-description = + Utilise le magnétomètre sur tous les capteurs dotés d’un firmware compatible, réduisant ainsi la dérive dans des environnements magnétiques stables. + Peut être désactivé par capteur dans les paramètres du capteur. Ne fermez aucun des capteurs en changeant cette option ! +settings-general-tracker_mechanics-use_mag_on_all_trackers-label = Utiliser le magnétomètre sur les capteurs ## FK/Tracking settings @@ -379,6 +426,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Réinitialisation de l settings-general-fk_settings-arm_fk = Capture des bras settings-general-fk_settings-arm_fk-description = Changez la façon dont les bras sont captés. settings-general-fk_settings-arm_fk-force_arms = Forcer les bras en provenance du casque VR +settings-general-fk_settings-reset_settings = Paramètres de réinitialisations +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Réinitialisez la rotation verticale du casque VR lors d’une réinitialisation complète. Utile pour porter un casque VR sur le front pour le VTubing ou l'animation. Ne pas activer pour la VR. +settings-general-fk_settings-reset_settings-reset_hmd_pitch = Réinitialiser la rotation verticale du casque VR settings-general-fk_settings-arm_fk-reset_mode-description = Changer la pose des bras attendue pour la réinitialisation de l'alignement. settings-general-fk_settings-arm_fk-back = En arrière settings-general-fk_settings-arm_fk-back-description = Le mode par défaut, avec les bras vers l’arrière et les avant-bras vers l’avant. @@ -447,6 +497,9 @@ settings-general-interface-dev_mode = Mode développeur settings-general-interface-dev_mode-description = Ce mode peut être utile pour avoir des données approfondies ou pour interagir avec des capteurs connectés à un niveau plus avancé. settings-general-interface-dev_mode-label = Mode développeur settings-general-interface-theme = Thème +settings-general-interface-show-navbar-onboarding = Afficher « { navbar-onboarding } » dans la barre de navigation +settings-general-interface-show-navbar-onboarding-description = Cela change si le bouton « { navbar-onboarding } » s’affiche dans la barre de navigation. +settings-general-interface-show-navbar-onboarding-label = Afficher « { navbar-onboarding } » settings-general-interface-lang = Langue settings-general-interface-lang-description = Choisir la langue par défaut. settings-general-interface-lang-placeholder = Langue @@ -458,6 +511,9 @@ settings-interface-appearance-font-os_font = Police du système d’exploitation settings-interface-appearance-font-slime_font = Police par défaut settings-interface-appearance-font_size = Agrandissement du texte settings-interface-appearance-font_size-description = Cela affecte la taille du texte de toute l'interface, sauf de ce menu. +settings-interface-appearance-decorations = Utiliser les décorations natives du système +settings-interface-appearance-decorations-description = Cela n'affichera pas la barre supérieure de l'interface et utilisera celle du système d'exploitation à la place. +settings-interface-appearance-decorations-label = Utiliser les décorations natives ## Notification settings @@ -475,6 +531,15 @@ settings-general-interface-connected_trackers_warning-label = Avertissement de c settings-general-interface-use_tray = Minimiser dans la zone de notifications settings-general-interface-use_tray-description = Vous permet de fermer la fenêtre sans fermer le serveur SlimeVR afin que vous puissiez continuer à l’utiliser sans l’interface graphique. settings-general-interface-use_tray-label = Minimiser dans la zone de notifications +settings-general-interface-discord_presence = Partager l'activité sur Discord +settings-general-interface-discord_presence-description = Indique à votre client Discord que vous utilisez SlimeVR avec le nombre de capteurs IMU que vous utilisez. +settings-general-interface-discord_presence-label = Partager l'activité sur Discord +settings-general-interface-discord_presence-message = + { $amount -> + [0] Aucun capteur + [one] Utilise { $amount } capteur + *[other] Utilise { $amount } capteurs + } ## Serial settings @@ -497,6 +562,8 @@ settings-serial-get_infos = Obtenir des informations settings-serial-serial_select = Sélectionnez un port série settings-serial-auto_dropdown_item = Automatique settings-serial-get_wifi_scan = Obtenir scan WiFi +settings-serial-file_type = Texte brut +settings-serial-save_logs = Enregistrer dans un fichier ## OSC router settings @@ -527,14 +594,17 @@ settings-osc-router-network-address-placeholder = Adresse IPv4 settings-osc-vrchat = Capteurs OSC VRChat # This cares about multilines -settings-osc-vrchat-description = - Modifiez les paramètres spécifiques à VRChat pour recevoir et envoyer - des capteurs par OSC (fonctionne sur Quest sans PC). +settings-osc-vrchat-description-v1 = + Modifier les paramètres spécifiques à la norme « OSC Trackers » utilisée pour l’envoi + des données de suivi vers des applications sans SteamVR (par exemple, sur Quest). + Assurez-vous d’activer le protocole OSC dans VRChat via le menu d'action (rond) sous OSC > Enabled. + Pour permettre de recevoir les données de suivi du casque VR et des manettes à partir de VRChat, + allez dans le menu principal sous Tracking & IK > Allow Sending Head and Wrist VR Tracking OSC Data. settings-osc-vrchat-enable = Activer settings-osc-vrchat-enable-description = Activer/désactiver l'envoi et la réception de données. settings-osc-vrchat-enable-label = Activer settings-osc-vrchat-network = Ports réseau -settings-osc-vrchat-network-description = Définissez les ports pour écouter et envoyer des données à VRChat. +settings-osc-vrchat-network-description-v1 = Définissez les ports d'écoute et d'envoi des données. Peut être laissé intact pour VRChat. settings-osc-vrchat-network-port_in = .label = Port d'entrée .placeholder = Port d'entrée (par défaut : 9001) @@ -542,7 +612,7 @@ settings-osc-vrchat-network-port_out = .label = Port de sortie .placeholder = Port de sortie (par défaut : 9000) settings-osc-vrchat-network-address = Adresse réseau -settings-osc-vrchat-network-address-description = Choisissez l'adresse à laquelle envoyer les données à VRChat (vérifiez les réseaux Wi-Fi de votre appareil). +settings-osc-vrchat-network-address-description-v1 = Choisissez l'adresse à laquelle envoyer des données. Peut être laissé intact pour VRChat. settings-osc-vrchat-network-address-placeholder = Adresse IP VRChat settings-osc-vrchat-network-trackers = capteurs settings-osc-vrchat-network-trackers-description = Sélectionner quels capteurs envoyer via OSC. @@ -585,6 +655,39 @@ settings-osc-vmc-vrm-file_select = Glissez et déposez un modèle à utiliser, o settings-osc-vmc-anchor_hip = Ancrage aux hanches settings-osc-vmc-anchor_hip-description = Ancrer la capture des mouvements aux hanches, utile pour le VTubing assis. settings-osc-vmc-anchor_hip-label = Ancrage aux hanches +settings-osc-vmc-mirror_tracking = Inverser les mouvements +settings-osc-vmc-mirror_tracking-description = Inverse les mouvements horizontalement +settings-osc-vmc-mirror_tracking-label = Inverser les mouvements + +## Advanced settings + +settings-utils-advanced = Avancé +settings-utils-advanced-reset-gui = Réinitialiser les paramètres de l’interface graphique +settings-utils-advanced-reset-gui-description = Restaurez les paramètres par défaut de l'interface. +settings-utils-advanced-reset-gui-label = Réinitialiser l’interface graphique +settings-utils-advanced-reset-server = Réinitialiser les paramètres de la capture +settings-utils-advanced-reset-server-description = Restaurez les paramètres par défaut de la capture +settings-utils-advanced-reset-server-label = Réinitialiser la capture +settings-utils-advanced-reset-all = Réinitialiser tous les paramètres +settings-utils-advanced-reset-all-description = Restaurez les paramètres de l'interface et de la capture. +settings-utils-advanced-reset-all-label = Tout réinitialiser +settings-utils-advanced-reset_warning = + { $type -> + [gui] + Avertissement: Cela réinitialisera vos paramètres de l'interface. + Êtes-vous sûr de vouloir faire cela ? + [server] + Avertissement: Cela réinitialisera vos paramètres de la capture. + Êtes-vous sûr de vouloir faire cela ? + *[all] + Avertissement: Cela réinitialisera tous vos paramètres. + Êtes-vous sûr de vouloir faire cela ? + } +settings-utils-advanced-reset_warning-reset = Réinitialiser les paramètres +settings-utils-advanced-reset_warning-cancel = Annuler +settings-utils-advanced-open_data = Dossier des données +settings-utils-advanced-open_data-description = Ouvre le dossier des données de SlimeVR dans l’explorateur de fichiers, contenant les fichiers de configuration ainsi que les logs. +settings-utils-advanced-open_data-label = Ouvrir le dossier ## Setup/onboarding menu @@ -697,6 +800,7 @@ onboarding-calibration_tutorial-status-waiting = En attente de vous onboarding-calibration_tutorial-status-calibrating = Calibration... onboarding-calibration_tutorial-status-success = Génial ! onboarding-calibration_tutorial-status-error = Le capteur a été déplacé +onboarding-calibration_tutorial-skip = Sauter le tutoriel ## Tracker assignment tutorial @@ -724,6 +828,27 @@ onboarding-assign_trackers-assigned = onboarding-assign_trackers-advanced = Afficher les emplacements d'attribution avancés onboarding-assign_trackers-next = J'ai attribué tous mes capteurs onboarding-assign_trackers-mirror_view = Vue miroir +onboarding-assign_trackers-option-amount = + { $trackersCount -> + [one] x{ $trackersCount } + *[other] x{ $trackersCount } + } +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] Kit du bas du corps + [core] Kit de base + [enhanced-core] Kit de base renforcé + [full-body] Kit du corps complet + *[all] Tous les capteurs + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] Minimum pour le suivi du corps en réalité virtuelle + [core] + Suivi amélioré de la colonne vertébrale + [enhanced-core] + Rotation des pieds + [full-body] + Suivi des coudes + *[all] Toutes les attributions de capteurs disponibles + } ## Tracker assignment warnings @@ -799,12 +924,12 @@ onboarding-choose_mounting = Quelle méthode de calibration de l’alignement ut # Multiline text onboarding-choose_mounting-description = La calibration de l'alignement ajuste pour l'orientation des capteurs sur votre corps. onboarding-choose_mounting-auto_mounting = Alignement automatique -# Italized text -onboarding-choose_mounting-auto_mounting-label = Expérimentale +# Italicized text +onboarding-choose_mounting-auto_mounting-label-v2 = Recommendée onboarding-choose_mounting-auto_mounting-description = Ceci permettra de détecter automatiquement la direction de tous vos capteurs à partir de 2 poses onboarding-choose_mounting-manual_mounting = Alignement manuel -# Italized text -onboarding-choose_mounting-manual_mounting-label = Recommendée +# Italicized text +onboarding-choose_mounting-manual_mounting-label-v2 = Peut manquer de précision onboarding-choose_mounting-manual_mounting-description = Ceci vous permettra de choisir la direction de chaque capteur manuellement # Multiline text onboarding-choose_mounting-manual_modal-title = @@ -852,14 +977,14 @@ onboarding-choose_proportions-description-v1 = Lorsque les proportions de votre corps ne correspondent pas à celles enregistrées, la précision du suivi sera moins bonne et vous remarquerez certains problèmes comme du patinage ou de la glisse, ou votre corps ne correspondra pas bien à votre avatar. Vous n’avez besoin de mesurer les proportions de votre corps qu’une seule fois ! À moins qu’elle ne soient incorrectes ou que votre corps ait changé, vous n’avez pas besoin de les refaire. onboarding-choose_proportions-auto_proportions = Proportions automatiques -# Italized text +# Italicized text onboarding-choose_proportions-auto_proportions-subtitle = Recommendée onboarding-choose_proportions-auto_proportions-descriptionv3 = Cela permettra d'estimer vos proportions en enregistrant un échantillon de vos mouvements et en le faisant passer par un algorithme. Cela nécessite d’avoir votre casque VR connecté à SlimeVR et sur votre tête ! onboarding-choose_proportions-manual_proportions = Proportions manuelles -# Italized text +# Italicized text onboarding-choose_proportions-manual_proportions-subtitle = Pour les retouches onboarding-choose_proportions-manual_proportions-description = Ceci vous permettra d'ajuster vos proportions manuellement en les modifiant directement onboarding-choose_proportions-export = Exporter les proportions @@ -939,9 +1064,10 @@ onboarding-automatic_proportions-verify_results-redo = Refaire l'enregistrement onboarding-automatic_proportions-verify_results-confirm = Les résultats sont corrects onboarding-automatic_proportions-done-title = Calibration terminée onboarding-automatic_proportions-done-description = La calibration de vos proportions est terminée ! -onboarding-automatic_proportions-error_modal = - Avertissement : Une erreur a été détectée lors de l’estimation des proportions ! - Veuillez consulter la documentation ou rejoindre notre Discord pour obtenir de l’aide ^_^ +onboarding-automatic_proportions-error_modal-v2 = + Avertissement: Il y a eu une erreur lors de l’estimation des proportions ! + Il s’agit probablement d’un problème avec la calibration de l'alignement. Assurez-vous que votre capture des mouvements fonctionne correctement avant de réessayer. + Veuillez consulter la documentation ou rejoindre notre Discord pour obtenir de l’aide ^_^ onboarding-automatic_proportions-error_modal-confirm = Compris ! ## Home @@ -966,6 +1092,7 @@ status_system-StatusSteamVRDisconnected = *[other] Impossible de se connecter à SteamVR via le pilote SlimeVR. } status_system-StatusTrackerError = Le capteur { $trackerName } a une erreur. +status_system-StatusUnassignedHMD = Le casque VR devrait être attribué en tant que capteur de la tête. ## Tray Menu diff --git a/gui/public/i18n/it/translation.ftl b/gui/public/i18n/it/translation.ftl index 3050f8aae..addde6038 100644 --- a/gui/public/i18n/it/translation.ftl +++ b/gui/public/i18n/it/translation.ftl @@ -381,6 +381,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Reset posizionamento d settings-general-fk_settings-arm_fk = Tracking delle braccia settings-general-fk_settings-arm_fk-description = Forza il calcolo della posizione delle braccia a utilizzare il visore anche se la posizione delle mani é disponibile. settings-general-fk_settings-arm_fk-force_arms = Forza il calcolo delle braccia dal visore +settings-general-fk_settings-reset_settings = Ripristina impostazioni +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Ripristina l'inclinazione dell'HMD (rotazione verticale) dopo un reset completo. Utile se si indossa un HMD sulla fronte per VTubing o mocap. Non abilitare per VR. +settings-general-fk_settings-reset_settings-reset_hmd_pitch = Ripristina l'inclinazione dell'HMD settings-general-fk_settings-arm_fk-reset_mode-description = Cambia la posa delle braccia usata per il reset posizionamento. settings-general-fk_settings-arm_fk-back = Indietro settings-general-fk_settings-arm_fk-back-description = La modalità predefinita, con la parte superiori delle braccia che vanno indietro e le parte inferiori delle braccia che vanno avanti. @@ -478,6 +481,15 @@ settings-general-interface-connected_trackers_warning-label = Avviso di tracker settings-general-interface-use_tray = Riduci a icona nella barra delle applicazioni settings-general-interface-use_tray-description = Ti consente di chiudere la finestra senza chiudere il server SlimeVR in modo da poter continuare a usarlo senza che la GUI ti infastidisca. settings-general-interface-use_tray-label = Riduci a icona nella barra delle applicazioni +settings-general-interface-discord_presence = Condividi attività su Discord +settings-general-interface-discord_presence-description = Dice al tuo client di Discord che stai utilizzando SlimeVR insieme al numero di tracker IMU che stai utilizzando. +settings-general-interface-discord_presence-label = Condividi attività su Discord +settings-general-interface-discord_presence-message = + { $amount -> + [0] Slimeggiando qua e là + [one] Sta usando 1 tracker + *[other] Sta usando { $amount } tracker + } ## Serial settings @@ -500,6 +512,8 @@ settings-serial-get_infos = Ottieni informazioni settings-serial-serial_select = Seleziona una porta seriale settings-serial-auto_dropdown_item = Automatico settings-serial-get_wifi_scan = Elenca WiFi Network +settings-serial-file_type = Testo normale +settings-serial-save_logs = Salva su file ## OSC router settings @@ -530,14 +544,17 @@ settings-osc-router-network-address-placeholder = Indirizzo IPV4 settings-osc-vrchat = Tracker OSC per VRChat # This cares about multilines -settings-osc-vrchat-description = - Modifica le impostazioni specifiche a VRChat per ricevere e inviare dati del HMD - Dati dei tracker per FBT (funziona su Quest standalone). +settings-osc-vrchat-description-v1 = + Modifica impostazioni specifiche dello standard dei Tracker OSC utilizzato per l'invio + di dati di tracciamento alle applicazioni senza l'utlizzo di SteamVR (es. Quest standalone). + Assicurarsi di abilitare l'OSC in VRChat tramite il menu Azione alla voce OSC > Abilitato. + Per consentire la ricezione dei dati dell'HMD e del controller da VRChat, vai nella sezione impostazioni del menu principale + in Tracciamento e IK > Consenti invio dati OSC tracciamento VR testa e polso. settings-osc-vrchat-enable = Attiva settings-osc-vrchat-enable-description = Attiva o disattiva l'invio e la ricezione dei dati settings-osc-vrchat-enable-label = Attiva settings-osc-vrchat-network = Porte di rete -settings-osc-vrchat-network-description = Impostare le porte di rete per ascoltare e inviare dati a VRChat +settings-osc-vrchat-network-description-v1 = Imposta le porte per l'ascolto e l'invio dei dati. Può essere lasciato come predefinito per utilizzo con VRChat. settings-osc-vrchat-network-port_in = .label = Porta in ingresso .placeholder = Porta in ingresso (predefinito: 9002) @@ -545,7 +562,7 @@ settings-osc-vrchat-network-port_out = .label = Porta in uscita .placeholder = Porta in uscita (predefinito: 9000) settings-osc-vrchat-network-address = Indirizzo di rete -settings-osc-vrchat-network-address-description = Scegli a quale indirizzo di rete inviare i dati di VRChat (controlla le impostazioni Wi-Fi sul tuo dispositivo) +settings-osc-vrchat-network-address-description-v1 = Scegli a quale indirizzo inviare i dati. Può essere lasciato come predefinito per utilizzo con VRChat. settings-osc-vrchat-network-address-placeholder = Indirizzo IP di VRChat settings-osc-vrchat-network-trackers = Tracker settings-osc-vrchat-network-trackers-description = Attiva o disattiva l'invio e la ricezione dei dati @@ -588,6 +605,9 @@ settings-osc-vmc-vrm-file_select = Trascina qui un modello da usare, o sfogli settings-osc-vmc-anchor_hip = Ancoraggio sul bacino settings-osc-vmc-anchor_hip-description = Ancora la posizione del tracciamento del bacino; utile per VTubing da seduti. Se disabilitato, carica un modello VRM. settings-osc-vmc-anchor_hip-label = Ancoraggio sul bacino +settings-osc-vmc-mirror_tracking = Tracciamento speculare +settings-osc-vmc-mirror_tracking-description = Specchia il tracciamento orizzontalmente. +settings-osc-vmc-mirror_tracking-label = Tracciamento speculare ## Setup/onboarding menu @@ -727,6 +747,27 @@ onboarding-assign_trackers-assigned = onboarding-assign_trackers-advanced = Mostra impostazioni avanzate di assegnazione onboarding-assign_trackers-next = Ho assegnato tutti i miei tracker onboarding-assign_trackers-mirror_view = Inverti interfaccia +onboarding-assign_trackers-option-amount = + { $trackersCount -> + [one] x{ $trackersCount } + *[other] x{ $trackersCount } + } +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] Pacchetto "Lower-Body" + [core] Pacchetto "Core" + [enhanced-core] Pacchetto "Enhanced Core" + [full-body] Pacchetto "Full-Body" + *[all] Tutti i tracker + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] Il minimo per full-body tracking in VR + [core] + Miglior tracciamento della spina dorsale + [enhanced-core] + Rotazione dei piedi + [full-body] + Tracciamento dei gomiti + *[all] Tutte le assegnazioni di tracker disponibili + } ## Tracker assignment warnings @@ -803,11 +844,11 @@ onboarding-choose_mounting = Quale metodo di calibrazione del posizionamento vuo onboarding-choose_mounting-description = L'orientamento di posizionamento corregge la posizione dei tracker sul corpo. onboarding-choose_mounting-auto_mounting = Posizionamento automatico # Italized text -onboarding-choose_mounting-auto_mounting-label = Sperimentale +onboarding-choose_mounting-auto_mounting-label-v2 = Raccomandato onboarding-choose_mounting-auto_mounting-description = Questo processo identificherá automaticamente le direzioni per la posizione di montaggio di tutti i traker facendo 2 pose onboarding-choose_mounting-manual_mounting = Posizionamento manuale # Italized text -onboarding-choose_mounting-manual_mounting-label = Raccomandato +onboarding-choose_mounting-manual_mounting-label-v2 = Potrebbe non essere abbastanza preciso onboarding-choose_mounting-manual_mounting-description = Questo processo ti lascerá scegliere manualmente le direzioni per la posizione di montaggio di tutti i tracker # Multiline text onboarding-choose_mounting-manual_modal-title = @@ -970,6 +1011,7 @@ status_system-StatusSteamVRDisconnected = *[other] Attualmente non è connesso a SteamVR tramite il driver SlimeVR. } status_system-StatusTrackerError = Il tracker { $trackerName } ha un errore. +status_system-StatusUnassignedHMD = Il visore deve essere assegnato come tracker della testa. ## Tray Menu diff --git a/gui/public/i18n/ja/translation.ftl b/gui/public/i18n/ja/translation.ftl index 0306956e0..c3d5cc5f2 100644 --- a/gui/public/i18n/ja/translation.ftl +++ b/gui/public/i18n/ja/translation.ftl @@ -23,6 +23,8 @@ tips-find_tracker = どのトラッカーがどれだかわからない?トラ tips-do_not_move_heels = レコーディング中にかかとが動かないように注意しましょう! tips-file_select = 使用するファイルをドラッグ&ドロップするか、 参照します。 tips-tap_setup = 追跡装置をゆっくり2回軽くタップして選択することができます、メニューから選ぶ必要はありません +tips-turn_on_tracker = SlimeVRの公式トラッカーを使っていますか?トラッカーをPCに接続した後は必ず電源を入れてください! +tips-failed_webgl = WebGLの初期化に失敗しました。 ## Body parts @@ -161,8 +163,8 @@ tracker-status-timed_out = タイムアウト ## Tracker status columns -tracker-table-column-name = Name -tracker-table-column-type = Type +tracker-table-column-name = 名前 +tracker-table-column-type = タイプ tracker-table-column-battery = バッテリー tracker-table-column-ping = Ping tracker-table-column-tps = TPS @@ -196,6 +198,7 @@ tracker-infos-hardware_rev = ハードウエアのリビジョン tracker-infos-hardware_identifier = ハードウェアID tracker-infos-imu = 慣性計測センサー tracker-infos-board_type = メインボード +tracker-infos-network_version = プロトコル・バージョン ## Tracker settings @@ -215,6 +218,8 @@ tracker-settings-drift_compensation_section-edit = ドリフト補正を行う tracker-settings-name_section = トラッカー名称 tracker-settings-name_section-description = 自由に名称をつけてください tracker-settings-name_section-placeholder = NightyBeast's left leg +tracker-settings-forget = フォーゲット・トラッカー +tracker-settings-forget-label = フォーゲット・トラッカー ## Tracker part card info @@ -302,10 +307,8 @@ settings-general-steamvr-description = SlimeVRが行うことをよりコントロールしたい場合に便利です。 settings-general-steamvr-trackers-waist = 腰 settings-general-steamvr-trackers-chest = 胸 -settings-general-steamvr-trackers-feet = 足 -settings-general-steamvr-trackers-knees = 膝 -settings-general-steamvr-trackers-elbows = 肘 -settings-general-steamvr-trackers-hands = 手 +settings-general-steamvr-trackers-hands-warning-cancel = キャンセル +settings-general-steamvr-trackers-hands-warning-done = はい ## Tracker mechanics @@ -390,6 +393,9 @@ settings-general-gesture_control-taps = [one] 1 tap *[other] { $amount } タップ } +# This is a unit: 3 trackers, 2 trackers, 1 tracker +# $amount (Number) - Amount of trackers +settings-general-gesture_control-trackers = { $amount } トラッカー settings-general-gesture_control-yawResetEnabled = タップによるヨーリセットを有効にします settings-general-gesture_control-yawResetDelay = ヨーリセット遅延 settings-general-gesture_control-yawResetTaps = ヨーリセット用のタップ @@ -402,6 +408,7 @@ settings-general-gesture_control-mountingResetTaps = タップによるマウン ## Appearance settings +settings-interface-appearance = 外観 settings-general-interface-dev_mode = 開発者モード settings-general-interface-dev_mode-description = このモードは、詳細なデータが必要な場合や、接続されたトラッカーをより高度なレベルで操作する場合に役立ちます。 settings-general-interface-dev_mode-label = 開発者モード @@ -411,7 +418,9 @@ settings-general-interface-lang-description = 使用したいデフォルトの settings-general-interface-lang-placeholder = 使用する言語を選択する # Keep the font name untranslated settings-interface-appearance-font = GUIフォント +settings-interface-appearance-font-placeholder = デフォルトフォント settings-interface-appearance-font-os_font = OSフォント +settings-interface-appearance-font-slime_font = デフォルトフォント ## Notification settings @@ -422,6 +431,8 @@ settings-general-interface-serial_detection-label = シリアルデバイスの settings-general-interface-feedback_sound = フィードバック音 settings-general-interface-feedback_sound-label = フィードバック音 settings-general-interface-feedback_sound-volume = フィードバック音量 +settings-general-interface-connected_trackers_warning = 接続されたトラッカー警告 +settings-general-interface-use_tray-label = システムトレイに最小化する ## Serial settings @@ -467,15 +478,10 @@ settings-osc-router-network-address-placeholder = IPV4アドレス ## OSC VRChat settings settings-osc-vrchat = VRChat OSCトラッカー -# This cares about multilines -settings-osc-vrchat-description = - HMDのデータを受信して送信するためにVRChat固有の設定を変更する。 - FBT用のトラッカーデータ(Questスタンドアロンで動作します) settings-osc-vrchat-enable = 有効 settings-osc-vrchat-enable-description = データの送受信を切り替える。 settings-osc-vrchat-enable-label = 有効 settings-osc-vrchat-network = ネットワークポート -settings-osc-vrchat-network-description = VRChatへのデータを送受信するためのポートを設定します。 settings-osc-vrchat-network-port_in = .label = ポートイン .placeholder = ポートイン (デフォルト: 9001) @@ -483,7 +489,6 @@ settings-osc-vrchat-network-port_out = .label = ポートアウト .placeholder = ポートアウト (デフォルト: 9000) settings-osc-vrchat-network-address = ネットワークアドレス -settings-osc-vrchat-network-address-description = VRChatにデータを送信するアドレスを選択してください(デバイスのWi-Fi設定を確認してください) settings-osc-vrchat-network-address-placeholder = VRChatのIPアドレス settings-osc-vrchat-network-trackers = トラッカー settings-osc-vrchat-network-trackers-description = データの送受信を切り替える。 @@ -587,7 +592,9 @@ onboarding-connect_tracker-next = すべてのトラッカーを接続しまし onboarding-calibration_tutorial = IMU校正チュートリアル onboarding-calibration_tutorial-subtitle = これにより、センサーのドリフトを減らすことが役立ちます +onboarding-calibration_tutorial-status-waiting = あなたを待っている... onboarding-calibration_tutorial-status-calibrating = 校正中 +onboarding-calibration_tutorial-status-success = ナイス! ## Tracker assignment tutorial @@ -615,8 +622,7 @@ onboarding-assign_trackers-next = すべてのトラッカーを割り当てま ## Tracker mounting method choose -# Italized text -onboarding-choose_mounting-auto_mounting-label = 実験的な +onboarding-choose_mounting-manual_modal-cancel = キャンセル ## Tracker manual mounting setup @@ -651,6 +657,7 @@ onboarding-automatic_mounting-put_trackers_on-next = すべてのトラッカー # Italized text onboarding-choose_proportions-auto_proportions-subtitle = おすすめされた +onboarding-choose_proportions-import-failed = 失敗 ## Tracker manual proportions setup @@ -671,6 +678,8 @@ onboarding-automatic_proportions-put_trackers_on-description = プロポーシ onboarding-automatic_proportions-put_trackers_on-next = すべてのトラッカーを装着しました onboarding-automatic_proportions-requirements-title = 要件 onboarding-automatic_proportions-requirements-next = 要件を読みました +# Context is that the height is unknown +onboarding-automatic_proportions-check_height-unknown = 不明 onboarding-automatic_proportions-start_recording-title = 測定の準備をする onboarding-automatic_proportions-start_recording-description = これから具体的なポーズや動きを記録します。これらは次の画面に表示されます。ボタンが押されたらすぐに始められるように準備しておいてください! onboarding-automatic_proportions-start_recording-next = レコーディングスタート @@ -692,6 +701,7 @@ onboarding-automatic_proportions-verify_results-redo = レコーディングや onboarding-automatic_proportions-verify_results-confirm = 正確です onboarding-automatic_proportions-done-title = 体を測定して保存 onboarding-automatic_proportions-done-description = ボディプロポーションのキャリブレーションが完了しました! +onboarding-automatic_proportions-error_modal-confirm = 了解! ## Home @@ -699,6 +709,8 @@ home-no_trackers = トラッカーを検出できません。もしくは割り ## Trackers Still On notification +trackers_still_on-modal-confirm = SlimeVRを終了する +trackers_still_on-modal-cancel = ちょっと待って... ## Status system @@ -712,9 +724,16 @@ status_system-StatusTrackerError = { $trackerName } トラッカーにエラー ## Tray Menu +tray_menu-show = ショー +tray_menu-hide = 隠す +tray_menu-quit = 辞める ## First exit modal +tray_or_exit_modal-submit = セーブ +tray_or_exit_modal-cancel = キャンセル ## Unknown device modal +unknown_device-modal-confirm = もちろん! +unknown_device-modal-forget = 無視する diff --git a/gui/public/i18n/ko/translation.ftl b/gui/public/i18n/ko/translation.ftl index f2b06947e..3fe3711a9 100644 --- a/gui/public/i18n/ko/translation.ftl +++ b/gui/public/i18n/ko/translation.ftl @@ -19,7 +19,7 @@ version_update-close = 닫기 ## Tips -tips-find_tracker = 어떤 트래커가 어디에 대응되는지 모르겠나요? 트래커를 흔들면 해당 트래커에 해당되는 항목이 강조 표시됩니다. +tips-find_tracker = 어떤 트래커가 어디에 대응되는지 모르겠나요? 트래커를 흔들면 해당 트래커에 해당되는 항목이 강조 표시돼요. tips-do_not_move_heels = 기록하는 동안 발뒤꿈치가 움직이지 않도록 조심하세요! tips-file_select = 파일을 열거나, 여기에 드래그&드롭하세요. tips-tap_setup = 목록에서 트래커를 선택하는 대신 트래커를 천천히 2번 탭해서 선택할 수 있어요. @@ -81,6 +81,11 @@ skeleton_bone-ELBOW_OFFSET = 팔꿈치 오프셋 ## Tracker reset buttons reset-reset_all = 모든 신체 비율 초기화 +reset-reset_all_warning = + 경고: 이렇게 하면 지금까지 변경한 신체 비율 설정이 사라지고 설정했던 키를 기반으로 초기화돼요. + 계속하시겠어요? +reset-reset_all_warning-reset = 신체 비율 초기화 +reset-reset_all_warning-cancel = 취소 reset-full = 전체 정렬 reset-mounting = 착용 방향 정렬 reset-yaw = Yaw 정렬 @@ -142,9 +147,12 @@ widget-developer_mode-more_info = 더 많은 정보 보기 ## Widget: IMU Visualizer widget-imu_visualizer = 회전 +widget-imu_visualizer-preview = 미리보기 +widget-imu_visualizer-hide = 숨기기 widget-imu_visualizer-rotation_raw = Raw widget-imu_visualizer-rotation_preview = 미리보기 -widget-imu_visualizer-rotation_hide = 숨기기 +widget-imu_visualizer-acceleration = 가속도 +widget-imu_visualizer-position = 위치 ## Widget: Skeleton Visualizer @@ -199,6 +207,13 @@ tracker-infos-hardware_identifier = 하드웨어 ID tracker-infos-imu = IMU 센서 tracker-infos-board_type = 메인보드 tracker-infos-network_version = 프로토콜 버전 +tracker-infos-magnetometer = 자력계 +tracker-infos-magnetometer-status-v1 = + { $status -> + [DISABLED] 비활성화됨 + [ENABLED] 활성화됨 + *[NOT_SUPPORTED] 지원되지 않음 + } ## Tracker settings @@ -213,11 +228,19 @@ tracker-settings-mounting_section-edit = 방향 수정 tracker-settings-drift_compensation_section = 틀어짐 보정 사용 tracker-settings-drift_compensation_section-description = 틀어짐 보정이 켜져 있을 때 이 트래커의 틀어짐을 보정할까요? tracker-settings-drift_compensation_section-edit = 틀어짐 보정 사용 +tracker-settings-use_mag = 이 트래커에서 자력계 활성화하기 +# Multiline! +tracker-settings-use_mag-description = + 이 트래커는 자력계 사용이 허용될 때 드리프트를 줄이기 위해 자력계를 사용해야 합니까? 이것을 토글하는 동안 트래커를 종료하지 마십시오! + + 먼저 자력계를 사용하도록 설정한 다음, 여기를 클릭하여 설정으로 이동하세요. +tracker-settings-use_mag-label = 자력계 활성화 # The . means it's an attribute and it's related to the top key. # In this case that is the settings for the assignment section. tracker-settings-name_section = 트래커 이름 tracker-settings-name_section-description = 귀여운 이름을 지어주세요! >_< tracker-settings-name_section-placeholder = NightyBeast's left leg +tracker-settings-name_section-label = 트래커 이름 tracker-settings-forget = 트래커 삭제 tracker-settings-forget-description = SlimeVR 서버에서 트래커를 제거하고 서버를 다시 시작할 때까지 자동으로 연결하지 않아요. 트래커의 설정은 지워지지 않아요. tracker-settings-forget-label = 트래커 삭제 @@ -296,6 +319,7 @@ settings-sidebar-utils = 유틸리티 settings-sidebar-serial = 시리얼 콘솔 settings-sidebar-appearance = 모양 settings-sidebar-notifications = 알림 +settings-sidebar-advanced = 고급 ## SteamVR settings @@ -343,20 +367,38 @@ settings-general-tracker_mechanics-filtering-type-smoothing-description = 움직 settings-general-tracker_mechanics-filtering-type-prediction = Prediction settings-general-tracker_mechanics-filtering-type-prediction-description = 대기 시간이 줄어들고 움직임이 더 빨라지지만 지터가 증가할 수 있어요. settings-general-tracker_mechanics-filtering-amount = 강도 -settings-general-tracker_mechanics-yaw-reset-smooth-time = 부드러운 Yaw 리셋 작용 시간 (0초는 부드러운 Yaw 리셋을 비활성화 합니다) +settings-general-tracker_mechanics-yaw-reset-smooth-time = Yaw 정렬할 때 부드럽게 움직이는 시간 (비활성화: 0초) settings-general-tracker_mechanics-drift_compensation = 틀어짐 보정 # This cares about multilines settings-general-tracker_mechanics-drift_compensation-description = 틀어지는 방향의 반대 방향으로 회전해서 IMU Yaw 드리프트를 보정할 수 있어요. 보정하는 강도와 감지할 최근 정렬 횟수를 설정할 수 있어요. settings-general-tracker_mechanics-drift_compensation-enabled-label = 틀어짐 보정 +settings-general-tracker_mechanics-drift_compensation-prediction = 틀어짐 보정 예측 +# This cares about multilines +settings-general-tracker_mechanics-drift_compensation-prediction-description = + 점점 심하게 틀어지는 트래커의 틀어짐 방향을 예측해요. + 틀어짐 보정을 사용해도 트래커가 Yaw 축에서 계속 틀어지면 이 옵션을 켜세요. +settings-general-tracker_mechanics-drift_compensation-prediction-label = 예측해서 틀어짐 보정하기 +settings-general-tracker_mechanics-drift_compensation_warning = + 경고: 트래커를 지나치게 자주 정렬해야 하는 경우에만 틀어짐 보정을 사용하세요 (5~10분마다). + + Joy-Con, owoTrack 및 MPU 시리즈 IMU(최신 펌웨어 제외) + 등과 같은 트래커들이 해당합니다. +settings-general-tracker_mechanics-drift_compensation_warning-cancel = 취소 +settings-general-tracker_mechanics-drift_compensation_warning-done = 이해했어요 settings-general-tracker_mechanics-drift_compensation-amount-label = 보정 강도 settings-general-tracker_mechanics-drift_compensation-max_resets-label = 보정에 사용할 최근 정렬 횟수 settings-general-tracker_mechanics-save_mounting_reset = 자동 착용 방향 정렬 보정값 저장 settings-general-tracker_mechanics-save_mounting_reset-description = - 트래커의 자동 마운팅 리셋 보정값을 저장합니다. 트래커들의 위치가 고정된 - 모션 캡처 슈트 같은 것을 사용할 때 유용합니다. 일반 사용자들에게는 권장되지 않아요! + 트래커의 착용 방향 정렬 보정값을 저장합니다. 트래커들의 위치가 고정된 + 모션 캡처 슈트 같은 것을 사용할 때 유용해요. 일반 사용자들에게는 권장되지 않아요! 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 = + 호환 가능한 펌웨어가 있는 모든 트래커에서 자력계를 사용하여 안정적인 자기 환경에서 틀어짐을 줄일 수 있어요. + 트래커의 설정에서 트래커별로 비활성화할 수 있어요. 이 기능을 토글하는 동안 트래커를 종료하지 마세요! +settings-general-tracker_mechanics-use_mag_on_all_trackers-label = 트래커에서 자력계 사용하기 ## FK/Tracking settings @@ -383,6 +425,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = 발 트래커 착용 settings-general-fk_settings-arm_fk = 팔 트래킹 settings-general-fk_settings-arm_fk-description = 손 컨트롤러 위치 데이터를 사용할 수 없는 경우에도 VR 헤드셋(HMD)으로부터 팔을 추적하도록 할 수 있어요. settings-general-fk_settings-arm_fk-force_arms = 팔을 HMD에서만 받아오기 +settings-general-fk_settings-reset_settings = 정렬 설정 +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = 전체 정렬을 수행하면 HMD의 피치(앞뒤 회전각)도 재설정해요. VTubing 또는 모션 캡처에서 이마에 HMD를 걸쳐두거나 할 때 유용해요. 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-back = 뒤쪽 settings-general-fk_settings-arm_fk-back-description = 기본값. 위쪽 팔은 뒤를 향하고 아래쪽 팔은 앞을 향하게 하는 자세. @@ -446,6 +491,9 @@ settings-general-interface-dev_mode = 개발자 모드 settings-general-interface-dev_mode-description = 이 모드는 더 많은 데이터가 필요하거나 고급 수준에서 연결된 트래커와 상호 작용하는 경우에 유용할 수 있어요. settings-general-interface-dev_mode-label = 개발자 모드 settings-general-interface-theme = 컬러 테마 +settings-general-interface-show-navbar-onboarding = 내비게이션 바에 "{ navbar-onboarding }" 표시 +settings-general-interface-show-navbar-onboarding-description = 이 설정은 내비게이션 바에 "{ navbar-onboarding }" 버튼을 표시할 지 결정해요. +settings-general-interface-show-navbar-onboarding-label = "{ navbar-onboarding }" 보이기 settings-general-interface-lang = 언어 선택 settings-general-interface-lang-description = 사용하고 싶은 기본 언어를 선택하세요. settings-general-interface-lang-placeholder = 사용할 언어를 선택하세요 @@ -457,6 +505,9 @@ settings-interface-appearance-font-os_font = OS 글꼴 settings-interface-appearance-font-slime_font = 기본 글꼴 settings-interface-appearance-font_size = 글꼴 크기 조정 settings-interface-appearance-font_size-description = 변경하면 이 설정 패널을 제외하고 모든 인터페이스의 글꼴 크기가 달라져요. +settings-interface-appearance-decorations = 인터페이스 +settings-interface-appearance-decorations-description = 상단바 인터페이스를 자체적으로 랜더링하는 대신 시스템의 기본 인터페이스를 유지하기 +settings-interface-appearance-decorations-label = 시스템 기본 인터페이스 사용 ## Notification settings @@ -474,6 +525,14 @@ settings-general-interface-connected_trackers_warning-label = 종료 시 작동 settings-general-interface-use_tray = 작업 표시줄로 최소화 settings-general-interface-use_tray-description = SlimeVR 서버를 닫지 않고 창만 닫을 수 있게 하여 사용 시 항상 GUI를 띄워 놓을 필요가 없게 해요. settings-general-interface-use_tray-label = 작업 표시줄로 최소화 +settings-general-interface-discord_presence = Discord에서 활동 공유 +settings-general-interface-discord_presence-description = Discord 활동 상태에 SlimeVR을 사용 중이라는 것과 사용 중인 트래커의 개수를 같이 표시합니다. +settings-general-interface-discord_presence-label = DIscord에서 활동 공유 +settings-general-interface-discord_presence-message = + { $amount -> + [0] 슬라임 갖고 노는 중 + *[other] 트래커 { $amount } 개 사용 중 + } ## Serial settings @@ -496,6 +555,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 @@ -526,14 +587,15 @@ settings-osc-router-network-address-placeholder = IPV4 주소 settings-osc-vrchat = VRChat OSC Trackers # This cares about multilines -settings-osc-vrchat-description = - 헤드셋 (HMD) 데이터를 수신하고 SteamVR 없이도 (예: Quest 단독 사용) - 트래커 정보를 전송하도록 VRChat 관련 설정을 변경 +settings-osc-vrchat-description-v1 = + SteamVR이 없는 애플리케이션(예: Quest 단독 실행)에 추적 데이터를 전송하는 데 사용되는 OSC 트래커 표준에 관한 설정. + VRChat에서 OSC를 사용하려면 액션 메뉴에서 '옵션' > 'OSC' > '활성화됨' 토글 스위치를 켜 주세요. + 그리고 HMD 및 컨트롤러 데이터를 수신하려면 '트래킹 및 IK' > 'OSC를 통한 머리와 손목 트래킹 데이터 전송'을 활성화 해주세요. settings-osc-vrchat-enable = 활성화 settings-osc-vrchat-enable-description = 데이터 송/수신 활성화 settings-osc-vrchat-enable-label = 활성화 settings-osc-vrchat-network = 네트워크 포트 -settings-osc-vrchat-network-description = VRChat과 데이터를 주고받는 포트 설정 +settings-osc-vrchat-network-description-v1 = 들어오는 포트와 나가는 포트 설정하기, VRChat에서 사용하려면 그냥 두세요. settings-osc-vrchat-network-port_in = .label = 들어오는 포트 .placeholder = Port in (기본값: 9001) @@ -541,7 +603,7 @@ settings-osc-vrchat-network-port_out = .label = 나가는 포트 .placeholder = Port out (기본값: 9000) settings-osc-vrchat-network-address = 네트워크 주소 -settings-osc-vrchat-network-address-description = VRChat으로 데이터를 보낼 주소를 선택하세요(장치의 Wi-Fi 설정 확인). +settings-osc-vrchat-network-address-description-v1 = OSC 데이터를 보낼 주소, VRChat에서 사용하려면 그냥 두세요. settings-osc-vrchat-network-address-placeholder = VRChat IP 주소 settings-osc-vrchat-network-trackers = 트래커 settings-osc-vrchat-network-trackers-description = OSC를 통한 특정 트래커의 전송 여부 설정 @@ -584,6 +646,33 @@ settings-osc-vmc-vrm-file_select = 모델을 열거나, 여기에 드래 settings-osc-vmc-anchor_hip = 골반에 앵커 설정 settings-osc-vmc-anchor_hip-description = 추적을 엉덩이에 고정해요. 앉은 자세로 VTubing할 때 유용해요. 비활성화하는 경우 VRM 모델에서 가져와요. settings-osc-vmc-anchor_hip-label = 골반에 앵커 설정 +settings-osc-vmc-mirror_tracking = 움직임 좌우 반전 +settings-osc-vmc-mirror_tracking-description = 움직임을 수평 방향으로 반전시킵니다. +settings-osc-vmc-mirror_tracking-label = 움직임 좌우 반전 + +## Advanced settings + +settings-utils-advanced = 고급 +settings-utils-advanced-reset-gui = GUI 설정 초기화하기 +settings-utils-advanced-reset-gui-description = 인터페이스 관련 설정을 원래대로 되돌려요. +settings-utils-advanced-reset-gui-label = GUI 설정 초기화 +settings-utils-advanced-reset-server = 트래킹 설정 초기화하기 +settings-utils-advanced-reset-server-description = 트래킹 관련 설정을 원래대로 되돌려요. +settings-utils-advanced-reset-server-label = 트래킹 설정 초기화 +settings-utils-advanced-reset-all = 모든 설정 초기화하기 +settings-utils-advanced-reset-all-description = 인터페이스와 트래킹 설정을 모두 원래대로 되돌려요. +settings-utils-advanced-reset-all-label = 모든 설정 초기화 +settings-utils-advanced-reset_warning = + { $type -> + [gui] 경고: 이렇게 하면 화면 표시와 관련된 모든 설정이 초기화돼요. 계속하시겠어요? + [server] 경고: 이렇게 하면 화면 트래커의 움직임에 관한 모든 설정이 초기화돼요. 계속하시겠어요? + *[all] 경고: 이렇게 하면 지금까지 변경한 모든 설정이 초기화돼요. 계속하시겠어요? + } +settings-utils-advanced-reset_warning-reset = 설정 초기화 +settings-utils-advanced-reset_warning-cancel = 취소 +settings-utils-advanced-open_data = 데이터 폴더 열기 +settings-utils-advanced-open_data-description = 설정 파일과 로그 파일이 들어 있는 SlimeVR의 데이터 폴더를 파일 탐색기에서 엽니다. +settings-utils-advanced-open_data-label = 폴더 열기 ## Setup/onboarding menu @@ -619,7 +708,7 @@ onboarding-wifi_creds-password = onboarding-reset_tutorial-back = 착용 방향 정렬로 돌아가기 onboarding-reset_tutorial = 정렬 튜토리얼 onboarding-reset_tutorial-explanation = 트래커를 사용하다 보면 IMU의 yaw 드리프트 또는 트래커의 위치가 달라져서 틀어짐이 발생할 수 있어요. 이러한 문제들을 해결하는 몇 가지 방법을 알려 드릴게요. -onboarding-reset_tutorial-skip = 무시하고 건너뛰기 +onboarding-reset_tutorial-skip = 단계 건너뛰기 # Cares about multiline onboarding-reset_tutorial-0 = Yaw 정렬을 시도하려면 강조된 트래커를 { $taps }번 탭하세요. @@ -695,6 +784,7 @@ onboarding-calibration_tutorial-status-waiting = 대기 중 onboarding-calibration_tutorial-status-calibrating = 보정 중 onboarding-calibration_tutorial-status-success = 좋아요! onboarding-calibration_tutorial-status-error = 트래커가 움직였습니다 +onboarding-calibration_tutorial-skip = 튜토리얼 건너뛰기 ## Tracker assignment tutorial @@ -703,7 +793,7 @@ onboarding-assignment_tutorial-first_step = 1. 신체 부위가 적힌 스티커 # This text has a character limit of around 11 characters, so please keep it short onboarding-assignment_tutorial-sticker = 스티커 onboarding-assignment_tutorial-second_step-v2 = 2. 스트랩을 트래커에 장착하되, 벨크로 접착면이 트래커의 Slime 얼굴과 같은 방향을 바라보도록 해 주세요: -onboarding-assignment_tutorial-second_step-continuation-v2 = 확장 모듈의 벨크로 접착면이 다음 이미지처럼 위를 바라봐야 합니다: +onboarding-assignment_tutorial-second_step-continuation-v2 = 확장 모듈의 벨크로 접착면이 다음 이미지처럼 위를 향하게 해 주세요: onboarding-assignment_tutorial-done = 스트랩과 스티커를 트래커에 잘 부착했어요! ## Tracker assignment setup @@ -718,6 +808,23 @@ onboarding-assign_trackers-assigned = 트래커 { $trackers }개 중 { $assigned onboarding-assign_trackers-advanced = 고급 할당 위치 보기 onboarding-assign_trackers-next = 모든 트래커를 배치했어요 onboarding-assign_trackers-mirror_view = 좌우 반전 +onboarding-assign_trackers-option-amount = x{ $trackersCount } +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] 하반신 세트 + [core] 코어 세트 + [enhanced-core] 향상된 코어 세트 + [full-body] 풀 바디 세트 + *[all] 전부 다 + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] VR 신체 추적에 필요한 최소 할당 + [core] + 골반 추적 향상 + [enhanced-core] + 발 회전 감지 + [full-body] + 팔꿈치 추적 + *[all] 가능한 모든 트래커 할당 + } ## Tracker assignment warnings @@ -793,12 +900,12 @@ onboarding-choose_mounting = 착용 방향 보정을 위해 어떤 방법을 사 # Multiline text onboarding-choose_mounting-description = 착용 방향 정렬은 트래커가 몸에 착용된 방향을 찾아 수정하도록 도와줘요. onboarding-choose_mounting-auto_mounting = 자동으로 방향 설정 -# Italized text -onboarding-choose_mounting-auto_mounting-label = 실험적 +# Italicized text +onboarding-choose_mounting-auto_mounting-label-v2 = 권장됨 onboarding-choose_mounting-auto_mounting-description = 이렇게 하면 2가지 자세로 모든 트래커의 착용 방향을 자동으로 설정할 수 있어요 onboarding-choose_mounting-manual_mounting = 수동으로 방향 설정 -# Italized text -onboarding-choose_mounting-manual_mounting-label = 권장됨 +# Italicized text +onboarding-choose_mounting-manual_mounting-label-v2 = 정확하지 않을 수도 있어요 onboarding-choose_mounting-manual_mounting-description = 이렇게 하면 각 트래커의 착용 방향을 직접 고를 수 있어요 # Multiline text onboarding-choose_mounting-manual_modal-title = 자동으로 착용 방향을 설정하시겠어요? @@ -844,13 +951,13 @@ onboarding-choose_proportions-description-v1 = 설정된 신체 비율과 실제 신체 비율이 다를 경우, 트래킹 정확도가 훨씬 낮아질 수 있으며 사용 중 스케이팅, 슬라이딩, 또는 아바타와 신체 동작이 일치하지 않게 되는 경우가 발생할 수 있어요. 신체 비율 측정은 한 번이면 충분해요! 측정치가 부정확하거나 신체 비율이 달라진 경우를 제외하고는 다시 측정할 필요가 없어요. onboarding-choose_proportions-auto_proportions = 자동으로 비율 설정 -# Italized text +# Italicized text onboarding-choose_proportions-auto_proportions-subtitle = 권장 onboarding-choose_proportions-auto_proportions-descriptionv3 = 몸을 이리저리 움직여 샘플을 기록한 다음 알고리즘을 통해 연산하는 방식으로 신체 비율을 추산합니다. 사용하기 위해서는 VR 헤드셋이 SlimeVR과 연결되어 있어야 해요 onboarding-choose_proportions-manual_proportions = 수동으로 비율 설정 -# Italized text +# Italicized text onboarding-choose_proportions-manual_proportions-subtitle = 정밀하게 설정하고 싶다면 onboarding-choose_proportions-manual_proportions-description = 이 옵션을 사용하면 신체 비율을 직접 입력해 수동으로 조절할 수 있어요. onboarding-choose_proportions-export = 다른 이름으로 저장 @@ -929,9 +1036,10 @@ onboarding-automatic_proportions-verify_results-redo = 다시 기록하기 onboarding-automatic_proportions-verify_results-confirm = 정확해요! onboarding-automatic_proportions-done-title = 몸을 측정하고 저장했어요 onboarding-automatic_proportions-done-description = 신체 비율 보정이 완료되었어요! -onboarding-automatic_proportions-error_modal = - 경고: 신체 비율을 계산하는 동안 오류가 발생했습니다! - 도움말을 확인하거나 디스코드 서버에서 도움을 받으세요 ^_^ +onboarding-automatic_proportions-error_modal-v2 = + 경고: 신체 비율을 추정하는 동안 오류가 발생했어요..! + 이는 착용 방향 정렬 문제일 수 있어요. 다시 시도하기 전에 추적이 제대로 작동하는지 확인해보세요. + 설명서를 읽어보거나 Discord 서버에 가입해서 도와달라고 해 보세요! ^_^ onboarding-automatic_proportions-error_modal-confirm = 이해했어요! ## Home @@ -954,6 +1062,7 @@ status_system-StatusSteamVRDisconnected = *[other] SlimeVR 드라이버가 SteamVR과 연결되지 않음 } status_system-StatusTrackerError = { $trackerName } 트래커에 문제가 발생했어요. +status_system-StatusUnassignedHMD = VR 헤드셋은 머리 트래커로 할당되어야 해요. ## Tray Menu diff --git a/gui/public/i18n/nl/translation.ftl b/gui/public/i18n/nl/translation.ftl index 4856cfc54..a23af7deb 100644 --- a/gui/public/i18n/nl/translation.ftl +++ b/gui/public/i18n/nl/translation.ftl @@ -100,7 +100,7 @@ serial_detection-close = Sluiten navbar-home = Startpagina navbar-body_proportions = Lichaamsverhoudingen navbar-trackers_assign = Tracker-toewijzing -navbar-mounting = Bevestigings-kalibratie +navbar-mounting = Montage-kalibratie navbar-onboarding = Installatiewizard navbar-settings = Instellingen @@ -207,9 +207,9 @@ tracker-settings-title = Trackersinstellingen tracker-settings-assignment_section = Toewijzing tracker-settings-assignment_section-description = Aan welk lichaamsdeel de tracker is toegewezen. tracker-settings-assignment_section-edit = Toewijzing bewerken -tracker-settings-mounting_section = Bevestigingsorientatie +tracker-settings-mounting_section = Montage oriëntatie tracker-settings-mounting_section-description = Waar is de tracker gemonteerd? -tracker-settings-mounting_section-edit = Bevestiging bewerken +tracker-settings-mounting_section-edit = Montage bewerken tracker-settings-drift_compensation_section = Laat drift compensatie toe tracker-settings-drift_compensation_section-description = Moet deze tracker compenseren voor drift wanneer drift compensatie is ingeschakeld? tracker-settings-drift_compensation_section-edit = Laat drift compensatie toe @@ -310,6 +310,14 @@ settings-general-steamvr-description = Handig voor games of apps die alleen bepaalde trackers ondersteunen. settings-general-steamvr-trackers-waist = Taille settings-general-steamvr-trackers-chest = Borst +settings-general-steamvr-trackers-left_foot = Linkervoet +settings-general-steamvr-trackers-right_foot = Rechtervoet +settings-general-steamvr-trackers-left_knee = Linkerknie +settings-general-steamvr-trackers-right_knee = Rechterknie +settings-general-steamvr-trackers-left_elbow = Linker elleboog +settings-general-steamvr-trackers-right_elbow = Rechter elleboog +settings-general-steamvr-trackers-left_hand = Linkerhand +settings-general-steamvr-trackers-right_hand = Rechterhand settings-general-steamvr-trackers-tracker_toggling = Automatische tracker toewijzing settings-general-steamvr-trackers-tracker_toggling-description = Zorgt automatisch voor het in- en uitschakelen van SteamVR-trackers, afhankelijk van je huidige tracker toewijzingen. settings-general-steamvr-trackers-tracker_toggling-label = Automatische tracker toewijzing @@ -342,8 +350,9 @@ settings-general-tracker_mechanics-drift_compensation-description = settings-general-tracker_mechanics-drift_compensation-enabled-label = Drift compensate settings-general-tracker_mechanics-drift_compensation-amount-label = Compensatiesterkte settings-general-tracker_mechanics-drift_compensation-max_resets-label = Gebruik de laatste x resets -settings-general-tracker_mechanics-save_mounting_reset = Sla automatische mounting reset kalibratie op -settings-general-tracker_mechanics-save_mounting_reset-description = Slaat de automatische mounting reset kalibraties van de trackers op tussen herstarts. Nuttig als je een pak draagt waarbij trackers niet bewegen tussen sessies. Niet aanbevolen voor normale gebruikers! +settings-general-tracker_mechanics-save_mounting_reset = Sla de automatische montage reset kalibratie op +settings-general-tracker_mechanics-save_mounting_reset-description = Slaat de automatische montage reset kalibraties van de trackers op tussen herstarts. Nuttig als je een pak draagt waarbij trackers niet bewegen tussen sessies. Niet aanbevolen voor normale gebruikers! +settings-general-tracker_mechanics-save_mounting_reset-enabled-label = Montage configuratie opslaan ## FK/Tracking settings @@ -372,6 +381,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Voeten montage reset. settings-general-fk_settings-arm_fk = Arm tracking settings-general-fk_settings-arm_fk-description = Verander de manier waarop de armen worden getrackt. settings-general-fk_settings-arm_fk-force_arms = Dwing armen vanuit HMD +settings-general-fk_settings-reset_settings = Instellingen resetten +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Reset de pitch (verticale rotatie) van de HMD na een volledige reset. Dit is handig als je de HMD op je voorhoofd draagt voor VTubing of mocap. Niet inschakelen voor VR. +settings-general-fk_settings-reset_settings-reset_hmd_pitch = HMD pitch resetten settings-general-fk_settings-arm_fk-reset_mode-description = Pas de verwachte armhouding aan voor het resetten van de montage. settings-general-fk_settings-arm_fk-back = Achterzijde settings-general-fk_settings-arm_fk-back-description = De standaardmodus, waarbij de bovenarmen naar achteren gaan en de onderarmen naar voren. @@ -405,7 +417,7 @@ settings-general-fk_settings-vive_emulation-label = Vive-emulatie inschakelen settings-general-gesture_control = Gesture control settings-general-gesture_control-subtitle = Op tik gebaseerde resets -settings-general-gesture_control-description = Maakt het mogelijk om resets te activeren door op een tracker te tikken. De tracker het hoogst op je bovenlichaam wordt gebruikt voor Quick Reset, de tracker het hoogst op je linkerbeen voor Reset en de tracker het hoogst op je rechterbeen voor Mounting Reset. Het moet worden vermeld dat tikken binnen 0,6 seconden moeten gebeuren om geregistreerd te worden. +settings-general-gesture_control-description = Maakt het mogelijk om resets te activeren door op een tracker te tikken. De tracker het hoogst op je bovenlichaam wordt gebruikt voor Quick Reset, de tracker het hoogst op je linkerbeen voor Reset en de tracker het hoogst op je rechterbeen voor Montage Reset. Het moet worden vermeld dat tikken binnen 0,6 seconden moeten gebeuren om geregistreerd te worden. # 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 = @@ -426,9 +438,9 @@ settings-general-gesture_control-yawResetTaps = Hoeveelheid tikken voor horizont settings-general-gesture_control-fullResetEnabled = Activeer tikken voor volledige reset settings-general-gesture_control-fullResetDelay = Vertraging volledige reset settings-general-gesture_control-fullResetTaps = Hoeveelheid tikken voor volledige reset -settings-general-gesture_control-mountingResetEnabled = Activeer tikken voor bevestigingskalibratie -settings-general-gesture_control-mountingResetDelay = Vertraging bevestigingskalibratie -settings-general-gesture_control-mountingResetTaps = Hoeveelheid tikken voor bevestigingskalibratie +settings-general-gesture_control-mountingResetEnabled = Activeer tikken voor montage-kalibratie +settings-general-gesture_control-mountingResetDelay = Vertraging montage-kalibratie +settings-general-gesture_control-mountingResetTaps = Hoeveelheid tikken voor montage-kalibratie # The number of trackers that can have higher acceleration before a tap is rejected settings-general-gesture_control-numberTrackersOverThreshold = Trackers over drempelwaarde settings-general-gesture_control-numberTrackersOverThreshold-description = Verhoog deze waarde als de tik detectie niet werkt. Zet deze waarde niet te hoog om tik detectie te laten werken, dit kan vals positieve resultaten creëren. @@ -463,10 +475,20 @@ settings-general-interface-feedback_sound-description = Speelt een geluid telken settings-general-interface-feedback_sound-label = Feedback geluid settings-general-interface-feedback_sound-volume = Feedback geluid volume settings-general-interface-connected_trackers_warning = Waarschuwing voor verbonden trackers +settings-general-interface-connected_trackers_warning-description = Deze optie toont een pop-up bericht telkens wanneer je SlimeVR probeert af te sluiten terwijl er nog trackers verbonden zijn. Dit bericht herinnert je eraan om je trackers uit te schakelen wanneer je klaar bent om de batterijduur te sparen. settings-general-interface-connected_trackers_warning-label = Waarschuwing voor verbonden trackers bij het afsluiten settings-general-interface-use_tray = Minimaliseren naar systeem vak settings-general-interface-use_tray-description = Hiermee kun je het venster sluiten zonder de SlimeVR server te beëindigen, zodat je deze op de achtergrond kunt blijven gebruiken zonder dat de GUI in de weg zit. settings-general-interface-use_tray-label = Minimaliseren naar systeem vak +settings-general-interface-discord_presence = Activiteit delen op Discord +settings-general-interface-discord_presence-description = Deelt op Discord dat je de SlimeVR server gebruikt, tezamen met het aantal IMU-Trackers. +settings-general-interface-discord_presence-label = Activiteit delen op Discord +settings-general-interface-discord_presence-message = + { $amount -> + [0] Aan het slimen + [one] Gebruikt 1 tracker + *[other] Gebruikt { $amount } trackers + } ## Serial settings @@ -489,6 +511,8 @@ settings-serial-get_infos = Informatie ophalen settings-serial-serial_select = Selecteer een seriële poort settings-serial-auto_dropdown_item = Automatisch settings-serial-get_wifi_scan = WiFi-scan uitvoeren +settings-serial-file_type = Gewone tekst +settings-serial-save_logs = Opslaan in bestand ## OSC router settings @@ -519,14 +543,12 @@ settings-osc-router-network-address-placeholder = IPV4-adres settings-osc-vrchat = VRChat OSC Trackers # This cares about multilines -settings-osc-vrchat-description = - Wijzig VRChat-specifieke instellingen om HMD-data te ontvangen en te verzenden - trackergegevens voor FBT (werkt op Quest standalone). +settings-osc-vrchat-description-v1 = Wijzig instellingen die specifiek zijn voor de OSC Trackers-standaard die wordt gebruikt voor het verzenden van trackinggegevens naar applicaties zonder SteamVR (bijv. Quest standalone). Zorg ervoor dat OSC is ingeschakeld in VRChat via het Actiemenu onder OSC > Ingeschakeld. Om het ontvangen van HMD- en controllergegevens van VRChat mogelijk te maken, ga in je hoofdmenu naar Instellingen onder Tracking & IK > Allow Sending Head and Wrist VR Tracking OSC Data. settings-osc-vrchat-enable = Inschakelen settings-osc-vrchat-enable-description = Schakel het verzenden en ontvangen van gegevens in en uit. settings-osc-vrchat-enable-label = Inschakelen settings-osc-vrchat-network = Netwerkpoorten -settings-osc-vrchat-network-description = Stel de poorten in voor het zenden en ontvangen van OSC-gegevens naar VRChat. +settings-osc-vrchat-network-description-v1 = Stel de poorten in voor het ontvangen en verzenden van tracking data. Kan op standaardinstellingen blijven voor VRChat. settings-osc-vrchat-network-port_in = .label = Poort In .placeholder = Poort in (standaard: 9001) @@ -534,7 +556,7 @@ settings-osc-vrchat-network-port_out = .label = Poort Out .placeholder = Poort uit (standaard: 9000) settings-osc-vrchat-network-address = Netwerkadres -settings-osc-vrchat-network-address-description = Kies naar welk adres je gegevens naar VRChat wilt verzenden (controleer de wifi-instellingen op je apparaat). +settings-osc-vrchat-network-address-description-v1 = Kies naar welk adres u gegevens wilt verzenden. Kan op standaardinstellingen blijven voor VRChat. settings-osc-vrchat-network-address-placeholder = VRChat IP-adres settings-osc-vrchat-network-trackers = Trackers settings-osc-vrchat-network-trackers-description = Schakel het verzenden van specifieke trackers via OSC in en uit. @@ -577,6 +599,9 @@ settings-osc-vmc-vrm-file_select = Sleep een modelbestand naar hier om ze te geb settings-osc-vmc-anchor_hip = Heupverankering settings-osc-vmc-anchor_hip-description = Veranker de tracking aan de heupen, handig voor zittende VTubing. Als u deze uitschakelt, laadt u een VRM-model. settings-osc-vmc-anchor_hip-label = Heupverankering +settings-osc-vmc-mirror_tracking = Gespiegelde tracking +settings-osc-vmc-mirror_tracking-description = De tracking horizontaal spiegelen. +settings-osc-vmc-mirror_tracking-label = Gespiegelde tracking ## Setup/onboarding menu @@ -609,7 +634,7 @@ onboarding-wifi_creds-password = ## Mounting setup -onboarding-reset_tutorial-back = Ga terug naar de bevestigingskalibratie +onboarding-reset_tutorial-back = Ga terug naar de montage-kalibratie onboarding-reset_tutorial = Reset tutorial onboarding-reset_tutorial-explanation = Terwijl je jouw trackers gebruikt, kunnen ze uit de lijn raken vanwege IMU-yaw-drift, of omdat je ze fysiek hebt verplaatst. Je hebt verschillende manieren om dit op te lossen. onboarding-reset_tutorial-skip = Stap overslaan @@ -716,6 +741,27 @@ onboarding-assign_trackers-assigned = onboarding-assign_trackers-advanced = Geavanceerde toewijzingslocaties weergeven onboarding-assign_trackers-next = Ik heb alle trackers toegewezen onboarding-assign_trackers-mirror_view = Gespiegelde weergave +onboarding-assign_trackers-option-amount = + { $trackersCount -> + [one] x{ $trackersCount } + *[other] x{ $trackersCount } + } +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] Lower-Body Set + [core] Core Set + [enhanced-core] Enhanced Core Set + [full-body] Full-Body Set + *[all] Alle trackers + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] Minimaal aantal voor VR full-body tracking + [core] + betere torso tracking + [enhanced-core] + voeten rotatie + [full-body] + elleboog tracking + *[all] Alle beschikbare tracker locaties + } ## Tracker assignment warnings @@ -792,44 +838,45 @@ onboarding-choose_mounting = Welke montagekalibratiemethode moet worden gebruikt onboarding-choose_mounting-description = De oriëntatie van de montage corrigeert de plaatsing van trackers op uw lichaam. onboarding-choose_mounting-auto_mounting = Automatische bevestiging # Italized text -onboarding-choose_mounting-auto_mounting-label = Experimenteel +onboarding-choose_mounting-auto_mounting-label-v2 = Aanbevolen onboarding-choose_mounting-auto_mounting-description = Dit detecteert automatisch de montagerichtingen voor al uw trackers door middel van 2 poses onboarding-choose_mounting-manual_mounting = Handmatige bevestiging # Italized text -onboarding-choose_mounting-manual_mounting-label = Aanbevolen +onboarding-choose_mounting-manual_mounting-label-v2 = Misschien niet precies genoeg onboarding-choose_mounting-manual_mounting-description = Hiermee kunt u de montagerichting handmatig kiezen voor elke tracker # Multiline text onboarding-choose_mounting-manual_modal-title = Ben je zeker dat je de automatische kalibratie wilt uitvoeren? +onboarding-choose_mounting-manual_modal-description = De handmatige montagekalibratie word aangeraden voor nieuwe gebruikers., De posities die je moet doen voor de automatische kalibratie kunnen lastig zijn om in één keer goed te krijgen en vereisen mogelijk wat oefening. onboarding-choose_mounting-manual_modal-confirm = Ik weet zeker wat ik doe onboarding-choose_mounting-manual_modal-cancel = Annuleren ## Tracker manual mounting setup onboarding-manual_mounting-back = Ga terug naar de VR sectie -onboarding-manual_mounting = Handmatige bevestiging +onboarding-manual_mounting = Handmatige montage onboarding-manual_mounting-description = Klik op elke tracker en selecteer op welke manier ze zijn bevestigd -onboarding-manual_mounting-auto_mounting = Automatische bevestiging +onboarding-manual_mounting-auto_mounting = Automatische montage onboarding-manual_mounting-next = Volgende stap ## Tracker automatic mounting setup onboarding-automatic_mounting-back = Ga terug naar de VR sectie -onboarding-automatic_mounting-title = Bevestigingskalibratie +onboarding-automatic_mounting-title = Montage-kalibratie onboarding-automatic_mounting-description = Om je trackers te laten werken, moet de rotatie worden ingesteld hoe deze zijn bevestigd op je lichaam. -onboarding-automatic_mounting-manual_mounting = Bevestiging handmatig instellen +onboarding-automatic_mounting-manual_mounting = Montage handmatig instellen onboarding-automatic_mounting-next = Volgende stap onboarding-automatic_mounting-prev_step = Vorige stap -onboarding-automatic_mounting-done-title = Bevestigingsrotaties gekalibreerd. -onboarding-automatic_mounting-done-description = Je bevestigingskalibratie is compleet! +onboarding-automatic_mounting-done-title = Montagerichtingen gekalibreerd. +onboarding-automatic_mounting-done-description = Je montage-kalibratie is compleet! onboarding-automatic_mounting-done-restart = Terug naar start -onboarding-automatic_mounting-mounting_reset-title = Bevestiging kalibreren +onboarding-automatic_mounting-mounting_reset-title = Montage-reset onboarding-automatic_mounting-mounting_reset-step-0 = 1. Ga staan in een "skie"-houding met gebogen benen, je bovenlichaam naar voren gekanteld en armen gebogen. -onboarding-automatic_mounting-mounting_reset-step-1 = 2. Druk op de knop "Bevestiging resetten" en wacht 3 seconden voordat de bevestigingsrotaties van de trackers opnieuw worden ingesteld. +onboarding-automatic_mounting-mounting_reset-step-1 = 2. Druk op de knop "Reset montage" en wacht 3 seconden voordat de montagerichtingen van de trackers opnieuw worden ingesteld. onboarding-automatic_mounting-preparation-title = Voorbereiding onboarding-automatic_mounting-preparation-step-0 = 1. Sta rechtop met je armen langs je zij. onboarding-automatic_mounting-preparation-step-1 = 2. Druk op de knop "Resetten" en wacht 3 seconden voordat de trackers opnieuw worden ingesteld. onboarding-automatic_mounting-put_trackers_on-title = Doe je trackers aan -onboarding-automatic_mounting-put_trackers_on-description = Om bevestigingsrotaties te kalibreren, gaan we gebruik maken van de trackers die je net hebt toegewezen. Doe al je trackers aan, je kunt zien welke trackers welke zijn in de figuur rechts. +onboarding-automatic_mounting-put_trackers_on-description = Om montagerichtingen te kalibreren gaan we gebruik maken van de trackers die je net hebt toegewezen. Doe al je trackers aan, je kunt zien welke trackers welke zijn in de figuur rechts. onboarding-automatic_mounting-put_trackers_on-next = Ik heb al mijn trackers aan ## Tracker proportions method choose @@ -875,6 +922,8 @@ onboarding-automatic_proportions-put_trackers_on-title = Doe je trackers aan onboarding-automatic_proportions-put_trackers_on-description = Om je verhoudingen te kalibreren, gaan we gebruik maken van de trackers die je net hebt toegewezen. Doe al je trackers aan, je kunt zien welke trackers welke zijn in de figuur rechts. onboarding-automatic_proportions-put_trackers_on-next = Ik heb al mijn trackers aan onboarding-automatic_proportions-requirements-title = Vereisten +# Each line of text is a different list item +onboarding-automatic_proportions-requirements-descriptionv2 = Je hebt voldaan aan de minimale vereisten om je voeten te tracken (over het algemeen 5 trackers). Je hebt je trackers en headset aan en draagt ze. Je trackers en headset zijn verbonden met de SlimeVR server en werken naar behoren (zonder haperingen, loskoppelingen etc.). Je headset stuurt positiedata naar de SlimeVR server (dit vereist doorgaans dat SteamVR draait en verbonden is met SlimeVR via de SlimeVR SteamVR-driver). De tracking werkt en registreert je bewegingen nauwkeurig (je hebt bijvoorbeeld een volledige reset uitgevoerd en de trackers bewegen in de juiste richting bij schoppen, bukken, zitten etc.). onboarding-automatic_proportions-requirements-next = Ik heb de vereisten gelezen onboarding-automatic_proportions-check_height-title = Controleer je lengte onboarding-automatic_proportions-check_height-description = @@ -882,6 +931,7 @@ onboarding-automatic_proportions-check_height-description = Maar het is beter om zelf te controleren of dit klopt. # All the text is in bold! onboarding-automatic_proportions-check_height-calculation_warning = Druk op de knop terwijl je rechtop staat om je lengte te berekenen. Je hebt 3 seconden na dat je op de knop drukt! +onboarding-automatic_proportions-check_height-guardian_tip = Als je een losse VR-bril gebruikt, zorg er dan voor dat je guardian/veilige zone is ingeschakeld zodat je lengte correct is gekalibreerd! onboarding-automatic_proportions-check_height-fetch_height = Ik sta! # Context is that the height is unknown onboarding-automatic_proportions-check_height-unknown = Onbekend @@ -946,6 +996,7 @@ status_system-StatusSteamVRDisconnected = *[other] Momenteel niet verbonden naar SteamVR via de SlimeVR driver. } status_system-StatusTrackerError = De { $trackerName } tracker heeft een error. +status_system-StatusUnassignedHMD = De VR-headset moet worden toegewezen als hoofdtracker. ## Tray Menu diff --git a/gui/public/i18n/pl/translation.ftl b/gui/public/i18n/pl/translation.ftl index ef5139fa4..0d351b66a 100644 --- a/gui/public/i18n/pl/translation.ftl +++ b/gui/public/i18n/pl/translation.ftl @@ -13,14 +13,14 @@ websocket-connection_lost = Połączenie z serwerem zostało utracone. Próba po ## Update notification version_update-title = Dostępna jest nowa wersja: { $version } -version_update-description = Kliknięcie „Aktualizuj” spowoduje pobranie instalatora SlimeVR. +version_update-description = Kliknięcie "{ version_update-update }" spowoduje pobranie instalatora SlimeVR. version_update-update = Aktualizacja version_update-close = Zamknij ## Tips -tips-find_tracker = Nie wiesz który tracker to który? Poruszaj trackerem, a będzie sie on podświetlał na serwerze. -tips-do_not_move_heels = Upewnij się, aby pięty pozostały w bezruchu podczas nagrywania. +tips-find_tracker = Nie jesteś pewien, który tracker jest który? Potrząśnij trackerem, a podświetli on odpowiedni element. +tips-do_not_move_heels = Upewnij się, aby pięty nie ruszały się podczas nagrywania. tips-file_select = Przeciągnij i upuść pliki, których chcesz użyć, lub przeglądaj. tips-tap_setup = Możesz powoli stuknąć 2 razy tracker, aby go wybrać, zamiast wybierać go z menu. tips-turn_on_tracker = Używasz oficjalnych trackerów SlimeVR? Pamiętaj, aby włączyć tracker po podłączeniu go do komputera! @@ -107,7 +107,7 @@ navbar-settings = Ustawienia ## Biovision hierarchy recording bvh-start_recording = Nagraj BVH -bvh-recording = Nagrywam... +bvh-recording = Nagrywanie... ## Tracking pause @@ -141,7 +141,7 @@ widget-developer_mode-more_info = Więcej info ## Widget: IMU Visualizer -widget-imu_visualizer = Obrót +widget-imu_visualizer = Rotacja widget-imu_visualizer-rotation_raw = Raw widget-imu_visualizer-rotation_preview = Podgląd widget-imu_visualizer-rotation_hide = Ukryj @@ -169,7 +169,7 @@ tracker-table-column-battery = Bateria tracker-table-column-ping = Ping tracker-table-column-tps = TPS tracker-table-column-temperature = Temp. °C -tracker-table-column-linear-acceleration = Accel. X/Y/Z +tracker-table-column-linear-acceleration = Akceleracja X/Y/Z tracker-table-column-rotation = Rotacja X/Y/Z tracker-table-column-position = Pozycja X/Y/Z tracker-table-column-url = URL @@ -206,7 +206,7 @@ tracker-settings-back = Wróć do listy trackerów tracker-settings-title = Ustawienia Trackerów tracker-settings-assignment_section = Przydzielanie tracker-settings-assignment_section-description = Do jakiej części ciała przydzielony jest tracker. -tracker-settings-assignment_section-edit = Edytuj +tracker-settings-assignment_section-edit = Edytuj przypisanie tracker-settings-mounting_section = Położenie Trackera tracker-settings-mounting_section-description = Gdzie zamontowany jest tracker? tracker-settings-mounting_section-edit = Edytuj @@ -244,11 +244,11 @@ body_assignment_menu-unassign_tracker = Usuń przydzielenie # maybe your language does. -tracker_selection-part = Which tracker to assign to your tracker_selection_menu-NONE = Któremu trackerowi chcesz cofnąć przypisanie? -tracker_selection_menu-HEAD = { -tracker_selection-part } head? +tracker_selection_menu-HEAD = { -tracker_selection-part } głowa? tracker_selection_menu-NECK = { -tracker_selection-part } szyja? tracker_selection_menu-RIGHT_SHOULDER = { -tracker_selection-part } prawe ramię? -tracker_selection_menu-RIGHT_UPPER_ARM = { -tracker_selection-part } right upper arm? -tracker_selection_menu-RIGHT_LOWER_ARM = { -tracker_selection-part } right lower arm? +tracker_selection_menu-RIGHT_UPPER_ARM = { -tracker_selection-part } prawe ramię? +tracker_selection_menu-RIGHT_LOWER_ARM = { -tracker_selection-part }prawe przedramię? tracker_selection_menu-RIGHT_HAND = { -tracker_selection-part } prawa ręka? tracker_selection_menu-RIGHT_UPPER_LEG = { -tracker_selection-part } prawe udo? tracker_selection_menu-RIGHT_LOWER_LEG = { -tracker_selection-part } prawa kostka? @@ -287,20 +287,20 @@ mounting_selection_menu-close = Zamknij settings-sidebar-title = Ustawienia settings-sidebar-general = Ogólne settings-sidebar-tracker_mechanics = Mechanika trackerów -settings-sidebar-fk_settings = FK settings +settings-sidebar-fk_settings = Ustawienia śledzenia settings-sidebar-gesture_control = Sterowanie gestami settings-sidebar-interface = Interfejs settings-sidebar-osc_router = OSC router settings-sidebar-osc_trackers = Śledzenie VRChat OSC settings-sidebar-utils = Narzędzia -settings-sidebar-serial = Konsola Seryjna +settings-sidebar-serial = Konsola szeregowa settings-sidebar-appearance = Wygląd settings-sidebar-notifications = Powiadomienia ## SteamVR settings settings-general-steamvr = SteamVR -settings-general-steamvr-subtitle = SteamVR trackers +settings-general-steamvr-subtitle = Trackery SteamVR # Not all translation keys support multiline, only the ones that specify it will actually # split it in lines (that also means you can split in lines however you want in those). # The first spaces (not tabs) for indentation will be ignored, just to make the file look nice when writing. @@ -318,7 +318,7 @@ settings-general-steamvr-trackers-left_elbow = Lewy łokieć settings-general-steamvr-trackers-right_elbow = Prawy łokieć settings-general-steamvr-trackers-left_hand = Lewa dłoń settings-general-steamvr-trackers-right_hand = Prawa dłoń -settings-general-steamvr-trackers-tracker_toggling = Automatyczne przypisanie wirtualnych trackerów +settings-general-steamvr-trackers-tracker_toggling = Automatyczne przypisanie trackerów settings-general-steamvr-trackers-tracker_toggling-description = Automatycznie obsługuje włączanie i wyłączanie wirtualnych trackerów SteamVR w zależności od bieżących przypisań fizycznych trackerów settings-general-steamvr-trackers-tracker_toggling-label = Automatyczne przypisanie wirtualnych trackerów SteamVR settings-general-steamvr-trackers-hands-warning = @@ -350,7 +350,7 @@ settings-general-tracker_mechanics-drift_compensation-description = Kompensuje dryf odchylenia IMU poprzez zastosowanie odwrotnej rotacji. Zmień wysokość kompensacji i do ilu resetów jest branych pod uwagę. settings-general-tracker_mechanics-drift_compensation-enabled-label = Kompensacja dryfu -settings-general-tracker_mechanics-drift_compensation-amount-label = Compensation amount +settings-general-tracker_mechanics-drift_compensation-amount-label = Ilość kompensacji settings-general-tracker_mechanics-drift_compensation-max_resets-label = Użyj maksymalnie x ostatnich resetów settings-general-tracker_mechanics-save_mounting_reset = Zapisz pozycję trackerów na ciele settings-general-tracker_mechanics-save_mounting_reset-description = @@ -383,6 +383,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Reset mocowania stóp settings-general-fk_settings-arm_fk = Śledzenie ramienia settings-general-fk_settings-arm_fk-description = Zmień sposób śledzenia ramion. settings-general-fk_settings-arm_fk-force_arms = Śledź ramiona z gogli VR +settings-general-fk_settings-reset_settings = Zresetuj ustawienia +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Resetuj kąt nachylenia headsetu (rotacja pionowa) podczas pełnego resetu. Przydatne, jeśli nosisz headset na czole do VTubingu lub mocapu. Nie włączaj do VR. +settings-general-fk_settings-reset_settings-reset_hmd_pitch = Resetuj kąt nachylenia headsetu settings-general-fk_settings-arm_fk-reset_mode-description = Zmień pozycję ramienia oczekiwaną przy resetowaniu montażu. settings-general-fk_settings-arm_fk-back = Wstecz settings-general-fk_settings-arm_fk-back-description = Tryb domyślny, w którym górne ramiona cofają się, a dolne ramiona przesuwają się do przodu. @@ -397,7 +400,7 @@ settings-general-fk_settings-skeleton_settings-description = Włącz lub wyłąc settings-general-fk_settings-skeleton_settings-extended_spine_model = Wydłużony model kręgosłupa settings-general-fk_settings-skeleton_settings-extended_pelvis_model = Rozszerzony model miednicy settings-general-fk_settings-skeleton_settings-extended_knees_model = Model z przedłużonym kolanem -settings-general-fk_settings-skeleton_settings-ratios = Współczynniki szkieletu +settings-general-fk_settings-skeleton_settings-ratios = Proporcje szkieletu settings-general-fk_settings-skeleton_settings-ratios-description = Zmień wartości ustawień szkieletu. Po zmianie może być konieczne dostosowanie proporcji. settings-general-fk_settings-skeleton_settings-impute_waist_from_chest_hip = Przypisz talię od klatki piersiowej do bioder settings-general-fk_settings-skeleton_settings-impute_waist_from_chest_legs = Przypisz talię od klatki piersiowej do nóg @@ -415,16 +418,16 @@ settings-general-fk_settings-vive_emulation-label = Włącz emulację Vive ## Gesture control settings (tracker tapping) settings-general-gesture_control = Kontrola Gestami -settings-general-gesture_control-subtitle = Dotknij 2 razy by wykonać szybki reset +settings-general-gesture_control-subtitle = Resetowanie na podstawie stuknięć settings-general-gesture_control-description = Umożliwia wyzwalanie resetów przez stuknięcie modułu śledzącego. Układ śledzący znajdujący się najwyżej na tułowiu służy do resetowania odchylenia, układ śledzący znajdujący się najwyżej na lewej nodze służy do pełnego resetu, a układ śledzący znajdujący się najwyżej na prawej nodze służy do resetowania montażu. Należy wspomnieć, że stuknięcia muszą nastąpić w ciągu 0,6 sekundy, aby zostały zarejestrowane. # 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 -> - [one] 1 dotknięcie - [few] { $amount } dotknięcia - [many] { $amount } dotknięć - *[other] { $amount } dotknięć + [one] 1 stuknięcie + [few] { $amount } stuknięcia + [many] { $amount } stuknięć + *[other] { $amount } stuknięć } # This is a unit: 3 trackers, 2 trackers, 1 tracker # $amount (Number) - Amount of trackers @@ -437,10 +440,10 @@ settings-general-gesture_control-trackers = } settings-general-gesture_control-yawResetEnabled = Włącz stuknięcie, aby zresetować odchylanie settings-general-gesture_control-yawResetDelay = Opóźnienie resetowania odchylenia -settings-general-gesture_control-yawResetTaps = Stuknięcie do resetowania odchylenia +settings-general-gesture_control-yawResetTaps = Stuknięć do zresetowania odchylenia settings-general-gesture_control-fullResetEnabled = Włącz stuknięcie, aby całkowicie zresetować settings-general-gesture_control-fullResetDelay = Pełne opóźnienie resetu -settings-general-gesture_control-fullResetTaps = Stuknij do pełnego resetu +settings-general-gesture_control-fullResetTaps = Stuknięć do pełnego resetu settings-general-gesture_control-mountingResetEnabled = Włącz stuknięcie, aby zresetować położenie settings-general-gesture_control-mountingResetDelay = Opóźnienie resetowania położenia settings-general-gesture_control-mountingResetTaps = Stuknięcie do resetowania położenia @@ -457,14 +460,14 @@ settings-general-interface-dev_mode-label = Tryb Dewelopera settings-general-interface-theme = Motyw kolorystyczny settings-general-interface-lang = Wybierz Język settings-general-interface-lang-description = Zmień podstawowy język jaki chcesz używać -settings-general-interface-lang-placeholder = Wybierz Język który będziesz używać +settings-general-interface-lang-placeholder = Wybierz język, który będziesz używać # Keep the font name untranslated settings-interface-appearance-font = Czcionka interfejsu użytkownika settings-interface-appearance-font-description = Spowoduje to zmianę czcionki używanej przez interfejs settings-interface-appearance-font-placeholder = Domyślna czcionka settings-interface-appearance-font-os_font = Czcionka systemu operacyjnego settings-interface-appearance-font-slime_font = Domyślna czcionka -settings-interface-appearance-font_size = Skalowanie czcionki bazowej +settings-interface-appearance-font_size = Skalowanie czcionki settings-interface-appearance-font_size-description = Wpływa to na rozmiar czcionki całego interfejsu z wyjątkiem tego panelu ustawień ## Notification settings @@ -476,13 +479,23 @@ settings-general-interface-serial_detection-label = Wykrywanie urządzeń settings-general-interface-feedback_sound = Dźwięk zwrotny settings-general-interface-feedback_sound-description = Ta opcja odtworzy dźwięk, gdy reset zostanie uruchomiony settings-general-interface-feedback_sound-label = Dźwięk Informacji -settings-general-interface-feedback_sound-volume = Poziom głośności sprzężenia zwrotnego +settings-general-interface-feedback_sound-volume = Poziom głośności dzwięku zwrotnego settings-general-interface-connected_trackers_warning = Ostrzeżenie o podłączonych trackerach settings-general-interface-connected_trackers_warning-description = Ta opcja wyświetli wyskakujące okienko za każdym razem, gdy spróbujesz wyjść ze SlimeVR, mając jeden lub więcej podłączonych trackerów. Przypomina o wyłączeniu trackerów, gdy skończysz, aby wydłużyć żywotność baterii. settings-general-interface-connected_trackers_warning-label = Ostrzeżenie o podłączonych trackerach przy wyjściu settings-general-interface-use_tray = Minimalizuj do zasobnika systemowego settings-general-interface-use_tray-description = Pozwala zamknąć okno bez wyłączania serwera SlimeVR, aby używać trackerów bez interfejsu graficznego. settings-general-interface-use_tray-label = Minimalizuj do zasobnika systemowego +settings-general-interface-discord_presence = Udostępniaj aktywność na Discordzie +settings-general-interface-discord_presence-description = Informuje Twojego klienta Discord o korzystaniu ze SlimeVR oraz o liczbie używanych trackerów IMU. +settings-general-interface-discord_presence-label = Udostępniaj aktywność na Discordzie +settings-general-interface-discord_presence-message = + { $amount -> + [0] Brak trackerów + [one] Użwanie 1 trackera + [few] Używanie { $amount } trackerów + *[many] Używanie { $amount } trackerów + } ## Serial settings @@ -505,6 +518,8 @@ settings-serial-get_infos = Uzyskaj informacje settings-serial-serial_select = Wybierz port szeregowy settings-serial-auto_dropdown_item = Auto settings-serial-get_wifi_scan = Skanuj sieci WiFi +settings-serial-file_type = Zwykły tekst +settings-serial-save_logs = Zapisz do pliku ## OSC router settings @@ -534,15 +549,11 @@ settings-osc-router-network-address-placeholder = IPV4 address ## OSC VRChat settings settings-osc-vrchat = VRChat OSC Trackers -# This cares about multilines -settings-osc-vrchat-description = - Zmień ustawienia specyficzne dla VRChat, aby odbierać i wysyłać dane HMD - dane trackerów dla FBT (działa na samodzielnym Quest). settings-osc-vrchat-enable = Zezwól settings-osc-vrchat-enable-description = Zezwól na wysyłanie i odbieranie danych. settings-osc-vrchat-enable-label = Zezwól settings-osc-vrchat-network = Porty sieciowe -settings-osc-vrchat-network-description = Ustaw porty do odbierania i wysyłania danych do VRChat. +settings-osc-vrchat-network-description-v1 = Ustaw porty do odbierania i wysyłania danych. Nie trzeba tego zmieniać dla VRChata. settings-osc-vrchat-network-port_in = .label = Port In .placeholder = Port in (default: 9001) @@ -550,7 +561,7 @@ settings-osc-vrchat-network-port_out = .label = Port Out .placeholder = Port out (default: 9000) settings-osc-vrchat-network-address = Adres sieciowy -settings-osc-vrchat-network-address-description = Wybierz adres, na który chcesz wysłać dane do VRChat (sprawdź ustawienia Wi-Fi na swoim urządzeniu). +settings-osc-vrchat-network-address-description-v1 = Wybierz adres, na który mają być wysyłane dane. Można pozostawić domyślnie dla VRChata. settings-osc-vrchat-network-address-placeholder = Adres IP VRChata settings-osc-vrchat-network-trackers = Trackers settings-osc-vrchat-network-trackers-description = Przełącz wysyłanie określonych trackerów przez OSC. @@ -593,6 +604,9 @@ settings-osc-vmc-vrm-file_select = Przeciągnij i upuść model, którego chcesz settings-osc-vmc-anchor_hip = Blokada na biodrach settings-osc-vmc-anchor_hip-description = Zablokuj śledzenie na biodrach, przydatne podczas siedzenia VTubing. W przypadku wyłączenia załaduj model VRM. settings-osc-vmc-anchor_hip-label = Blokada na biodrach +settings-osc-vmc-mirror_tracking = Odbicie lustrzane śledzenia +settings-osc-vmc-mirror_tracking-description = Odbij śledzenie w poziomie. +settings-osc-vmc-mirror_tracking-label = Odbicie lustrzane śledzenia ## Setup/onboarding menu @@ -736,6 +750,28 @@ onboarding-assign_trackers-assigned = onboarding-assign_trackers-advanced = Pokaż zaawansowane ustawienia pozycji onboarding-assign_trackers-next = Przydzieliłem już wszystkie trackery onboarding-assign_trackers-mirror_view = Widok lustrzany +onboarding-assign_trackers-option-amount = + { $trackersCount -> + [one] x{ $trackersCount } + [few] x{ $trackersCount } + *[many] x{ $trackersCount } + } +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] Zestaw na dolną część ciała + [core] Zestaw podstawowy + [enhanced-core] Rozszerzony zestaw podstawowy + [full-body] Pełny zestaw + *[all] Wszystkie trackery + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] Minimum do śledzenia ciała w rzeczywistości wirtualnej + [core] + Ulepszone śledzenie kręgosłupa + [enhanced-core] + Śledzenie stóp + [full-body] + Śledzenie łokci + *[all] Wszystkie możliwe przypisania trackerów + } ## Tracker assignment warnings @@ -812,11 +848,11 @@ onboarding-choose_mounting = Jakiej metody kalibracji montażu użyć? onboarding-choose_mounting-description = Orientacja montażu koryguje umieszczenie trackerów na ciele. onboarding-choose_mounting-auto_mounting = Automatyczne mocowanie # Italized text -onboarding-choose_mounting-auto_mounting-label = Eksperymentalny +onboarding-choose_mounting-auto_mounting-label-v2 = Zalecane onboarding-choose_mounting-auto_mounting-description = To automatycznie wykryje kierunki montażu dla wszystkich twoich trackerów z 2 pozycji onboarding-choose_mounting-manual_mounting = Montaż ręczny # Italized text -onboarding-choose_mounting-manual_mounting-label = Zalecany +onboarding-choose_mounting-manual_mounting-label-v2 = Może nie być wystarczająco dokładne onboarding-choose_mounting-manual_mounting-description = Umożliwi to ręczne wybranie kierunku montażu dla każdego trackera # Multiline text onboarding-choose_mounting-manual_modal-title = @@ -960,7 +996,7 @@ onboarding-automatic_proportions-error_modal-confirm = Zrozumiano! ## Home -home-no_trackers = Nie wykryto trackerów +home-no_trackers = Nie wykryto ani nie przypisano żadnych trackerów ## Trackers Still On notification @@ -969,7 +1005,7 @@ trackers_still_on-modal-description = Jeden lub więcej modułów śledzących jest nadal włączonych. Czy nadal chcesz wyjść ze SlimeVR? trackers_still_on-modal-confirm = Wyjdź ze SlimeVR -trackers_still_on-modal-cancel = Poczekaj! +trackers_still_on-modal-cancel = Poczekaj... ## Status system @@ -980,6 +1016,7 @@ status_system-StatusSteamVRDisconnected = *[other] Nie można połączyć się ze SteamVR przez sterownik SlimeVR. } status_system-StatusTrackerError = Tracker { $trackerName } ma błąd. +status_system-StatusUnassignedHMD = Headset powinien być przypisany do śledzenia głowy. ## Tray Menu @@ -1004,7 +1041,7 @@ tray_or_exit_modal-cancel = Anuluj unknown_device-modal-title = Znaleziono nowy tracker! unknown_device-modal-description = - Dostępny jest nowy tracker z adresem MAC b { $deviceId } /b .¶ + Dostępny jest nowy tracker z adresem MAC { $deviceId } .¶ Czy chcesz podłączyć go do SlimeVR? unknown_device-modal-confirm = Jasne! unknown_device-modal-forget = Ignoruj diff --git a/gui/public/i18n/pt-BR/translation.ftl b/gui/public/i18n/pt-BR/translation.ftl index ed48df4be..729e59870 100644 --- a/gui/public/i18n/pt-BR/translation.ftl +++ b/gui/public/i18n/pt-BR/translation.ftl @@ -81,6 +81,11 @@ skeleton_bone-ELBOW_OFFSET = Compensação do Cotovelo ## Tracker reset buttons reset-reset_all = Redefinir todas as proporções +reset-reset_all_warning = + Aviso: Isso irá resetar suas proporções para serem baseadas apenas em sua altura. + Você tem certeza que deseja fazer isso? +reset-reset_all_warning-reset = Resetar proporções +reset-reset_all_warning-cancel = Cancelar reset-full = Reset Completo reset-mounting = Reset de Posição reset-yaw = Reset de guinada (yaw) @@ -111,8 +116,8 @@ bvh-recording = Gravando... ## Tracking pause -tracking-unpaused = Pausar tracking -tracking-paused = Resumir tracking +tracking-unpaused = Pausar rastreamento +tracking-paused = Retomar rastreamento ## Widget: Overlay settings @@ -136,15 +141,18 @@ widget-developer_mode-precise_rotation = Precise rotation widget-developer_mode-fast_data_feed = Fast data feed widget-developer_mode-filter_slimes_and_hmd = Filter slimes and HMD widget-developer_mode-sort_by_name = Sort by name -widget-developer_mode-raw_slime_rotation = Raw rotation +widget-developer_mode-raw_slime_rotation = Rotação bruta widget-developer_mode-more_info = More info ## Widget: IMU Visualizer -widget-imu_visualizer = Rotation -widget-imu_visualizer-rotation_raw = Raw -widget-imu_visualizer-rotation_preview = Preview -widget-imu_visualizer-rotation_hide = Esconder +widget-imu_visualizer = Rotação do tracker +widget-imu_visualizer-preview = Pré-visualização +widget-imu_visualizer-hide = Esconder +widget-imu_visualizer-rotation_raw = Bruta +widget-imu_visualizer-rotation_preview = Pré-visualizar rotação +widget-imu_visualizer-acceleration = Aceleração +widget-imu_visualizer-position = Posição ## Widget: Skeleton Visualizer @@ -169,7 +177,7 @@ tracker-table-column-battery = Bateria tracker-table-column-ping = Ping tracker-table-column-tps = TPS tracker-table-column-temperature = Temp. °C -tracker-table-column-linear-acceleration = Accel. X/Y/Z +tracker-table-column-linear-acceleration = Aceleração. X/Y/Z tracker-table-column-rotation = Rotação X/Y/Z tracker-table-column-position = Posição X/Y/Z tracker-table-column-url = URL @@ -185,7 +193,7 @@ tracker-rotation-back = Atrás tracker-rotation-back_left = Trás-esquerda tracker-rotation-back_right = Trás-direita tracker-rotation-custom = Personalizado -tracker-rotation-overriden = (substituído por reset de posição) +tracker-rotation-overriden = (substituído pelo reset de posição) ## Tracker information @@ -199,6 +207,13 @@ tracker-infos-hardware_identifier = ID do Hardware tracker-infos-imu = Sensor IMU tracker-infos-board_type = Placa principal tracker-infos-network_version = Versão do protocolo +tracker-infos-magnetometer = Magnetômetro +tracker-infos-magnetometer-status-v1 = + { $status -> + [DISABLED] Desabilitado + [ENABLED] Habilitado + *[NOT_SUPPORTED] Incompatível + } ## Tracker settings @@ -213,11 +228,19 @@ tracker-settings-mounting_section-edit = Editar posição tracker-settings-drift_compensation_section = Ligar a compensação de drift tracker-settings-drift_compensation_section-description = Esse tracker deverá compensar pelo drift quando a compensação de drift estiver ligado? tracker-settings-drift_compensation_section-edit = Ligar a compensação de drift +tracker-settings-use_mag = Permitir o uso do magnetômetro neste tracker +# Multiline! +tracker-settings-use_mag-description = + Esse tracker deve usar o magnetômetro para reduzir o drift quando o uso de magnetômetro estiver permitido? Não desligue seu tracker enquanto altera esta opção! + + Você precisa permitir o uso de magnetômetro primeiro, clique aqui para ir para as configurações. +tracker-settings-use_mag-label = Permitir o uso do magnetômetro # The . means it's an attribute and it's related to the top key. # In this case that is the settings for the assignment section. tracker-settings-name_section = Nome do tracker tracker-settings-name_section-description = Dê um apelido fofo :) tracker-settings-name_section-placeholder = Coxa esquerda de NightyBeast +tracker-settings-name_section-label = Nome do tracker tracker-settings-forget = Esquecer o tracker tracker-settings-forget-description = Remove o tracker do servidor SlimeVR e impede que ele se conecte a ele até que o servidor seja reiniciado. A configuração do tracker não será perdida. tracker-settings-forget-label = Esquecer o tracker @@ -287,7 +310,7 @@ mounting_selection_menu-close = Fechar settings-sidebar-title = Opções settings-sidebar-general = Geral settings-sidebar-tracker_mechanics = Mecânicas do Tracker -settings-sidebar-fk_settings = Opções de Tracker +settings-sidebar-fk_settings = Opções dos trackers settings-sidebar-gesture_control = Controle de Gestos settings-sidebar-interface = Interface settings-sidebar-osc_router = Roteador OSC @@ -296,6 +319,7 @@ settings-sidebar-utils = Utilidades settings-sidebar-serial = Console Serial settings-sidebar-appearance = Aparência settings-sidebar-notifications = Notificações +settings-sidebar-advanced = Avançado ## SteamVR settings @@ -350,6 +374,20 @@ settings-general-tracker_mechanics-drift_compensation-description = Compensa o drift de guinada (yaw) aplicando uma rotação inversa. Mudar a quantidade de compensação e até quantos resets vão ser levados em conta. settings-general-tracker_mechanics-drift_compensation-enabled-label = Compensação de drift +settings-general-tracker_mechanics-drift_compensation-prediction = Predição de compensação de drift +# This cares about multilines +settings-general-tracker_mechanics-drift_compensation-prediction-description = + Antecipa a compensação de drift além do intervalo medido anteriormente. + Ative essa opção se o tracker estiver girando continuamente no eixo de guinada (yaw). +settings-general-tracker_mechanics-drift_compensation-prediction-label = Predição de compensação de drift +settings-general-tracker_mechanics-drift_compensation_warning = + Aviso: Use a compensação de drift somente se você precisar resetar + com muita frequência (a cada 5 a 10 minutos). + + Algumas IMUs sujeitas a resets mais frequentes incluem: + Joy-Cons, owoTrack e MPUs (sem firmware recente). +settings-general-tracker_mechanics-drift_compensation_warning-cancel = Cancelar +settings-general-tracker_mechanics-drift_compensation_warning-done = Eu entedi settings-general-tracker_mechanics-drift_compensation-amount-label = Quantidade de compensação settings-general-tracker_mechanics-drift_compensation-max_resets-label = Use até x últimos resets settings-general-tracker_mechanics-save_mounting_reset = Salvar a calibragem automática de posição @@ -357,6 +395,11 @@ settings-general-tracker_mechanics-save_mounting_reset-description = Salva as calibrações automáticas de reset de posição para os trackers entre as reinicializações. Útil ao usar uma roupa em que os trackers não se movem entre as sessões. Não recomendado para usuários normais! settings-general-tracker_mechanics-save_mounting_reset-enabled-label = Salvar reset de Posição +settings-general-tracker_mechanics-use_mag_on_all_trackers = Usar o magnetômetro em todos os trackers IMUs compatíveis +settings-general-tracker_mechanics-use_mag_on_all_trackers-description = + Usa o magnetômetro em todos os trackers com firmware compatível, reduzindo o drift em ambientes magneticamente estáveis. + Essa opção pode ser desativada indivualmente nas configurações de cada tracker. Não desligue nenhum dos trackers enquanto altera esta opção! +settings-general-tracker_mechanics-use_mag_on_all_trackers-label = Usar o magnetômetro nos trackers ## FK/Tracking settings @@ -383,6 +426,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Reset de Posição dos settings-general-fk_settings-arm_fk = Opções do Braço settings-general-fk_settings-arm_fk-description = Muda o jeito que os braços são rastreados. settings-general-fk_settings-arm_fk-force_arms = Forçar braços do HMD +settings-general-fk_settings-reset_settings = Redefinir configurações +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Redefine a inclinação (rotação vertical) do HMD ao fazer um reset completo. Útil se estiver usando um HMD na testa para VTubing ou captura de movimento. Não ative para VR. +settings-general-fk_settings-reset_settings-reset_hmd_pitch = Redefinir a inclinação do HMD settings-general-fk_settings-arm_fk-reset_mode-description = Mudar a pose do braço esperada para o reset de posição. settings-general-fk_settings-arm_fk-back = Atrás settings-general-fk_settings-arm_fk-back-description = O modo padrão, com os braços voltados para trás e os antebraços para frente. @@ -447,11 +493,14 @@ settings-general-gesture_control-numberTrackersOverThreshold-description = Aumen ## Appearance settings -settings-interface-appearance = Aparênia +settings-interface-appearance = Aparência settings-general-interface-dev_mode = Modo de desenvolvedor settings-general-interface-dev_mode-description = Este modo pode ser útil se precisar de dados específicos ou para interagir com trackers conectados a um nível mais avançado settings-general-interface-dev_mode-label = Modo de desenvolvedor settings-general-interface-theme = Cor do tema +settings-general-interface-show-navbar-onboarding = Mostrar "{ navbar-onboarding }" na barra de navegação +settings-general-interface-show-navbar-onboarding-description = Isso muda se o botão "{ navbar-onboarding }" for exibido na barra de navegação. +settings-general-interface-show-navbar-onboarding-label = Mostrar "{ navbar-onboarding }" settings-general-interface-lang = Selecione o idioma settings-general-interface-lang-description = Alterar o idioma padrão que pretende utilizar settings-general-interface-lang-placeholder = Selecione o idioma que vai usar @@ -463,6 +512,9 @@ settings-interface-appearance-font-os_font = Fonte do sistema settings-interface-appearance-font-slime_font = Fonte padrão settings-interface-appearance-font_size = Escala da fonte settings-interface-appearance-font_size-description = Isso afeta o tamanho da fonte de toda a interface, exceto neste painel de configurações. +settings-interface-appearance-decorations = Use as decorações nativas do sistema +settings-interface-appearance-decorations-description = Quando essa opção estiver ativada, a barra de título do SlimeVR não será exibida, mas será substituída pela barra de título nativa do sistema. +settings-interface-appearance-decorations-label = Usar a barra de título nativa do sistema ## Notification settings @@ -480,6 +532,15 @@ settings-general-interface-connected_trackers_warning-label = Aviso de trackers settings-general-interface-use_tray = Minimizar para bandeja do sistema settings-general-interface-use_tray-description = Permite que você feche a janela sem fechar o servidor do SlimeVR, para que possa continuar usando-o sem que a interface gráfica o incomode. settings-general-interface-use_tray-label = Minimizar para a bandeja do sistema +settings-general-interface-discord_presence = Compartilhar atividade no Discord +settings-general-interface-discord_presence-description = Informa ao seu Discord que o SlimeVR está aberto, juntamente com o número de trackers IMU que você está utilizando. +settings-general-interface-discord_presence-label = Compartilhar atividade no Discord +settings-general-interface-discord_presence-message = + { $amount -> + [0] Dando uma voltinha + [one] Usando 1 tracker + *[other] Usando { $amount } trackers + } ## Serial settings @@ -502,6 +563,8 @@ settings-serial-get_infos = Obter informações settings-serial-serial_select = Selecione uma porta serial settings-serial-auto_dropdown_item = Auto settings-serial-get_wifi_scan = Obter varredura WiFi +settings-serial-file_type = Texto simples +settings-serial-save_logs = Salvar em arquivo ## OSC router settings @@ -532,14 +595,17 @@ settings-osc-router-network-address-placeholder = Endereço IPV4 settings-osc-vrchat = VRChat OSC Trackers # This cares about multilines -settings-osc-vrchat-description = - Mudar opções específicas do VRChat para receber e mandar dados do HMD - dados de trackers para FBT (funciona no Quest standalone). +settings-osc-vrchat-description-v1 = + Altere as configurações específicas do padrão de trackers OSC usado para enviar + dados de rastreamento para aplicativos sem o SteamVR (por exemplo, Quest standalone). + Certifique-se de habilitar o OSC no VRChat através do menu de ações em OSC > Habilitado. + Para permitir o recebimento de dados do HMD e dos controles do VRChat, vá nas configurações do menu principal + em Rastreamento e IK > Permitir o envio de dados OSC de Rastreio de RV da cabeça e do pulso. settings-osc-vrchat-enable = Ativar settings-osc-vrchat-enable-description = Ligar ou desligar o envio e recebimento de dados settings-osc-vrchat-enable-label = Ativar settings-osc-vrchat-network = Portas de rede -settings-osc-vrchat-network-description = Defina as portas para receber e enviar dados para o VRChat +settings-osc-vrchat-network-description-v1 = Define as portas para receber e enviar dados. Pode ser deixado como está para o VRChat. settings-osc-vrchat-network-port_in = .label = Porta de entrada .placeholder = Porta de entrada (padrão: 9001) @@ -547,7 +613,7 @@ settings-osc-vrchat-network-port_out = .label = Porta de saída .placeholder = Porta de saída (padrão: 9000) settings-osc-vrchat-network-address = Endereço de rede -settings-osc-vrchat-network-address-description = Escolha qual o endereço para enviar dados para o VRChat (verifique as suas opções de Wi-Fi no seu dispositivo) +settings-osc-vrchat-network-address-description-v1 = Escolha o endereço para enviar os dados. Pode ser deixado como está para o VRChat. settings-osc-vrchat-network-address-placeholder = Endereço de ip do VRChat settings-osc-vrchat-network-trackers = Trackers settings-osc-vrchat-network-trackers-description = Ligar ou desligar o envio e recepção de dados. @@ -590,6 +656,39 @@ settings-osc-vmc-vrm-file_select = Arraste e solte um modelo para usar, ou na settings-osc-vmc-anchor_hip = Ancorar no quadril settings-osc-vmc-anchor_hip-description = Ancorar o rastreamento no quadril, útil para VTubing sentado. Se desativar, carregue um modelo VRM. settings-osc-vmc-anchor_hip-label = Ancorar no quadril +settings-osc-vmc-mirror_tracking = Espelhar rastreamento +settings-osc-vmc-mirror_tracking-description = Espelhar o rastreamento horizontalmente. +settings-osc-vmc-mirror_tracking-label = Espelhar rastreamento + +## Advanced settings + +settings-utils-advanced = Avançado +settings-utils-advanced-reset-gui = Resetar configurações da interface +settings-utils-advanced-reset-gui-description = Restaura a interface para as configurações iniciais. +settings-utils-advanced-reset-gui-label = Resetar interface +settings-utils-advanced-reset-server = Resetar configuraçõse de tracking +settings-utils-advanced-reset-server-description = Restaura as configurações de tracking para as configurações iniciais. +settings-utils-advanced-reset-server-label = Resetar tracking +settings-utils-advanced-reset-all = Resetar todas as configurações +settings-utils-advanced-reset-all-description = Restaura a configuração da interface e de tracking para as configurações iniciais. +settings-utils-advanced-reset-all-label = Resetar todas as configurações +settings-utils-advanced-reset_warning = + { $type -> + [gui] + Aviso: Isso irá restaurar as configurações da interface gráfica para as configurações iniciais. + Tem certeza de que deseja fazer isso? + [server] + Aviso: Isso irá restaurar as configurações de tracking para as configurações iniciais. + Tem certeza de que deseja fazer isso? + *[all] + Aviso: Isso irá restaurar todas as suas configurações para as configurações iniciais. + Tem certeza de que deseja fazer isso? + } +settings-utils-advanced-reset_warning-reset = Resetar configurações +settings-utils-advanced-reset_warning-cancel = Cancelar +settings-utils-advanced-open_data = Pasta de arquivos +settings-utils-advanced-open_data-description = Abre a pasta de arquivos do SlimeVR no explorador de arquivos, a qual contém os arquivos de configuração e de registro. +settings-utils-advanced-open_data-label = Abrir pasta ## Setup/onboarding menu @@ -702,6 +801,7 @@ onboarding-calibration_tutorial-status-waiting = Esperando por você onboarding-calibration_tutorial-status-calibrating = Calibrando onboarding-calibration_tutorial-status-success = Legal! onboarding-calibration_tutorial-status-error = O tracker foi movido +onboarding-calibration_tutorial-skip = Pular tutorial ## Tracker assignment tutorial @@ -729,6 +829,27 @@ onboarding-assign_trackers-assigned = onboarding-assign_trackers-advanced = Mostrar locais de atribuição avançados onboarding-assign_trackers-next = Atribui todos os trackers onboarding-assign_trackers-mirror_view = Inverter visão +onboarding-assign_trackers-option-amount = + { $trackersCount -> + [one] x + *[other] x + } +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] Conjunto Lower-Body + [core] Conjunto Core + [enhanced-core] Conjunto Enhanced + [full-body] Conjunto Full-Body + *[all] Todos os trackers + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] O mínimo para rastrear seu corpo no VR + [core] + Rastreamento melhorado da coluna + [enhanced-core] + Rotação dos pés + [full-body] + Rastreamento dos cotovelos + *[all] Todas as atribuições de trackers disponíveis + } ## Tracker assignment warnings @@ -804,12 +925,12 @@ onboarding-choose_mounting = Qual método de calibração de posição você des # Multiline text onboarding-choose_mounting-description = A orientação de posição corrige a colocação dos trackers no seu corpo. onboarding-choose_mounting-auto_mounting = Posição automática -# Italized text -onboarding-choose_mounting-auto_mounting-label = Experimental +# Italicized text +onboarding-choose_mounting-auto_mounting-label-v2 = Recomendado onboarding-choose_mounting-auto_mounting-description = Isso detectará automaticamente as direções de posição para todos os seus trackers a partir de 2 poses onboarding-choose_mounting-manual_mounting = Posição manual -# Italized text -onboarding-choose_mounting-manual_mounting-label = Recomendado +# Italicized text +onboarding-choose_mounting-manual_mounting-label-v2 = Pode não ser precisa o suficiente onboarding-choose_mounting-manual_mounting-description = Isso permitirá que você escolha manualmente a direção de posição para cada tracker # Multiline text onboarding-choose_mounting-manual_modal-title = @@ -843,7 +964,7 @@ onboarding-automatic_mounting-mounting_reset-step-0 = 1. Agache-se em uma pose d onboarding-automatic_mounting-mounting_reset-step-1 = 2. Pressione o botão "Resetar Posição" e aguarde 3 segundos antes que as rotações de posição dos trackers sejam redefinidas. onboarding-automatic_mounting-preparation-title = Preparação onboarding-automatic_mounting-preparation-step-0 = 1. Fique de pé com os braços ao lado do corpo. -onboarding-automatic_mounting-preparation-step-1 = 2. Pressione o botão "Reset" e aguarde 3 segundos antes que os rastreadores sejam reiniciados. +onboarding-automatic_mounting-preparation-step-1 = 2. Pressione o botão "Reset" e aguarde 3 segundos antes que os trackers sejam reiniciados. onboarding-automatic_mounting-put_trackers_on-title = Coloque seus trackers onboarding-automatic_mounting-put_trackers_on-description = Para calibrar as rotações de posicionamento, usaremos os trackers que você atribuiu. Coloque todos os seus trackers, você pode ver qual é qual na figura na direita. onboarding-automatic_mounting-put_trackers_on-next = Coloquei todos os meus trackers @@ -857,14 +978,14 @@ onboarding-choose_proportions-description-v1 = Quando as proporções do seu corpo não corresponderem às que estão salvas, a precisão do rastreamento será pior e você observará problemas como efeito de patinação ou deslizamento, ou que seu corpo não corresponde bem ao seu avatar. Você precisará medir seu corpo apenas uma vez! Se as medições estiverem corretas e o seu corpo não tiver passado por mudanças significativas, não há necessidade de repeti-las. onboarding-choose_proportions-auto_proportions = Proporções automáticas -# Italized text +# Italicized text onboarding-choose_proportions-auto_proportions-subtitle = Recomendado onboarding-choose_proportions-auto_proportions-descriptionv3 = Isso irá estimar suas proporções gravando uma amostra de seus movimentos e passando-a por um algoritmo. Isso requer ter seu headset (HMD) conectado ao SlimeVR e na sua cabeça! onboarding-choose_proportions-manual_proportions = Proporções manuais -# Italized text +# Italicized text onboarding-choose_proportions-manual_proportions-subtitle = Para pequenos ajustes onboarding-choose_proportions-manual_proportions-description = Isso permitirá que você ajuste suas proporções manualmente, modificando-as diretamente onboarding-choose_proportions-export = Exportar proporções @@ -944,9 +1065,10 @@ onboarding-automatic_proportions-verify_results-redo = Refazer a gravação onboarding-automatic_proportions-verify_results-confirm = Eles estão corretos onboarding-automatic_proportions-done-title = Corpo medido e salvo. onboarding-automatic_proportions-done-description = Sua calibragem de proporção de corpo está completa! -onboarding-automatic_proportions-error_modal = - Aviso: Um erro foi encontrado ao estimar proporções! - Por favor, verifique a documentação ou junte-se ao nosso Discord para obter ajuda ^_^ +onboarding-automatic_proportions-error_modal-v2 = + Aviso: Ocorreu um erro ao calcular as proporções! + Isso provavelmente é um problema da calibragem de posição. Verifique se o rastreamento está funcionando corretamente antes de tentar novamente. + Por favor, verifique a documentação ou entre em nosso Discord para obter ajuda ^_^ onboarding-automatic_proportions-error_modal-confirm = Entendido! ## Home @@ -971,6 +1093,7 @@ status_system-StatusSteamVRDisconnected = *[other] Atualmente não conectado ao SteamVR via driver SlimeVR. } status_system-StatusTrackerError = O tracker { $trackerName } tem um erro. +status_system-StatusUnassignedHMD = O headset (HMD) deve ser designado como o tracker da cabeça. ## Tray Menu diff --git a/gui/public/i18n/ru/translation.ftl b/gui/public/i18n/ru/translation.ftl index 57ca62448..1834e55c2 100644 --- a/gui/public/i18n/ru/translation.ftl +++ b/gui/public/i18n/ru/translation.ftl @@ -21,7 +21,7 @@ version_update-close = Закрыть tips-find_tracker = Не уверены, какой трекер какой? Встряхните его, и трекер выделится в списке. tips-do_not_move_heels = Убедитесь, что ваши пятки не двигаются во время записи! -tips-file_select = Выберите или перетащите файлы для использования выбрать. +tips-file_select = Выберите и перетащите файлы, чтобы использовать, или нажмите выбрать. tips-tap_setup = Вы можете медленно нажать 2 раза на свой трекер, чтобы выбрать его, вместо того чтобы выбирать его из меню. tips-turn_on_tracker = Используете официальные трекеры SlimeVR? Не забудьте включить трекер после его подключения к ПК! tips-failed_webgl = Не удалось инициализировать WebGL. @@ -81,6 +81,11 @@ skeleton_bone-ELBOW_OFFSET = Смещение локтя ## Tracker reset buttons reset-reset_all = Сбросить все пропорции +reset-reset_all_warning = + Внимание: Это сбросит ваши пропорции до основанных только на вашем росте. + Вы уверены, что хотите это сделать? +reset-reset_all_warning-reset = Сброс пропорций +reset-reset_all_warning-cancel = Отмена reset-full = Полный сброс reset-mounting = Сбросить крепление reset-yaw = Горизонтальный сброс @@ -142,9 +147,12 @@ widget-developer_mode-more_info = Дополнительная информац ## Widget: IMU Visualizer widget-imu_visualizer = Вращение +widget-imu_visualizer-preview = Предпросмотр +widget-imu_visualizer-hide = Скрыть widget-imu_visualizer-rotation_raw = RAW widget-imu_visualizer-rotation_preview = Предпросмотр -widget-imu_visualizer-rotation_hide = Скрыть +widget-imu_visualizer-acceleration = Ускорение +widget-imu_visualizer-position = Позиция ## Widget: Skeleton Visualizer @@ -199,6 +207,13 @@ tracker-infos-hardware_identifier = ID оборудования tracker-infos-imu = Датчик IMU tracker-infos-board_type = Основная плата tracker-infos-network_version = Версия Протокола +tracker-infos-magnetometer = Магнитометр +tracker-infos-magnetometer-status-v1 = + { $status -> + [DISABLED] Выключено + [ENABLED] Включено + *[NOT_SUPPORTED] Не Поддерживается + } ## Tracker settings @@ -213,11 +228,16 @@ tracker-settings-mounting_section-edit = Изменить прикреплени tracker-settings-drift_compensation_section = Разрешить компенсацию дрейфа tracker-settings-drift_compensation_section-description = Должен ли этот трекер компенсировать свой дрифт? tracker-settings-drift_compensation_section-edit = Разрешить компенсацию дрейфа +tracker-settings-use_mag = Разрешить использование магнитометра для этого трекера +# Multiline! +tracker-settings-use_mag-description = Должен ли этот трекер использовать магнитометр для компенсации дрифта, когда использование магнитометра разрешено?Пожалуйста, не выключайте трекер во время включения данной функции! Вам сначала нужно разрешить использование магнитометра, нажмите здесь чтобы зайти в настройки. +tracker-settings-use_mag-label = Разрешить магнитометр # The . means it's an attribute and it's related to the top key. # In this case that is the settings for the assignment section. tracker-settings-name_section = Имя трекера tracker-settings-name_section-description = Дай ему милое имя :) tracker-settings-name_section-placeholder = Левая нога NightyBeast'а +tracker-settings-name_section-label = Имя трекера tracker-settings-forget = Забыть трекер tracker-settings-forget-description = Убирает трекер с SlimeVR Сервер и запрещает ему подключаться к серверу до того как он будет перезапущен. Конфигурация трекера не будет потеряна. tracker-settings-forget-label = Забыть трекер @@ -296,6 +316,7 @@ settings-sidebar-utils = Утилиты settings-sidebar-serial = Консоль settings-sidebar-appearance = Внешний вид settings-sidebar-notifications = Уведомление +settings-sidebar-advanced = Продвинутые ## SteamVR settings @@ -310,6 +331,14 @@ settings-general-steamvr-description = Полезно для игр или приложений, которые поддерживают только определенные трекеры. settings-general-steamvr-trackers-waist = Талия settings-general-steamvr-trackers-chest = Грудь +settings-general-steamvr-trackers-left_foot = Левая ступня +settings-general-steamvr-trackers-right_foot = Правая ступня +settings-general-steamvr-trackers-left_knee = Левое колено +settings-general-steamvr-trackers-right_knee = Правое колено +settings-general-steamvr-trackers-left_elbow = Левый локоть +settings-general-steamvr-trackers-right_elbow = Правый локоть +settings-general-steamvr-trackers-left_hand = Левая рука +settings-general-steamvr-trackers-right_hand = Правая рука settings-general-steamvr-trackers-tracker_toggling = Автоматическое назначение трекеров settings-general-steamvr-trackers-tracker_toggling-description = Автоматически занимается включением и выключением трекеров SlimeVR в зависимости от текущих назначений ваших трекеров settings-general-steamvr-trackers-tracker_toggling-label = Автоматическое назначение трекеров @@ -342,6 +371,16 @@ settings-general-tracker_mechanics-drift_compensation-description = Компенсирует дрейф IMU по рысканию путем применения обратного вращения. Измените количество компенсации и до скольких сбросов учитывается. settings-general-tracker_mechanics-drift_compensation-enabled-label = Компенсация дрейфа +settings-general-tracker_mechanics-drift_compensation-prediction = Прогноз компенсации дрифта +settings-general-tracker_mechanics-drift_compensation-prediction-label = Прогноз компенсации дрифта +settings-general-tracker_mechanics-drift_compensation_warning = + Предупреждение: Используйте компенсацию дрифта только в том случае, если вам нужно сбросить настройки + очень часто (каждые ~5-10 минут). + + IMU, склонные к частым сбросам, включают: + Joy-Con, owoTrack, и MPU (без последней прошивки). +settings-general-tracker_mechanics-drift_compensation_warning-cancel = Отмена +settings-general-tracker_mechanics-drift_compensation_warning-done = Я понимаю 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 = Сохранить калибровку автоматического сброса крепления @@ -349,6 +388,11 @@ settings-general-tracker_mechanics-save_mounting_reset-description = Сохраняет автоматические калибровки сброса крепления для трекеров между перезапусками. Полезный при ношении костюма, в котором трекеры не перемещаются между сессиями. Не рекомендуется для обычных пользователей! 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 = + Использует магнитометр на всех трекерах, которые имеют совместимую с ним прошивку, уменьшая дрифт в стабильных магнитных средах. + Может быть отключен для каждого трекера в настройках трекера. Пожалуйста, не выключайте ни один из трекеров во время переключения! +settings-general-tracker_mechanics-use_mag_on_all_trackers-label = Использовать магнитометр трекеров ## FK/Tracking settings @@ -375,6 +419,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Сброс крепл settings-general-fk_settings-arm_fk = Отслеживание рук settings-general-fk_settings-arm_fk-description = Измените способ отслеживания рук. settings-general-fk_settings-arm_fk-force_arms = Руки от HMD +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-back = Назад settings-general-fk_settings-arm_fk-back-description = Режим по умолчанию, в котором плечи идут назад, а предплечья — вперед. @@ -446,6 +493,8 @@ settings-general-interface-dev_mode = Режим разработчика settings-general-interface-dev_mode-description = Этот режим может быть полезен, если вам нужны подробные данные или для взаимодействия с подключенными трекерами на более продвинутом уровне. settings-general-interface-dev_mode-label = Режим разработчика settings-general-interface-theme = Варианты оформления +settings-general-interface-show-navbar-onboarding = Показать "{ navbar-onboarding }" на панели навигации +settings-general-interface-show-navbar-onboarding-label = Показать "{ navbar-onboarding }" settings-general-interface-lang = Выбрать язык settings-general-interface-lang-description = Измените язык по умолчанию, который вы хотите использовать. settings-general-interface-lang-placeholder = Выберите язык для использования @@ -457,6 +506,7 @@ settings-interface-appearance-font-os_font = Шрифт ОС settings-interface-appearance-font-slime_font = Шрифт по умолчанию settings-interface-appearance-font_size = Базовое масштабирование шрифта settings-interface-appearance-font_size-description = Это влияет на размер шрифта всего интерфейса, за исключением этой панели настроек. +settings-interface-appearance-decorations-description = Это не будет отображать верхнюю панель интерфейса, а вместо этого будет использоваться панель операционной системы. ## Notification settings @@ -474,6 +524,16 @@ settings-general-interface-connected_trackers_warning-label = Предупреж settings-general-interface-use_tray = Свернуть в системный трей settings-general-interface-use_tray-description = Позволяет закрыть окно, не закрывая сервер SlimeVR, так что вы можете продолжать использовать его, не беспокоясь о графическом интерфейсе. settings-general-interface-use_tray-label = Свернуть в системный трей +settings-general-interface-discord_presence = Поделиться активностью в Discord +settings-general-interface-discord_presence-description = Сообщает вашему приложению Discord, что вы используете SlimeVR, вместе с количеством IMU трекеров, которые вы используете. +settings-general-interface-discord_presence-label = Поделиться активностью в Discord +settings-general-interface-discord_presence-message = + { $amount -> + [0] Чиллим со Слаймами + [one] Используется { $amount } трекер + [few] Используется { $amount } трекера + *[many] Используется { $amount } трекеров + } ## Serial settings @@ -496,6 +556,8 @@ settings-serial-get_infos = Получить информацию settings-serial-serial_select = Выбрать серийный порт settings-serial-auto_dropdown_item = Авто settings-serial-get_wifi_scan = Получить сканирование Wi-Fi +settings-serial-file_type = Обычный текст +settings-serial-save_logs = Сохранить в файл ## OSC router settings @@ -526,14 +588,17 @@ settings-osc-router-network-address-placeholder = IPV4 адрес settings-osc-vrchat = VRChat OSC Трекеры # This cares about multilines -settings-osc-vrchat-description = - Измените настройки, специфичные для VRChat, чтобы получать данные HMD и отправлять - данные трекеров для FBT (работает с Quest). +settings-osc-vrchat-description-v1 = + Изменение настроек, специфичных для стандарта OSC Трекеров, используемых для отправки + данных о трекинге приложениям без SteamVR (например, Oculus Quest). + Убедитесь, что вы включили OSC в VRChat через меню действия в OSC > Включено. + Чтобы разрешить получение данных об HMD и контроллерах от VRChat, перейдите в настройки в главном меню, + и далее перейдите в Tracking & IK > Allow Sending Head and Wrist VR Tracking OSC Data. settings-osc-vrchat-enable = Включить settings-osc-vrchat-enable-description = Переключайте отправку и получение данных. settings-osc-vrchat-enable-label = Включить settings-osc-vrchat-network = Порты сети -settings-osc-vrchat-network-description = Установите порты для прослушивания и отправки данных в VRChat. +settings-osc-vrchat-network-description-v1 = Настройте порты для прослушивания и отправки данных. Можно оставить нетронутым для VRChat. settings-osc-vrchat-network-port_in = .label = Порт вход .placeholder = Порт вход (default: 9001) @@ -541,7 +606,7 @@ settings-osc-vrchat-network-port_out = .label = Порт выход .placeholder = Порт выход (default: 9000) settings-osc-vrchat-network-address = Адрес сети -settings-osc-vrchat-network-address-description = Выберите, на какой адрес отправлять данные в VRChat (проверьте настройки Wi-Fi на вашем устройстве). +settings-osc-vrchat-network-address-description-v1 = Выберите, на какой адрес отправлять данные. Можно оставить нетронутым для VRChat. settings-osc-vrchat-network-address-placeholder = VRChat ip адрес settings-osc-vrchat-network-trackers = Трекеры settings-osc-vrchat-network-trackers-description = Переключите отправку определенных трекеров через OSC. @@ -584,6 +649,39 @@ settings-osc-vmc-vrm-file_select = Перетащите модель для ис settings-osc-vmc-anchor_hip = Привязать к бедрам settings-osc-vmc-anchor_hip-description = Привязать трекинг к бедрам, полезно для сидячего VTubing'а. Если выключено, загрузите VRM модель. settings-osc-vmc-anchor_hip-label = Привязать к бедрам +settings-osc-vmc-mirror_tracking = Отзеркалить отслеживание +settings-osc-vmc-mirror_tracking-description = Отзеркалить отслеживание горизонтально. +settings-osc-vmc-mirror_tracking-label = Отзеркалить отслеживание + +## Advanced settings + +settings-utils-advanced = Продвинутые +settings-utils-advanced-reset-gui = Сброс настроек графического интерфейса +settings-utils-advanced-reset-gui-description = Восстановить стандартные настройки интерфейса. +settings-utils-advanced-reset-gui-label = Сбросить графический интерфейс +settings-utils-advanced-reset-server = Сброс настроек отслеживания +settings-utils-advanced-reset-server-description = Восстановить стандартные настройки для отслеживания. +settings-utils-advanced-reset-server-label = Сбросить отслеживание +settings-utils-advanced-reset-all = Сбросить все настройки +settings-utils-advanced-reset-all-description = Восстановить стандартные настройки как для интерфейса, так и для отслеживания. +settings-utils-advanced-reset-all-label = Сбросить всё +settings-utils-advanced-reset_warning = + { $type -> + [gui] + Предупреждение: Это сбросит ваши настройки графического интерфейса до значений по умолчанию. + Вы уверены, что хотите это сделать? + [server] + Предупреждение: Это сбросит ваши настройки отслеживания до значений по умолчанию. + Вы уверены, что хотите это сделать? + *[all] + Предупреждение: Это сбросит все ваши настройки до значений по умолчанию. + Вы уверены, что хотите это сделать? + } +settings-utils-advanced-reset_warning-reset = Сброс настроек +settings-utils-advanced-reset_warning-cancel = Отмена +settings-utils-advanced-open_data = Папка данных +settings-utils-advanced-open_data-description = Откройте в проводнике папку данных SlimeVR, содержащую файлы конфигурации и логи. +settings-utils-advanced-open_data-label = Открыть папку ## Setup/onboarding menu @@ -698,6 +796,7 @@ onboarding-calibration_tutorial-status-waiting = Ждем вас onboarding-calibration_tutorial-status-calibrating = Калибровка onboarding-calibration_tutorial-status-success = Хорошо! onboarding-calibration_tutorial-status-error = Трекер был перемещен +onboarding-calibration_tutorial-skip = Пропуск туториала ## Tracker assignment tutorial @@ -727,6 +826,28 @@ onboarding-assign_trackers-assigned = onboarding-assign_trackers-advanced = Показать дополнительные места привязки onboarding-assign_trackers-next = Я привязал все трекеры onboarding-assign_trackers-mirror_view = Зеркальный вид +onboarding-assign_trackers-option-amount = + { $trackersCount -> + [one] x{ $trackersCount } + [few] x{ $trackersCount } + *[many] x{ $trackersCount } + } +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] Комплект нижней части тела + [core] Базовый комплект + [enhanced-core] Улучшенный базовый комплект + [full-body] Комплект для всего тела + *[all] Все трекеры + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] Минимум для отслеживания тела в VR + [core] + Улучшенное отслеживание позвоночника + [enhanced-core] + Отслеживание поворота ступней + [full-body] + Отслеживание локтей + *[all] Все доступные привязки для трекеров + } ## Tracker assignment warnings @@ -802,12 +923,12 @@ onboarding-choose_mounting = Какой метод калибровки креп # Multiline text onboarding-choose_mounting-description = Ориентация крепления корректирует размещение трекеров на вашем теле. onboarding-choose_mounting-auto_mounting = Автоматическая привязка -# Italized text -onboarding-choose_mounting-auto_mounting-label = Экспериментальный +# Italicized text +onboarding-choose_mounting-auto_mounting-label-v2 = Рекомендуется onboarding-choose_mounting-auto_mounting-description = Это автоматически определит направления монтажа для всех ваших трекеров из 2 поз onboarding-choose_mounting-manual_mounting = Ручная привязка -# Italized text -onboarding-choose_mounting-manual_mounting-label = Рекомендованный +# Italicized text +onboarding-choose_mounting-manual_mounting-label-v2 = Может быть недостаточно точным onboarding-choose_mounting-manual_mounting-description = Это позволит вам выбрать направление монтажа вручную для каждого трекера # Multiline text onboarding-choose_mounting-manual_modal-title = @@ -855,14 +976,14 @@ onboarding-choose_proportions-description-v1 = Когда пропорции вашего тела не совпадают с сохраненными, точность отслеживания будет хуже, и вы заметите такие вещи, как скольжение или дрифт, или ваше тело не очень хорошо соответствует вашему аватару. Вам нужно измерить свое тело только один раз! Если они не неправильны или ваше тело не изменилось, то вам не нужно делать их снова. onboarding-choose_proportions-auto_proportions = Автоматическая привязка -# Italized text +# Italicized text onboarding-choose_proportions-auto_proportions-subtitle = Рекомендуется onboarding-choose_proportions-auto_proportions-descriptionv3 = Это попробует угадать ваши пропорции, записывая образец ваших движений и пропуская его через алгоритм. Для этого необходимо, чтобы ваш Шлем (HMD) был подключен к SlimeVR и был надет на голову! onboarding-choose_proportions-manual_proportions = Ручные пропорции -# Italized text +# Italicized text onboarding-choose_proportions-manual_proportions-subtitle = Для небольших штрихов onboarding-choose_proportions-manual_proportions-description = Это позволит вам настроить пропорции вручную, изменив их напрямую. onboarding-choose_proportions-export = Экспорт пропорций @@ -942,9 +1063,10 @@ onboarding-automatic_proportions-verify_results-redo = Перезаписать onboarding-automatic_proportions-verify_results-confirm = Они правильные onboarding-automatic_proportions-done-title = Тело измерено и сохранено. onboarding-automatic_proportions-done-description = Калибровка пропорций вашего тела завершена! -onboarding-automatic_proportions-error_modal = - Предупреждение: Была обнаружена ошибка при расчёте пропорций! - Пожалуйста, ознакомьтесь с документацией, или присоединитесь к нашему Discord серверу для получения помощи ^_^ +onboarding-automatic_proportions-error_modal-v2 = + Внимание: Произошла ошибка при оценке пропорций! + Скорее всего, это проблема с калибровкой крепления. Прежде чем повторить попытку, убедитесь, что отслеживание работает правильно. + Пожалуйста, проверьте документацию или присоединитесь к нашему Discord для получения помощи ^_^ onboarding-automatic_proportions-error_modal-confirm = Принято! ## Home @@ -969,6 +1091,7 @@ status_system-StatusSteamVRDisconnected = *[other] В настоящее время не подключен к SteamVR через драйвер SlimeVR. } status_system-StatusTrackerError = В трекере { $trackerName } обнаружена ошибка. +status_system-StatusUnassignedHMD = VR гарнитура должна быть назначена как трекер головы. ## Tray Menu diff --git a/gui/public/i18n/vi/translation.ftl b/gui/public/i18n/vi/translation.ftl index 19bd81821..2bf15fda8 100644 --- a/gui/public/i18n/vi/translation.ftl +++ b/gui/public/i18n/vi/translation.ftl @@ -23,6 +23,8 @@ tips-find_tracker = Không rõ tracker nào đang được chọn? Di chuyển n tips-do_not_move_heels = Không di chuyển gót chân trong khi đo tips-file_select = Kéo và thả tệp để sử dụng hoặc duyệt. tips-tap_setup = Bạn có thể từ từ nhấn vào 2 lần trình theo dõi của mình để chọn nó thay vì chọn nó từ menu. +tips-turn_on_tracker = Sử dụng thiết bị SlimeVR chính thức? Hãy nhớ bật trình theo dõi của bạn sau khi kết nối thiết bị với máy tính! +tips-failed_webgl = Không thể khởi tạo WebGL. ## Body parts @@ -79,9 +81,11 @@ skeleton_bone-ELBOW_OFFSET = Sai số khuỷu tay ## Tracker reset buttons reset-reset_all = Đặt lại tất cả bộ phận +reset-reset_all_warning-reset = Đặt lại tỷ lệ +reset-reset_all_warning-cancel = Hủy reset-full = Đặt lại reset-mounting = Đặt lại hướng gắn tracker -reset-yaw = Reset Yaw +reset-yaw = Đặt lại chiều quay lệch ## Serial detection stuff @@ -140,9 +144,12 @@ widget-developer_mode-more_info = Thêm thông tin ## Widget: IMU Visualizer widget-imu_visualizer = Góc quay +widget-imu_visualizer-preview = Xem trước +widget-imu_visualizer-hide = Ẩn widget-imu_visualizer-rotation_raw = Gốc widget-imu_visualizer-rotation_preview = Qua xử lí -widget-imu_visualizer-rotation_hide = Ẩn +widget-imu_visualizer-acceleration = Gia tốc +widget-imu_visualizer-position = Vị trí ## Widget: Skeleton Visualizer @@ -196,6 +203,7 @@ tracker-infos-hardware_rev = Revision phần cứng tracker-infos-hardware_identifier = Hardware ID tracker-infos-imu = Cảm biến IMU (IMU Sensor) tracker-infos-board_type = Bảng mạch chính +tracker-infos-network_version = Phiên bản giao thức ## Tracker settings @@ -215,6 +223,9 @@ tracker-settings-drift_compensation_section-edit = Cho phép bù trừ sai số tracker-settings-name_section = Tên tracker tracker-settings-name_section-description = Đặt cho nó một cái tên đẹp :3 tracker-settings-name_section-placeholder = Chân trái của JINODK +tracker-settings-forget = Quên thiết bị +tracker-settings-forget-description = Xóa thiết bị khỏi phần mềm SlimeVR và ngăn nó kết nối với nó cho đến khi máy chủ được khởi động lại. Cấu hình của trình theo dõi sẽ không bị mất. +tracker-settings-forget-label = Quên thiết bị ## Tracker part card info @@ -290,6 +301,7 @@ settings-sidebar-utils = Công cụ settings-sidebar-serial = Cổng Serial settings-sidebar-appearance = Giao diện settings-sidebar-notifications = Thông báo +settings-sidebar-advanced = Cài đặt mở rộng ## SteamVR settings @@ -304,10 +316,22 @@ settings-general-steamvr-description = Hữu dụng nếu game chỉ hỗ trợ số lượng tracker giới hạn. settings-general-steamvr-trackers-waist = Eo settings-general-steamvr-trackers-chest = Ngực -settings-general-steamvr-trackers-feet = Bàn chân -settings-general-steamvr-trackers-knees = Đầu gối -settings-general-steamvr-trackers-elbows = Khuỷu tay -settings-general-steamvr-trackers-hands = Tay +settings-general-steamvr-trackers-left_foot = Bàn chân trái +settings-general-steamvr-trackers-right_foot = Bàn chân phải +settings-general-steamvr-trackers-left_knee = Đầu gối trái +settings-general-steamvr-trackers-right_knee = Đầu gối phải +settings-general-steamvr-trackers-left_elbow = Khuỷu tay trái +settings-general-steamvr-trackers-right_elbow = Khuỷu tay phải +settings-general-steamvr-trackers-left_hand = Tay trái +settings-general-steamvr-trackers-right_hand = Tay phải +settings-general-steamvr-trackers-tracker_toggling = Tự động giao thiết bị +settings-general-steamvr-trackers-tracker_toggling-description = Tự động xử lý bật hoặc tắt thiết bị đo SteamVR chuyển đổi tùy thuộc vào thiết bị đã giao của bạn +settings-general-steamvr-trackers-tracker_toggling-label = Tự động giao thiết bị +settings-general-steamvr-trackers-hands-warning = + Lưu ý: bộ theo dõi tay sẽ dùng đè tay cầm điều khiển của bạn. + Bạn có chắc không? +settings-general-steamvr-trackers-hands-warning-cancel = Hủy +settings-general-steamvr-trackers-hands-warning-done = Có ## Tracker mechanics @@ -325,14 +349,24 @@ settings-general-tracker_mechanics-filtering-type-smoothing-description = Làm c settings-general-tracker_mechanics-filtering-type-prediction = Dự đoán settings-general-tracker_mechanics-filtering-type-prediction-description = Giảm độ trễ và làm chuyển động chân thật hơn, có thể khiến chuyển động không mượt mà settings-general-tracker_mechanics-filtering-amount = Mức độ lọc +settings-general-tracker_mechanics-yaw-reset-smooth-time = Thời gian thiết lập lại chiều quay lệch (0s tắt làm mượt) settings-general-tracker_mechanics-drift_compensation = Bù trừ sai số # This cares about multilines settings-general-tracker_mechanics-drift_compensation-description = Bù trừ sai lệch trục ngang của cảm biến bằng cách thêm một sai lệch chống lại nó Thay đổi mức độ bù trừ và số lần đặt lại được áp dụng bù trừ settings-general-tracker_mechanics-drift_compensation-enabled-label = Bù trừ sai số +settings-general-tracker_mechanics-drift_compensation-prediction = Dự đoán bù trôi (drift compensation) +settings-general-tracker_mechanics-drift_compensation-prediction-label = Dự đoán bù trôi (drift compensation) +settings-general-tracker_mechanics-drift_compensation_warning-cancel = Hủy +settings-general-tracker_mechanics-drift_compensation_warning-done = Tôi hiểu settings-general-tracker_mechanics-drift_compensation-amount-label = Mức độ bù trừ settings-general-tracker_mechanics-drift_compensation-max_resets-label = Số lần đặt lại được áp dụng bù trừ +settings-general-tracker_mechanics-save_mounting_reset = Lưu thiết bị đã giao tự động +settings-general-tracker_mechanics-save_mounting_reset-description = + Lưu thiết bị đã giao tự động cho các thiết bị giữa các lần khởi động lại. Có ích + khi mặc một bộ đồ SlimeVR mà trình theo dõi không di chuyển giữa các phiên. Không được khuyến khích cho người dùng bình thường! +settings-general-tracker_mechanics-save_mounting_reset-enabled-label = Đặt lại hướng gắn thiết bị ## FK/Tracking settings @@ -359,6 +393,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Đặt lại hướng settings-general-fk_settings-arm_fk = Track cánh tay settings-general-fk_settings-arm_fk-description = Thay đổi cách cánh tay được track settings-general-fk_settings-arm_fk-force_arms = Lấy dữ liệu cánh tay từ kính +settings-general-fk_settings-reset_settings = Đặt lại cài đặt +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Đặt lại cao độ của HMD (xoay dọc) khi thiết lập lại toàn bộ. Hữu ích nếu đeo HMD trên trán cho VTubing hoặc mocap. Lưu ý không bật VR khi sử dụng. +settings-general-fk_settings-reset_settings-reset_hmd_pitch = Đặt lại cao độ HMD settings-general-fk_settings-arm_fk-reset_mode-description = Thay đổi tư thế cánh tay để đặt lại hướng gắn tracker. settings-general-fk_settings-arm_fk-back = Khuỷu tay ra sau settings-general-fk_settings-arm_fk-back-description = Chế độ mặc định, với cánh tay trên trỏ về phía sau và cánh tay dưới hướng về phía trước. @@ -368,8 +405,22 @@ settings-general-fk_settings-arm_fk-tpose_down = T-pose (ngược lại) settings-general-fk_settings-arm_fk-tpose_down-description = Hai tay của bạn sẽ đưa lên 90 độ sang hai bên khi đặt lại hoàn toàn, và hai tay hướng xuống hai bên khi đặt lại hướng gắn tracker. settings-general-fk_settings-arm_fk-forward = Hai tay ra trước settings-general-fk_settings-arm_fk-forward-description = Hai cánh tay của bạn nâng lên 90 độ về phía trước. Hữu dụng cho việc VTubing. +settings-general-fk_settings-skeleton_settings-toggles = Bật tắt bộ xương settings-general-fk_settings-skeleton_settings-description = Bật hoặc tắt các cài đặt về khung cơ thể. Các lựa chọn này nên được giữ bật +settings-general-fk_settings-skeleton_settings-extended_spine_model = Mô hình cột sống mở rộng +settings-general-fk_settings-skeleton_settings-extended_pelvis_model = Mô hình xương chậu mở rộng +settings-general-fk_settings-skeleton_settings-extended_knees_model = Mô hình đầu gối mở rộng +settings-general-fk_settings-skeleton_settings-ratios = Tỷ lệ khung xương +settings-general-fk_settings-skeleton_settings-ratios-description = Thay đổi các giá trị của cài đặt bộ xương. Bạn có thể cần phải điều chỉnh tỷ lệ của bạn sau khi thay đổi những điều này. +settings-general-fk_settings-skeleton_settings-impute_waist_from_chest_hip = Quy kết eo từ ngực đến hông +settings-general-fk_settings-skeleton_settings-impute_waist_from_chest_legs = Quy kết eo từ ngực đến hông +settings-general-fk_settings-skeleton_settings-impute_hip_from_chest_legs = Gán hông từ ngực đến chân +settings-general-fk_settings-skeleton_settings-impute_hip_from_waist_legs = Gán hông từ eo đến chân +settings-general-fk_settings-skeleton_settings-interp_hip_legs = Tính trung bình số quay hông và lăn bằng chân. +settings-general-fk_settings-skeleton_settings-interp_knee_tracker_ankle = Tính trung bình của máy theo dõi đầu gối ngáp và lăn bằng mắt cá chân ' +settings-general-fk_settings-skeleton_settings-interp_knee_ankle = Tính trung bình của chiều quay đầu gối ngáp và lăn bằng mắt cá chân ' settings-general-fk_settings-self_localization-title = Chế độ Mocap +settings-general-fk_settings-self_localization-description = Chế độ Mocap cho phép bộ xương theo dõi đại khái vị trí của chính nó mà không cần kính VR hoặc các thiết bị theo dõi khác. Lưu ý rằng điều này yêu cầu bộ theo dõi chân và đầu để hoạt động và chức năng này vẫn đang trong quá trình thử nghiệm. settings-general-fk_settings-vive_emulation-title = Giả lập tracker Vive settings-general-fk_settings-vive_emulation-description = Giả lập cách tracker của Vive gặp vấn đề với việc theo dõi eo, đây là 1 tính năng được làm cho vui và sẽ làm giảm độ chính xác settings-general-fk_settings-vive_emulation-label = Giả lập tracker Vive @@ -389,9 +440,18 @@ settings-general-gesture_control-taps = # This is a unit: 3 trackers, 2 trackers, 1 tracker # $amount (Number) - Amount of trackers settings-general-gesture_control-trackers = { $amount } trackers +settings-general-gesture_control-yawResetEnabled = Bật chạm để đặt lại chiều quay +settings-general-gesture_control-yawResetDelay = Thời gian delay trước khi đặt lại +settings-general-gesture_control-yawResetTaps = Số lần chạm để đặt lại chiều quay +settings-general-gesture_control-fullResetEnabled = Bật chạm để đặt lại chiều quay +settings-general-gesture_control-fullResetDelay = Thời gian delay trước khi đặt lại full +settings-general-gesture_control-fullResetTaps = Số lần chạm để đặt lại full settings-general-gesture_control-mountingResetEnabled = Chạm để đặt lại hướng gắn tracker settings-general-gesture_control-mountingResetDelay = Thời gian delay trước khi đặt lại hướng gắn tracker settings-general-gesture_control-mountingResetTaps = Số lần chạm cho đặt lại hướng gắn tracker +# The number of trackers that can have higher acceleration before a tap is rejected +settings-general-gesture_control-numberTrackersOverThreshold = Số thiết bị có thể vượt phát hiện +settings-general-gesture_control-numberTrackersOverThreshold-description = Tăng số này nếu tính năng chạm thiết bị không hoạt động. Không tăng nó quá trên mức cần thiết để làm cho phát hiện chạm hoạt động vì nó sẽ gây ra nhiều kết quả sai hơn. ## Appearance settings @@ -405,9 +465,12 @@ settings-general-interface-lang-description = Đổi ngôn ngữ hiển thị (C settings-general-interface-lang-placeholder = Chọn ngôn ngữ để sử dụng (Select the language to use) # Keep the font name untranslated settings-interface-appearance-font = Phông chữ cho GUI +settings-interface-appearance-font-description = Cài đặt này thay đổi phông chữ được sử dụng bởi giao diện. settings-interface-appearance-font-placeholder = Phông chữ mặc định settings-interface-appearance-font-os_font = Phông chữ hệ điều hành settings-interface-appearance-font-slime_font = Phông chữ mặc định +settings-interface-appearance-font_size = Tỷ lệ phông chữ cơ bản +settings-interface-appearance-font_size-description = Điều này ảnh hưởng đến kích thước phông chữ của toàn bộ giao diện ngoại trừ bảng cài đặt này. ## Notification settings @@ -415,7 +478,24 @@ settings-interface-notifications = Thông báo settings-general-interface-serial_detection = Nhận dạng thiết bị Serial mới settings-general-interface-serial_detection-description = Hiển thị pop-up mỗi lần một thiết bị Serial mới được kết nối qua USB (có thể là tracker), giúp cải thiện quá trình thiết lập tracker settings-general-interface-serial_detection-label = Nhận dạng thiết bị Serial mới +settings-general-interface-feedback_sound = Âm thanh phản hồi settings-general-interface-feedback_sound-description = Tùy chọn này sẽ phát âm thanh khi thiết lập lại được kích hoạt. +settings-general-interface-feedback_sound-label = Âm thanh phản hồi +settings-general-interface-feedback_sound-volume = Âm lượng phản hồi +settings-general-interface-connected_trackers_warning = Cảnh báo với thiết bị đã kết nối +settings-general-interface-connected_trackers_warning-description = Tùy chọn này sẽ hiển thị cửa sổ bật lên mỗi khi bạn thử thoát khỏi SlimeVR trong khi có một hoặc nhiều thiết bị theo dõi được kết nối. Nó nhắc nhở bạn tắt trình theo dõi khi bạn hoàn tất để duy trì tuổi thọ pin. +settings-general-interface-connected_trackers_warning-label = Cảnh báo thiết bị đã kết nối khi thoát chương trình +settings-general-interface-use_tray = Thu nhỏ vào khay hệ thống +settings-general-interface-use_tray-description = Cho phép bạn đóng cửa sổ mà không cần đóng máy chủ SlimeVR để bạn có thể tiếp tục sử dụng nó mà không bị GUI làm phiền. +settings-general-interface-use_tray-label = Thu nhỏ vào khay hệ thống +settings-general-interface-discord_presence = Chia sẻ hoạt động trên Discord +settings-general-interface-discord_presence-description = Cho Discord của bạn biết rằng bạn đang sử dụng SlimeVR cùng với số lượng trình theo dõi IMU bạn đang sử dụng. +settings-general-interface-discord_presence-label = Chia sẻ hoạt động trên Discord +settings-general-interface-discord_presence-message = + { $amount -> + [0] Đang quay trên Slime + *[other] Đang dùng { $amount } điểm full body + } ## Serial settings @@ -427,11 +507,19 @@ settings-serial-description = settings-serial-connection_lost = Kết nối đến Serial đã mất, đang kết nối lại... settings-serial-reboot = Khởi động lại settings-serial-factory_reset = Khôi phục cài đặt gốc +# This cares about multilines +# text means that the text should be bold +settings-serial-factory_reset-warning = + Lưu ý: Thao tác này sẽ đặt lại trình theo dõi về cài đặt gốc. + Đặt lại bao gồm tất cả các cài đặt Wi-Fi và hiệu chuẩn (Calibrate) sẽ bị mất! settings-serial-factory_reset-warning-ok = Tôi biết mình đang làm gì settings-serial-factory_reset-warning-cancel = Hủy settings-serial-get_infos = Lấy thông tin settings-serial-serial_select = Chọn cổng Serial settings-serial-auto_dropdown_item = Tự động +settings-serial-get_wifi_scan = Quét WiFi +settings-serial-file_type = Văn bản thô +settings-serial-save_logs = Lưu vào tệp ## OSC router settings @@ -462,14 +550,17 @@ settings-osc-router-network-address-placeholder = Địa chỉ IPv4 settings-osc-vrchat = VRChat OSC Trackers # This cares about multilines -settings-osc-vrchat-description = - Thay đổi các cài đặt liên quan đến VRChat để nhận dữ liệu từ kính và - gửi dữ liệu tracker cho Full-body tracking (hoạt động với kính ở chế độ standalone) +settings-osc-vrchat-description-v1 = + Thay đổi cài đặt cụ thể cho OSC Trackers được sử dụng để gửi + dữ liệu đo đến các ứng dụng không có SteamVR (ví dụ: Quest Standalone). + Hãy đảm bảo bật OSC trong VRChat thông qua Menu hành động trong OSC > Enabled. + Để cho phép nhận kính thực tế ảo HMD và dữ liệu bộ điều khiển từ VRChat, hãy vào menu chính của bạn + cài đặt trong Tracking & IK > Allow Sending Head and Wrist VR Tracking OSC Data. settings-osc-vrchat-enable = Dữ liệu OSC settings-osc-vrchat-enable-description = Cho phép nhận và gửi dữ liệu OSC settings-osc-vrchat-enable-label = Giao tiếp dữ liệu OSC settings-osc-vrchat-network = Cổng mạng -settings-osc-vrchat-network-description = Chọn cổng mạng để nhận và gửi dữ liệu OSC đến VRChat +settings-osc-vrchat-network-description-v1 = Đặt các cổng để lấy và gửi dữ liệu. Có thể giữ nguyên cho VRChat. settings-osc-vrchat-network-port_in = .label = Cổng vào .placeholder = Cổng vào (Mặc định: 9001) @@ -477,7 +568,7 @@ settings-osc-vrchat-network-port_out = .label = Cổng ra .placeholder = Cổng ra (Mặc định: 9000) settings-osc-vrchat-network-address = Địa chỉ mạng -settings-osc-vrchat-network-address-description = Địa chỉ mạng mà SlimeVR sẽ gửi dữ liệu OSC đến VRChat (có thể tìm thấy địa chỉ mạng trong menu cài đặt Wi-Fi) +settings-osc-vrchat-network-address-description-v1 = Chọn địa chỉ để gửi dữ liệu đến. Có thể giữ nguyên cho VRChat. settings-osc-vrchat-network-address-placeholder = Địa chỉ IP của thiết bị chơi VRChat settings-osc-vrchat-network-trackers = Cấu hình Tracker settings-osc-vrchat-network-trackers-description = Chọn các tracker mà SlimeVR sẽ gửi dữ liệu OSC đến VRChat @@ -490,6 +581,10 @@ settings-osc-vrchat-network-trackers-elbows = Khuỷu tay ## VMC OSC settings settings-osc-vmc = Virtual Motion Capture +# This cares about multilines +settings-osc-vmc-description = + Thay đổi cài đặt cụ thể cho giao thức VMC (Virtual Motion Capture) + để gửi dữ liệu thân của SlimeVR và nhận dữ liệu thân từ các ứng dụng khác. settings-osc-vmc-enable = Bật settings-osc-vmc-enable-description = Cho phép nhận và gửi dữ liệu OSC settings-osc-vmc-enable-label = Chuyển tiếp dữ liệu OSC @@ -513,6 +608,23 @@ settings-osc-vmc-vrm-model_loaded = *[other] Mô hình chưa có tiêu đề đã được tải } settings-osc-vmc-vrm-file_select = Kéo và thả mô hình để sử dụng hoặc duyệt file +settings-osc-vmc-anchor_hip = Cố định ở hông +settings-osc-vmc-anchor_hip-description = Cố định theo dõi ở hông, hữu ích cho VTubing ngồi. Nếu tắt, hãy tải mô hình VRM. +settings-osc-vmc-anchor_hip-label = Cố định ở hông +settings-osc-vmc-mirror_tracking = Phản chiếu ngược theo dõi cơ thể +settings-osc-vmc-mirror_tracking-description = Phản chiếu theo dõi theo chiều ngang. +settings-osc-vmc-mirror_tracking-label = Phản chiếu ngược theo dõi cơ thể + +## Advanced settings + +settings-utils-advanced = Cài đặt mở rộng +settings-utils-advanced-reset-gui = Đặt lại cài đặt GUI +settings-utils-advanced-reset-all-label = Đặt lại tất cả +settings-utils-advanced-reset_warning-reset = Đặt lại cài đặt +settings-utils-advanced-reset_warning-cancel = Hủy +settings-utils-advanced-open_data = Thư mục dữ liệu +settings-utils-advanced-open_data-description = Mở thư mục dữ liệu của SlimeVR trong tệp, chứa các tệp cấu hình và logs. +settings-utils-advanced-open_data-label = Mở thư mục ## Setup/onboarding menu @@ -520,6 +632,9 @@ onboarding-skip = Bỏ qua cài đặt onboarding-continue = Tiếp tục onboarding-wip = Chưa hoàn thiện onboarding-previous_step = Quay lại +onboarding-setup_warning = + Lưu ý: Trình thiết lập ban đầu là cần thiết để theo dõi tốt, + bước này cần thiết nếu đây là lần đầu tiên bạn sử dụng SlimeVR. onboarding-setup_warning-skip = Bỏ qua cài đặt onboarding-setup_warning-cancel = Tiếp tục thiết lập @@ -546,6 +661,24 @@ onboarding-reset_tutorial-back = Quay lại cân chỉnh vị trí gắn tracker onboarding-reset_tutorial = Làm lại onboarding-reset_tutorial-explanation = Trong khi bạn sử dụng trình theo dõi của mình, tracker có thể bị lệch khỏi căn chỉnh do IMU bị trượt, trôi dạt hoặc vì bạn có thể đã di chuyển chúng về mặt vật lý. Bạn có một số cách để khắc phục điều này. onboarding-reset_tutorial-skip = Bỏ qua bước +# Cares about multiline +onboarding-reset_tutorial-0 = + Nhấn { $taps } lần thiết bị được đánh dấu để kích hoạt đặt lại chiều quay. + + Điều này sẽ làm cho các trình theo dõi quay mặt về cùng hướng với kính thực thế ảo (HMD) của bạn. +# Cares about multiline +onboarding-reset_tutorial-1 = + Nhấn vào { $taps } lần thiết bị được đánh dấu để kích hoạt đặt lại toàn bộ. + + Bạn cần phải đứng thẳng tay để làm việc này (i-pose). Có độ trễ 3 giây (có thể định cấu hình) trước khi nó thực sự xảy ra. + Điều này đặt lại hoàn toàn vị trí và xoay của tất cả các trình theo dõi của bạn. Nó sẽ khắc phục hầu hết các vấn đề. +# Cares about multiline +onboarding-reset_tutorial-2 = + Nhấn vào { $taps } lần thiết bị được đánh dấu để kích hoạt đặt lại lắp. + + Thiết lập lại gắn kết giúp ích cho cách các trình theo dõi thực sự được đặt vào bạn, vì vậy nếu bạn vô tình di chuyển chúng và thay đổi cách chúng được định hướng với số lượng lớn, điều này sẽ hữu ích. + + Bạn cần phải ở trên một tư thế như bạn đang trượt tuyết như nó được hiển thị trên trình hướng dẫn gắn tự động và bạn có độ trễ 3 giây (có thể định cấu hình) trước khi nó được kích hoạt. ## Setup start @@ -569,8 +702,8 @@ onboarding-done-close = Đóng hướng dẫn onboarding-connect_tracker-back = Quay lại cài đặt Wi-Fi onboarding-connect_tracker-title = Kết nối tracker -onboarding-connect_tracker-description-p0 = Cập nhật thông tin Wi-Fi cho tracker -onboarding-connect_tracker-description-p1 = Hãy kết nối các tracker chưa thiết lập qua cổng USB +onboarding-connect_tracker-description-p0-v1 = Bây giờ vào phần thú vị, kết nối thiết bị! +onboarding-connect_tracker-description-p1-v1 = Kết nối từng thiết bị một lần thông qua cổng USB. onboarding-connect_tracker-issue-serial = Có vấn đề với việc kết nối? Kiểm tra thông tin qua cổng Serial onboarding-connect_tracker-usb = USB Tracker onboarding-connect_tracker-connection_status-none = Đang tìm tracker @@ -596,10 +729,15 @@ onboarding-connect_tracker-next = Đã kết nối với tất cả tracker ## Tracker calibration tutorial +onboarding-calibration_tutorial = Hướng dẫn hiệu chuẩn IMU onboarding-calibration_tutorial-subtitle = Cái này sẽ giúp giảm trôi trượt theo dõi! +onboarding-calibration_tutorial-description = Mỗi khi bạn bật thiết bị theo dõi, chúng cần nghỉ ngơi một lúc trên bề mặt phẳng để hiệu chỉnh. Hãy làm điều tương tự bằng cách nhấp vào nút "{ onboarding-calibration_tutorial-calibrate }", và không di chuyển chúng! onboarding-calibration_tutorial-calibrate = Tôi đã đặt thiết bị theo dõi của mình lên bàn onboarding-calibration_tutorial-status-waiting = Đang chờ bạn hoàn thành +onboarding-calibration_tutorial-status-calibrating = Đang hiệu chuẩn onboarding-calibration_tutorial-status-success = Nice! +onboarding-calibration_tutorial-status-error = Thiết bị đã di chuyển +onboarding-calibration_tutorial-skip = Bỏ qua hướng dẫn ## Tracker assignment tutorial @@ -607,6 +745,8 @@ onboarding-assignment_tutorial = Làm thế nào để chuẩn bị một Slime onboarding-assignment_tutorial-first_step = 1. Đặt nhãn dán bộ phận cơ thể (nếu có) trên tracker theo lựa chọn của bạn # This text has a character limit of around 11 characters, so please keep it short onboarding-assignment_tutorial-sticker = Sticker +onboarding-assignment_tutorial-second_step-v2 = 2. Gắn dây đeo vào thiết bị theo dõi của bạn, giữ cho mặt Velcro của dây đeo hướng cùng hướng với hướng thiết bị của trình theo dõi của bạn: +onboarding-assignment_tutorial-second_step-continuation-v2 = Mặt Velcro cho extension phải hướng lên như hình ảnh sau: onboarding-assignment_tutorial-done = Tôi đã dán nhãn dán và dây đai! ## Tracker assignment setup @@ -624,14 +764,112 @@ onboarding-assign_trackers-assigned = } đã giao onboarding-assign_trackers-advanced = Xem thêm vị trí đặt onboarding-assign_trackers-next = Hoàn thành +onboarding-assign_trackers-mirror_view = Xem hình phản chiếu +onboarding-assign_trackers-option-amount = x{ $trackersCount } +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] Tất cả thiết bị + [core] { "" } + [enhanced-core] { "" } + [full-body] { "" } + *[all] { "" } + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] Tối thiều để có full body tracking + [core] + Thân eo + [enhanced-core] + Quay bàn chân + [full-body] + Khửu tay + *[all] Tất cả thiết bị được giao + } ## Tracker assignment warnings +# Note for devs, number is used for representing boolean states per bit. +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-LEFT_FOOT = + { $unassigned -> + [6] Bàn chân trái được xác định nhưng bạn cần thêm chân dưới kèm theo để hoạt động! + [5] Bàn chân trái được xác định nhưng bạn cần thêm chân trên kèm theo để hoạt động! + [4] Bàn chân trái được xác định nhưng bạn cần thêm chân trên và chân dưới kèm theo để hoạt động! + [3] Bàn chân trái được xác định nhưng bạn cần thêm ngực, eo hoặc bụng kèm theo để hoạt động! + [2] Bàn chân trái được xác định nhưng bạn cần thêm chân trên, ngực, eo hoặc bụng kèm theo để hoạt động! + [1] Bàn chân trái được xác định nhưng bạn cần thêm chân dưới, ngực, eo hoặc bụng kèm theo để hoạt động! + [0] Bàn chân trái được xác định nhưng bạn cần thêm chân trên, chân dưới, ngực, eo hoặc bụng kèm theo để hoạt động! + *[unknown] Bàn chân trái được xác định nhưng cần thêm bộ phận cơ thể thiếu! + } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-RIGHT_FOOT = + { $unassigned -> + [0] Bàn chân phải được xác định nhưng bạn cần thêm chân trên, chân dưới, ngực, eo hoặc bụng kèm theo để hoạt động! + [1] Bàn chân phải được xác định nhưng bạn cần thêm chân dưới, ngực, eo hoặc bụng kèm theo để hoạt động! + [2] Bàn chân phải được xác định nhưng bạn cần thêm chân trên, ngực, eo hoặc bụng kèm theo để hoạt động! + [3] Bàn chân phải được xác định nhưng bạn cần thêm ngực, eo hoặc bụng kèm theo để hoạt động! + [4] Bàn chân phải được xác định nhưng bạn cần thêm chân trên và chân dưới kèm theo để hoạt động! + [5] Bàn chân phải được xác định nhưng bạn cần thêm chân trên kèm theo để hoạt động! + [6] Bàn chân phải được xác định nhưng bạn cần thêm chân dưới kèm theo để hoạt động! + *[unknown] Bàn chân phải được xác định nhưng cần thêm bộ phận cơ thể thiếu! + } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-LEFT_LOWER_LEG = + { $unassigned -> + [0] Chân trên trái được xác định nhưng cần thêm chân trên! + [1] Chân trên trái được xác định nhưng cần thêm ngực, eo và bụng được giao! + [2] Chân trên trái được xác định nhưng cần thêm chân trên! + *[unknown] Chân trên trái được xác định nhưng cần thêm bộ phận cơ thể thiếu! + } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-RIGHT_LOWER_LEG = + { $unassigned -> + [0] Chân trên phải được xác định nhưng cần thêm chân trên! + [1] Chân trên phải được xác định nhưng cần thêm ngực, eo và bụng được giao! + [2] Chân trên phải được xác định nhưng cần thêm chân trên! + *[unknown] Chân trên phải được xác định nhưng cần thêm bộ phận cơ thể thiếu! + } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-LEFT_UPPER_LEG = + { $unassigned -> + [0] Chân trái trên được xác định nhưng cần thêm ngực, eo hoặc bụng! + *[unknown] Chân trái trên được xác định nhưng cần thêm bộ phận cơ thể thiếu! + } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-RIGHT_UPPER_LEG = + { $unassigned -> + [0] Chân phải trên được xác định nhưng cần thêm ngực, eo hoặc bụng! + *[unknown] Chân phải trên được xác định nhưng cần thêm bộ phận cơ thể thiếu! + } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-HIP = + { $unassigned -> + [0] Eo được xác định được xác định nhưng cần thêm ngực! + *[unknown] Eo được xác định được xác định nhưng cần thêm bộ phận cơ thể thiếu! + } +# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order +onboarding-assign_trackers-warning-WAIST = + { $unassigned -> + [0] Bụng được xác định nhưng cần thêm ngực! + *[unknown] Bụng được xác định được xác định nhưng cần thêm bộ phận cơ thể thiếu! + } ## Tracker mounting method choose -# Italized text -onboarding-choose_mounting-auto_mounting-label = Thử nghiệm +onboarding-choose_mounting = Bạn muốn dùng phương pháp hiểu chuần nào? +# Multiline text +onboarding-choose_mounting-description = Hướng lắp đặt chính xác cho vị trí của thiết bị theo dõi trên cơ thể của bạn. +onboarding-choose_mounting-auto_mounting = Cân chỉnh tự động +# Italicized text +onboarding-choose_mounting-auto_mounting-label-v2 = Khuyến khích dùng +onboarding-choose_mounting-auto_mounting-description = Điều này sẽ tự động phát hiện các hướng lắp đặt cho tất cả các thiết bị của bạn từ 2 tư thế +onboarding-choose_mounting-manual_mounting = Cân chỉnh thủ công +# Italicized text +onboarding-choose_mounting-manual_mounting-label-v2 = Có thể không đủ chính xác +onboarding-choose_mounting-manual_mounting-description = Điều này sẽ cho phép bạn chọn hướng lắp theo cách thủ công cho từng thiết bị +# Multiline text +onboarding-choose_mounting-manual_modal-title = + Bạn có chắc chắn muốn + đo hướng quay tự động? +onboarding-choose_mounting-manual_modal-description = Hiệu chuẩn lắp thủ công được khuyến nghị cho người dùng mới, vì các tư thế của hiệu chuẩn lắp tự động có thể khó thực hiện ngay trước và có thể cần một số thực hành. +onboarding-choose_mounting-manual_modal-confirm = Tôi chắc chắn về những gì tôi đang làm onboarding-choose_mounting-manual_modal-cancel = Hủy ## Tracker manual mounting setup @@ -665,15 +903,21 @@ onboarding-automatic_mounting-put_trackers_on-next = Tiếp tục ## Tracker proportions method choose +onboarding-choose_proportions = Phương pháp hiệu chuẩn tỷ lệ nào để sử dụng? +# Multiline string +onboarding-choose_proportions-description-v1 = + Tỷ lệ cơ thể được sử dụng để biết các số đo của cơ thể bạn. Họ được yêu cầu tính toán vị trí của trình theo dõi. + Khi tỷ lệ cơ thể của bạn không khớp với tỷ lệ được lưu, độ chính xác theo dõi của bạn sẽ kém hơn và bạn sẽ nhận thấy những thứ như trượt băng hoặc trượt, hoặc cơ thể của bạn không khớp với hình đại diện của bạn. + Bạn chỉ cần đo cơ thể của bạn một lần! Trừ khi chúng sai hoặc cơ thể bạn đã thay đổi, thì bạn không cần phải làm lại. onboarding-choose_proportions-auto_proportions = Đo kích thước cơ thể tự động -# Italized text +# Italicized text onboarding-choose_proportions-auto_proportions-subtitle = Khuyến khích dùng onboarding-choose_proportions-auto_proportions-descriptionv3 = Tính năng này sẽ đoán tỷ lệ cơ thể của bạn bằng cách ghi lại một mẫu chuyển động của bạn và chuyển nó qua một thuật toán. Tính năng này sẽ yêu cầu headset của bạn (HMD) được kết nối với SlimeVR và đang nằm ở trên đầu của bạn! onboarding-choose_proportions-manual_proportions = Đo kích thước cơ thể thủ công -# Italized text +# Italicized text onboarding-choose_proportions-manual_proportions-subtitle = Cho chính xác onboarding-choose_proportions-manual_proportions-description = Tính năng này sẽ cho phép bạn điều chỉnh tỉ lệ cơ thể của mình theo cách thủ công bằng cách chỉnh sửa các con số một cách trực tiếp onboarding-choose_proportions-export = Xuất tỉ lệ cơ thể @@ -688,6 +932,7 @@ onboarding-manual_proportions-back = Quay lại cân chỉnh hướng gắn onboarding-manual_proportions-title = Đo kích thước cơ thể thủ công onboarding-manual_proportions-precision = Cân chỉnh cụ thể (giảm hệ số chỉnh) onboarding-manual_proportions-auto = Đo kích thước cơ thể tự động +onboarding-manual_proportions-ratio = Điều chỉnh theo nhóm tỷ lệ ## Tracker automatic proportions setup @@ -712,6 +957,9 @@ onboarding-automatic_proportions-check_height-title = Kiểm tra chiều cao c onboarding-automatic_proportions-check_height-description = Chúng tôi sử dụng chiều cao của bạn làm cơ sở cho các phép đo của chúng tôi bằng cách sử dụng chiều cao của headset (HMD) làm chiều cao ước tính thực tế của bạn, nhưng tốt hơn hết bạn nên tự kiểm tra xem chúng có đúng không! # All the text is in bold! onboarding-automatic_proportions-check_height-calculation_warning = Vui lòng nhấn nút trong khi đứng thẳng để tính chiều cao của bạn. Bạn có 3 giây sau khi nhấn nút! +onboarding-automatic_proportions-check_height-guardian_tip = + Nếu bạn đang sử dụng Kính VR Standalone, hãy đảm bảo có guardian / + Ranh giới được bật để chiều cao của bạn là chính xác! onboarding-automatic_proportions-check_height-fetch_height = Tôi đang đứng! # Context is that the height is unknown onboarding-automatic_proportions-check_height-unknown = Không rõ @@ -750,13 +998,13 @@ onboarding-automatic_proportions-verify_results-confirm = Kết quả tương đ onboarding-automatic_proportions-done-title = Đã lưu chỉ số đo onboarding-automatic_proportions-done-description = Quá trình đo đã hoàn tất onboarding-automatic_proportions-error_modal = - Cảnh báo: Một lỗi đã được tìm thấy trong khi ước tính tỷ lệ cơ thể! - Vui lòng kiểm tra tài liệu hoặc tham gia Discord của chúng tôi để được trợ giúp ^_^ + Lưu ý: Một lỗi đã được tìm thấy trong khi ước tính tỷ lệ cơ thể! + Vui lòng kiểm tra hướng dẫn hoặc tham gia Discord của chúng tôi để được trợ giúp ^_^ onboarding-automatic_proportions-error_modal-confirm = Đã hiểu! ## Home -home-no_trackers = Không tìm thấy tracker / Tracker chưa được gán +home-no_trackers = Chưa có thiết bị nào được phát hiện hoặc điều ra ## Trackers Still On notification @@ -772,7 +1020,36 @@ trackers_still_on-modal-cancel = Vui lòng đợi... status_system-StatusTrackerReset = Bạn nên thực hiện thiết lập lại toàn bộ vì một hoặc nhiều trình theo dõi không được điều chỉnh. status_system-StatusSteamVRDisconnected = { $type -> - [steamvr_feeder] Hiện đang không kết nối với SteamVR thông qua trình điều khiển SlimeVR Feeder App. - *[other] Hiện đang không kết nối với SteamVR thông qua driver SlimeVR. + [steamvr_feeder] Chưa kết nối với SteamVR thông qua trình điều khiển SlimeVR Feeder App. + *[other] Chưa kết nối với SteamVR thông qua driver SlimeVR. } status_system-StatusTrackerError = Tracker { $trackerName } có lỗi. +status_system-StatusUnassignedHMD = Kính thực tế ảo VR này nên được giao là bộ theo dõi đầu. + +## Tray Menu + +tray_menu-show = Xem +tray_menu-hide = Ẩn +tray_menu-quit = Thoát + +## First exit modal + +tray_or_exit_modal-title = Nút đóng nên làm gì? +# Multiline text +tray_or_exit_modal-description = + Điều này cho phép bạn chọn xem bạn muốn thoát khỏi chương trình hoặc thu nhỏ nó vào khay khi nhấn nút đóng. + + Bạn có thể thay đổi điều này sau trong cài đặt giao diện. +tray_or_exit_modal-radio-exit = Thoát khi đóng +tray_or_exit_modal-radio-tray = Thu nhỏ vào khay hệ thống +tray_or_exit_modal-submit = Lưu +tray_or_exit_modal-cancel = Hủy + +## Unknown device modal + +unknown_device-modal-title = Thiết bị mới đã được tìm thấy! +unknown_device-modal-description = + Có thiết bị mới với địa chỉ MAC { $deviceId }. + Bạn có muốn kết nối nó với SlimeVR không? +unknown_device-modal-confirm = Chắc! +unknown_device-modal-forget = Bỏ qua diff --git a/gui/public/i18n/zh-Hans/translation.ftl b/gui/public/i18n/zh-Hans/translation.ftl index 561617507..34ee40134 100644 --- a/gui/public/i18n/zh-Hans/translation.ftl +++ b/gui/public/i18n/zh-Hans/translation.ftl @@ -81,6 +81,11 @@ skeleton_bone-ELBOW_OFFSET = 肘部偏移 ## Tracker reset buttons reset-reset_all = 重置身体比例 +reset-reset_all_warning = + 警告: 这会将您的身体比例重置为仅基于身高的默认比例。 + 您确定要执行此操作吗? +reset-reset_all_warning-reset = 重置身体比例 +reset-reset_all_warning-cancel = 取消 reset-full = 完整重置 reset-mounting = 重置佩戴 reset-yaw = 重置航向轴 @@ -142,9 +147,12 @@ widget-developer_mode-more_info = 显示更多信息 ## Widget: IMU Visualizer widget-imu_visualizer = 旋转 +widget-imu_visualizer-preview = 预览 +widget-imu_visualizer-hide = 隐藏 widget-imu_visualizer-rotation_raw = 原始旋转 widget-imu_visualizer-rotation_preview = 预览 -widget-imu_visualizer-rotation_hide = 隐藏 +widget-imu_visualizer-acceleration = 加速度 +widget-imu_visualizer-position = 位置 ## Widget: Skeleton Visualizer @@ -296,6 +304,7 @@ settings-sidebar-utils = 工具 settings-sidebar-serial = 串口控制台 settings-sidebar-appearance = 外观 settings-sidebar-notifications = 通知 +settings-sidebar-advanced = 高级选项 ## SteamVR settings @@ -350,6 +359,20 @@ settings-general-tracker_mechanics-drift_compensation-description = 应用反向旋转以补偿IMU的偏航角漂移。 更改补偿量和使用多少次的重置结果用于计算补偿量。 settings-general-tracker_mechanics-drift_compensation-enabled-label = 漂移补偿 +settings-general-tracker_mechanics-drift_compensation-prediction = 预测式漂移补偿 +# This cares about multilines +settings-general-tracker_mechanics-drift_compensation-prediction-description = + 预测超过先前测量范围的偏航角漂移,并进行补偿。 + 适用于追踪器在偏航轴上持续旋转的场景。 +settings-general-tracker_mechanics-drift_compensation-prediction-label = 预测式漂移补偿 +settings-general-tracker_mechanics-drift_compensation_warning = + 警告: 仅在需要经常重置偏航角 + (大概5~10分钟左右需要重置一次) 时使用漂移补偿。 + + 一些可能需要此补偿的 IMU 包括: + Joy-Cons、owoTrack 和 MPU(使用旧DMP固件)。 +settings-general-tracker_mechanics-drift_compensation_warning-cancel = 取消 +settings-general-tracker_mechanics-drift_compensation_warning-done = 了解 settings-general-tracker_mechanics-drift_compensation-amount-label = 补偿量 settings-general-tracker_mechanics-drift_compensation-max_resets-label = 使用几次的重置结果? settings-general-tracker_mechanics-save_mounting_reset = 保存佩戴重置结果 @@ -383,6 +406,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = 脚部佩戴重置 settings-general-fk_settings-arm_fk = 手臂追踪 settings-general-fk_settings-arm_fk-description = 即使有手臂位置数据可用,也强制使用头显的数据追踪手臂。 settings-general-fk_settings-arm_fk-force_arms = 强制使用头显数据追踪手臂 +settings-general-fk_settings-reset_settings = 重置设置 +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = 在进行完整重置时重置头显的俯仰角(垂直旋转)。适合将头显斜戴在头上进行直播或动捕的场景。作为VR使用时不要开启此选项。 +settings-general-fk_settings-reset_settings-reset_hmd_pitch = 重置头显俯仰 settings-general-fk_settings-arm_fk-reset_mode-description = 更改佩戴重置时使用的手臂姿势。 settings-general-fk_settings-arm_fk-back = 向后弯折 settings-general-fk_settings-arm_fk-back-description = 默认,重置时大臂向后,小臂向前,类似滑雪。 @@ -446,6 +472,9 @@ settings-general-interface-dev_mode = 开发者模式 settings-general-interface-dev_mode-description = 如果你需要深入的资料或对连接的追踪器进行进阶调整,开启此模式将会非常有用。 settings-general-interface-dev_mode-label = 开发者模式 settings-general-interface-theme = 主题颜色 +settings-general-interface-show-navbar-onboarding = 在导航栏上显示 “{ navbar-onboarding }” +settings-general-interface-show-navbar-onboarding-description = 本选项设置是否将 "{ navbar-onboarding }" 按钮显示在导航栏上。 +settings-general-interface-show-navbar-onboarding-label = 显示 “{ navbar-onboarding }” settings-general-interface-lang = 选择语言 settings-general-interface-lang-description = 更改要使用的默认语言 settings-general-interface-lang-placeholder = 选择要使用的语言 @@ -457,6 +486,9 @@ settings-interface-appearance-font-os_font = 系统字体 settings-interface-appearance-font-slime_font = 默认字体 settings-interface-appearance-font_size = 字体缩放 settings-interface-appearance-font_size-description = 这会影响除此设置面板外所有界面的字体大小。 +settings-interface-appearance-decorations = 使用系统原生窗口标题栏 +settings-interface-appearance-decorations-description = 这个选项开启后,将不会显示SlimeVR的标题栏,而是显示使用系统原生标题栏。 +settings-interface-appearance-decorations-label = 使用系统原生窗口标题栏 ## Notification settings @@ -474,6 +506,14 @@ settings-general-interface-connected_trackers_warning-label = 退出时,有追 settings-general-interface-use_tray = 最小化至任务栏 settings-general-interface-use_tray-description = 关闭 SlimeVR 窗口时,SlimeVR 服务器将会隐藏至任务栏图标而不会直接退出,可以继续使用。 settings-general-interface-use_tray-label = 最小化至任务栏 +settings-general-interface-discord_presence = 向Discord发送状态 +settings-general-interface-discord_presence-description = 告诉你的Discord客户端你正在使用SlimeVR,同时显示你正在使用的IMU追踪器数量。 +settings-general-interface-discord_presence-label = 向Discord发送状态 +settings-general-interface-discord_presence-message = + { $amount -> + [0] { "" } + *[other] 正在使用 { $amount } 个追踪器 + } ## Serial settings @@ -496,6 +536,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 @@ -526,14 +568,16 @@ settings-osc-router-network-address-placeholder = IPV4 地址 settings-osc-vrchat = VRChat OSC Trackers # This cares about multilines -settings-osc-vrchat-description = - 改变 VRChat 的特定设置以接收和发送头显数据。 - 用于全身追踪的追踪器数据(在 Quest 端生效)。 +settings-osc-vrchat-description-v1 = + 修改与OSC追踪器相关的设置,可用于在不使用SteamVR时传输追踪数据(如一体机模式)。 + 在使用OSC追踪器时,请确保在VRChat的圆盘菜单中开启OSC功能(选项 > OSC > 开启)。 + 为了从VRChat中接收到头显和控制器的数据,还需要在VRChat主菜单中设置的“动捕与IK”下, + 打开“通过OSC共享头显和手柄信息”。 settings-osc-vrchat-enable = 启用 settings-osc-vrchat-enable-description = 切换数据的发送和接收 settings-osc-vrchat-enable-label = 启用 settings-osc-vrchat-network = 网络端口 -settings-osc-vrchat-network-description = 设置用于监听和向 VRChat 发送数据的端口 +settings-osc-vrchat-network-description-v1 = 设置传输OSC数据的端口。用于VRChat时无需修改。 settings-osc-vrchat-network-port_in = .label = 输入端口 .placeholder = 输入端口(默认 9001) @@ -541,7 +585,7 @@ settings-osc-vrchat-network-port_out = .label = 输出端口 .placeholder = 输出端口(默认 9000) settings-osc-vrchat-network-address = 网络地址 -settings-osc-vrchat-network-address-description = 选择将数据发送到 VRChat 的地址(检查设备上的 Wi-Fi 设置) +settings-osc-vrchat-network-address-description-v1 = 选择传输OSC数据的IP地址。用于VRChat时无需修改。 settings-osc-vrchat-network-address-placeholder = VRChat IP 地址 settings-osc-vrchat-network-trackers = 追踪器 settings-osc-vrchat-network-trackers-description = 切换数据的发送和接收 @@ -584,6 +628,39 @@ settings-osc-vmc-vrm-file_select = 拖曳文件或 浏览文件 以加载 settings-osc-vmc-anchor_hip = 髋部锚定 settings-osc-vmc-anchor_hip-description = 将追踪锚定在髋部,有利于坐姿进行虚拟直播。若本选项无法切换,请加载 VRM 模型。 settings-osc-vmc-anchor_hip-label = 髋部锚定 +settings-osc-vmc-mirror_tracking = 镜像追踪 +settings-osc-vmc-mirror_tracking-description = 水平镜像追踪结果 +settings-osc-vmc-mirror_tracking-label = 镜像追踪 + +## Advanced settings + +settings-utils-advanced = 高级选项 +settings-utils-advanced-reset-gui = 重置GUI设置 +settings-utils-advanced-reset-gui-description = 恢复界面设置的初始配置。 +settings-utils-advanced-reset-gui-label = 重置GUI设置 +settings-utils-advanced-reset-server = 重置追踪设置 +settings-utils-advanced-reset-server-description = 恢复追踪设置的初始配置。 +settings-utils-advanced-reset-server-label = 重置追踪设置 +settings-utils-advanced-reset-all = 重置所有设置 +settings-utils-advanced-reset-all-description = 恢复界面设置与追踪设置的初始配置。 +settings-utils-advanced-reset-all-label = 重置所有设置 +settings-utils-advanced-reset_warning = + { $type -> + [gui] + 警告: 将要恢复界面设置为初始配置。 + 是否确认进行此操作? + [server] + 警告: 将要恢复追踪设置为初始配置。 + 是否确认进行此操作? + *[all] + 警告: 将要恢复所有设置为初始配置。 + 是否确认进行此操作? + } +settings-utils-advanced-reset_warning-reset = 重置设置 +settings-utils-advanced-reset_warning-cancel = 取消 +settings-utils-advanced-open_data = 数据文件夹 +settings-utils-advanced-open_data-description = 在文件管理器中打开SlimeVR的数据文件夹,查看配置文件与日志文件。 +settings-utils-advanced-open_data-label = 打开文件夹 ## Setup/onboarding menu @@ -695,6 +772,7 @@ onboarding-calibration_tutorial-status-waiting = 等待你的操作 onboarding-calibration_tutorial-status-calibrating = 校准中 onboarding-calibration_tutorial-status-success = 很好! onboarding-calibration_tutorial-status-error = 追踪器被移动! +onboarding-calibration_tutorial-skip = 跳过教程 ## Tracker assignment tutorial @@ -718,6 +796,23 @@ onboarding-assign_trackers-assigned = { $assigned }/{ $trackers } 个追踪器 onboarding-assign_trackers-advanced = 显示高级分配部位 onboarding-assign_trackers-next = 所有的追踪器都分配好了 onboarding-assign_trackers-mirror_view = 镜像显示 +onboarding-assign_trackers-option-amount = { $trackersCount } 点 +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] 下半身追踪 + [core] 身体追踪 + [enhanced-core] 拓展身体追踪 + [full-body] 全身追踪 + *[all] 所有可选追踪 + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] VR全身追踪最少需要的点数 + [core] + 更准确的躯干追踪 + [enhanced-core] + 脚部转动 + [full-body] + 上臂追踪 + *[all] 所有可用的追踪器分配 + } ## Tracker assignment warnings @@ -793,12 +888,12 @@ onboarding-choose_mounting = 使用哪种方法校准佩戴朝向? # Multiline text onboarding-choose_mounting-description = 佩戴方向校准用于确定您身上的追踪器的朝向。 onboarding-choose_mounting-auto_mounting = 自动设置佩戴方向 -# Italized text -onboarding-choose_mounting-auto_mounting-label = 实验功能 +# Italicized text +onboarding-choose_mounting-auto_mounting-label-v2 = 推荐使用 onboarding-choose_mounting-auto_mounting-description = 这将需要你做2个动作以自动检测所有追踪器的佩戴方向 onboarding-choose_mounting-manual_mounting = 手动设置佩戴方向 -# Italized text -onboarding-choose_mounting-manual_mounting-label = 推荐 +# Italicized text +onboarding-choose_mounting-manual_mounting-label-v2 = 可能不够精确 onboarding-choose_mounting-manual_mounting-description = 这将需要你手动选择每个追踪器的佩戴方向 # Multiline text onboarding-choose_mounting-manual_modal-title = 确定要进行自动佩戴校准? @@ -844,14 +939,14 @@ onboarding-choose_proportions-description-v1 = 如果保存的身体比例和实际身体尺寸不匹配,追踪精度将会下降,并且会出现脚在地面滑动,或是身体和虚拟形象动作不一致的情况。 身体比例设置只要进行一次! 除非身体比例存在错误或是身体尺寸发生了改变,否则不需要重复进行身体比例设置。 onboarding-choose_proportions-auto_proportions = 自动调整身体比例 -# Italized text +# Italicized text onboarding-choose_proportions-auto_proportions-subtitle = 推荐 onboarding-choose_proportions-auto_proportions-descriptionv3 = 这将录制你的运动样本并通过算法来推测你的身体比例。 需要戴上头戴设备,并确保设备已连接到 SlimeVR! onboarding-choose_proportions-manual_proportions = 手动调整身体比例 -# Italized text +# Italicized text onboarding-choose_proportions-manual_proportions-subtitle = 用于精细调整 onboarding-choose_proportions-manual_proportions-description = 这将需要你手动修改以调整你的身体比例 onboarding-choose_proportions-export = 导出身体比例 @@ -954,6 +1049,7 @@ status_system-StatusSteamVRDisconnected = *[other] 尚未通过 SlimeVR 驱动程序连接到 SteamVR } status_system-StatusTrackerError = { $trackerName } 追踪器发生错误 +status_system-StatusUnassignedHMD = VR头显应被分配为头部追踪器。 ## Tray Menu diff --git a/gui/public/i18n/zh-Hant/translation.ftl b/gui/public/i18n/zh-Hant/translation.ftl index 3c5dc8e42..e345487fe 100644 --- a/gui/public/i18n/zh-Hant/translation.ftl +++ b/gui/public/i18n/zh-Hant/translation.ftl @@ -13,17 +13,17 @@ websocket-connection_lost = 與伺服器的連線已中斷,正在嘗試重新 ## Update notification version_update-title = 有可用的新版本:{ $version } -version_update-description = 按下「{ version_update-update }」將為您下載 SlimeVR 安裝程式。 +version_update-description = 按下「{ version_update-update }」將為你下載 SlimeVR 安裝程式。 version_update-update = 更新 version_update-close = 關閉 ## Tips -tips-find_tracker = 若你不確定手上的追蹤器是哪一個,搖一搖它,對應的項目就會顯示出來。 -tips-do_not_move_heels = 確保你的腳跟在測量過程時不會發生移動! -tips-file_select = 拖曳檔案或 瀏覽檔案 以使用 -tips-tap_setup = 除了從列表挑選追蹤器以外,您也可以慢慢敲擊 2 次追蹤器來選擇它。 -tips-turn_on_tracker = 您使用的是官方的 SlimeVR 追蹤器嗎?記得要在連接到電腦以後打開追蹤器的電源喔! +tips-find_tracker = 若你不確定手上的追蹤器是哪一個,搖一搖它,對應的項目會被高亮顯示出來。 +tips-do_not_move_heels = 測量過程中,請勿移動腳跟! +tips-file_select = 拖曳檔案或 瀏覽檔案 以使用。 +tips-tap_setup = 除了從列表挑選追蹤器以外,你也可以慢慢敲擊 2 次追蹤器來選擇它。 +tips-turn_on_tracker = 你使用的是官方的 SlimeVR 追蹤器嗎?記得要在連接到電腦以後打開追蹤器的電源喔! tips-failed_webgl = 初始化 WebGL 失敗。 ## Body parts @@ -81,6 +81,11 @@ skeleton_bone-ELBOW_OFFSET = 肘部偏移 ## Tracker reset buttons reset-reset_all = 重置軀幹比例 +reset-reset_all_warning = + 警告: 這會將軀幹比例重置為僅基於身高的比例。 + 你確定要執行此操作嗎? +reset-reset_all_warning-reset = 重置軀幹比例 +reset-reset_all_warning-cancel = 取消 reset-full = 完整重置 reset-mounting = 配戴重置 reset-yaw = 左右偏擺重置 @@ -142,9 +147,12 @@ widget-developer_mode-more_info = 更多資訊 ## Widget: IMU Visualizer widget-imu_visualizer = 旋轉 +widget-imu_visualizer-preview = 預覽 +widget-imu_visualizer-hide = 隱藏 widget-imu_visualizer-rotation_raw = 原始旋轉 widget-imu_visualizer-rotation_preview = 預覽 -widget-imu_visualizer-rotation_hide = 隱藏 +widget-imu_visualizer-acceleration = 加速度 +widget-imu_visualizer-position = 位置 ## Widget: Skeleton Visualizer @@ -199,6 +207,13 @@ tracker-infos-hardware_identifier = 硬體 ID tracker-infos-imu = 慣性測量單元 (IMU) tracker-infos-board_type = 主板 tracker-infos-network_version = 通訊協定版本 +tracker-infos-magnetometer = 磁力計 +tracker-infos-magnetometer-status-v1 = + { $status -> + [DISABLED] 已停用 + [ENABLED] 已啟用 + *[NOT_SUPPORTED] 不支援 + } ## Tracker settings @@ -213,11 +228,19 @@ tracker-settings-mounting_section-edit = 編輯配戴方式 tracker-settings-drift_compensation_section = 偏移補償 tracker-settings-drift_compensation_section-description = 是否在此追蹤器上套用偏移補償? tracker-settings-drift_compensation_section-edit = 允許偏移補償 +tracker-settings-use_mag = 允許使用這個追蹤器的磁力計 +# Multiline! +tracker-settings-use_mag-description = + 如果「在追蹤器上啟用磁力計」功能已開啟,是否要在這個追蹤器上啟用它來減緩偏移?切換本選項時請勿關閉追蹤器的電源! + + 請先開啟「在追蹤器上啟用磁力計」功能,點選此處以移動至該設定。 +tracker-settings-use_mag-label = 允許使用這個追蹤器的磁力計 # The . means it's an attribute and it's related to the top key. # In this case that is the settings for the assignment section. tracker-settings-name_section = 追蹤器名稱 tracker-settings-name_section-description = 給它起一個可愛的名字吧 ^^ tracker-settings-name_section-placeholder = ↖★煞氣a黑貓☆↘的美味右腿 +tracker-settings-name_section-label = 追蹤器名稱 tracker-settings-forget = 忘記追蹤器 tracker-settings-forget-description = 從 SlimeVR 伺服器程式中移除該追蹤器,且直到重新啟動伺服器前不會再次連接。該追蹤器的設定不會遺失。 tracker-settings-forget-label = 忘記追蹤器 @@ -296,6 +319,7 @@ settings-sidebar-utils = 工具 settings-sidebar-serial = 串列埠終端 settings-sidebar-appearance = 外觀 settings-sidebar-notifications = 通知 +settings-sidebar-advanced = 進階 ## SteamVR settings @@ -323,7 +347,7 @@ settings-general-steamvr-trackers-tracker_toggling-description = 根據目前的 settings-general-steamvr-trackers-tracker_toggling-label = 自動追蹤器分配 settings-general-steamvr-trackers-hands-warning = 警告:手部追蹤器將會取代控制器的追蹤。 - 您確定嗎? + 你確定嗎? settings-general-steamvr-trackers-hands-warning-cancel = 取消 settings-general-steamvr-trackers-hands-warning-done = 確定 @@ -347,9 +371,23 @@ settings-general-tracker_mechanics-yaw-reset-smooth-time = 左右偏擺重置平 settings-general-tracker_mechanics-drift_compensation = 偏移補償 # This cares about multilines settings-general-tracker_mechanics-drift_compensation-description = - 套用逆向旋轉以補償陀螺儀的左右偏擺位移。 + 套用逆向旋轉以補償 IMU 的左右偏擺位移。 你可以更改補償的強度,以及使用幾次以內的重置結果來進行補償。 settings-general-tracker_mechanics-drift_compensation-enabled-label = 偏移補償 +settings-general-tracker_mechanics-drift_compensation-prediction = 偏移補償預測 +# This cares about multilines +settings-general-tracker_mechanics-drift_compensation-prediction-description = + 預測超過先前測量範圍的偏航角漂移補償。 + 如果跟蹤器在偏航角上持續偏移,請啟用此選項。 +settings-general-tracker_mechanics-drift_compensation-prediction-label = 偏移補償預測 +settings-general-tracker_mechanics-drift_compensation_warning = + 警告: 只有在需要頻繁重置(約 5~10 分鐘重置一次) + 的時候才開啟此選項。 + + 容易頻繁重置的 IMU 包括: + Joy-Con、owoTrack、MPU(非近期韌體)。 +settings-general-tracker_mechanics-drift_compensation_warning-cancel = 取消 +settings-general-tracker_mechanics-drift_compensation_warning-done = 了解 settings-general-tracker_mechanics-drift_compensation-amount-label = 補償量 settings-general-tracker_mechanics-drift_compensation-max_resets-label = 使用幾次的重置結果? settings-general-tracker_mechanics-save_mounting_reset = 儲存自動配戴重置的校正 @@ -357,6 +395,11 @@ settings-general-tracker_mechanics-save_mounting_reset-description = 儲存自動配戴重置的校正,重新啟動 SlimeVR 後不需要再進行校正。 本設定適用於動捕服,因為多次穿戴後追蹤器的位置不會變化。不建議一般使用者使用! 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 = + 在所有有韌體支援的追蹤器上使用磁力計,在磁場穩定的環境中可以減緩偏移。 + 開啟此選項後,可以個別在追蹤器選項內停用磁力計。切換此選項時請勿關閉任何一個追蹤器的電源! +settings-general-tracker_mechanics-use_mag_on_all_trackers-label = 在追蹤器上啟用磁力計 ## FK/Tracking settings @@ -383,28 +426,31 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = 腳部配戴重置 settings-general-fk_settings-arm_fk = 手臂追蹤 settings-general-fk_settings-arm_fk-description = 強制透過頭戴顯示器來追蹤手臂,即使有手部的定位資料。 settings-general-fk_settings-arm_fk-force_arms = 強制從頭戴顯示器進行手臂追蹤 +settings-general-fk_settings-reset_settings = 重置設定 +settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = 進行完整重置時,也重置頭戴顯示器的仰角(垂直旋轉),適用於將頭顯戴在額頭上,以進行虛擬直播或是動作捕捉的情境。若用於 VR 請勿啟用本設定。 +settings-general-fk_settings-reset_settings-reset_hmd_pitch = 重置頭戴顯示器仰角 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 = T 型姿勢(抬起) -settings-general-fk_settings-arm_fk-tpose_up-description = 完整重置時手臂向下,呈立正姿勢;配戴重置時手臂向兩側伸展,與身體呈 90 度。 -settings-general-fk_settings-arm_fk-tpose_down = T 型姿勢(放下) -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 度,可用於坐姿進行虛擬直播。 +settings-general-fk_settings-arm_fk-back = 向後彎折 +settings-general-fk_settings-arm_fk-back-description = 預設模式,重置時手肘朝後,前臂向前,類似滑雪。 +settings-general-fk_settings-arm_fk-tpose_up = T-pose(抬起) +settings-general-fk_settings-arm_fk-tpose_up-description = 完整重置時手臂向下,呈立正姿勢;配戴重置時手臂向兩側伸平。 +settings-general-fk_settings-arm_fk-tpose_down = T-pose(放下) +settings-general-fk_settings-arm_fk-tpose_down-description = 完整重置時手臂向兩側伸平;配戴重置時手臂向下,呈立正姿勢。 +settings-general-fk_settings-arm_fk-forward = 向前伸平 +settings-general-fk_settings-arm_fk-forward-description = 重置時手臂向前伸平,有利於坐姿進行虛擬直播。 settings-general-fk_settings-skeleton_settings-toggles = 骨架設定 -settings-general-fk_settings-skeleton_settings-description = 開啟或關閉骨架設定。建議保持這些設定開啟。 +settings-general-fk_settings-skeleton_settings-description = 開啟或關閉骨架設定。建議保持以下設定開啟。 settings-general-fk_settings-skeleton_settings-extended_spine_model = 延伸脊椎模型 settings-general-fk_settings-skeleton_settings-extended_pelvis_model = 延伸骨盆模型 settings-general-fk_settings-skeleton_settings-extended_knees_model = 延伸膝蓋模型 settings-general-fk_settings-skeleton_settings-ratios = 骨架比例 -settings-general-fk_settings-skeleton_settings-ratios-description = 修改骨架設定的參數,您可能需要在修改後調整軀幹比例。 +settings-general-fk_settings-skeleton_settings-ratios-description = 修改骨架設定的參數,你可能需要在修改後調整軀幹比例。 settings-general-fk_settings-skeleton_settings-impute_waist_from_chest_hip = 推算腰部定位時,胸部與臀部定位使用的比例 settings-general-fk_settings-skeleton_settings-impute_waist_from_chest_legs = 推算腰部定位時,胸部與腿部定位使用的比例 settings-general-fk_settings-skeleton_settings-impute_hip_from_chest_legs = 推算臀部定位時,胸部與腿部定位使用的比例 settings-general-fk_settings-skeleton_settings-impute_hip_from_waist_legs = 推算臀部定位時, 腰部與腿部定位使用的比例 settings-general-fk_settings-skeleton_settings-interp_hip_legs = 臀部的偏航軸與翻滾軸,與腿部定位平均的比例 -settings-general-fk_settings-skeleton_settings-interp_knee_tracker_ankle = 膝部的偏航軸與翻滾軸,與腳踝定位平均的比例 +settings-general-fk_settings-skeleton_settings-interp_knee_tracker_ankle = 膝部追蹤器的偏航軸與翻滾軸,與腳踝定位平均的比例 settings-general-fk_settings-skeleton_settings-interp_knee_ankle = 膝部的偏航軸與翻滾軸,與腳踝定位平均的比例 settings-general-fk_settings-self_localization-title = 動作捕捉模式 settings-general-fk_settings-self_localization-description = 動作捕捉模式允許在沒有頭戴顯示器或其他追蹤器時,粗略的追蹤身體骨架的定位。請注意,本功能需要腳部與頭部的追蹤器,並且本功能仍在實驗階段。 @@ -433,8 +479,8 @@ settings-general-gesture_control-fullResetEnabled = 敲擊以完整重置 settings-general-gesture_control-fullResetDelay = 完整重置延遲 settings-general-gesture_control-fullResetTaps = 完整重置敲擊次數 settings-general-gesture_control-mountingResetEnabled = 敲擊以配戴重置 -settings-general-gesture_control-mountingResetDelay = 重置佩戴延遲 -settings-general-gesture_control-mountingResetTaps = 重置佩戴敲擊次數 +settings-general-gesture_control-mountingResetDelay = 重置配戴延遲 +settings-general-gesture_control-mountingResetTaps = 重置配戴敲擊次數 # The number of trackers that can have higher acceleration before a tap is rejected settings-general-gesture_control-numberTrackersOverThreshold = 觸發敲擊判定的最多追蹤器數量 settings-general-gesture_control-numberTrackersOverThreshold-description = 如果敲擊偵測無法作動,請嘗試增加此值以降低敲擊判定的門檻。為避免誤判,請勿設定超過所需要的數值。 @@ -446,6 +492,9 @@ settings-general-interface-dev_mode = 開發者模式 settings-general-interface-dev_mode-description = 本功能會提供更深入的資料,也能與已連線的追蹤器進行更進一步的控制。 settings-general-interface-dev_mode-label = 開發者模式 settings-general-interface-theme = 佈景主題色彩 +settings-general-interface-show-navbar-onboarding = 在導覽列上顯示「{ navbar-onboarding }」 +settings-general-interface-show-navbar-onboarding-description = 本選項變更 「{ navbar-onboarding }」 按鈕是否要顯示在導覽列上。 +settings-general-interface-show-navbar-onboarding-label = 顯示「{ navbar-onboarding }」 settings-general-interface-lang = 選擇語言 settings-general-interface-lang-description = 更改所使用的介面語言。 settings-general-interface-lang-placeholder = 選擇要使用的語言 @@ -457,6 +506,9 @@ settings-interface-appearance-font-os_font = 作業系統字體 settings-interface-appearance-font-slime_font = 預設字體 settings-interface-appearance-font_size = 文字縮放 settings-interface-appearance-font_size-description = 本設定會影響整個 UI 的文字大小,除了本設定面板以外。 +settings-interface-appearance-decorations = 使用系統原生的視窗邊框 +settings-interface-appearance-decorations-description = 不顯示標題列 UI,替換成作業系統提供的標題列。 +settings-interface-appearance-decorations-label = 使用原生的視窗邊框 ## Notification settings @@ -472,8 +524,16 @@ settings-general-interface-connected_trackers_warning = 已連接追蹤器警告 settings-general-interface-connected_trackers_warning-description = 啟用本選項後,每次當退出 SlimeVR 時仍有追蹤器連接著會顯示通知,提醒你在使用完畢時關閉追蹤器電源來節省電池電量。 settings-general-interface-connected_trackers_warning-label = 當退出程式時,有追蹤器連接中則顯示警告 settings-general-interface-use_tray = 最小化到系統列 -settings-general-interface-use_tray-description = 本選項可以讓您在關閉視窗時不會關閉 SlimeVR 的伺服器程式,讓您在不受圖形介面的打擾下繼續使用追蹤器。 +settings-general-interface-use_tray-description = 本選項可以讓你在關閉視窗時不會關閉 SlimeVR 的伺服器程式,讓你在不受圖形介面的打擾下繼續使用追蹤器。 settings-general-interface-use_tray-label = 最小化到系統列 +settings-general-interface-discord_presence = 在 Discord 上分享活動 +settings-general-interface-discord_presence-description = 在 Discord 上顯示你正在使用 SlimeVR,以及使用中的追蹤器的數量。 +settings-general-interface-discord_presence-label = 在 Discord 上分享活動 +settings-general-interface-discord_presence-message = + { $amount -> + [0] 正在捕捉史萊姆 + *[other] 正在使用 { $amount } 個追蹤器 + } ## Serial settings @@ -494,6 +554,8 @@ settings-serial-get_infos = 取得資訊 settings-serial-serial_select = 選擇串列埠 settings-serial-auto_dropdown_item = 自動 settings-serial-get_wifi_scan = 取得 Wi-Fi 掃描 +settings-serial-file_type = 純文字格式 +settings-serial-save_logs = 儲存到檔案 ## OSC router settings @@ -524,14 +586,15 @@ settings-osc-router-network-address-placeholder = IPV4 地址 settings-osc-vrchat = VRChat OSC 追蹤器 # This cares about multilines -settings-osc-vrchat-description = - 此處可更改 VRChat 專用的設定以取得頭戴顯示器的資料,並傳送追蹤器 - 資料以進行全身追蹤,不須透過 SteamVR(例如 Quest 單機版本)。 +settings-osc-vrchat-description-v1 = + 變更 OSC 追蹤器標準的設定,該標準可用於傳送追蹤器資料到不使用 SteamVR 的應用程式(例如 Quest 單機版)。 + 請確保 VRChat 中的動作選單內,OSC 設定「選項→OSC→已啟用」已經開啟。 + SlimeVR 若要能透過 VRChat 接收頭戴顯示器以及控制器的資料,請進入主選單的設定,並開啟「追蹤 & IK→允許透過 OSC 發送頭部與腕部的 VR 追蹤數據」。 settings-osc-vrchat-enable = 啟用 settings-osc-vrchat-enable-description = 切換資料的傳送和接收。 settings-osc-vrchat-enable-label = 啟用 settings-osc-vrchat-network = 連接埠 -settings-osc-vrchat-network-description = 設定與 VRChat 監聽和傳送資料的連接埠。 +settings-osc-vrchat-network-description-v1 = 設定收發追蹤器資料的連接埠埠號,使用 VRChat 不須更改。 settings-osc-vrchat-network-port_in = .label = 輸入埠 .placeholder = 輸入埠(預設:9001) @@ -539,7 +602,7 @@ settings-osc-vrchat-network-port_out = .label = 輸出埠 .placeholder = 輸出埠(預設:9000) settings-osc-vrchat-network-address = 網路位址 -settings-osc-vrchat-network-address-description = 設定用來發送資料到 VRChat 的位址(請檢查裝置的 Wi-Fi 設定)。 +settings-osc-vrchat-network-address-description-v1 = 設定收發追蹤器資料的 IP 位址,使用 VRChat 不須更改。 settings-osc-vrchat-network-address-placeholder = VRChat IP 位址 settings-osc-vrchat-network-trackers = 追蹤器 settings-osc-vrchat-network-trackers-description = 切換傳送指定追蹤器的資料。 @@ -582,6 +645,39 @@ settings-osc-vmc-vrm-file_select = 拖曳檔案或 瀏覽檔案 以載入 settings-osc-vmc-anchor_hip = 臀部錨定 settings-osc-vmc-anchor_hip-description = 將追蹤錨定在臀部,有利於坐姿進行虛擬直播。若本選項無法切換,請載入 VRM 模型。 settings-osc-vmc-anchor_hip-label = 臀部錨定 +settings-osc-vmc-mirror_tracking = 鏡像追蹤 +settings-osc-vmc-mirror_tracking-description = 將追蹤的結果水平鏡像。 +settings-osc-vmc-mirror_tracking-label = 鏡像追蹤 + +## Advanced settings + +settings-utils-advanced = 進階 +settings-utils-advanced-reset-gui = 重置 UI 設定 +settings-utils-advanced-reset-gui-description = 將 UI 設定恢復成預設值。 +settings-utils-advanced-reset-gui-label = 重置 UI 設定 +settings-utils-advanced-reset-server = 重置追蹤設定 +settings-utils-advanced-reset-server-description = 將追蹤設定恢復成預設值。 +settings-utils-advanced-reset-server-label = 重置追蹤設定 +settings-utils-advanced-reset-all = 重置全部設定 +settings-utils-advanced-reset-all-description = 將 UI 與追蹤設定恢復成預設值。 +settings-utils-advanced-reset-all-label = 重置全部設定 +settings-utils-advanced-reset_warning = + { $type -> + [gui] + 警告: 這會將 UI 設定重置為預設值。 + 你確定要執行此操作嗎? + [server] + 警告: 這會將追蹤設定重置為預設值。 + 你確定要執行此操作嗎? + *[all] + 警告: 這會將所有設定重置為預設值。 + 你確定要執行此操作嗎? + } +settings-utils-advanced-reset_warning-reset = 重置設定 +settings-utils-advanced-reset_warning-cancel = 取消 +settings-utils-advanced-open_data = 數據資料夾 +settings-utils-advanced-open_data-description = 在檔案管理器中開啟 SlimeVR 的數據資料夾,該資料夾包含設定與記錄檔。 +settings-utils-advanced-open_data-label = 打開資料夾 ## Setup/onboarding menu @@ -591,7 +687,7 @@ onboarding-wip = 施工中 onboarding-previous_step = 上一步 onboarding-setup_warning = 警告:若要有良好的追蹤效果,必須進行初始設定, - 如果這是您是第一次使用 SlimeVR,請繼續進行設定。 + 若是第一次使用 SlimeVR,請繼續進行設定。 onboarding-setup_warning-skip = 跳過設定 onboarding-setup_warning-cancel = 繼續設定 @@ -616,7 +712,7 @@ onboarding-wifi_creds-password = onboarding-reset_tutorial-back = 返回到配戴校正 onboarding-reset_tutorial = 重置教學 -onboarding-reset_tutorial-explanation = 當您使用追蹤器時追蹤器可能會跑位,原因來自於慣性測量單元 (IMU) 產生了左右飄移,或是您移動了追蹤器的實體位置。您有幾種方法來修正這個問題。 +onboarding-reset_tutorial-explanation = 當你使用追蹤器時追蹤器可能會跑位,原因來自於慣性測量單元 (IMU) 產生了左右飄移,或是你移動了追蹤器的實體位置。你有幾種方法來修正這個問題。 onboarding-reset_tutorial-skip = 跳過本步驟 # Cares about multiline onboarding-reset_tutorial-0 = @@ -633,7 +729,7 @@ onboarding-reset_tutorial-1 = onboarding-reset_tutorial-2 = 對所標記之追蹤器敲擊 { $taps } 次即可觸發配戴重置。 - 配戴重置能對追蹤器實際的配戴方式進行調整,因此若您不小心移動到追蹤器,或是大幅度的變更配戴方向,這個功能會有所幫助。 + 配戴重置能對追蹤器實際的配戴方式進行調整,因此若你不小心移動到追蹤器,或是大幅度的變更配戴方向,這個功能會有所幫助。 做此校正時需要進行滑雪姿勢,如自動配戴校正的畫面所示。在觸發 3 秒後(可修改)才會真正進行重置。 @@ -659,8 +755,8 @@ onboarding-done-close = 關閉設定 onboarding-connect_tracker-back = 返回到 Wi-Fi 認證資訊設定 onboarding-connect_tracker-title = 連接追蹤器 -onboarding-connect_tracker-description-p0-v1 = 來到了我第二喜歡的環節,連接追蹤器! -onboarding-connect_tracker-description-p1-v1 = 透過 USB,一次連接一個追蹤器。 +onboarding-connect_tracker-description-p0-v1 = 現在來到有趣的部分,連接追蹤器! +onboarding-connect_tracker-description-p1-v1 = 透過 USB 埠,一次連接一個追蹤器。 onboarding-connect_tracker-issue-serial = 我在連接時碰到問題了! onboarding-connect_tracker-usb = USB 追蹤器 onboarding-connect_tracker-connection_status-none = 正在尋找追蹤器 @@ -687,12 +783,13 @@ onboarding-connect_tracker-next = 所有的追蹤器都連接好了 onboarding-calibration_tutorial = IMU 校正教學 onboarding-calibration_tutorial-subtitle = 進行這項操作可以有效減少追蹤器發生飄移的機會 -onboarding-calibration_tutorial-description = 每次在打開追蹤器的開關時,需要將追蹤器放置在平面一會兒來進行自動校正。您也可以透過按下「{ onboarding-calibration_tutorial-calibrate }」按鈕來進行手動校正,校正過程中請勿移動追蹤器。 +onboarding-calibration_tutorial-description = 每次在打開追蹤器的開關時,需要將追蹤器平置一下來進行自動校正。你也可以透過按下「{ onboarding-calibration_tutorial-calibrate }」按鈕來進行手動校正,校正過程中請勿移動追蹤器。 onboarding-calibration_tutorial-calibrate = 追蹤器已經放置在桌上了 -onboarding-calibration_tutorial-status-waiting = 正在等待您完成動作 +onboarding-calibration_tutorial-status-waiting = 正在等待你完成動作 onboarding-calibration_tutorial-status-calibrating = 校正中 onboarding-calibration_tutorial-status-success = 很好,校正完成了! onboarding-calibration_tutorial-status-error = 追蹤器移動了 +onboarding-calibration_tutorial-skip = 跳過導覽 ## Tracker assignment tutorial @@ -716,6 +813,23 @@ onboarding-assign_trackers-assigned = { $assigned }/{ $trackers } 個追蹤器 onboarding-assign_trackers-advanced = 顯示進階分配部位 onboarding-assign_trackers-next = 所有的追蹤器都分配好了 onboarding-assign_trackers-mirror_view = 鏡像顯示 +onboarding-assign_trackers-option-amount = { $trackersCount } 點 +onboarding-assign_trackers-option-label = + { $mode -> + [lower-body] 腿部追蹤套裝 + [core] 核心套裝 + [enhanced-core] 核心套裝加強版 + [full-body] 全身追蹤套裝 + *[all] 全部部位 + } +onboarding-assign_trackers-option-description = + { $mode -> + [lower-body] VR 全身追蹤的基本需求 + [core] + 強化脊椎追蹤 + [enhanced-core] + 腳部旋轉 + [full-body] + 手肘追蹤 + *[all] 顯示全部可供追蹤器分配的部位 + } ## Tracker assignment warnings @@ -723,66 +837,66 @@ onboarding-assign_trackers-mirror_view = 鏡像顯示 # $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order onboarding-assign_trackers-warning-LEFT_FOOT = { $unassigned -> - [0] 左腳已分配,但您還需要分配左腳踝、左大腿和胸部、臀部或腰部! - [1] 左腳已分配,但您還需要分配左大腿和胸部、臀部或腰部! - [2] 左腳已分配,但您還需要分配左腳踝和胸部、臀部或腰部! - [3] 左腳已分配,但您還需要分配胸部、臀部或腰部! - [4] 左腳已分配,但您還需要分配左腳踝和左大腿! - [5] 左腳已分配,但您還需要分配左大腿! - [6] 左腳已分配,但您還需要分配左腳踝! - *[unknown] 左腳已分配,但您還需要分配其它未分配的身體部位! + [0] 左腳已分配,但你還需要分配左腳踝、左大腿和胸部、臀部或腰部! + [1] 左腳已分配,但你還需要分配左大腿和胸部、臀部或腰部! + [2] 左腳已分配,但你還需要分配左腳踝和胸部、臀部或腰部! + [3] 左腳已分配,但你還需要分配胸部、臀部或腰部! + [4] 左腳已分配,但你還需要分配左腳踝和左大腿! + [5] 左腳已分配,但你還需要分配左大腿! + [6] 左腳已分配,但你還需要分配左腳踝! + *[unknown] 左腳已分配,但你還需要分配其它未分配的身體部位! } # $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order onboarding-assign_trackers-warning-RIGHT_FOOT = { $unassigned -> - [0] 右腳已分配,但您還需要分配右腳踝、右大腿以及胸部、臀部或腰部! - [1] 右腳已分配,但您還需要分配右大腿和胸部、臀部或腰部! - [2] 右腳已分配,但您還需要分配右腳踝和胸部、臀部或腰部! - [3] 右腳已分配,但您還需要分配胸部、臀部或腰部! - [4] 右腳已分配,但您還需要分配右腳踝和右大腿! - [5] 右腳已分配,但您還需要分配右大腿! - [6] 右腳已分配,但您還需要分配右腳踝! - *[unknown] 右腳已分配,但您還需要分配其它未分配的身體部位! + [0] 右腳已分配,但你還需要分配右腳踝、右大腿以及胸部、臀部或腰部! + [1] 右腳已分配,但你還需要分配右大腿和胸部、臀部或腰部! + [2] 右腳已分配,但你還需要分配右腳踝和胸部、臀部或腰部! + [3] 右腳已分配,但你還需要分配胸部、臀部或腰部! + [4] 右腳已分配,但你還需要分配右腳踝和右大腿! + [5] 右腳已分配,但你還需要分配右大腿! + [6] 右腳已分配,但你還需要分配右腳踝! + *[unknown] 右腳已分配,但你還需要分配其它未分配的身體部位! } # $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order onboarding-assign_trackers-warning-LEFT_LOWER_LEG = { $unassigned -> - [0] 左腳踝已分配,但您還需要分配左大腿和胸部、臀部或腰部! - [1] 左腳踝已分配,但您還需要分配胸部、臀部或腰部! - [2] 左腳踝已分配,但您還需要分配左大腿! - *[unknown] 左腳踝已分配,但您還需要分配其它未分配的身體部位! + [0] 左腳踝已分配,但你還需要分配左大腿和胸部、臀部或腰部! + [1] 左腳踝已分配,但你還需要分配胸部、臀部或腰部! + [2] 左腳踝已分配,但你還需要分配左大腿! + *[unknown] 左腳踝已分配,但你還需要分配其它未分配的身體部位! } # $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order onboarding-assign_trackers-warning-RIGHT_LOWER_LEG = { $unassigned -> - [0] 右腳踝已分配,但您還需要分配右大腿和胸部、臀部或腰部! - [1] 右腳踝已分配,但您還需要分配胸部、臀部或腰部! - [2] 右腳踝已分配,但您還需要分配右大腿! - *[unknown] 右腳踝已分配,但您還需要分配其它未分配的身體部位! + [0] 右腳踝已分配,但你還需要分配右大腿和胸部、臀部或腰部! + [1] 右腳踝已分配,但你還需要分配胸部、臀部或腰部! + [2] 右腳踝已分配,但你還需要分配右大腿! + *[unknown] 右腳踝已分配,但你還需要分配其它未分配的身體部位! } # $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order onboarding-assign_trackers-warning-LEFT_UPPER_LEG = { $unassigned -> - [0] 左大腿已分配,但您還需要分配胸部、臀部或腰部! - *[unknown] 左大腿已分配,但您還需要分配其它未分配的身體部位! + [0] 左大腿已分配,但你還需要分配胸部、臀部或腰部! + *[unknown] 左大腿已分配,但你還需要分配其它未分配的身體部位! } # $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order onboarding-assign_trackers-warning-RIGHT_UPPER_LEG = { $unassigned -> - [0] 右大腿已分配,但您還需要分配胸部、臀部或腰部! - *[unknown] 右大腿已分配,但您還需要分配其它未分配的身體部位! + [0] 右大腿已分配,但你還需要分配胸部、臀部或腰部! + *[unknown] 右大腿已分配,但你還需要分配其它未分配的身體部位! } # $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order onboarding-assign_trackers-warning-HIP = { $unassigned -> - [0] 臀部已分配,但您還需要分配胸部! - *[unknown] 臀部已分配,但您還需要分配其它未分配的身體部位! + [0] 臀部已分配,但你還需要分配胸部! + *[unknown] 臀部已分配,但你還需要分配其它未分配的身體部位! } # $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order onboarding-assign_trackers-warning-WAIST = { $unassigned -> - [0] 腰部已分配,但您還需要分配胸部! - *[unknown] 腰部已分配,但您還需要分配其它未分配的身體部位! + [0] 腰部已分配,但你還需要分配胸部! + *[unknown] 腰部已分配,但你還需要分配其它未分配的身體部位! } ## Tracker mounting method choose @@ -791,12 +905,12 @@ onboarding-choose_mounting = 要使用哪一種配戴校正方式? # Multiline text onboarding-choose_mounting-description = 配戴校正可以校正追蹤器放在身上的位置。 onboarding-choose_mounting-auto_mounting = 自動配戴校正 -# Italized text -onboarding-choose_mounting-auto_mounting-label = 實驗功能 +# Italicized text +onboarding-choose_mounting-auto_mounting-label-v2 = 推薦使用 onboarding-choose_mounting-auto_mounting-description = 本選項會透過兩個身體姿勢,判斷所有追蹤器的配戴方位 onboarding-choose_mounting-manual_mounting = 手動配戴校正 -# Italized text -onboarding-choose_mounting-manual_mounting-label = 推薦使用 +# Italicized text +onboarding-choose_mounting-manual_mounting-label-v2 = 可能不夠精確 onboarding-choose_mounting-manual_mounting-description = 本選項可以讓你選擇每個追蹤器的配戴方位 # Multiline text onboarding-choose_mounting-manual_modal-title = 確定要進行自動配戴校正? @@ -816,7 +930,7 @@ onboarding-manual_mounting-next = 下一步 onboarding-automatic_mounting-back = 返回到進入 VR onboarding-automatic_mounting-title = 配戴校正 -onboarding-automatic_mounting-description = 為了讓 SlimeVR 追蹤器正常運作,我們需要為每個追蹤器設定配戴方向,以符合您實際的追蹤器配戴方式。 +onboarding-automatic_mounting-description = 為了讓 SlimeVR 追蹤器正常運作,我們需要為每個追蹤器設定配戴方向,以符合你實際的追蹤器配戴方式。 onboarding-automatic_mounting-manual_mounting = 進行手動設定 onboarding-automatic_mounting-next = 下一步 onboarding-automatic_mounting-prev_step = 上一步 @@ -839,17 +953,17 @@ onboarding-choose_proportions = 要使用哪一種軀幹比例的校正方式? # Multiline string onboarding-choose_proportions-description-v1 = 軀幹比例用於取得身體各個部位的長短,為計算追蹤器的位置而有所必要。 - 當您的軀幹比例與設定的比例有差異時,追蹤精確度會變差,您可能會注意到出現腳滑溜冰的情形,或者你的身體與你的虛擬角色對不太上。 + 當你的軀幹比例與設定的比例有差異時,追蹤精確度會變差,你可能會注意到出現腳滑溜冰的情形,或者你的身體與你的虛擬角色對不太上。 軀幹比例的測量只需要進行一次!除非設定有誤,或是身材有明顯變化,本設定不需要重複進行。 onboarding-choose_proportions-auto_proportions = 自動軀幹比例校正 -# Italized text +# Italicized text onboarding-choose_proportions-auto_proportions-subtitle = 推薦使用 onboarding-choose_proportions-auto_proportions-descriptionv3 = - 本選項會從您的身體動作錄製一段樣本,並通過演算法來推算您的軀幹比例。 + 本選項會從你的身體動作錄製一段樣本,並通過演算法來推算你的軀幹比例。 使用本功能需要連接頭戴顯示器到 SlimeVR,並且配戴在頭部! onboarding-choose_proportions-manual_proportions = 手動軀幹比例校正 -# Italized text +# Italicized text onboarding-choose_proportions-manual_proportions-subtitle = 適合進行微調 onboarding-choose_proportions-manual_proportions-description = 本選項可以讓你直接修改軀幹比例的設定值 onboarding-choose_proportions-export = 匯出軀幹比例 @@ -887,18 +1001,18 @@ onboarding-automatic_proportions-requirements-descriptionv2 = 頭戴顯示器會回報定位資料給 SlimeVR 伺服器(通常為執行 SteamVR 並透過 SlimeVR 的 SteamVR 驅動程式來連接 SlimeVR)。 追蹤狀態正常且能反映你的移動姿態(例如,進行完全重置後,踢腿、彎曲、坐下時的肢體方向是正確的)。 onboarding-automatic_proportions-requirements-next = 我已閱讀使用需求 -onboarding-automatic_proportions-check_height-title = 檢查您的身高 -onboarding-automatic_proportions-check_height-description = 我們會透過頭戴顯示器回報的高度來推算您的實際身高,但我們仍建議您檢查一下數值是否正確。 +onboarding-automatic_proportions-check_height-title = 檢查你的身高 +onboarding-automatic_proportions-check_height-description = 我們會透過頭戴顯示器回報的高度來推算你的實際身高,但仍建議檢查數值是否正確。 # All the text is in bold! -onboarding-automatic_proportions-check_height-calculation_warning = 請站直並按下按鈕以計算身高,按下按鈕後您有 3 秒鐘來調整姿勢。 -onboarding-automatic_proportions-check_height-guardian_tip = 如果您使用的是一體式 VR 頭盔,請確認頭盔的守護神/邊界設定已經開啟,以確保身高能正確測量。 +onboarding-automatic_proportions-check_height-calculation_warning = 請站直並按下按鈕以計算身高,按下按鈕後你有 3 秒鐘來調整姿勢。 +onboarding-automatic_proportions-check_height-guardian_tip = 如果你使用的是一體式 VR 頭顯,請確認頭盔的守護神/邊界設定已經開啟,以確保身高能正確測量。 onboarding-automatic_proportions-check_height-fetch_height = 我站著了! # Context is that the height is unknown onboarding-automatic_proportions-check_height-unknown = 不明 # Shows an element below it -onboarding-automatic_proportions-check_height-hmd_height1 = 您的頭戴顯示器高度是 +onboarding-automatic_proportions-check_height-hmd_height1 = 你的頭戴顯示器高度是 # Shows an element below it -onboarding-automatic_proportions-check_height-height1 = 所以您的實際身高是 +onboarding-automatic_proportions-check_height-height1 = 所以你的實際身高是 onboarding-automatic_proportions-check_height-next_step = 數值沒問題 onboarding-automatic_proportions-start_recording-title = 準備擺動作囉 onboarding-automatic_proportions-start_recording-description = 我們現在要記錄一些特定的姿勢和動作,將會在下一個畫面中提示。當按鈕被按下時,準備好開始! @@ -918,16 +1032,17 @@ onboarding-automatic_proportions-recording-processing = 正在處理結果 # $time (Number) - Seconds left for the automatic calibration recording to finish (max 20) onboarding-automatic_proportions-recording-timer = 倒數 { $time } 秒 onboarding-automatic_proportions-verify_results-title = 檢查結果 -onboarding-automatic_proportions-verify_results-description = 檢查下面的結果,它們看起來是正確的嗎? +onboarding-automatic_proportions-verify_results-description = 請檢查以下測量結果,看起來是正確的嗎? onboarding-automatic_proportions-verify_results-results = 錄製結果 onboarding-automatic_proportions-verify_results-processing = 正在處理結果 onboarding-automatic_proportions-verify_results-redo = 重新錄製 -onboarding-automatic_proportions-verify_results-confirm = 他們是正確的! +onboarding-automatic_proportions-verify_results-confirm = 看起來沒問題 onboarding-automatic_proportions-done-title = 身體資料已測量並儲存。 onboarding-automatic_proportions-done-description = 你的身體比例校正已完成! -onboarding-automatic_proportions-error_modal = - 警告: 推算軀幹比例時發生錯誤。 - 請閱讀文件或加入我們的 Discord 伺服器以尋求協助 ^_^ +onboarding-automatic_proportions-error_modal-v2 = + 警告:推算軀幹比例時發生錯誤! + 這有可能是配戴校正的問題,請確保追蹤功能運作正常之後再試一次。 + 請檢閱文件或加入我們的 Discord 以尋求幫助 ^_^ onboarding-automatic_proportions-error_modal-confirm = 瞭解! ## Home @@ -948,10 +1063,11 @@ trackers_still_on-modal-cancel = 先不要… status_system-StatusTrackerReset = 有至少一個追蹤器尚未進行調整,建議執行完整重置。 status_system-StatusSteamVRDisconnected = { $type -> - [steamvr_feeder] 尚未連接 SlimeVR 資料迴送程式 - *[other] 尚未透過 SlimeVR 驅動程式連接到 SteamVR + [steamvr_feeder] 尚未連接 SlimeVR 資料迴送程式。 + *[other] 尚未透過 SlimeVR 驅動程式連接到 SteamVR。 } -status_system-StatusTrackerError = { $trackerName } 追蹤器發生錯誤 +status_system-StatusTrackerError = 追蹤器{ $trackerName }發生錯誤 +status_system-StatusUnassignedHMD = VR 頭戴顯示器應被分配為頭部追蹤器。 ## Tray Menu @@ -964,7 +1080,7 @@ tray_menu-quit = 離開 tray_or_exit_modal-title = 關閉視窗的動作是什麼? # Multiline text tray_or_exit_modal-description = - 您可以選擇在關閉視窗時,一併退出伺服器程式,或是將視窗最小化到系統列圖示中。 + 你可以選擇在關閉視窗時,一併退出伺服器程式,或是將視窗最小化到系統列圖示中。 本設定之後也可以在使用者介面設定中更改。 tray_or_exit_modal-radio-exit = 退出 SlimeVR diff --git a/gui/src-tauri/Cargo.toml b/gui/src-tauri/Cargo.toml index 594e3404d..2f6985599 100644 --- a/gui/src-tauri/Cargo.toml +++ b/gui/src-tauri/Cargo.toml @@ -21,21 +21,21 @@ default = ["custom-protocol"] custom-protocol = ["tauri/custom-protocol"] [build-dependencies] -tauri-build = { version = "=2.0.0-beta.18", features = [] } +tauri-build = { version = "2.0", features = [] } cfg_aliases = "0.2" -shadow-rs = "0.27" +shadow-rs = "0.35" [dependencies] serde_json = "1" serde = { version = "1", features = ["derive"] } -tauri = { version = "=2.0.0-beta.23", features = ["devtools", "tray-icon", "image-png"] } -tauri-runtime = "=2.0.0-beta.19" -tauri-plugin-dialog = "=2.0.0-beta.10" -tauri-plugin-fs = "=2.0.0-beta.10" -tauri-plugin-os = "=2.0.0-beta.7" -tauri-plugin-shell = "=2.0.0-beta.8" -tauri-plugin-store = "=2.0.0-beta.9" -flexi_logger = "0.28" +tauri = { version = "2.0", features = ["devtools", "tray-icon", "image-png", "rustls-tls"] } +tauri-runtime = "2.0" +tauri-plugin-dialog = "2.0" +tauri-plugin-fs = "2.0" +tauri-plugin-os = "2.0" +tauri-plugin-shell = "2.0" +tauri-plugin-store = "2.0" +flexi_logger = "0.29" log-panics = { version = "2", features = ["with-backtrace"] } log = "0.4" clap = { version = "4.0.29", features = ["derive"] } @@ -45,11 +45,11 @@ tempfile = "3" which = "6.0" glob = "0.3" open = "5" -shadow-rs = { version = "0.27", default-features = false } +shadow-rs = { version = "0.35", default-features = false } const_format = "0.2.30" cfg-if = "1" color-eyre = "0.6" -rfd = { version = "0.14", features = ["gtk3"], default-features = false } +rfd = { version = "0.15", features = ["gtk3"], default-features = false } dirs-next = "2.0.0" discord-sdk = "0.3.6" tokio = { version = "1.37.0", features = ["time"] } @@ -57,3 +57,6 @@ tokio = { version = "1.37.0", features = ["time"] } [target.'cfg(windows)'.dependencies] win32job = "1" winreg = "0.52" + +[target.'cfg(target_os = "linux")'.dependencies] +libloading = "0.8" diff --git a/gui/src-tauri/capabilities/migrated.json b/gui/src-tauri/capabilities/migrated.json index 834fa4b61..5e8916e03 100644 --- a/gui/src-tauri/capabilities/migrated.json +++ b/gui/src-tauri/capabilities/migrated.json @@ -6,24 +6,25 @@ "main" ], "permissions": [ - "path:default", - "event:default", - "window:default", - "app:default", - "resources:default", - "menu:default", - "tray:default", + "core:path:default", + "core:event:default", + "core:window:default", + "core:app:default", + "core:resources:default", + "core:menu:default", + "core:tray:default", + "core:webview:default", + "core:window:allow-close", + "core:window:allow-toggle-maximize", + "core:window:allow-minimize", + "core:window:allow-start-dragging", + "core:window:allow-hide", + "core:window:allow-show", + "core:window:allow-set-focus", + "core:window:allow-set-decorations", "store:default", "os:allow-os-type", - "webview:default", "dialog:allow-save", - "window:allow-close", - "window:allow-toggle-maximize", - "window:allow-minimize", - "window:allow-start-dragging", - "window:allow-hide", - "window:allow-show", - "window:allow-set-focus", "shell:allow-open", "store:allow-get", "store:allow-set", diff --git a/gui/src-tauri/src/main.rs b/gui/src-tauri/src/main.rs index 01c7321ae..337ca37b5 100644 --- a/gui/src-tauri/src/main.rs +++ b/gui/src-tauri/src/main.rs @@ -11,6 +11,7 @@ use std::time::Instant; use clap::Parser; use color_eyre::Result; use state::WindowState; +use tauri::Emitter; use tauri::{Manager, RunEvent, WindowEvent}; use tauri_plugin_shell::process::CommandChild; @@ -89,8 +90,12 @@ fn main() -> Result<()> { .log_to_file( FileSpec::default().directory(path.expect("We need a log dir")), ) - .format_for_files(util::logger_format) - .format_for_stderr(util::logger_format) + .format_for_files(|w, now, record| { + util::logger_format(w, now, record, false) + }) + .format_for_stderr(|w, now, record| { + util::logger_format(w, now, record, true) + }) .rotate( Criterion::Age(Age::Day), Naming::Timestamps, @@ -179,6 +184,7 @@ fn main() -> Result<()> { warning, tray::update_translations, tray::update_tray_text, + tray::is_tray_available, presence::discord_client_exists, presence::update_presence, presence::clear_presence, @@ -208,11 +214,12 @@ fn main() -> Result<()> { window_state.update_window(&window.as_ref().window(), false)?; } - #[cfg(desktop)] - { + if cfg!(desktop) { let handle = app.handle(); tray::create_tray(handle)?; presence::create_presence(handle)?; + } else { + app.manage(tray::TrayAvailable(false)); } app.manage(Mutex::new(window_state)); @@ -226,7 +233,7 @@ fn main() -> Result<()> { .shell() .command(java_bin.to_str().unwrap()) .current_dir(p) - .args(["-Xmx512M", "-jar", "slimevr.jar", "run"]) + .args(["-Xmx128M", "-jar", "slimevr.jar", "run"]) .spawn() .expect("Unable to start the server jar"); diff --git a/gui/src-tauri/src/state.rs b/gui/src-tauri/src/state.rs index d0223875d..03c58d589 100644 --- a/gui/src-tauri/src/state.rs +++ b/gui/src-tauri/src/state.rs @@ -15,6 +15,7 @@ pub struct WindowState { height: f64, x: i32, y: i32, + decorated: bool, #[serde(skip)] old: bool, } @@ -50,6 +51,8 @@ impl WindowState { window: &Window, ignore_maximized: bool, ) -> Result<()> { + self.decorated = window.is_decorated()?; + let maximized = window.is_maximized()?; self.maximized = maximized || (self.maximized && ignore_maximized); // We early return when it's maximized because we dont have to save the state @@ -70,6 +73,8 @@ impl WindowState { } pub fn update_window(&self, window: &Window, ignore_maximized: bool) -> Result<()> { + window.set_decorations(self.decorated)?; + let maximized = !ignore_maximized && window.is_maximized()?; if maximized && !self.maximized { window.unmaximize()?; diff --git a/gui/src-tauri/src/tray.rs b/gui/src-tauri/src/tray.rs index 3b315f2a4..0ca65a49d 100644 --- a/gui/src-tauri/src/tray.rs +++ b/gui/src-tauri/src/tray.rs @@ -1,13 +1,14 @@ use std::{collections::HashMap, sync::Mutex}; use tauri::{ - image::Image, + include_image, menu::{Menu, MenuBuilder, MenuItemBuilder, MenuItemKind}, tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}, - AppHandle, Manager, Runtime, State, + AppHandle, Emitter, Manager, Runtime, State, }; pub struct TrayMenu(Menu); +pub struct TrayAvailable(pub bool); pub struct TrayTranslations { store: Mutex>, @@ -21,11 +22,16 @@ impl TrayTranslations { } } +#[tauri::command] +pub fn is_tray_available(tray_available: State) -> bool { + tray_available.0 +} + #[tauri::command] pub fn update_translations( app: AppHandle, i18n: State, - menu: State>, + menu: State>>, new_i18n: HashMap, ) -> color_eyre::Result<(), String> { { @@ -44,8 +50,11 @@ pub fn update_translations( pub fn update_tray_text( app: AppHandle, i18n: State, - menu: State>, + menu: State>>, ) -> color_eyre::Result<(), String> { + let Some(menu) = menu.as_ref() else { + return Ok(()); + }; if let Some((window, MenuItemKind::MenuItem(toggle_i))) = app.get_webview_window("main").zip(menu.0.get("toggle")) { @@ -67,6 +76,26 @@ pub fn update_tray_text( } pub fn create_tray(app: &tauri::AppHandle) -> tauri::Result<()> { + #[cfg(target_os = "linux")] + unsafe { + const LIBS_TO_CHECK: &[&str] = &[ + "libayatana-appindicator3.so.1", + "libappindicator3.so.1", + "libayatana-appindicator3.so", + "libappindicator3.so", + ]; + let found = LIBS_TO_CHECK + .iter() + .any(|lib| libloading::Library::new(lib).is_ok()); + if !found { + log::warn!( + "libappindicator couldn't be found so tray support has been disabled!" + ); + app.manage(TrayAvailable(false)); + return Ok(()); + } + } + let toggle_i = MenuItemBuilder::with_id("toggle", "Hide").build(app)?; let quit_i = MenuItemBuilder::with_id("quit", "Quit").build(app)?; let menu1 = MenuBuilder::new(app).items(&[&toggle_i, &quit_i]).build()?; @@ -78,10 +107,10 @@ pub fn create_tray(app: &tauri::AppHandle) -> tauri::Result<()> { .icon_as_template(true) .menu_on_left_click(false) .icon(if cfg!(target_os = "macos") { - Image::from_bytes(include_bytes!("../icons/appleTrayIcon.png")) + include_image!("icons/appleTrayIcon.png") } else { - Image::from_bytes(include_bytes!("../icons/128x128.png")) - }?) + include_image!("icons/128x128.png") + }) .on_menu_event(move |app, event| match event.id.as_ref() { "quit" => app.emit("try-close", "tray").unwrap(), "toggle" => { @@ -120,7 +149,8 @@ pub fn create_tray(app: &tauri::AppHandle) -> tauri::Result<()> { .menu_on_left_click(false) .build(app)?; - app.manage(TrayMenu(menu1)); + app.manage(TrayAvailable(true)); + app.manage(Some(TrayMenu(menu1))); app.manage(TrayTranslations { store: Default::default(), }); diff --git a/gui/src-tauri/src/util.rs b/gui/src-tauri/src/util.rs index feb2b2d13..f47fdb0c9 100644 --- a/gui/src-tauri/src/util.rs +++ b/gui/src-tauri/src/util.rs @@ -107,7 +107,8 @@ pub fn show_error(text: &str) -> bool { .set_description(text) .set_buttons(MessageButtons::Ok) .set_level(MessageLevel::Error) - .show() == MessageDialogResult::Ok + .show() + == MessageDialogResult::Ok } #[cfg(mobile)] @@ -222,20 +223,26 @@ pub fn logger_format( w: &mut dyn std::io::Write, _now: &mut DeferredNow, record: &Record, + ansi: bool, ) -> Result<(), std::io::Error> { let level = record.level(); let module_path = record.module_path().unwrap_or(""); - // optionally print target + // Optionally print target let target = if module_path.starts_with(record.target()) { "".to_string() } else { format!(", {}", record.target()) }; - write!( - w, - "{} [{}{target}] {}", - style(level).paint(level.to_string()), - record.module_path().unwrap_or(""), - style(level).paint(record.args().to_string()) - ) + // A toggle for ansi formatting, mainly disabled for file logs, but enabled for terminal logs. + if ansi { + write!( + w, + "{} [{}{target}] {}", + style(level).paint(level.to_string()), + module_path, + style(level).paint(record.args().to_string()) + ) + } else { + write!(w, "{} [{}{target}] {}", level, module_path, record.args()) + } } diff --git a/gui/src-tauri/tauri.conf.json b/gui/src-tauri/tauri.conf.json index f73e7d4e6..dffdcde05 100644 --- a/gui/src-tauri/tauri.conf.json +++ b/gui/src-tauri/tauri.conf.json @@ -62,29 +62,8 @@ "licenseFile": "../../LICENSE-MIT" }, "plugins": { - "fs": { - "all": true, - "scope": [ - "$APP/*", - "$APP" - ] - }, - "os": { - "all": true - }, "shell": { - "open": true - }, - "window": { - "close": true, - "maximize": true, - "minimize": true, - "setResizable": true, - "setSize": true, - "setTitle": true, - "startDragging": true, - "unmaximize": true, - "unminimize": true + "open": "^((https?://\\w+)|(file://)).+" } }, "productName": "slimevr", diff --git a/gui/src/App.tsx b/gui/src/App.tsx index 0c8454e62..49ff46592 100644 --- a/gui/src/App.tsx +++ b/gui/src/App.tsx @@ -56,6 +56,7 @@ import { Preload } from './components/Preload'; import { UnknownDeviceModal } from './components/UnknownDeviceModal'; import { useDiscordPresence } from './hooks/discord-presence'; import { withSentryReactRouterV6Routing } from '@sentry/react'; +import { AdvancedSettings } from './components/settings/pages/AdvancedSettings'; export const GH_REPO = 'SlimeVR/SlimeVR-Server'; export const VersionContext = createContext(''); @@ -113,6 +114,7 @@ function Layout() { } /> } /> } /> + } /> {l10n.getString('navbar-body_proportions')} - }> - {l10n.getString('navbar-onboarding')} - + {config?.showNavbarOnboarding && ( + }> + {l10n.getString('navbar-onboarding')} + + )} ); } diff --git a/gui/src/components/TopBar.tsx b/gui/src/components/TopBar.tsx index 8c7216e52..63973af56 100644 --- a/gui/src/components/TopBar.tsx +++ b/gui/src/components/TopBar.tsx @@ -1,4 +1,4 @@ -import { getCurrent } from '@tauri-apps/api/webviewWindow'; +import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'; import { ReactNode, useContext, useEffect, useState } from 'react'; import { NavLink, useMatch } from 'react-router-dom'; import { @@ -27,6 +27,9 @@ import { TrackersStillOnModal } from './TrackersStillOnModal'; import { useConfig } from '@/hooks/config'; import { listen } from '@tauri-apps/api/event'; import { TrayOrExitModal } from './TrayOrExitModal'; +import { error } from '@/utils/logging'; +import { useDoubleTap } from 'use-double-tap'; +import { isTrayAvailable } from '@/utils/tauri'; export function VersionTag() { return ( @@ -57,27 +60,29 @@ export function TopBar({ const { useRPCPacket, sendRPCPacket } = useWebsocketAPI(); const { useConnectedIMUTrackers } = useTrackers(); const connectedIMUTrackers = useConnectedIMUTrackers(); - const { config, setConfig } = useConfig(); + const { config, setConfig, saveConfig } = useConfig(); const version = useContext(VersionContext); const [localIp, setLocalIp] = useState(null); const [showConnectedTrackersWarning, setConnectedTrackerWarning] = useState(false); + const [showVersionMobile, setShowVersionMobile] = useState(false); const [showTrayOrExitModal, setShowTrayOrExitModal] = useState(false); const doesMatchSettings = useMatch({ path: '/settings/*', }); const closeApp = async () => { + await saveConfig(); await invoke('update_window_state'); - await getCurrent().close(); + await getCurrentWebviewWindow().close(); }; const tryCloseApp = async (dontTray = false) => { - if (isTauri && config?.useTray === null) { + if (isTrayAvailable && config?.useTray === null) { setShowTrayOrExitModal(true); return; } if (config?.useTray && !dontTray) { - await getCurrent().hide(); + await getCurrentWebviewWindow().hide(); await invoke('update_tray_text'); } else if ( config?.connectedTrackersWarning && @@ -90,13 +95,15 @@ export function TopBar({ await closeApp(); } }; + const showVersionBind = useDoubleTap(() => setShowVersionMobile(true)); + const unshowVersionBind = useDoubleTap(() => setShowVersionMobile(false)); useEffect(() => { const unlisten = listen('try-close', async () => { - const window = getCurrent(); + const window = getCurrentWebviewWindow(); await window.show(); await window.setFocus(); - await invoke('update_tray_text'); + if (isTrayAvailable) await invoke('update_tray_text'); await tryCloseApp(true); }); return () => { @@ -104,6 +111,11 @@ export function TopBar({ }; }, [config?.useTray, config?.connectedTrackersWarning]); + useEffect(() => { + if (config === null || !isTauri) return; + getCurrentWebviewWindow().setDecorations(config?.decorations).catch(error); + }, [config?.decorations]); + useEffect(() => { sendRPCPacket(RpcMessage.ServerInfosRequest, new ServerInfosRequestT()); }, []); @@ -121,18 +133,20 @@ export function TopBar({
+ + + + ); +} diff --git a/gui/src/components/onboarding/pages/body-proportions/autobone-steps/AutoboneErrorModal.tsx b/gui/src/components/onboarding/pages/body-proportions/autobone-steps/AutoboneErrorModal.tsx index 7200495d3..caee7db6e 100644 --- a/gui/src/components/onboarding/pages/body-proportions/autobone-steps/AutoboneErrorModal.tsx +++ b/gui/src/components/onboarding/pages/body-proportions/autobone-steps/AutoboneErrorModal.tsx @@ -34,7 +34,7 @@ export function AutoboneErrorModal({
-
- - - - {(isTauri || !isMobile) && ( +
+ {!config?.decorations && ( + + + + )} + {(isTauri || !isMobile) && !config?.decorations && (
SlimeVR
)} - {!isMobile && ( + {(!(isMobile && !config?.decorations) || showVersionMobile) && ( <> {doesMatchSettings && ( @@ -149,6 +163,7 @@ export function TopBar({ 'flex justify-around flex-col text-standard-bold text-status-special', 'bg-status-special bg-opacity-20 rounded-lg px-3 select-text' )} + {...unshowVersionBind} > {localIp || 'unknown local ip'}
@@ -192,8 +207,11 @@ export function TopBar({ )} - {!isTauri && ( -
+ {!isTauri && !showVersionMobile && !config?.decorations && ( +
)} - {isTauri && ( + {isTauri && !config?.decorations && ( <>
getCurrent().minimize()} + onClick={() => getCurrentWebviewWindow().minimize()} >
getCurrent().toggleMaximize()} + onClick={() => getCurrentWebviewWindow().toggleMaximize()} >
@@ -268,7 +286,7 @@ export function TopBar({ // Doing this in here just in case config doesn't get updated in time if (useTray) { - await getCurrent().hide(); + await getCurrentWebviewWindow().hide(); await invoke('update_tray_text'); } else if ( config?.connectedTrackersWarning && diff --git a/gui/src/components/commons/BodyPartIcon.tsx b/gui/src/components/commons/BodyPartIcon.tsx index 8bfbbde48..ae539b0c2 100644 --- a/gui/src/components/commons/BodyPartIcon.tsx +++ b/gui/src/components/commons/BodyPartIcon.tsx @@ -15,6 +15,7 @@ import { UpperArmIcon } from './icon/UpperArmIcon'; import { UpperLegIcon } from './icon/UpperLegIcon'; import { WaistIcon } from './icon/WaistIcon'; import { UpperChestIcon } from './icon/UpperChestIcon'; +import { FingersIcon } from './icon/FingersIcon'; // All body parts that are right or left, are by default left! export const mapPart: Record< @@ -86,6 +87,96 @@ export const mapPart: Record< ), [BodyPart.WAIST]: ({ width }) => , + [BodyPart.LEFT_THUMB_METACARPAL]: ({ width }) => ( + + ), + [BodyPart.LEFT_THUMB_PROXIMAL]: ({ width }) => ( + + ), + [BodyPart.LEFT_THUMB_DISTAL]: ({ width }) => ( + + ), + [BodyPart.LEFT_INDEX_PROXIMAL]: ({ width }) => ( + + ), + [BodyPart.LEFT_INDEX_INTERMEDIATE]: ({ width }) => ( + + ), + [BodyPart.LEFT_INDEX_DISTAL]: ({ width }) => ( + + ), + [BodyPart.LEFT_MIDDLE_PROXIMAL]: ({ width }) => ( + + ), + [BodyPart.LEFT_MIDDLE_INTERMEDIATE]: ({ width }) => ( + + ), + [BodyPart.LEFT_MIDDLE_DISTAL]: ({ width }) => ( + + ), + [BodyPart.LEFT_RING_PROXIMAL]: ({ width }) => ( + + ), + [BodyPart.LEFT_RING_INTERMEDIATE]: ({ width }) => ( + + ), + [BodyPart.LEFT_RING_DISTAL]: ({ width }) => ( + + ), + [BodyPart.LEFT_LITTLE_PROXIMAL]: ({ width }) => ( + + ), + [BodyPart.LEFT_LITTLE_INTERMEDIATE]: ({ width }) => ( + + ), + [BodyPart.LEFT_LITTLE_DISTAL]: ({ width }) => ( + + ), + [BodyPart.RIGHT_THUMB_METACARPAL]: ({ width }) => ( + + ), + [BodyPart.RIGHT_THUMB_PROXIMAL]: ({ width }) => ( + + ), + [BodyPart.RIGHT_THUMB_DISTAL]: ({ width }) => ( + + ), + [BodyPart.RIGHT_INDEX_PROXIMAL]: ({ width }) => ( + + ), + [BodyPart.RIGHT_INDEX_INTERMEDIATE]: ({ width }) => ( + + ), + [BodyPart.RIGHT_INDEX_DISTAL]: ({ width }) => ( + + ), + [BodyPart.RIGHT_MIDDLE_PROXIMAL]: ({ width }) => ( + + ), + [BodyPart.RIGHT_MIDDLE_INTERMEDIATE]: ({ width }) => ( + + ), + [BodyPart.RIGHT_MIDDLE_DISTAL]: ({ width }) => ( + + ), + [BodyPart.RIGHT_RING_PROXIMAL]: ({ width }) => ( + + ), + [BodyPart.RIGHT_RING_INTERMEDIATE]: ({ width }) => ( + + ), + [BodyPart.RIGHT_RING_DISTAL]: ({ width }) => ( + + ), + [BodyPart.RIGHT_LITTLE_PROXIMAL]: ({ width }) => ( + + ), + [BodyPart.RIGHT_LITTLE_INTERMEDIATE]: ({ width }) => ( + + ), + [BodyPart.RIGHT_LITTLE_DISTAL]: ({ width }) => ( + + ), }; export function BodyPartIcon({ diff --git a/gui/src/components/commons/Checkbox.tsx b/gui/src/components/commons/Checkbox.tsx index 2ac8cb8e8..728740361 100644 --- a/gui/src/components/commons/Checkbox.tsx +++ b/gui/src/components/commons/Checkbox.tsx @@ -9,6 +9,7 @@ export function CheckBox({ control, outlined, name, + loading, // input props disabled, ...props @@ -19,6 +20,7 @@ export function CheckBox({ variant?: 'checkbox' | 'toggle'; color?: 'primary' | 'secondary' | 'tertiary'; outlined?: boolean; + loading?: boolean; } & React.HTMLProps) { const classes = useMemo(() => { const vriantsMap = { @@ -32,7 +34,9 @@ export function CheckBox({ toggle: { checkbox: classNames('hidden'), toggle: classNames('w-10 h-4 rounded-full relative transition-colors'), - pin: classNames('h-2 w-2 bg-background-10 rounded-full absolute m-1'), + pin: classNames( + 'h-2 w-2 bg-background-10 rounded-full absolute m-1 transition-opacity' + ), }, }; return vriantsMap[variant]; @@ -60,7 +64,8 @@ export function CheckBox({ 'w-full py-3 flex gap-2 items-center text-standard-bold', { 'px-3': outlined, - 'cursor-pointer': !disabled, + 'cursor-pointer': !disabled || !loading, + 'cursor-default': disabled || loading, } )} > @@ -71,23 +76,26 @@ export function CheckBox({ name={name} className={classes.checkbox} type="checkbox" - disabled={disabled} + disabled={disabled || loading} {...props} /> {variant === 'toggle' && (
diff --git a/gui/src/components/commons/FileInput.tsx b/gui/src/components/commons/FileInput.tsx index 0b2042017..33d521bfe 100644 --- a/gui/src/components/commons/FileInput.tsx +++ b/gui/src/components/commons/FileInput.tsx @@ -1,9 +1,17 @@ import { Localized } from '@fluent/react'; import classNames from 'classnames'; -import { forwardRef, useMemo, useState } from 'react'; +import { + forwardRef, + useImperativeHandle, + useMemo, + useRef, + useState, +} from 'react'; import { Control, Controller, UseControllerProps } from 'react-hook-form'; import { FileIcon } from './icon/FileIcon'; +import { UploadFileIcon } from './icon/UploadFileIcon'; import { Typography } from './Typography'; +import { CloseIcon } from './icon/CloseIcon'; interface InputProps { variant?: 'primary' | 'secondary'; @@ -11,6 +19,80 @@ interface InputProps { name: string; } +const FileInputContentBlank = ({ + isDragging, + label, +}: { + isDragging: boolean; + label: string; +}) => { + return ( +
+ + +
+ , + }} + > + + Drop files to attach, or{' '} + browse + + +
+
+
+ ); +}; + +const FileInputContentFile = ({ + importedFileName, + onClearPicker, +}: { + importedFileName: string; + onClearPicker: () => any; +}) => { + return ( +
+
+
+ + {importedFileName} +
+ + { + onClearPicker(); + }} + > + + +
+
+ ); +}; + export const FileInputInside = forwardRef< HTMLInputElement, { @@ -22,44 +104,36 @@ export const FileInputInside = forwardRef< value: FileList; onChange: (...event: any[]) => void; name: string; + importedFileName: string | null; } >(function AppInput( { label = 'tips-file_select', name, onChange, - variant = 'primary', accept, capture, multiple = false, + importedFileName, }, ref ) { - const classes = useMemo(() => { - const variantsMap = { - primary: classNames('bg-background-60 border-background-60'), - secondary: classNames('bg-background-50 border-background-50'), - }; + const innerRef = useRef(null); + + useImperativeHandle(ref, () => innerRef.current!); - return classNames( - variantsMap[variant], - 'w-full focus:ring-transparent focus:ring-offset-transparent', - 'focus:outline-transparent rounded-md bg-background-60 border-background-60', - 'focus:border-accent-background-40 placeholder:text-background-30 text-standard', - 'relative hidden' - ); - }, [variant]); const acceptList = useMemo(() => accept.split(/, ?/), [accept]); const [isDragging, setDragging] = useState(false); + const isFileImported = importedFileName !== null && !isDragging; + + const onClearPicker = () => { + onChange([]); + innerRef.current!.value = ''; + }; + return (
diff --git a/gui/src/components/onboarding/pages/CalibrationTutorial.tsx b/gui/src/components/onboarding/pages/CalibrationTutorial.tsx index 9271f91af..d889e271f 100644 --- a/gui/src/components/onboarding/pages/CalibrationTutorial.tsx +++ b/gui/src/components/onboarding/pages/CalibrationTutorial.tsx @@ -12,6 +12,7 @@ import { useTrackers } from '@/hooks/tracker'; import { useRestCalibrationTrackers } from '@/hooks/imu-logic'; import { averageVector, Vector3FromVec3fT } from '@/maths/vector3'; import { Vector3 } from 'three'; +import { useTimeout } from '@/hooks/timeout'; export enum CalibrationStatus { SUCCESS, @@ -29,10 +30,12 @@ export function CalibrationTutorialPage() { const [calibrationStatus, setCalibrationStatus] = useState( CalibrationStatus.WAITING ); + const [skipButton, setSkipButton] = useState(false); const { timer, isCounting, startCountdown, abortCountdown } = useCountdown({ duration: IMU_CALIBRATION_TIME, onCountdownEnd: () => setCalibrationStatus(CalibrationStatus.SUCCESS), }); + useTimeout(() => setSkipButton(true), 10000); const { useConnectedIMUTrackers } = useTrackers(); const connectedIMUTrackers = useConnectedIMUTrackers(); const restCalibrationTrackers = @@ -192,6 +195,13 @@ export function CalibrationTutorialPage() { {l10n.getString('onboarding-continue')}
+
diff --git a/gui/src/components/onboarding/pages/ConnectTracker.tsx b/gui/src/components/onboarding/pages/ConnectTracker.tsx index e55c5c156..cc93ba47f 100644 --- a/gui/src/components/onboarding/pages/ConnectTracker.tsx +++ b/gui/src/components/onboarding/pages/ConnectTracker.tsx @@ -29,6 +29,8 @@ const statusLabelMap = { 'onboarding-connect_tracker-connection_status-none', [WifiProvisioningStatus.SERIAL_INIT]: 'onboarding-connect_tracker-connection_status-serial_init', + [WifiProvisioningStatus.OBTAINING_MAC_ADDRESS]: + 'onboarding-connect_tracker-connection_status-obtaining_mac_address', [WifiProvisioningStatus.PROVISIONING]: 'onboarding-connect_tracker-connection_status-provisioning', [WifiProvisioningStatus.CONNECTING]: @@ -46,6 +48,7 @@ const statusLabelMap = { const statusProgressMap = { [WifiProvisioningStatus.NONE]: 0, [WifiProvisioningStatus.SERIAL_INIT]: 0.2, + [WifiProvisioningStatus.OBTAINING_MAC_ADDRESS]: 0.3, [WifiProvisioningStatus.PROVISIONING]: 0.4, [WifiProvisioningStatus.CONNECTING]: 0.6, [WifiProvisioningStatus.LOOKING_FOR_SERVER]: 0.8, diff --git a/gui/src/components/onboarding/pages/Done.tsx b/gui/src/components/onboarding/pages/Done.tsx index bd7dc81d9..40f6a9d76 100644 --- a/gui/src/components/onboarding/pages/Done.tsx +++ b/gui/src/components/onboarding/pages/Done.tsx @@ -3,9 +3,11 @@ import { useOnboarding } from '@/hooks/onboarding'; import { Button } from '@/components/commons/Button'; import { SlimeVRIcon } from '@/components/commons/icon/SimevrIcon'; import { Typography } from '@/components/commons/Typography'; +import { useNavigate } from 'react-router-dom'; export function DonePage() { const { l10n } = useLocalization(); + const navigate = useNavigate(); const { applyProgress, skipSetup } = useOnboarding(); applyProgress(1); @@ -22,7 +24,13 @@ export function DonePage() { {l10n.getString('onboarding-done-description')}
-
diff --git a/gui/src/components/onboarding/pages/body-proportions/AutomaticProportions.tsx b/gui/src/components/onboarding/pages/body-proportions/AutomaticProportions.tsx index e9f832feb..b843ba135 100644 --- a/gui/src/components/onboarding/pages/body-proportions/AutomaticProportions.tsx +++ b/gui/src/components/onboarding/pages/body-proportions/AutomaticProportions.tsx @@ -15,6 +15,8 @@ import { VerifyResultsStep } from './autobone-steps/VerifyResults'; import { useCountdown } from '@/hooks/countdown'; import { CheckHeight } from './autobone-steps/CheckHeight'; import { PreparationStep } from './autobone-steps/Preparation'; +import { useState } from 'react'; +import { ProportionsResetModal } from './ProportionsResetModal'; export function AutomaticProportionsPage() { const { l10n } = useLocalization(); @@ -30,6 +32,8 @@ export function AutomaticProportionsPage() { }, }); + const [showWarning, setShowWarning] = useState(false); + applyProgress(0.9); return ( @@ -65,7 +69,7 @@ export function AutomaticProportionsPage() {
+ { + startCountdown(); + setShowWarning(false); + }} + onClose={() => setShowWarning(false)} + isOpen={showWarning} + >
); diff --git a/gui/src/components/onboarding/pages/body-proportions/BodyProportions.tsx b/gui/src/components/onboarding/pages/body-proportions/BodyProportions.tsx index d58f405b0..cce31e00c 100644 --- a/gui/src/components/onboarding/pages/body-proportions/BodyProportions.tsx +++ b/gui/src/components/onboarding/pages/body-proportions/BodyProportions.tsx @@ -278,7 +278,7 @@ export function BodyProportions({ className={classNames( 'h-12 w-32 rounded-lg bg-background-60 flex flex-col justify-center', 'items-center fill-background-10', - scrollerRef?.current?.scrollTop ?? 0 > 0 + (scrollerRef?.current?.scrollTop ?? 0 > 0) ? 'opacity-100 active:bg-accent-background-30' : 'opacity-50' )} diff --git a/gui/src/components/onboarding/pages/body-proportions/ManualProportions.tsx b/gui/src/components/onboarding/pages/body-proportions/ManualProportions.tsx index 55a0ad785..71b6accdd 100644 --- a/gui/src/components/onboarding/pages/body-proportions/ManualProportions.tsx +++ b/gui/src/components/onboarding/pages/body-proportions/ManualProportions.tsx @@ -7,15 +7,17 @@ import { CheckBox } from '@/components/commons/Checkbox'; import { Typography } from '@/components/commons/Typography'; import { BodyProportions } from './BodyProportions'; import { useLocalization } from '@fluent/react'; -import { useEffect, useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useBreakpoint } from '@/hooks/breakpoint'; import { SkeletonVisualizerWidget } from '@/components/widgets/SkeletonVisualizerWidget'; +import { ProportionsResetModal } from './ProportionsResetModal'; export function ButtonsControl() { const { l10n } = useLocalization(); const { state } = useOnboarding(); const { sendRPCPacket } = useWebsocketAPI(); + const [showWarning, setShowWarning] = useState(false); const resetAll = () => { sendRPCPacket( RpcMessage.SkeletonResetAllRequest, @@ -32,9 +34,17 @@ export function ButtonsControl() { > {l10n.getString('onboarding-previous_step')} - + { + resetAll(); + setShowWarning(false); + }} + onClose={() => setShowWarning(false)} + isOpen={showWarning} + > {!state.alonePage && (
+ +
, docs: ( diff --git a/gui/src/components/onboarding/pages/body-proportions/autobone-steps/CheckHeight.tsx b/gui/src/components/onboarding/pages/body-proportions/autobone-steps/CheckHeight.tsx index 4a97d0ab5..80943a426 100644 --- a/gui/src/components/onboarding/pages/body-proportions/autobone-steps/CheckHeight.tsx +++ b/gui/src/components/onboarding/pages/body-proportions/autobone-steps/CheckHeight.tsx @@ -12,16 +12,12 @@ import { Localized, useLocalization } from '@fluent/react'; import { useForm } from 'react-hook-form'; import { useMemo, useState } from 'react'; import { NumberSelector } from '@/components/commons/NumberSelector'; -import { - DEFAULT_HEIGHT, - MIN_HEIGHT, -} from '@/components/onboarding/pages/body-proportions/ProportionsChoose'; +import { MIN_HEIGHT } from '@/components/onboarding/pages/body-proportions/ProportionsChoose'; import { useLocaleConfig } from '@/i18n/config'; import { useCountdown } from '@/hooks/countdown'; import { TipBox } from '@/components/commons/TipBox'; interface HeightForm { - height: number; hmdHeight: number; } @@ -62,18 +58,13 @@ export function CheckHeight({ [currentLocales] ); - useRPCPacket( - RpcMessage.HeightResponse, - ({ hmdHeight, estimatedFullHeight }: HeightResponseT) => { - setValue('height', estimatedFullHeight || DEFAULT_HEIGHT); - setValue('hmdHeight', hmdHeight); - } - ); + useRPCPacket(RpcMessage.HeightResponse, ({ hmdHeight }: HeightResponseT) => { + setValue('hmdHeight', hmdHeight); + }); const onSubmit = (values: HeightForm) => { const changeSettings = new ChangeSettingsRequestT(); const autobone = new AutoBoneSettingsT(); - autobone.targetFullHeight = values.height; autobone.targetHmdHeight = values.hmdHeight; changeSettings.autoBoneSettings = autobone; @@ -143,23 +134,6 @@ export function CheckHeight({ step={0.01} disabled={true} /> - - isNaN(value) - ? l10n.getString( - 'onboarding-automatic_proportions-check_height-unknown' - ) - : mFormat.format(value) - } - min={MIN_HEIGHT} - max={4} - step={0.01} - />
diff --git a/gui/src/components/onboarding/pages/body-proportions/autobone-steps/Recording.tsx b/gui/src/components/onboarding/pages/body-proportions/autobone-steps/Recording.tsx index ca434961b..ea0185002 100644 --- a/gui/src/components/onboarding/pages/body-proportions/autobone-steps/Recording.tsx +++ b/gui/src/components/onboarding/pages/body-proportions/autobone-steps/Recording.tsx @@ -8,6 +8,7 @@ import { P, match } from 'ts-pattern'; import { AutoboneErrorModal } from './AutoboneErrorModal'; import { PlayCircleIcon } from '@/components/commons/icon/PlayIcon'; import { useDebouncedEffect } from '@/hooks/timeout'; +import { AUTOBONE_VIDEO } from '@/utils/tauri'; export function Recording({ nextStep, @@ -165,7 +166,7 @@ export function Recording({
diff --git a/gui/src/components/settings/pages/AdvancedSettings.tsx b/gui/src/components/settings/pages/AdvancedSettings.tsx new file mode 100644 index 000000000..9130b70e3 --- /dev/null +++ b/gui/src/components/settings/pages/AdvancedSettings.tsx @@ -0,0 +1,190 @@ +import { useLocalization } from '@fluent/react'; +import { useState } from 'react'; +import { Typography } from '@/components/commons/Typography'; +import { + SettingsPageLayout, + SettingsPagePaneLayout, +} from '@/components/settings/SettingsPageLayout'; +import { BugIcon } from '@/components/commons/icon/BugIcon'; +import { Button } from '@/components/commons/Button'; +import { SettingsResetModal } from '@/components/settings/SettingsResetModal'; + +import { open } from '@tauri-apps/plugin-shell'; +import { error } from '@/utils/logging'; +import { appConfigDir } from '@tauri-apps/api/path'; +import { defaultConfig as defaultGUIConfig, useConfig } from '@/hooks/config'; +import { defaultValues as defaultDevConfig } from '@/components/widgets/DeveloperModeWidget'; +import { RpcMessage, SettingsResetRequestT } from 'solarxr-protocol'; +import { useWebsocketAPI } from '@/hooks/websocket-api'; + +function guiDefaults() { + // Destructure the properties to exclude "lang" + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { lang, ...guiDefaults } = defaultGUIConfig; + + // Include "devSettings" which has all the properties of "defaultDevConfig" + // @ts-expect-error "devSettings" is not in the "guiDefaults" object but we want to include it (from "defaultDevConfig") + guiDefaults.devSettings = defaultDevConfig; + + return guiDefaults; +} + +export function AdvancedSettings() { + const { l10n } = useLocalization(); + const { setConfig } = useConfig(); + + const [showWarningGUI, setShowWarningGUI] = useState(false); + const [showWarningServer, setShowWarningServer] = useState(false); + const [showWarningAll, setShowWarningAll] = useState(false); + const { sendRPCPacket } = useWebsocketAPI(); + + const openConfigFolder = async () => { + try { + const configPath = await appConfigDir(); + await open('file://' + configPath); + } catch (err) { + error('Failed to open config folder:', err); + } + }; + + return ( + +
+ } id="advanced"> + <> + + {l10n.getString('settings-utils-advanced')} + + +
+
+
+ + {l10n.getString('settings-utils-advanced-reset-gui')} + +
+ + {l10n.getString( + 'settings-utils-advanced-reset-gui-description' + )} + +
+
+
+ + { + setConfig(guiDefaults()); + setShowWarningGUI(false); + }} + onClose={() => setShowWarningGUI(false)} + isOpen={showWarningGUI} + variant="gui" + > +
+
+ +
+
+ + {l10n.getString('settings-utils-advanced-reset-server')} + +
+ + {l10n.getString( + 'settings-utils-advanced-reset-server-description' + )} + +
+
+
+ + { + sendRPCPacket( + RpcMessage.SettingsResetRequest, + new SettingsResetRequestT() + ); + setShowWarningServer(false); + }} + onClose={() => setShowWarningServer(false)} + isOpen={showWarningServer} + variant="server" + > +
+
+ +
+
+ + {l10n.getString('settings-utils-advanced-reset-all')} + +
+ + {l10n.getString( + 'settings-utils-advanced-reset-all-description' + )} + +
+
+
+ + { + sendRPCPacket( + RpcMessage.SettingsResetRequest, + new SettingsResetRequestT() + ); + setConfig(guiDefaults()); + setShowWarningAll(false); + }} + onClose={() => setShowWarningAll(false)} + isOpen={showWarningAll} + variant="all" + > +
+
+ +
+
+ + {l10n.getString('settings-utils-advanced-open_data')} + +
+ + {l10n.getString( + 'settings-utils-advanced-open_data-description' + )} + +
+
+
+ +
+
+
+ +
+
+
+ ); +} diff --git a/gui/src/components/settings/pages/GeneralSettings.tsx b/gui/src/components/settings/pages/GeneralSettings.tsx index f6d0c1c0e..d384670e7 100644 --- a/gui/src/components/settings/pages/GeneralSettings.tsx +++ b/gui/src/components/settings/pages/GeneralSettings.tsx @@ -31,6 +31,8 @@ import { SettingsPagePaneLayout, } from '@/components/settings/SettingsPageLayout'; import { HandsWarningModal } from '@/components/settings/HandsWarningModal'; +import { MagnetometerToggleSetting } from './MagnetometerToggleSetting'; +import { DriftCompensationModal } from '@/components/settings/DriftCompensationModal'; interface SettingsForm { trackers: { @@ -52,6 +54,7 @@ interface SettingsForm { }; driftCompensation: { enabled: boolean; + prediction: boolean; amount: number; maxResets: number; }; @@ -138,6 +141,7 @@ const defaultValues: SettingsForm = { filtering: { amount: 0.1, type: FilteringType.NONE }, driftCompensation: { enabled: false, + prediction: false, amount: 0.1, maxResets: 1, }, @@ -282,6 +286,7 @@ export function GeneralSettings() { const driftCompensation = new DriftCompensationSettingsT(); driftCompensation.enabled = values.driftCompensation.enabled; + driftCompensation.prediction = values.driftCompensation.prediction; driftCompensation.amount = values.driftCompensation.amount; driftCompensation.maxResets = values.driftCompensation.maxResets; settings.driftCompensation = driftCompensation; @@ -435,6 +440,8 @@ export function GeneralSettings() { // } // }, [state]); + const [showDriftCompWarning, setShowDriftCompWarning] = useState(false); + return ( { + if (getValues('driftCompensation.enabled')) { + return; + } + + setShowDriftCompWarning(true); + }} /> +
+ + {l10n.getString( + 'settings-general-tracker_mechanics-drift_compensation-prediction' + )} + +
+ {l10n + .getString( + 'settings-general-tracker_mechanics-drift_compensation-prediction-description' + ) + .split('\n') + .map((line, i) => ( + + {line} + + ))} +
+ + { + setShowDriftCompWarning(false); + }} + onClose={() => { + setShowDriftCompWarning(false); + setValue('driftCompensation.enabled', false); + }} + isOpen={showDriftCompWarning} + >
+
- - {l10n.getString('settings-general-interface-use_tray')} - -
- - {l10n.getString( - 'settings-general-interface-use_tray-description' - )} - -
-
- -
+ {isTrayAvailable && ( + <> + + {l10n.getString('settings-general-interface-use_tray')} + +
+ + {l10n.getString( + 'settings-general-interface-use_tray-description' + )} + +
+
+ +
+ + )} {l10n.getString('settings-general-interface-discord_presence')} @@ -306,6 +320,27 @@ export function InterfaceSettings() { {l10n.getString('settings-interface-appearance')} + + {l10n.getString('settings-interface-appearance-decorations')} + +
+ + {l10n.getString( + 'settings-interface-appearance-decorations-description' + )} + +
+
+ +
@@ -360,9 +395,39 @@ export function InterfaceSettings() { value={'trans'} colors="!bg-trans-flag" > +
+ + {l10n.getString( + 'settings-general-interface-show-navbar-onboarding' + )} + +
+ + {l10n.getString( + 'settings-general-interface-show-navbar-onboarding-description' + )} + +
+
+ +
+ {l10n.getString('settings-interface-appearance-font')} @@ -387,7 +452,7 @@ export function InterfaceSettings() { 'settings-interface-appearance-font-slime_font' ), value: 'poppins', - fontName: 'poppins', + fontName: 'poppins, Noto Sans CJK', }, { label: 'OpenDyslexic', diff --git a/gui/src/components/settings/pages/MagnetometerToggleSetting.tsx b/gui/src/components/settings/pages/MagnetometerToggleSetting.tsx new file mode 100644 index 000000000..91860d194 --- /dev/null +++ b/gui/src/components/settings/pages/MagnetometerToggleSetting.tsx @@ -0,0 +1,160 @@ +import { CheckBox } from '@/components/commons/Checkbox'; +import { Typography } from '@/components/commons/Typography'; +import { useWebsocketAPI } from '@/hooks/websocket-api'; +import { Localized, useLocalization } from '@fluent/react'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { + ChangeMagToggleRequestT, + DeviceIdT, + MagToggleRequestT, + MagToggleResponseT, + RpcMessage, + TrackerIdT, +} from 'solarxr-protocol'; +import { Link } from 'react-router-dom'; + +interface MagnetometerToggleForm { + magToggle: boolean; +} + +export function MagnetometerToggleSetting({ + trackerNum, + deviceId, + settingType, + id, +}: { + trackerNum?: number; + deviceId?: number; + settingType: 'general' | 'tracker'; + id?: string; +}) { + const { l10n } = useLocalization(); + const { sendRPCPacket, useRPCPacket } = useWebsocketAPI(); + const originalValue = useRef(null); + // used to disable the tracker specific toggle if false + const [globalToggle, setGlobalToggle] = useState(false); + const [waitingMag, setWaitingMag] = useState(false); + const { control, watch, handleSubmit, reset } = + useForm({ + defaultValues: { magToggle: settingType === 'tracker' }, + }); + + const onSubmit = useCallback( + (values: MagnetometerToggleForm) => { + if (originalValue.current === values.magToggle) return; + setWaitingMag(true); + const req = new ChangeMagToggleRequestT(); + if (trackerNum !== undefined) { + const id = new TrackerIdT( + deviceId ? new DeviceIdT(deviceId) : undefined, + trackerNum + ); + req.trackerId = id; + } + + req.enable = values.magToggle; + sendRPCPacket(RpcMessage.ChangeMagToggleRequest, req); + }, + [trackerNum, deviceId] + ); + + useEffect(() => { + const subscription = watch(() => handleSubmit(onSubmit)()); + return () => subscription.unsubscribe(); + }, []); + + useEffect(() => { + const req = new MagToggleRequestT(); + if (trackerNum !== undefined) { + const id = new TrackerIdT( + deviceId ? new DeviceIdT(deviceId) : undefined, + trackerNum + ); + req.trackerId = id; + sendRPCPacket(RpcMessage.MagToggleRequest, new MagToggleRequestT()); + } + sendRPCPacket(RpcMessage.MagToggleRequest, req); + }, [trackerNum, deviceId]); + + useRPCPacket(RpcMessage.MagToggleResponse, (mag: MagToggleResponseT) => { + if (trackerNum !== undefined && mag.trackerId?.trackerNum === undefined) { + setGlobalToggle(mag.enable); + } + if ( + mag.trackerId?.trackerNum !== trackerNum || + mag.trackerId?.deviceId?.id !== deviceId + ) { + return; + } + originalValue.current = mag.enable; + setWaitingMag(false); + reset({ magToggle: mag.enable }); + }); + + return settingType === 'general' ? ( + <> +
+ + {l10n.getString( + 'settings-general-tracker_mechanics-use_mag_on_all_trackers' + )} + + }} + > + + +
+ + + ) : ( +
+ + {l10n.getString('tracker-settings-use_mag')} + + , + magSetting: ( + + ), + }} + > + + +
+ +
+
+ ); +} diff --git a/gui/src/components/settings/pages/VMCSettings.tsx b/gui/src/components/settings/pages/VMCSettings.tsx index a6d2d6cc8..83b77c867 100644 --- a/gui/src/components/settings/pages/VMCSettings.tsx +++ b/gui/src/components/settings/pages/VMCSettings.tsx @@ -53,12 +53,6 @@ export function VMCSettings() { const { l10n } = useLocalization(); const { sendRPCPacket, useRPCPacket } = useWebsocketAPI(); const [modelName, setModelName] = useState(null); - const [flashLoaded, setFlashLoaded] = useState(false); - - const toggleFlash = (bool: boolean) => { - setFlashLoaded(bool); - setTimeout(() => setFlashLoaded(!bool), 1000); - }; const { reset, control, watch, handleSubmit } = useForm({ defaultValues, @@ -74,11 +68,17 @@ export function VMCSettings() { new OSCSettingsT(), values.vmc.oscSettings ); - if (values.vmc.vrmJson?.length) { - vmcOsc.vrmJson = await parseVRMFile(values.vmc.vrmJson[0]); - if (vmcOsc.vrmJson) { - toggleFlash(true); - setModelName(JSON.parse(vmcOsc.vrmJson).extensions.VRM.meta.title); + if (values.vmc.vrmJson !== undefined) { + if (values.vmc.vrmJson.length > 0) { + vmcOsc.vrmJson = await parseVRMFile(values.vmc.vrmJson[0]); + if (vmcOsc.vrmJson) { + setModelName( + JSON.parse(vmcOsc.vrmJson)?.extensions?.VRM?.meta?.title || '' + ); + } + } else { + vmcOsc.vrmJson = ''; + setModelName(null); } } vmcOsc.anchorHip = values.vmc.anchorHip; @@ -114,7 +114,7 @@ export function VMCSettings() { } const vrmJson = settings.vmcOsc.vrmJson?.toString(); if (vrmJson) { - setModelName(JSON.parse(vrmJson).extensions.VRM.meta.title); + setModelName(JSON.parse(vrmJson)?.extensions?.VRM?.meta?.title || ''); } formData.vmc.anchorHip = settings.vmcOsc.anchorHip; @@ -236,16 +236,6 @@ export function VMCSettings() { {l10n.getString('settings-osc-vmc-vrm-description')} -
- - {modelName === null - ? l10n.getString('settings-osc-vmc-vrm-model_unloaded') - : l10n.getString('settings-osc-vmc-vrm-model_loaded', { - name: modelName, - titled: (!!modelName).toString(), - })} - -
diff --git a/gui/src/components/tracker/TrackerCard.tsx b/gui/src/components/tracker/TrackerCard.tsx index 0d70423a4..69de178c9 100644 --- a/gui/src/components/tracker/TrackerCard.tsx +++ b/gui/src/components/tracker/TrackerCard.tsx @@ -78,7 +78,7 @@ function TrackerSmol({
-
+
{trackerName} @@ -150,7 +150,7 @@ export function TrackerCard({ ? { boxShadow: `0px 0px ${Math.floor(velocity * 8)}px ${Math.floor( velocity * 8 - )}px #BB8AE5`, + )}px rgb(var(--accent-background-30))`, } : {} } diff --git a/gui/src/components/tracker/TrackerPartCard.tsx b/gui/src/components/tracker/TrackerPartCard.tsx index 38197e0d2..cfaa22bab 100644 --- a/gui/src/components/tracker/TrackerPartCard.tsx +++ b/gui/src/components/tracker/TrackerPartCard.tsx @@ -86,7 +86,7 @@ export function TrackerPartCard({ style={{ boxShadow: `0px 0px ${globalVelocity * 3}px ${ globalVelocity * 3 - }px #BB8AE5`, + }px rgb(var(--accent-background-30))`, }} > {roleError && ( diff --git a/gui/src/components/tracker/TrackerSettings.tsx b/gui/src/components/tracker/TrackerSettings.tsx index 9d47ea07f..591f387ee 100644 --- a/gui/src/components/tracker/TrackerSettings.tsx +++ b/gui/src/components/tracker/TrackerSettings.tsx @@ -9,7 +9,9 @@ import { BodyPart, ForgetDeviceRequestT, ImuType, + MagnetometerStatus, RpcMessage, + TrackerDataType, } from 'solarxr-protocol'; import { useDebouncedEffect } from '@/hooks/timeout'; import { useTrackerFromId } from '@/hooks/tracker'; @@ -33,6 +35,7 @@ import { SingleTrackerBodyAssignmentMenu } from './SingleTrackerBodyAssignmentMe import { TrackerCard } from './TrackerCard'; import { Quaternion } from 'three'; import { useAppContext } from '@/hooks/app'; +import { MagnetometerToggleSetting } from '@/components/settings/pages/MagnetometerToggleSetting'; const rotationsLabels: [Quaternion, string][] = [ [rotationToQuatMap.BACK, 'tracker-rotation-back'], @@ -258,6 +261,16 @@ export function TrackerSettingsPage() { {tracker?.device?.hardwareInfo?.hardwareIdentifier || '--'}
+
+ + {l10n.getString('tracker-infos-data_support')} + + + {tracker?.tracker.info?.dataSupport + ? TrackerDataType[tracker?.tracker.info?.dataSupport] + : '--'} + +
{l10n.getString('tracker-infos-imu')} @@ -276,6 +289,19 @@ export function TrackerSettingsPage() { {tracker?.device?.hardwareInfo?.boardType || '--'}
+
+ + {l10n.getString('tracker-infos-magnetometer')} + + + {tracker?.tracker.info?.magnetometer === undefined + ? '--' + : l10n.getString('tracker-infos-magnetometer-status-v1', { + status: + MagnetometerStatus[tracker.tracker.info.magnetometer], + })} + +
{l10n.getString('tracker-infos-network_version')} @@ -315,11 +341,11 @@ export function TrackerSettingsPage() { > )} {tracker?.tracker.info?.bodyPart === BodyPart.NONE && ( - + )} @@ -403,6 +429,15 @@ export function TrackerSettingsPage() {
)} + {tracker?.tracker.info?.isImu && + tracker?.tracker.info?.magnetometer !== + MagnetometerStatus.NOT_SUPPORTED && ( + + )}
{l10n.getString('tracker-settings-name_section')} @@ -419,7 +454,7 @@ export function TrackerSettingsPage() { control={control} autocomplete="off" rules={undefined} - label="Tracker name" + label={l10n.getString('tracker-settings-name_section-label')} >
{macAddress && ( @@ -432,7 +467,7 @@ export function TrackerSettingsPage() { )} {enabled && ( @@ -157,7 +177,7 @@ export function IMUVisualizerWidget({ tracker }: { tracker: TrackerDataT }) { localStorage.setItem('modelPreview', 'false'); }} > - {l10n.getString('widget-imu_visualizer-rotation_hide')} + {l10n.getString('widget-imu_visualizer-hide')} = { assignMode: AssignMode.Core, discordPresence: false, errorTracking: false, + decorations: false, + showNavbarOnboarding: true, }; interface CrossStorage { @@ -71,13 +76,15 @@ interface CrossStorage { get(key: string): Promise; } -export const TAURI_STORE: CrossStorage = new Store('gui-settings.dat'); - -export const LOCAL_STORE: CrossStorage = { +const localStore: CrossStorage = { get: async (key) => localStorage.getItem(key), set: async (key, value) => localStorage.setItem(key, value), }; +const store: CrossStorage = isTauri() + ? await createStore('gui-settings.dat', { autoSave: 100 as never }) + : localStore; + function fallbackToDefaults(loadedConfig: any): Config { return Object.assign({}, defaultConfig, loadedConfig); } @@ -86,7 +93,6 @@ export function useConfigProvider(): ConfigContext { const [currConfig, set] = useState(null); const [loading, setLoading] = useState(false); const tauri = useIsTauri(); - const store = useMemo(() => (tauri ? TAURI_STORE : LOCAL_STORE), [tauri]); useDebouncedEffect( () => { diff --git a/gui/src/hooks/imu-logic.ts b/gui/src/hooks/imu-logic.ts index db331b8e4..84e8a92d5 100644 --- a/gui/src/hooks/imu-logic.ts +++ b/gui/src/hooks/imu-logic.ts @@ -1,11 +1,21 @@ import { useMemo } from 'react'; import { FlatDeviceTracker } from './app'; +const IGNORED_BOARDS = new Set(['Sony Mocopi', 'Haritora']); + export function useIsRestCalibrationTrackers( connectedTrackers: FlatDeviceTracker[] ): boolean { const imuExists = useMemo( - () => connectedTrackers.some((tracker) => tracker.tracker.info?.isImu), + () => + connectedTrackers.some( + (tracker) => + tracker.tracker.info?.isImu && + !( + tracker.device?.hardwareInfo?.boardType && + IGNORED_BOARDS.has(tracker.device?.hardwareInfo?.boardType as string) + ) + ), [connectedTrackers] ); diff --git a/gui/src/i18n/config.tsx b/gui/src/i18n/config.tsx index 3c24c54c5..66baa1c51 100644 --- a/gui/src/i18n/config.tsx +++ b/gui/src/i18n/config.tsx @@ -12,6 +12,7 @@ import { import { exists, readTextFile, BaseDirectory } from '@tauri-apps/plugin-fs'; import { error } from '@/utils/logging'; import { invoke } from '@tauri-apps/api/core'; +import { isTrayAvailable } from '@/utils/tauri'; export const defaultNS = 'translation'; export const DEFAULT_LOCALE = 'en'; @@ -200,7 +201,7 @@ export function AppLocalizationProvider(props: AppLocalizationProviderProps) { }, []); useEffect(() => { - if (l10n === null) return; + if (l10n === null || !isTrayAvailable) return; const newI18n: Record = {}; TRAY_MENU_KEYS.forEach((key) => { diff --git a/gui/src/index.scss b/gui/src/index.scss index e70ede169..354e141bd 100644 --- a/gui/src/index.scss +++ b/gui/src/index.scss @@ -316,6 +316,32 @@ body { --default-color: 0, 0, 0; } +:root[data-theme='asexual'] { + --background-10: 255, 255, 255; + --background-20: 230, 230, 230; + --background-30: 200, 200, 200; + --background-40: 120, 120, 120; + --background-50: 90, 90, 90; + --background-60: 60, 60, 60; + --background-70: 30, 30, 30; + --background-80: 15, 15, 15; + --background-90: 0, 0, 0; + + --accent-background-10: 230, 0, 230; + --accent-background-20: 210, 0, 210; + --accent-background-30: 150, 0, 150; + --accent-background-40: 130, 0, 130; + --accent-background-50: 70, 0, 70; + + --success: 100, 230, 10; + --warning: 220, 200, 50; + --critical: 220, 40, 110; + --special: 230, 0, 230; + --window-icon-stroke: 200, 130, 200; + + --default-color: 255, 255, 255; +} + #root { height: 100%; } diff --git a/gui/src/sounds/sounds.tsx b/gui/src/sounds/sounds.tsx index f5a23057e..fbc6da181 100644 --- a/gui/src/sounds/sounds.tsx +++ b/gui/src/sounds/sounds.tsx @@ -1,19 +1,36 @@ +import { fetchResourceUrl } from '@/utils/tauri'; import { ResetType } from 'solarxr-protocol'; const quickResetStartedSound = new Audio( - '/sounds/quick-reset-started-sound.mp3' + await fetchResourceUrl('/sounds/quick-reset-started-sound.mp3') +); +const fullResetStartedSound = new Audio( + await fetchResourceUrl('/sounds/full-reset-started-sound.mp3') ); -const fullResetStartedSound = new Audio('/sounds/full-reset-started-sound.mp3'); const mountingResetStartedSound = new Audio( - '/sounds/mounting-reset-started-sound.mp3' + await fetchResourceUrl('/sounds/mounting-reset-started-sound.mp3') +); +const tapSetupSound1 = new Audio( + await fetchResourceUrl('/sounds/first-tap.mp3') +); +const tapSetupSound2 = new Audio( + await fetchResourceUrl('/sounds/second-tap.mp3') +); +const tapSetupSound3 = new Audio( + await fetchResourceUrl('/sounds/third-tap.mp3') +); +const tapSetupSound4 = new Audio( + await fetchResourceUrl('/sounds/fourth-tap.mp3') +); +const tapSetupSound5 = new Audio( + await fetchResourceUrl('/sounds/fifth-tap.mp3') +); +const tapSetupSoundEnd = new Audio( + await fetchResourceUrl('/sounds/end-tap.mp3') +); +const tapSetupExtraSound = new Audio( + await fetchResourceUrl('/sounds/tapextrasetup.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'); function restartAndPlay(audio: HTMLAudioElement, volume: number) { audio.volume = Math.min(1, Math.pow(volume, Math.E) + 0.05); diff --git a/gui/src/utils/skeletonHelper.ts b/gui/src/utils/skeletonHelper.ts index 578174b75..0ff8f8e23 100644 --- a/gui/src/utils/skeletonHelper.ts +++ b/gui/src/utils/skeletonHelper.ts @@ -223,6 +223,37 @@ export class BoneKind extends Bone { case BodyPart.LEFT_HIP: case BodyPart.RIGHT_HIP: return new Color('pink'); + case BodyPart.LEFT_THUMB_METACARPAL: + case BodyPart.LEFT_THUMB_PROXIMAL: + case BodyPart.LEFT_THUMB_DISTAL: + case BodyPart.LEFT_INDEX_PROXIMAL: + case BodyPart.LEFT_INDEX_INTERMEDIATE: + case BodyPart.LEFT_INDEX_DISTAL: + case BodyPart.LEFT_MIDDLE_PROXIMAL: + case BodyPart.LEFT_MIDDLE_INTERMEDIATE: + case BodyPart.LEFT_MIDDLE_DISTAL: + case BodyPart.LEFT_RING_PROXIMAL: + case BodyPart.LEFT_RING_INTERMEDIATE: + case BodyPart.LEFT_RING_DISTAL: + case BodyPart.LEFT_LITTLE_PROXIMAL: + case BodyPart.LEFT_LITTLE_INTERMEDIATE: + case BodyPart.LEFT_LITTLE_DISTAL: + case BodyPart.RIGHT_THUMB_METACARPAL: + case BodyPart.RIGHT_THUMB_PROXIMAL: + case BodyPart.RIGHT_THUMB_DISTAL: + case BodyPart.RIGHT_INDEX_PROXIMAL: + case BodyPart.RIGHT_INDEX_INTERMEDIATE: + case BodyPart.RIGHT_INDEX_DISTAL: + case BodyPart.RIGHT_MIDDLE_PROXIMAL: + case BodyPart.RIGHT_MIDDLE_INTERMEDIATE: + case BodyPart.RIGHT_MIDDLE_DISTAL: + case BodyPart.RIGHT_RING_PROXIMAL: + case BodyPart.RIGHT_RING_INTERMEDIATE: + case BodyPart.RIGHT_RING_DISTAL: + case BodyPart.RIGHT_LITTLE_PROXIMAL: + case BodyPart.RIGHT_LITTLE_INTERMEDIATE: + case BodyPart.RIGHT_LITTLE_DISTAL: + return new Color('pink'); } } @@ -275,8 +306,81 @@ export class BoneKind extends Bone { case BodyPart.RIGHT_LOWER_ARM: return [BodyPart.RIGHT_HAND]; case BodyPart.LEFT_HAND: - return []; + return [ + BodyPart.LEFT_THUMB_METACARPAL, + BodyPart.LEFT_INDEX_PROXIMAL, + BodyPart.LEFT_MIDDLE_PROXIMAL, + BodyPart.LEFT_RING_PROXIMAL, + BodyPart.LEFT_LITTLE_PROXIMAL, + ]; case BodyPart.RIGHT_HAND: + return [ + BodyPart.RIGHT_THUMB_METACARPAL, + BodyPart.RIGHT_INDEX_PROXIMAL, + BodyPart.RIGHT_MIDDLE_PROXIMAL, + BodyPart.RIGHT_RING_PROXIMAL, + BodyPart.RIGHT_LITTLE_PROXIMAL, + ]; + + case BodyPart.LEFT_THUMB_METACARPAL: + return [BodyPart.LEFT_THUMB_PROXIMAL]; + case BodyPart.LEFT_THUMB_PROXIMAL: + return [BodyPart.LEFT_THUMB_DISTAL]; + case BodyPart.LEFT_THUMB_DISTAL: + return []; + case BodyPart.LEFT_INDEX_PROXIMAL: + return [BodyPart.LEFT_INDEX_INTERMEDIATE]; + case BodyPart.LEFT_INDEX_INTERMEDIATE: + return [BodyPart.LEFT_INDEX_DISTAL]; + case BodyPart.LEFT_INDEX_DISTAL: + return []; + case BodyPart.LEFT_MIDDLE_PROXIMAL: + return [BodyPart.LEFT_MIDDLE_INTERMEDIATE]; + case BodyPart.LEFT_MIDDLE_INTERMEDIATE: + return [BodyPart.LEFT_MIDDLE_DISTAL]; + case BodyPart.LEFT_MIDDLE_DISTAL: + return []; + case BodyPart.LEFT_RING_PROXIMAL: + return [BodyPart.LEFT_RING_INTERMEDIATE]; + case BodyPart.LEFT_RING_INTERMEDIATE: + return [BodyPart.LEFT_RING_DISTAL]; + case BodyPart.LEFT_RING_DISTAL: + return []; + case BodyPart.LEFT_LITTLE_PROXIMAL: + return [BodyPart.LEFT_LITTLE_INTERMEDIATE]; + case BodyPart.LEFT_LITTLE_INTERMEDIATE: + return [BodyPart.LEFT_LITTLE_DISTAL]; + case BodyPart.LEFT_LITTLE_DISTAL: + return []; + case BodyPart.RIGHT_THUMB_METACARPAL: + return [BodyPart.RIGHT_THUMB_PROXIMAL]; + case BodyPart.RIGHT_THUMB_PROXIMAL: + return [BodyPart.RIGHT_THUMB_DISTAL]; + case BodyPart.RIGHT_THUMB_DISTAL: + return []; + case BodyPart.RIGHT_INDEX_PROXIMAL: + return [BodyPart.RIGHT_INDEX_INTERMEDIATE]; + case BodyPart.RIGHT_INDEX_INTERMEDIATE: + return [BodyPart.RIGHT_INDEX_DISTAL]; + case BodyPart.RIGHT_INDEX_DISTAL: + return []; + case BodyPart.RIGHT_MIDDLE_PROXIMAL: + return [BodyPart.RIGHT_MIDDLE_INTERMEDIATE]; + case BodyPart.RIGHT_MIDDLE_INTERMEDIATE: + return [BodyPart.RIGHT_MIDDLE_DISTAL]; + case BodyPart.RIGHT_MIDDLE_DISTAL: + return []; + case BodyPart.RIGHT_RING_PROXIMAL: + return [BodyPart.RIGHT_RING_INTERMEDIATE]; + case BodyPart.RIGHT_RING_INTERMEDIATE: + return [BodyPart.RIGHT_RING_DISTAL]; + case BodyPart.RIGHT_RING_DISTAL: + return []; + case BodyPart.RIGHT_LITTLE_PROXIMAL: + return [BodyPart.RIGHT_LITTLE_INTERMEDIATE]; + case BodyPart.RIGHT_LITTLE_INTERMEDIATE: + return [BodyPart.RIGHT_LITTLE_DISTAL]; + case BodyPart.RIGHT_LITTLE_DISTAL: return []; } } @@ -329,6 +433,67 @@ export class BoneKind extends Bone { return BodyPart.LEFT_LOWER_ARM; case BodyPart.RIGHT_HAND: return BodyPart.RIGHT_LOWER_ARM; + + case BodyPart.LEFT_THUMB_METACARPAL: + return BodyPart.LEFT_HAND; + case BodyPart.LEFT_THUMB_PROXIMAL: + return BodyPart.LEFT_THUMB_METACARPAL; + case BodyPart.LEFT_THUMB_DISTAL: + return BodyPart.LEFT_THUMB_PROXIMAL; + case BodyPart.LEFT_INDEX_PROXIMAL: + return BodyPart.LEFT_HAND; + case BodyPart.LEFT_INDEX_INTERMEDIATE: + return BodyPart.LEFT_INDEX_PROXIMAL; + case BodyPart.LEFT_INDEX_DISTAL: + return BodyPart.LEFT_INDEX_INTERMEDIATE; + case BodyPart.LEFT_MIDDLE_PROXIMAL: + return BodyPart.LEFT_HAND; + case BodyPart.LEFT_MIDDLE_INTERMEDIATE: + return BodyPart.LEFT_MIDDLE_PROXIMAL; + case BodyPart.LEFT_MIDDLE_DISTAL: + return BodyPart.LEFT_MIDDLE_INTERMEDIATE; + case BodyPart.LEFT_RING_PROXIMAL: + return BodyPart.LEFT_HAND; + case BodyPart.LEFT_RING_INTERMEDIATE: + return BodyPart.LEFT_RING_PROXIMAL; + case BodyPart.LEFT_RING_DISTAL: + return BodyPart.LEFT_RING_INTERMEDIATE; + case BodyPart.LEFT_LITTLE_PROXIMAL: + return BodyPart.LEFT_HAND; + case BodyPart.LEFT_LITTLE_INTERMEDIATE: + return BodyPart.LEFT_LITTLE_PROXIMAL; + case BodyPart.LEFT_LITTLE_DISTAL: + return BodyPart.LEFT_LITTLE_INTERMEDIATE; + case BodyPart.RIGHT_THUMB_METACARPAL: + return BodyPart.RIGHT_HAND; + case BodyPart.RIGHT_THUMB_PROXIMAL: + return BodyPart.RIGHT_THUMB_METACARPAL; + case BodyPart.RIGHT_THUMB_DISTAL: + return BodyPart.RIGHT_THUMB_PROXIMAL; + case BodyPart.RIGHT_INDEX_PROXIMAL: + return BodyPart.RIGHT_HAND; + case BodyPart.RIGHT_INDEX_INTERMEDIATE: + return BodyPart.RIGHT_INDEX_PROXIMAL; + case BodyPart.RIGHT_INDEX_DISTAL: + return BodyPart.RIGHT_INDEX_INTERMEDIATE; + case BodyPart.RIGHT_MIDDLE_PROXIMAL: + return BodyPart.RIGHT_HAND; + case BodyPart.RIGHT_MIDDLE_INTERMEDIATE: + return BodyPart.RIGHT_MIDDLE_PROXIMAL; + case BodyPart.RIGHT_MIDDLE_DISTAL: + return BodyPart.RIGHT_MIDDLE_INTERMEDIATE; + case BodyPart.RIGHT_RING_PROXIMAL: + return BodyPart.RIGHT_HAND; + case BodyPart.RIGHT_RING_INTERMEDIATE: + return BodyPart.RIGHT_RING_PROXIMAL; + case BodyPart.RIGHT_RING_DISTAL: + return BodyPart.RIGHT_RING_INTERMEDIATE; + case BodyPart.RIGHT_LITTLE_PROXIMAL: + return BodyPart.RIGHT_HAND; + case BodyPart.RIGHT_LITTLE_INTERMEDIATE: + return BodyPart.RIGHT_LITTLE_PROXIMAL; + case BodyPart.RIGHT_LITTLE_DISTAL: + return BodyPart.RIGHT_LITTLE_INTERMEDIATE; } } } diff --git a/gui/src/utils/tauri.ts b/gui/src/utils/tauri.ts new file mode 100644 index 000000000..ab9905ed0 --- /dev/null +++ b/gui/src/utils/tauri.ts @@ -0,0 +1,19 @@ +import { invoke, isTauri } from '@tauri-apps/api/core'; +import { type } from '@tauri-apps/plugin-os'; + +/** + * Fetches the resource as a blob if necessary because of https://github.com/tauri-apps/tauri/issues/3725 + * @param url static asset to fetch + * @returns URL + */ +export async function fetchResourceUrl(url: string) { + if (!isTauri() || type() !== 'linux') return url; + return URL.createObjectURL(await fetch(url).then((res) => res.blob())); +} + +// FIXME: For some fucking reason, you can't top-level await on a react component file +// on Chromium on developments builds specifically -Uriel +export const AUTOBONE_VIDEO = await fetchResourceUrl('/videos/autobone.webm'); + +export const isTrayAvailable = + isTauri() && (await invoke('is_tray_available')); diff --git a/gui/tailwind.config.ts b/gui/tailwind.config.ts index 3ecedb7ce..d612158bf 100644 --- a/gui/tailwind.config.ts +++ b/gui/tailwind.config.ts @@ -150,6 +150,12 @@ const colors = { 700: '#b3b3b3', 900: '#d8d8d8', }, + 'asexual': { + 100: '#000000', + 200: '#A3A3A3', + 300: '#FFFFFF', + 400: '#800080', + }, }; const config = { @@ -160,6 +166,7 @@ const config = { smol: '525px', mobile: { raw: 'not (min-width: 800px)' }, xs: '800px', + nsm: { raw: 'not (min-width: 900px)' }, sm: '900px', md: '1100px', 'md-max': { raw: 'not (min-width: 1100px)' }, @@ -228,6 +235,7 @@ const config = { dark: `linear-gradient(135deg, ${colors['dark-accent'][100]} 50%, ${colors['dark-background'][700]} 50% 100%)`, light: `linear-gradient(135deg, ${colors['light-accent'][100]} 50%, ${colors['light-background'][700]} 50% 100%)`, 'trans-flag': `linear-gradient(135deg, ${colors['trans-blue'][800]} 40%, ${colors['trans-blue'][700]} 40% 70%, ${colors['trans-blue'][600]} 70% 100%)`, + 'asexual-flag': `linear-gradient(135deg, ${colors['asexual'][100]} 30%, ${colors['asexual'][200]} 30% 50%, ${colors['asexual'][300]} 50% 70%, ${colors['asexual'][400]} 70% 100%)`, }, }, data: { diff --git a/gui/tsconfig.json b/gui/tsconfig.json index 5b7b679bc..1093a665f 100644 --- a/gui/tsconfig.json +++ b/gui/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2020", + "target": "es2022", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, @@ -17,9 +17,7 @@ "jsx": "react-jsx", "baseUrl": ".", "paths": { - "@/*": [ - "./src/*" - ], + "@/*": ["./src/*"] } }, "include": ["src"], diff --git a/gui/vite.config.ts b/gui/vite.config.ts index 503e85619..1afb61dd8 100644 --- a/gui/vite.config.ts +++ b/gui/vite.config.ts @@ -48,7 +48,7 @@ export default defineConfig({ }), ], build: { - target: 'es2020', + target: 'es2022', emptyOutDir: true, commonjsOptions: { @@ -59,7 +59,7 @@ export default defineConfig({ }, optimizeDeps: { esbuildOptions: { - target: 'es2020', + target: 'es2022', }, needsInterop: ['solarxr-protocol'], include: ['solarxr-protocol'], @@ -69,4 +69,11 @@ export default defineConfig({ '@': path.resolve(__dirname, 'src'), }, }, + css: { + preprocessorOptions: { + scss: { + api: 'modern', + }, + }, + }, }); diff --git a/package.json b/package.json index 86eaf3c86..f3204639d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "slimevr-ui", "version": "0.5.1", "private": true, - "packageManager": "pnpm@9.4.0", + "packageManager": "pnpm@9.12.2", "workspaces": [ "solarxr-protocol", "gui" @@ -13,11 +13,11 @@ "skipbundler": "cd gui && pnpm run skipbundler", "build": "pnpm run tauri build", "update-solarxr": "cd solarxr-protocol && pnpm run build", - "prepare": "husky install && pnpm run update-solarxr", + "prepare": "husky && pnpm run update-solarxr", "preinstall": "npx only-allow pnpm" }, "devDependencies": { - "husky": "^9.0.11", - "lint-staged": "^15.2.7" + "husky": "^9.1.6", + "lint-staged": "^15.2.10" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4cc790c9e..aacd7ba0a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,11 +9,11 @@ importers: .: devDependencies: husky: - specifier: ^9.0.11 - version: 9.0.11 + specifier: ^9.1.6 + version: 9.1.6 lint-staged: - specifier: ^15.2.7 - version: 15.2.7 + specifier: ^15.2.10 + version: 15.2.10 gui: dependencies: @@ -24,41 +24,41 @@ importers: specifier: ^0.15.2 version: 0.15.2(@fluent/bundle@0.18.0)(react@18.3.1) '@fontsource/poppins': - specifier: ^5.0.14 - version: 5.0.14 + specifier: ^5.1.0 + version: 5.1.0 '@formatjs/intl-localematcher': specifier: ^0.2.32 version: 0.2.32 '@react-three/drei': - specifier: ^9.107.0 - version: 9.107.0(@react-three/fiber@8.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(@types/react@18.3.3)(@types/three@0.163.0)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) + specifier: ^9.114.3 + version: 9.114.3(@react-three/fiber@8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(@types/react@18.3.11)(@types/three@0.163.0)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) '@react-three/fiber': - specifier: ^8.16.8 - version: 8.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) + specifier: ^8.17.10 + version: 8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) '@sentry/react': - specifier: ^8.26.0 - version: 8.26.0(react@18.3.1) + specifier: ^8.44.0 + version: 8.44.0(react@18.3.1) '@sentry/vite-plugin': - specifier: ^2.22.2 - version: 2.22.2 + specifier: ^2.22.7 + version: 2.22.7 '@tauri-apps/api': - specifier: 2.0.0-beta.14 - version: 2.0.0-beta.14 + specifier: ^2.0.2 + version: 2.0.2 '@tauri-apps/plugin-dialog': - specifier: 2.0.0-beta.6 - version: 2.0.0-beta.6 + specifier: ^2.0.0 + version: 2.0.0 '@tauri-apps/plugin-fs': - specifier: 2.0.0-beta.6 - version: 2.0.0-beta.6 + specifier: ^2.0.0 + version: 2.0.0 '@tauri-apps/plugin-os': - specifier: 2.0.0-beta.6 - version: 2.0.0-beta.6 + specifier: ^2.0.0 + version: 2.0.0 '@tauri-apps/plugin-shell': - specifier: 2.0.0-beta.7 - version: 2.0.0-beta.7 + specifier: ^2.0.0 + version: 2.0.0 '@tauri-apps/plugin-store': - specifier: 2.0.0-beta.6 - version: 2.0.0-beta.6 + specifier: ^2.0.0 + version: 2.0.0 browser-fs-access: specifier: ^0.35.0 version: 0.35.0 @@ -90,8 +90,8 @@ importers: specifier: ^6.1.0 version: 6.1.0(react@18.3.1) react-hook-form: - specifier: ^7.52.0 - version: 7.52.0(react@18.3.1) + specifier: ^7.53.0 + version: 7.53.0(react@18.3.1) react-modal: specifier: ^3.16.1 version: 3.16.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -99,11 +99,11 @@ importers: specifier: ^10.0.0 version: 10.0.0(react@18.3.1) react-router-dom: - specifier: ^6.23.1 - version: 6.23.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^6.26.2 + version: 6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) semver: - specifier: ^7.6.2 - version: 7.6.2 + specifier: ^7.6.3 + version: 7.6.3 solarxr-protocol: specifier: file:../solarxr-protocol version: file:solarxr-protocol @@ -111,27 +111,30 @@ importers: specifier: ^0.163.0 version: 0.163.0 ts-pattern: - specifier: ^5.2.0 - version: 5.2.0 + specifier: ^5.4.0 + version: 5.4.0 typescript: - specifier: ^5.4.5 - version: 5.4.5 + specifier: ^5.6.3 + version: 5.6.3 + use-double-tap: + specifier: ^1.3.6 + version: 1.3.6(react@18.3.1) devDependencies: '@dword-design/eslint-plugin-import-alias': specifier: ^4.0.9 version: 4.0.9 '@tailwindcss/forms': - specifier: ^0.5.7 - version: 0.5.7(tailwindcss@3.4.4(ts-node@9.1.1(typescript@5.4.5))) + specifier: ^0.5.9 + version: 0.5.9(tailwindcss@3.4.13(ts-node@9.1.1(typescript@5.6.3))) '@tauri-apps/cli': - specifier: 2.0.0-beta.21 - version: 2.0.0-beta.21 + specifier: ^2.0.2 + version: 2.0.2 '@types/file-saver': specifier: ^2.0.7 version: 2.0.7 '@types/react': - specifier: ^18.3.3 - version: 18.3.3 + specifier: ^18.3.11 + version: 18.3.11 '@types/react-dom': specifier: ^18.3.0 version: 18.3.0 @@ -148,50 +151,50 @@ importers: specifier: ^0.163.0 version: 0.163.0 '@typescript-eslint/eslint-plugin': - specifier: ^7.13.0 - version: 7.13.0(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + specifier: ^7.18.0 + version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) '@typescript-eslint/parser': - specifier: ^7.13.0 - version: 7.13.0(eslint@8.57.0)(typescript@5.4.5) + specifier: ^7.18.0 + version: 7.18.0(eslint@8.57.1)(typescript@5.6.3) '@vitejs/plugin-react': - specifier: ^4.3.1 - version: 4.3.1(vite@5.3.1(@types/node@20.14.2)(sass@1.77.6)(terser@5.31.1)) + specifier: ^4.3.2 + version: 4.3.2(vite@5.4.8(@types/node@20.14.2)(sass@1.79.4)(terser@5.31.1)) autoprefixer: - specifier: ^10.4.19 - version: 10.4.19(postcss@8.4.38) + specifier: ^10.4.20 + version: 10.4.20(postcss@8.4.47) cross-env: specifier: ^7.0.3 version: 7.0.3 eslint: - specifier: ^8.57.0 - version: 8.57.0 + specifier: ^8.57.1 + version: 8.57.1 eslint-config-airbnb: specifier: ^19.0.4 - version: 19.0.4(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.34.2(eslint@8.57.0))(eslint@8.57.0) + version: 19.0.4(eslint-plugin-import@2.31.0)(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1) eslint-import-resolver-typescript: - specifier: ^3.6.1 - version: 3.6.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0) + specifier: ^3.6.3 + version: 3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1) eslint-plugin-import: - specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + specifier: ^2.31.0 + version: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-jsx-a11y: - specifier: ^6.8.0 - version: 6.8.0(eslint@8.57.0) + specifier: ^6.10.0 + version: 6.10.0(eslint@8.57.1) eslint-plugin-react: - specifier: ^7.34.2 - version: 7.34.2(eslint@8.57.0) + specifier: ^7.37.1 + version: 7.37.1(eslint@8.57.1) eslint-plugin-react-hooks: specifier: ^4.6.2 - version: 4.6.2(eslint@8.57.0) + version: 4.6.2(eslint@8.57.1) prettier: - specifier: ^3.3.2 - version: 3.3.2 + specifier: ^3.3.3 + version: 3.3.3 rollup-plugin-visualizer: specifier: ^5.12.0 - version: 5.12.0(rollup@4.18.0) + version: 5.12.0(rollup@4.24.0) sass: - specifier: ^1.77.5 - version: 1.77.6 + specifier: ^1.79.4 + version: 1.79.4 spdx-satisfies: specifier: ^5.0.1 version: 5.0.1 @@ -199,11 +202,11 @@ importers: specifier: ^1.2.0 version: 1.2.0 tailwindcss: - specifier: ^3.4.4 - version: 3.4.4(ts-node@9.1.1(typescript@5.4.5)) + specifier: ^3.4.13 + version: 3.4.13(ts-node@9.1.1(typescript@5.6.3)) vite: - specifier: ^5.3.1 - version: 5.3.1(@types/node@20.14.2)(sass@1.77.6)(terser@5.31.1) + specifier: ^5.4.8 + version: 5.4.8(@types/node@20.14.2)(sass@1.79.4)(terser@5.31.1) solarxr-protocol: dependencies: @@ -228,111 +231,95 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@babel/code-frame@7.24.7': - resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} + '@babel/code-frame@7.25.7': + resolution: {integrity: sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.24.7': - resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==} + '@babel/compat-data@7.25.7': + resolution: {integrity: sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw==} engines: {node: '>=6.9.0'} - '@babel/core@7.24.7': - resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==} + '@babel/core@7.25.7': + resolution: {integrity: sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==} engines: {node: '>=6.9.0'} - '@babel/generator@7.24.7': - resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==} + '@babel/generator@7.25.7': + resolution: {integrity: sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.24.7': - resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==} + '@babel/helper-compilation-targets@7.25.7': + resolution: {integrity: sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==} engines: {node: '>=6.9.0'} - '@babel/helper-environment-visitor@7.24.7': - resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} + '@babel/helper-module-imports@7.25.7': + resolution: {integrity: sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==} engines: {node: '>=6.9.0'} - '@babel/helper-function-name@7.24.7': - resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-hoist-variables@7.24.7': - resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.24.7': - resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.24.7': - resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==} + '@babel/helper-module-transforms@7.25.7': + resolution: {integrity: sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-plugin-utils@7.24.7': - resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==} + '@babel/helper-plugin-utils@7.25.7': + resolution: {integrity: sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==} engines: {node: '>=6.9.0'} - '@babel/helper-simple-access@7.24.7': - resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} + '@babel/helper-simple-access@7.25.7': + resolution: {integrity: sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==} engines: {node: '>=6.9.0'} - '@babel/helper-split-export-declaration@7.24.7': - resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} + '@babel/helper-string-parser@7.25.7': + resolution: {integrity: sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.24.7': - resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} + '@babel/helper-validator-identifier@7.25.7': + resolution: {integrity: sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.24.7': - resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + '@babel/helper-validator-option@7.25.7': + resolution: {integrity: sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.24.7': - resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==} + '@babel/helpers@7.25.7': + resolution: {integrity: sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.24.7': - resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==} + '@babel/highlight@7.25.7': + resolution: {integrity: sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.24.7': - resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.24.7': - resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} + '@babel/parser@7.25.7': + resolution: {integrity: sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-transform-react-jsx-self@7.24.7': - resolution: {integrity: sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==} + '@babel/plugin-transform-react-jsx-self@7.25.7': + resolution: {integrity: sha512-JD9MUnLbPL0WdVK8AWC7F7tTG2OS6u/AKKnsK+NdRhUiVdnzyR1S3kKQCaRLOiaULvUiqK6Z4JQE635VgtCFeg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-source@7.24.7': - resolution: {integrity: sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==} + '@babel/plugin-transform-react-jsx-source@7.25.7': + resolution: {integrity: sha512-S/JXG/KrbIY06iyJPKfxr0qRxnhNOdkNXYBl/rmwgDd72cQLH9tEGkDm/yJPGvcSIUoikzfjMios9i+xT/uv9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.24.7': - resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} + '@babel/runtime@7.25.7': + resolution: {integrity: sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==} engines: {node: '>=6.9.0'} - '@babel/template@7.24.7': - resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} + '@babel/template@7.25.7': + resolution: {integrity: sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.24.7': - resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==} + '@babel/traverse@7.25.7': + resolution: {integrity: sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==} engines: {node: '>=6.9.0'} - '@babel/types@7.24.7': - resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} + '@babel/types@7.25.7': + resolution: {integrity: sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==} engines: {node: '>=6.9.0'} '@dword-design/dedent@0.7.0': @@ -493,16 +480,16 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.10.1': - resolution: {integrity: sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==} + '@eslint-community/regexpp@4.11.1': + resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} '@eslint/eslintrc@2.1.4': resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/js@8.57.0': - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} '@fluent/bundle@0.18.0': @@ -522,14 +509,14 @@ packages: peerDependencies: '@fluent/bundle': '>= 0.13.0' - '@fontsource/poppins@5.0.14': - resolution: {integrity: sha512-nmM1zpPo3Uh4JcGAVSQuWaZNYh2FbbwWhZ5t6hRaynmJaNTBW85d3nEh9zMmzI0HX7X5xqQVdRHeDatKpOGsnA==} + '@fontsource/poppins@5.1.0': + resolution: {integrity: sha512-tpLXlnNi2fwQjiipvuj4uNFHCdoLA8izRsKdoexZuEzjx0r/g1aKLf4ta6lFgF7L+/+AFdmaXFlUwwvmDzYH+g==} '@formatjs/intl-localematcher@0.2.32': resolution: {integrity: sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==} - '@humanwhocodes/config-array@0.11.14': - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} deprecated: Use @eslint/config-array instead @@ -560,8 +547,8 @@ packages: '@jridgewell/source-map@0.3.6': resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} - '@jridgewell/sourcemap-codec@1.4.15': - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} @@ -573,8 +560,8 @@ packages: resolution: {integrity: sha512-sf9vaoiR/SR0dpV568GhsoLbd6659StJ4Gl9jszZL/bsJJaF5VmLYbI57OSI4JDm+L6d3osVMl9mkchox9j6/g==} hasBin: true - '@monogrid/gainmap-js@3.0.5': - resolution: {integrity: sha512-53sCTG4FaJBaAq/tcufARtVYDMDGqyBT9i7F453pWGhZ5LqubDHDWtYoHo9VhQqMcHTEexdJqSsR58y+9HVmQA==} + '@monogrid/gainmap-js@3.0.6': + resolution: {integrity: sha512-ireqJg7cw0tUn/JePDG8rAL7RyXgUKSDbjYdiygkrnye1WuKGLAWDBwF/ICwCwJ9iZBAF5caU8gSu+c34HLGdQ==} peerDependencies: three: '>= 0.159.0' @@ -590,6 +577,10 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -622,8 +613,8 @@ packages: '@react-spring/types@9.6.1': resolution: {integrity: sha512-POu8Mk0hIU3lRXB3bGIGe4VHIwwDsQyoD1F394OK7STTiX9w4dG3cTLljjYswkQN+hDSHRrj4O36kuVa7KPU8Q==} - '@react-three/drei@9.107.0': - resolution: {integrity: sha512-8AxMfk3NmE/tPwN/wAcTyYIZgi4YCsm+ID3vEVb28CCJ4bo4b2UZPWfrMskO7zM1T2ePZaQwmN4Q+cxSpYWn0A==} + '@react-three/drei@9.114.3': + resolution: {integrity: sha512-hPKPYmxTb2P1mOdhkouJbKJVcfFK5JmThr/97i4zkweoNzWBHNde090A6r0SFFb4tGaTtHM4/kyfVx5PrzjTMw==} peerDependencies: '@react-three/fiber': '>=8.0' react: '>=18.0' @@ -633,8 +624,8 @@ packages: react-dom: optional: true - '@react-three/fiber@8.16.8': - resolution: {integrity: sha512-Lc8fjATtvQEfSd8d5iKdbpHtRm/aPMeFj7jQvp6TNHfpo8IQTW3wwcE1ZMrGGoUH+w2mnyS+0MK1NLPLnuzGkQ==} + '@react-three/fiber@8.17.10': + resolution: {integrity: sha512-S6bqa4DqUooEkInYv/W+Jklv2zjSYCXAhm6qKpAQyOXhTEt5gBXnA7W6aoJ0bjmp9pAeaSj/AZUoz1HCSof/uA==} peerDependencies: expo: '>=43.0' expo-asset: '>=8.4' @@ -658,277 +649,271 @@ packages: react-native: optional: true - '@remix-run/router@1.16.1': - resolution: {integrity: sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==} + '@remix-run/router@1.19.2': + resolution: {integrity: sha512-baiMx18+IMuD1yyvOGaHM9QrVUPGGG0jC+z+IPHnRJWUAUvaKuWKyE8gjDj2rzv3sz9zOGoRSPgeBVHRhZnBlA==} engines: {node: '>=14.0.0'} - '@rollup/rollup-android-arm-eabi@4.18.0': - resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} + '@rollup/rollup-android-arm-eabi@4.24.0': + resolution: {integrity: sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.18.0': - resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} + '@rollup/rollup-android-arm64@4.24.0': + resolution: {integrity: sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.18.0': - resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} + '@rollup/rollup-darwin-arm64@4.24.0': + resolution: {integrity: sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.18.0': - resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} + '@rollup/rollup-darwin-x64@4.24.0': + resolution: {integrity: sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.18.0': - resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} + '@rollup/rollup-linux-arm-gnueabihf@4.24.0': + resolution: {integrity: sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.18.0': - resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==} + '@rollup/rollup-linux-arm-musleabihf@4.24.0': + resolution: {integrity: sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.18.0': - resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==} + '@rollup/rollup-linux-arm64-gnu@4.24.0': + resolution: {integrity: sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.18.0': - resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==} + '@rollup/rollup-linux-arm64-musl@4.24.0': + resolution: {integrity: sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': - resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==} + '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': + resolution: {integrity: sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.18.0': - resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==} + '@rollup/rollup-linux-riscv64-gnu@4.24.0': + resolution: {integrity: sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.18.0': - resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==} + '@rollup/rollup-linux-s390x-gnu@4.24.0': + resolution: {integrity: sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.18.0': - resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==} + '@rollup/rollup-linux-x64-gnu@4.24.0': + resolution: {integrity: sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.18.0': - resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==} + '@rollup/rollup-linux-x64-musl@4.24.0': + resolution: {integrity: sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.18.0': - resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==} + '@rollup/rollup-win32-arm64-msvc@4.24.0': + resolution: {integrity: sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.18.0': - resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==} + '@rollup/rollup-win32-ia32-msvc@4.24.0': + resolution: {integrity: sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.18.0': - resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==} + '@rollup/rollup-win32-x64-msvc@4.24.0': + resolution: {integrity: sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==} cpu: [x64] os: [win32] - '@sentry-internal/browser-utils@8.26.0': - resolution: {integrity: sha512-O2Tj+WK33/ZVp5STnz6ZL0OO+/Idk2KqsH0ITQkQmyZ2z0kdzWOeqK7s7q3/My6rB1GfPcyqPcBBv4dVv92FYQ==} + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@sentry-internal/browser-utils@8.44.0': + resolution: {integrity: sha512-kmSRdS1r2G3i0wTJJv69uMZqf/UwP3pVqrCq/0hvNaF4L5v+vrEOKTDZghDvCqutEqOFXI0V/l9SuDpgjElcZQ==} engines: {node: '>=14.18'} - '@sentry-internal/feedback@8.26.0': - resolution: {integrity: sha512-hQtw1gg8n6ERK1UH47F7ZI1zOsbhu0J2VX+TrnkpaQR2FgxDW1oe9Ja6oCV4CQKuR4w+1ZI/Kj4imSt0K33kEw==} + '@sentry-internal/feedback@8.44.0': + resolution: {integrity: sha512-x/7dilh9VRpsPRgx+1kT3Aulgj0X02GF+JfNeaFA2p786+2jBHTupGBu7AGiq1b1YRbDefkFXQxS1MaeqEEeOg==} engines: {node: '>=14.18'} - '@sentry-internal/replay-canvas@8.26.0': - resolution: {integrity: sha512-2CFQW6f9aJHIo/DqmqYa9PaYoLn1o36ywc0h8oyGrD4oPCbrnE5F++PmTdc71GBODu41HBn/yoCTLmxOD+UjpA==} + '@sentry-internal/replay-canvas@8.44.0': + resolution: {integrity: sha512-hFCUHDekuJknzVCu5JnDkgUuOTJbwu82RR+VfbT+2lfIpZoT+gH44LzSH5bQUPXgmznRae4OYHblWAPue9U1Bw==} engines: {node: '>=14.18'} - '@sentry-internal/replay@8.26.0': - resolution: {integrity: sha512-JDY7W2bswlp5c3483lKP4kcb75fHNwGNfwD8x8FsY9xMjv7nxeXjLpR5cCEk1XqPq2+n6w4j7mJOXhEXGiUIKg==} + '@sentry-internal/replay@8.44.0': + resolution: {integrity: sha512-ZPX3Bg8ShuWZZzL5lw/fHjHdRhxxhhdzsVXq2jItg3CPvuO7oQofZsG4po6vgXTlj+fdtjUMQanj/6Ah4+jwsQ==} engines: {node: '>=14.18'} - '@sentry/babel-plugin-component-annotate@2.22.2': - resolution: {integrity: sha512-6kFAHGcs0npIC4HTt4ULs8uOfEucvMI7VW4hoyk17jhRaW8CbxzxfWCfIeRbDkE8pYwnARaq83tu025Hrk2zgA==} + '@sentry/babel-plugin-component-annotate@2.22.7': + resolution: {integrity: sha512-aa7XKgZMVl6l04NY+3X7BP7yvQ/s8scn8KzQfTLrGRarziTlMGrsCOBQtCNWXOPEbtxAIHpZ9dsrAn5EJSivOQ==} engines: {node: '>= 14'} - '@sentry/browser@8.26.0': - resolution: {integrity: sha512-e5s6eKlwLZWzTwQcBwqyAGZMMuQROW9Z677VzwkSyREWAIkKjfH2VBxHATnNGc0IVkNHjD7iH3ixo3C0rLKM3w==} + '@sentry/browser@8.44.0': + resolution: {integrity: sha512-s12u8rz2aYjiWPzoE7StL7fiCS2Z5p5BYmk9bhGDqDWyAPVEVZFUB3u/hwcPUF4yDAroWCbsNzTiBwr813zihg==} engines: {node: '>=14.18'} - '@sentry/bundler-plugin-core@2.22.2': - resolution: {integrity: sha512-TwEEW4FeEJ5Mamp4fGnktfVjzN77KAW0xFQsEPuxZtOAPG17zX/PGvdyRX/TE1jkZWhTzqUDIdgzqlNLjyEnUw==} + '@sentry/bundler-plugin-core@2.22.7': + resolution: {integrity: sha512-ouQh5sqcB8vsJ8yTTe0rf+iaUkwmeUlGNFi35IkCFUQlWJ22qS6OfvNjOqFI19e6eGUXks0c/2ieFC4+9wJ+1g==} engines: {node: '>= 14'} - '@sentry/cli-darwin@2.33.1': - resolution: {integrity: sha512-+4/VIx/E1L2hChj5nGf5MHyEPHUNHJ/HoG5RY+B+vyEutGily1c1+DM2bum7RbD0xs6wKLIyup5F02guzSzG8A==} + '@sentry/cli-darwin@2.39.1': + resolution: {integrity: sha512-kiNGNSAkg46LNGatfNH5tfsmI/kCAaPA62KQuFZloZiemTNzhy9/6NJP8HZ/GxGs8GDMxic6wNrV9CkVEgFLJQ==} engines: {node: '>=10'} os: [darwin] - '@sentry/cli-linux-arm64@2.33.1': - resolution: {integrity: sha512-DbGV56PRKOLsAZJX27Jt2uZ11QfQEMmWB4cIvxkKcFVE+LJP4MVA+MGGRUL6p+Bs1R9ZUuGbpKGtj0JiG6CoXw==} + '@sentry/cli-linux-arm64@2.39.1': + resolution: {integrity: sha512-5VbVJDatolDrWOgaffsEM7znjs0cR8bHt9Bq0mStM3tBolgAeSDHE89NgHggfZR+DJ2VWOy4vgCwkObrUD6NQw==} engines: {node: '>=10'} cpu: [arm64] os: [linux, freebsd] - '@sentry/cli-linux-arm@2.33.1': - resolution: {integrity: sha512-zbxEvQju+tgNvzTOt635le4kS/Fbm2XC2RtYbCTs034Vb8xjrAxLnK0z1bQnStUV8BkeBHtsNVrG+NSQDym2wg==} + '@sentry/cli-linux-arm@2.39.1': + resolution: {integrity: sha512-DkENbxyRxUrfLnJLXTA4s5UL/GoctU5Cm4ER1eB7XN7p9WsamFJd/yf2KpltkjEyiTuplv0yAbdjl1KX3vKmEQ==} engines: {node: '>=10'} cpu: [arm] os: [linux, freebsd] - '@sentry/cli-linux-i686@2.33.1': - resolution: {integrity: sha512-g2LS4oPXkPWOfKWukKzYp4FnXVRRSwBxhuQ9eSw2peeb58ZIObr4YKGOA/8HJRGkooBJIKGaAR2mH2Pk1TKaiA==} + '@sentry/cli-linux-i686@2.39.1': + resolution: {integrity: sha512-pXWVoKXCRrY7N8vc9H7mETiV9ZCz+zSnX65JQCzZxgYrayQPJTc+NPRnZTdYdk5RlAupXaFicBI2GwOCRqVRkg==} engines: {node: '>=10'} cpu: [x86, ia32] os: [linux, freebsd] - '@sentry/cli-linux-x64@2.33.1': - resolution: {integrity: sha512-IV3dcYV/ZcvO+VGu9U6kuxSdbsV2kzxaBwWUQxtzxJ+cOa7J8Hn1t0koKGtU53JVZNBa06qJWIcqgl4/pCuKIg==} + '@sentry/cli-linux-x64@2.39.1': + resolution: {integrity: sha512-IwayNZy+it7FWG4M9LayyUmG1a/8kT9+/IEm67sT5+7dkMIMcpmHDqL8rWcPojOXuTKaOBBjkVdNMBTXy0mXlA==} engines: {node: '>=10'} cpu: [x64] os: [linux, freebsd] - '@sentry/cli-win32-i686@2.33.1': - resolution: {integrity: sha512-F7cJySvkpzIu7fnLKNHYwBzZYYwlhoDbAUnaFX0UZCN+5DNp/5LwTp37a5TWOsmCaHMZT4i9IO4SIsnNw16/zQ==} + '@sentry/cli-win32-i686@2.39.1': + resolution: {integrity: sha512-NglnNoqHSmE+Dz/wHeIVRnV2bLMx7tIn3IQ8vXGO5HWA2f8zYJGktbkLq1Lg23PaQmeZLPGlja3gBQfZYSG10Q==} engines: {node: '>=10'} cpu: [x86, ia32] os: [win32] - '@sentry/cli-win32-x64@2.33.1': - resolution: {integrity: sha512-8VyRoJqtb2uQ8/bFRKNuACYZt7r+Xx0k2wXRGTyH05lCjAiVIXn7DiS2BxHFty7M1QEWUCMNsb/UC/x/Cu2wuA==} + '@sentry/cli-win32-x64@2.39.1': + resolution: {integrity: sha512-xv0R2CMf/X1Fte3cMWie1NXuHmUyQPDBfCyIt6k6RPFPxAYUgcqgMPznYwVMwWEA1W43PaOkSn3d8ZylsDaETw==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@sentry/cli@2.33.1': - resolution: {integrity: sha512-dUlZ4EFh98VFRPJ+f6OW3JEYQ7VvqGNMa0AMcmvk07ePNeK/GicAWmSQE4ZfJTTl80ul6HZw1kY01fGQOQlVRA==} + '@sentry/cli@2.39.1': + resolution: {integrity: sha512-JIb3e9vh0+OmQ0KxmexMXg9oZsR/G7HMwxt5BUIKAXZ9m17Xll4ETXTRnRUBT3sf7EpNGAmlQk1xEmVN9pYZYQ==} engines: {node: '>= 10'} hasBin: true - '@sentry/core@8.26.0': - resolution: {integrity: sha512-g/tVmTZD4GNbLFf++hKJfBpcCAtduFEMLnbfa9iT/QEZjlmP+EzY+GsH9bafM5VsNe8DiOUp+kJKWtShzlVdBA==} + '@sentry/core@8.44.0': + resolution: {integrity: sha512-C43eW9Mr1WGpxCeI6pXUl7TeTwR2TwWhuU8wHx2s5eoATDQwbjz9l+JXXjVJf5YXXEwNOZL2WAx/f0diLA5rTQ==} engines: {node: '>=14.18'} - '@sentry/react@8.26.0': - resolution: {integrity: sha512-dYoC0xzcqq8zmNMFoTWidhA7mVd3RDz/nAUn6C8yK/hkKA7bUknYCkhpESGLZfHaGwSKzeXRXKd/o/cgUVM9eA==} + '@sentry/react@8.44.0': + resolution: {integrity: sha512-LGqkLC+Sf1iEMmlHTBtCpEoZgwkeXjDDjc1rQjCq/5PG04jrCgXBTTAP7UqoetrYhQLNxtrgkGXmU4CE2BnIBw==} engines: {node: '>=14.18'} peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x - '@sentry/types@8.26.0': - resolution: {integrity: sha512-zKmh6SWsJh630rpt7a9vP4Cm4m1C2gDTUqUiH565CajCL/4cePpNWYrNwalSqsOSL7B9OrczA1+n6a6XvND+ng==} - engines: {node: '>=14.18'} - - '@sentry/utils@8.26.0': - resolution: {integrity: sha512-xvlPU9Hd2BlyT+FhWHGNwnxWqdVRk2AHnDtVcW4Ma0Ri5EwS+uy4Jeik5UkSv8C5RVb9VlxFmS8LN3I1MPJsLw==} - engines: {node: '>=14.18'} - - '@sentry/vite-plugin@2.22.2': - resolution: {integrity: sha512-LJSNTw75UJq77v2jCan8cRh0w1u6W30jxQsbqF7YyyhhfjPTyFUXYday9RDDe84qDEnspbZmgeTSWTvaTGsBRg==} + '@sentry/vite-plugin@2.22.7': + resolution: {integrity: sha512-sYRNiNm4toQGq2BfZSJPdw36em3eQaLu+3NTFpA7Hl4g3Sp2Rt3CYObnW5bxlFEruRhxzvdyB383N9OefVZ6KA==} engines: {node: '>= 14'} - '@tailwindcss/forms@0.5.7': - resolution: {integrity: sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==} + '@tailwindcss/forms@0.5.9': + resolution: {integrity: sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg==} peerDependencies: - tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1' + tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20' - '@tauri-apps/api@2.0.0-beta.14': - resolution: {integrity: sha512-YLYgHqdwWswr4Y70+hRzaLD6kLIUgHhE3shLXNquPiTaQ9+cX3Q2dB0AFfqsua6NXYFNe7LfkmMzaqEzqv3yQg==} - engines: {node: '>= 18.18', npm: '>= 6.6.0', yarn: '>= 1.19.1'} + '@tauri-apps/api@2.0.2': + resolution: {integrity: sha512-3wSwmG+1kr6WrgAFKK5ijkNFPp8TT3FLj3YHUb5EwMO+3FxX4uWlfSWkeeBy+Kc1RsKzugtYLuuya+98Flj+3w==} - '@tauri-apps/cli-darwin-arm64@2.0.0-beta.21': - resolution: {integrity: sha512-okI7PRSC6RO4JfrOTqu4oWf0IfBPbkGHisyDOTay6K5uhz4zzry5fFJVa8S/DTrKtdjau4vcik/EDCxiGRun9Q==} + '@tauri-apps/cli-darwin-arm64@2.0.2': + resolution: {integrity: sha512-B+/a8Q6wAqmB4A4HVeK0oQP5TdQGKW60ZLOI9O2ktH2HPr9ETr3XkwXPuJ2uAOuGEgtRZHBgFOIgG000vMnKlg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tauri-apps/cli-darwin-x64@2.0.0-beta.21': - resolution: {integrity: sha512-mXoJDXB6CBoqUnFb4TCsSVC6FJRZsN1DHRZAyn6iNLIhOrObcM4L2xz8rzt3WirANwJ/ayrNv95fEt8Fq1jmgA==} + '@tauri-apps/cli-darwin-x64@2.0.2': + resolution: {integrity: sha512-kaurhn6XT4gAVCPAQSSHl/CHFxTS0ljc47N7iGTSlYJ03sCWPRZeNuVa/bn6rolz9MA2JfnRnFqB1pUL6jzp9Q==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tauri-apps/cli-linux-arm-gnueabihf@2.0.0-beta.21': - resolution: {integrity: sha512-LYPOx3LE2eZ0g8Zh/HYaNg6B1pZzH4BPMcma7wGZ0XPu+4fKLLGgav13xP2lknLnxiRP9jJCaTIBKXgcQEtLyg==} + '@tauri-apps/cli-linux-arm-gnueabihf@2.0.2': + resolution: {integrity: sha512-bVrofjlacMxmGMcqK18iBW05tsZXOd19/MnqruFFcHSVjvkGGIXHMtUbMXnZNXBPkHDsnfytNtkY9SZGfCFaBA==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tauri-apps/cli-linux-arm64-gnu@2.0.0-beta.21': - resolution: {integrity: sha512-VP2L729tgY889OZj5U436EntjwkI8MyVB+GrvBv8k2mj1nWB651KiVIpcUmsUgjXZ2r01bifN9J0l+3EFEXUAQ==} + '@tauri-apps/cli-linux-arm64-gnu@2.0.2': + resolution: {integrity: sha512-7XCBn0TTBVQGnV42dXcbHPLg/9W8kJoVzuliIozvNGyRWxfXqDbQYzpI48HUQG3LgHMabcw8+pVZAfGhevLrCA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tauri-apps/cli-linux-arm64-musl@2.0.0-beta.21': - resolution: {integrity: sha512-s1rV01RIdowlPHfw7hTBnCEm2C3mZbynF+xpyRSv9vSczu4dpfwILMRwxB4nzMzdJ7RPHsf/R+5Ww86e8QM4Gw==} + '@tauri-apps/cli-linux-arm64-musl@2.0.2': + resolution: {integrity: sha512-1xi2SreGVlpAL68MCsDUY63rdItUdPZreXIAcOVqvUehcJRYOa1XGSBhrV0YXRgZeh0AtKC19z6PRzcv4rosZA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tauri-apps/cli-linux-x64-gnu@2.0.0-beta.21': - resolution: {integrity: sha512-yGh7ktUycHT3mAnKxC7cx/vjcbjJzoxQCxnjWpmIayVwq+iXLD1mK7nRXRdJpL/rnBFTqqD29CKuypCEFiq3/A==} + '@tauri-apps/cli-linux-x64-gnu@2.0.2': + resolution: {integrity: sha512-WVjwYzPWFqZVg1fx6KSU5w47Q0VbMyaCp34qs5EcS8EIU0/RnofdzqUoOYqvgGVgNgoz7Pj5dXK2SkS8BHXMmA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tauri-apps/cli-linux-x64-musl@2.0.0-beta.21': - resolution: {integrity: sha512-+79b8O3tsjbGR47pJtcSKGmtqj4rsSxB5AfMb4UCkmoNkbaOzB0YS/ZieUGAb+SHXZ/MMs7mcl96N9SqYOL7hw==} + '@tauri-apps/cli-linux-x64-musl@2.0.2': + resolution: {integrity: sha512-h5miE2mctgaQNn/BbG9o1pnJcrx+VGBi2A6JFqGu934lFgSV5+s28M8Gc8AF2JgFH4hQV4IuMkeSw8Chu5Dodg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tauri-apps/cli-win32-arm64-msvc@2.0.0-beta.21': - resolution: {integrity: sha512-rKlpcjx6t1ECZciMmHT5xkXKjC+O+TVxRKmA21tEq/Ezt7XdnufGko1hduwQmVJWkHxKg6ab7uf98ImMpDC5UA==} + '@tauri-apps/cli-win32-arm64-msvc@2.0.2': + resolution: {integrity: sha512-2b8oO0+dYonahG5PfA/zoq0zlafLclfmXgqoWDZ++UiPtQHJNpNeEQ8GWbSFKGHQ494Jo6jHvazOojGRE1kqAg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tauri-apps/cli-win32-ia32-msvc@2.0.0-beta.21': - resolution: {integrity: sha512-ExdhvRfgAoZi4/7re6OkmfqsHvTJQgWouTNphHWRilUEqBM7TEQV1UxYtwWfgyOKelyx4cxUYDFAJxootTb2Nw==} + '@tauri-apps/cli-win32-ia32-msvc@2.0.2': + resolution: {integrity: sha512-axgICLunFi0To3EibdCBgbST5RocsSmtM4c04+CbcX8WQQosJ9ziWlCSrrOTRr+gJERAMSvEyVUS98f6bWMw9A==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@tauri-apps/cli-win32-x64-msvc@2.0.0-beta.21': - resolution: {integrity: sha512-JtNTwNXIOfE04Cs3ieTvkdcMyJM9Sujw5MM9zNmusJKE03s/OLqbNK/2ISlcb/puwYGGPhhyYtL5hCmYXIrHHQ==} + '@tauri-apps/cli-win32-x64-msvc@2.0.2': + resolution: {integrity: sha512-JR17cM6+DyExZRgpXr2/DdqvcFYi/EKvQt8dI5R1/uQoesWd8jeNnrU7c1FG1Zmw9+pTzDztsNqEKsrNq2sNIg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tauri-apps/cli@2.0.0-beta.21': - resolution: {integrity: sha512-lqV4pD0iTs8ASd19slH0eRoVAjbxtD0cCsZFVD7kG4sYkeZ0IkvtxbvnHAOUbALfvnHZr1dVXFDVxQUqJK2OXw==} + '@tauri-apps/cli@2.0.2': + resolution: {integrity: sha512-R4ontHZvXORArERAHIidp5zRfZEshZczTiK+poslBv7AGKpQZoMw+E49zns7mOmP64i2Cq9Ci0pJvi4Rm8Okzw==} engines: {node: '>= 10'} hasBin: true - '@tauri-apps/plugin-dialog@2.0.0-beta.6': - resolution: {integrity: sha512-Rw8C8t/0y3QExEinp+cAOZi/BDt0c9jifv0bS3WDCwQt9ANdmfCWKamsIhqwemt3MjepkU2RV8bvphzoWlbOGw==} + '@tauri-apps/plugin-dialog@2.0.0': + resolution: {integrity: sha512-ApNkejXP2jpPBSifznPPcHTXxu9/YaRW+eJ+8+nYwqp0lLUtebFHG4QhxitM43wwReHE81WAV1DQ/b+2VBftOA==} - '@tauri-apps/plugin-fs@2.0.0-beta.6': - resolution: {integrity: sha512-R7M5wggENzJhiA0HwP63AzdF6uzdXRYe0z+ETSue9gvJmqKtqVp+qx9JLsWSfwENHy8RDKmrnuDL18kx/Q2aFA==} + '@tauri-apps/plugin-fs@2.0.0': + resolution: {integrity: sha512-BNEeQQ5aH8J5SwYuWgRszVyItsmquRuzK2QRkVj8Z0sCsLnSvJFYI3JHRzzr3ltZGq1nMPtblrlZzuKqVzRawA==} - '@tauri-apps/plugin-os@2.0.0-beta.6': - resolution: {integrity: sha512-28Ts286o4YH3vZ+swptVblRMuMa1MLjLbgPpnR1wuPNzzR4p7J6+Hr3Euge71RIsFJhjAeP1XkNbHgpAFj4Mpg==} + '@tauri-apps/plugin-os@2.0.0': + resolution: {integrity: sha512-M7hG/nNyQYTJxVG/UhTKhp9mpXriwWzrs9mqDreB8mIgqA3ek5nHLdwRZJWhkKjZrnDT4v9CpA9BhYeplTlAiA==} - '@tauri-apps/plugin-shell@2.0.0-beta.7': - resolution: {integrity: sha512-oJxWbEiNRcoMM0PrePjJnjPHEAN1sbYuWaQ1QMtLPdjHsl83RLk+RpFzkL5WvtGknfiKY7T2qEthOID4br+mvg==} + '@tauri-apps/plugin-shell@2.0.0': + resolution: {integrity: sha512-OpW2+ycgJLrEoZityWeWYk+6ZWP9VyiAfbO+N/O8VfLkqyOym8kXh7odKDfINx9RAotkSGBtQM4abyKfJDkcUg==} - '@tauri-apps/plugin-store@2.0.0-beta.6': - resolution: {integrity: sha512-EBMGUYeeLoJwFbUMdj0PhS7YGih2jhYr/cCHRXZgAhaXTsXdrE7SyW5QfgcMyZH6y7u1gywiIbMIsnjABVOJ7Q==} + '@tauri-apps/plugin-store@2.0.0': + resolution: {integrity: sha512-l4xsbxAXrKGdBdYNNswrLfcRv3v1kOatdycOcVPYW+jKwkznCr1HEOrPXkPhXsZLSLyYmNXpgfOmdSZNmcykDg==} - '@tweenjs/tween.js@23.1.2': - resolution: {integrity: sha512-kMCNaZCJugWI86xiEHaY338CU5JpD0B97p1j1IKNn/Zto8PgACjQx0UxbHjmOcLl/dDOBnItwD07KmCs75pxtQ==} + '@tweenjs/tween.js@23.1.3': + resolution: {integrity: sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==} '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -942,11 +927,14 @@ packages: '@types/babel__traverse@7.20.6': resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + '@types/debounce@1.2.4': + resolution: {integrity: sha512-jBqiORIzKDOToaF63Fm//haOCHuwQuLa2202RK4MozpA6lh93eCBc+/8+wZn5OzjJt3ySdc+74SXWXB55Ewtyw==} + '@types/draco3d@1.4.10': resolution: {integrity: sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==} - '@types/estree@1.0.5': - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} '@types/file-saver@2.0.7': resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==} @@ -960,8 +948,8 @@ packages: '@types/offscreencanvas@2019.7.3': resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==} - '@types/prop-types@15.7.12': - resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} + '@types/prop-types@15.7.13': + resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} '@types/react-dom@18.3.0': resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} @@ -978,8 +966,8 @@ packages: '@types/react-reconciler@0.28.8': resolution: {integrity: sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==} - '@types/react@18.3.3': - resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} + '@types/react@18.3.11': + resolution: {integrity: sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==} '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} @@ -990,11 +978,11 @@ packages: '@types/three@0.163.0': resolution: {integrity: sha512-uIdDhsXRpQiBUkflBS/i1l3JX14fW6Ot9csed60nfbZNXHDTRsnV2xnTVwXcgbvTiboAR4IW+t+lTL5f1rqIqA==} - '@types/webxr@0.5.16': - resolution: {integrity: sha512-0E0Cl84FECtzrB4qG19TNTqpunw0F1YF0QZZnFMF6pDw1kNKJtrlTKlVB34stGIsHbZsYQ7H0tNjPfZftkHHoA==} + '@types/webxr@0.5.20': + resolution: {integrity: sha512-JGpU6qiIJQKUuVSKx1GtQnHJGxRjtfGIhzO2ilq43VZZS//f1h1Sgexbdk+Lq+7569a6EYhOWrUpIruR/1Enmg==} - '@typescript-eslint/eslint-plugin@7.13.0': - resolution: {integrity: sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==} + '@typescript-eslint/eslint-plugin@7.18.0': + resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -1004,8 +992,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@7.13.0': - resolution: {integrity: sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==} + '@typescript-eslint/parser@7.18.0': + resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1014,12 +1002,12 @@ packages: typescript: optional: true - '@typescript-eslint/scope-manager@7.13.0': - resolution: {integrity: sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==} + '@typescript-eslint/scope-manager@7.18.0': + resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/type-utils@7.13.0': - resolution: {integrity: sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==} + '@typescript-eslint/type-utils@7.18.0': + resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1028,12 +1016,12 @@ packages: typescript: optional: true - '@typescript-eslint/types@7.13.0': - resolution: {integrity: sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==} + '@typescript-eslint/types@7.18.0': + resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/typescript-estree@7.13.0': - resolution: {integrity: sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==} + '@typescript-eslint/typescript-estree@7.18.0': + resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -1041,14 +1029,14 @@ packages: typescript: optional: true - '@typescript-eslint/utils@7.13.0': - resolution: {integrity: sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==} + '@typescript-eslint/utils@7.18.0': + resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 - '@typescript-eslint/visitor-keys@7.13.0': - resolution: {integrity: sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==} + '@typescript-eslint/visitor-keys@7.18.0': + resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} engines: {node: ^18.18.0 || >=20.0.0} '@ungap/structured-clone@1.2.0': @@ -1062,8 +1050,8 @@ packages: peerDependencies: react: '>= 16.8.0' - '@vitejs/plugin-react@4.3.1': - resolution: {integrity: sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==} + '@vitejs/plugin-react@4.3.2': + resolution: {integrity: sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 @@ -1073,8 +1061,8 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.12.0: - resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==} + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} engines: {node: '>=0.4.0'} hasBin: true @@ -1085,9 +1073,9 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ansi-escapes@6.2.1: - resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} - engines: {node: '>=14.16'} + ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -1125,8 +1113,8 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - aria-query@5.3.0: - resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + aria-query@5.1.3: + resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} @@ -1163,9 +1151,6 @@ packages: resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} engines: {node: '>= 0.4'} - array.prototype.toreversed@1.1.2: - resolution: {integrity: sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==} - array.prototype.tosorted@1.1.4: resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} engines: {node: '>= 0.4'} @@ -1177,8 +1162,8 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} - autoprefixer@10.4.19: - resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} + autoprefixer@10.4.20: + resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: @@ -1192,12 +1177,13 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axe-core@4.7.0: - resolution: {integrity: sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==} + axe-core@4.10.0: + resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==} engines: {node: '>=4'} - axobject-query@3.2.1: - resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} babel-plugin-add-module-exports@1.0.4: resolution: {integrity: sha512-g+8yxHUZ60RcyaUpfNzy56OtWW+x9cyEe9j+CranqLiqbju2yf/Cy6ZtYK40EZxtrdHllzlVZgLmcOUCTlJ7Jg==} @@ -1231,8 +1217,8 @@ packages: browser-fs-access@0.35.0: resolution: {integrity: sha512-sLoadumpRfsjprP8XzVjpQc0jK8yqHBx0PtUTGYj2fftT+P/t+uyDAQdMgGAPKD011in/O+YYGh7fIs0oG/viw==} - browserslist@4.23.1: - resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==} + browserslist@4.24.0: + resolution: {integrity: sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -1261,13 +1247,13 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - camera-controls@2.8.5: - resolution: {integrity: sha512-7VTwRk7Nu1nRKsY7bEt9HVBfKt8DETvzyYhLN4OW26OByBayMDB5fUaNcPI+z++vG23RH5yqn6ZRhZcgLQy2rA==} + camera-controls@2.9.0: + resolution: {integrity: sha512-TpCujnP0vqPppTXXJRYpvIy0xq9Tro6jQf2iYUxlDpPCNxkvE/XGaTuwIxnhINOkVP/ob2CRYXtY3iVYXeMEzA==} peerDependencies: three: '>=0.126.1' - caniuse-lite@1.0.30001636: - resolution: {integrity: sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==} + caniuse-lite@1.0.30001667: + resolution: {integrity: sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==} chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} @@ -1285,12 +1271,16 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} + classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} - cli-cursor@4.0.0: - resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} cli-truncate@4.0.0: resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} @@ -1388,8 +1378,8 @@ packages: supports-color: optional: true - debug@4.3.5: - resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -1400,6 +1390,10 @@ packages: deep-equal@2.2.2: resolution: {integrity: sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==} + deep-equal@2.2.3: + resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} + engines: {node: '>= 0.4'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -1423,12 +1417,8 @@ packages: resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} engines: {node: '>=10'} - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - detect-gpu@5.0.38: - resolution: {integrity: sha512-36QeGHSXYcJ/RfrnPEScR8GDprbXFG4ZhXsfVNVHztZr38+fRxgHnJl3CjYXXjbeRUhu3ZZBJh6Lg0A9v0Qd8A==} + detect-gpu@5.0.51: + resolution: {integrity: sha512-7P+5KDthVGXXWS06EuqBIq7YBijxfaNfm+BSFNTRAkZP26J97ASssh5KoR53diWNcBNOEb1ILfdsz2pzesSgYw==} didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} @@ -1469,11 +1459,11 @@ packages: resolution: {integrity: sha512-uW2UKSsuty9ANJ3YByIQE4ANkD8nqUPO7r6Fwcc1ADKPe9FRdcPpMl3VEput4JSvKBJ4J86npIC2MLP0pYkCuw==} hasBin: true - electron-to-chromium@1.4.803: - resolution: {integrity: sha512-61H9mLzGOCLLVsnLiRzCbc63uldP0AniRYPV3hbGVtONA1pI7qSGILdbofR7A8TMbOypDocEAjH/e+9k1QIe3g==} + electron-to-chromium@1.5.34: + resolution: {integrity: sha512-/TZAiChbAflBNjCg+VvstbcwAtIL/VdMFO3NgRFIzBjpvPzWOTIbbO8kNb6RwU4bt9TP7K+3KqBKw/lOU+Y+GA==} - emoji-regex@10.3.0: - resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1484,10 +1474,14 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - enhanced-resolve@5.17.0: - resolution: {integrity: sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==} + enhanced-resolve@5.17.1: + resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} engines: {node: '>=10.13.0'} + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + es-abstract@1.23.3: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} @@ -1503,8 +1497,8 @@ packages: es-get-iterator@1.1.3: resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} - es-iterator-helpers@1.0.19: - resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} + es-iterator-helpers@1.1.0: + resolution: {integrity: sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==} engines: {node: '>= 0.4'} es-object-atoms@1.0.0: @@ -1531,8 +1525,8 @@ packages: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} - escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} escape-string-regexp@1.0.5: @@ -1563,15 +1557,21 @@ packages: eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - eslint-import-resolver-typescript@3.6.1: - resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} + eslint-import-resolver-typescript@3.6.3: + resolution: {integrity: sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '*' eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true - eslint-module-utils@2.8.1: - resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} + eslint-module-utils@2.12.0: + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -1591,21 +1591,21 @@ packages: eslint-import-resolver-webpack: optional: true - eslint-plugin-import@2.29.1: - resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} + eslint-plugin-import@2.31.0: + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 peerDependenciesMeta: '@typescript-eslint/parser': optional: true - eslint-plugin-jsx-a11y@6.8.0: - resolution: {integrity: sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==} + eslint-plugin-jsx-a11y@6.10.0: + resolution: {integrity: sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg==} engines: {node: '>=4.0'} peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 eslint-plugin-react-hooks@4.6.2: resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} @@ -1613,11 +1613,11 @@ packages: peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - eslint-plugin-react@7.34.2: - resolution: {integrity: sha512-2HCmrU+/JNigDN6tg55cRDKCQWicYAPB38JGSFDQt95jDm8rrvSUo7YPkOIm5l6ts1j1zCvysNcasvfTMQzUOw==} + eslint-plugin-react@7.37.1: + resolution: {integrity: sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==} engines: {node: '>=4'} peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 eslint-scope@7.2.2: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} @@ -1627,17 +1627,18 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -1699,8 +1700,8 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - find-babel-config@2.1.1: - resolution: {integrity: sha512-5Ji+EAysHGe1OipH7GN4qDjok5Z1uw5KAwDCbicU/4wyTZY7CqOCzcWbG7J5ad9mazq67k89fXlbc1MuIfl9uA==} + find-babel-config@2.1.2: + resolution: {integrity: sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg==} find-up@3.0.0: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} @@ -1729,8 +1730,8 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - foreground-child@3.2.1: - resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==} + foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} fraction.js@4.3.7: @@ -1785,8 +1786,8 @@ packages: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} - get-tsconfig@4.7.5: - resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} + get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -1796,9 +1797,8 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob@10.4.1: - resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==} - engines: {node: '>=16 || 14 >=14.18'} + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true glob@7.2.3: @@ -1893,8 +1893,8 @@ packages: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} - husky@9.0.11: - resolution: {integrity: sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==} + husky@9.1.6: + resolution: {integrity: sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A==} engines: {node: '>=18'} hasBin: true @@ -1904,8 +1904,8 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} immediate@3.0.6: @@ -1914,8 +1914,8 @@ packages: immer@9.0.21: resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} - immutable@4.3.6: - resolution: {integrity: sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==} + immutable@4.3.7: + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} @@ -1968,12 +1968,16 @@ packages: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} + is-bun-module@1.2.1: + resolution: {integrity: sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==} + is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} is-data-view@1.0.1: resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} @@ -2110,17 +2114,17 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - iterator.prototype@1.1.2: - resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + iterator.prototype@1.1.3: + resolution: {integrity: sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==} + engines: {node: '>= 0.4'} its-fine@1.2.5: resolution: {integrity: sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==} peerDependencies: react: '>=18.0' - jackspeak@3.4.0: - resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==} - engines: {node: '>=14'} + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} jiti@1.21.6: resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} @@ -2133,9 +2137,9 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} + jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} hasBin: true json-buffer@3.0.1: @@ -2192,13 +2196,13 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - lint-staged@15.2.7: - resolution: {integrity: sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==} + lint-staged@15.2.10: + resolution: {integrity: sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==} engines: {node: '>=18.12.0'} hasBin: true - listr2@8.2.1: - resolution: {integrity: sha512-irTfvpib/rNiD637xeevjO2l3Z5loZmuaRi0L0YE5LfijwVY96oyVn0DFD3o/teAok7nfobMG1THvvcHh/BP6g==} + listr2@8.2.5: + resolution: {integrity: sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==} engines: {node: '>=18.0.0'} locate-path@3.0.0: @@ -2215,26 +2219,25 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - log-update@6.0.0: - resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==} + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - lru-cache@10.2.2: - resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} - engines: {node: 14 || >=16.14} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - maath@0.10.7: - resolution: {integrity: sha512-zQ2xd7dNOIVTjAS+hj22fyj1EFYmOJX6tzKjZ92r6WDoq8hyFxjuGA2q950tmR4iC/EKXoMQdSipkaJVuUHDTg==} + maath@0.10.8: + resolution: {integrity: sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==} peerDependencies: - '@types/three': '>=0.144.0' - three: '>=0.144.0' + '@types/three': '>=0.134.0' + three: '>=0.134.0' magic-string@0.30.8: resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} @@ -2261,8 +2264,8 @@ packages: meshoptimizer@0.18.1: resolution: {integrity: sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==} - micromatch@4.0.7: - resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} mimic-fn@2.1.0: @@ -2273,6 +2276,10 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + mini-svg-data-uri@1.4.4: resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} hasBin: true @@ -2284,8 +2291,8 @@ packages: resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} engines: {node: '>=16 || 14 >=14.17'} - minimatch@9.0.4: - resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: @@ -2299,9 +2306,6 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2325,8 +2329,8 @@ packages: encoding: optional: true - node-releases@2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -2355,13 +2359,18 @@ packages: object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} - object-inspect@1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + engines: {node: '>= 0.4'} object-is@1.1.5: resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} engines: {node: '>= 0.4'} + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -2382,10 +2391,6 @@ packages: resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} engines: {node: '>= 0.4'} - object.hasown@1.1.4: - resolution: {integrity: sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==} - engines: {node: '>= 0.4'} - object.values@1.2.0: resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} @@ -2404,6 +2409,10 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} @@ -2432,6 +2441,9 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -2472,8 +2484,8 @@ packages: engines: {node: '>=0.10'} hasBin: true - picocolors@1.0.1: - resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + picocolors@1.1.0: + resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -2524,21 +2536,21 @@ packages: ts-node: optional: true - postcss-nested@6.0.1: - resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} engines: {node: '>=12.0'} peerDependencies: postcss: ^8.2.14 - postcss-selector-parser@6.1.0: - resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==} + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} engines: {node: '>=4'} postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.4.38: - resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + postcss@8.4.47: + resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} engines: {node: ^10 || ^12 || >=14} potpack@1.0.2: @@ -2548,8 +2560,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.3.2: - resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} + prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} hasBin: true @@ -2603,9 +2615,9 @@ packages: peerDependencies: react: '>=16.3.0' - react-hook-form@7.52.0: - resolution: {integrity: sha512-mJX506Xc6mirzLsmXUJyqlAI3Kj9Ph2RhplYhUVffeOQSnubK2uVqBFOBJmvKikvbFV91pxVXmDiR+QMF19x6A==} - engines: {node: '>=12.22.0'} + react-hook-form@7.53.0: + resolution: {integrity: sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ==} + engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 @@ -2638,15 +2650,15 @@ packages: peerDependencies: react: '>=16.8.0' - react-router-dom@6.23.1: - resolution: {integrity: sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==} + react-router-dom@6.26.2: + resolution: {integrity: sha512-z7YkaEW0Dy35T3/QKPYB1LjMK2R1fxnHO8kWpUMTBdfVzZrWOiY9a7CtN8HqdWtDUWd5FY6Dl8HFsqVwH4uOtQ==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' react-dom: '>=16.8' - react-router@6.23.1: - resolution: {integrity: sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==} + react-router@6.26.2: + resolution: {integrity: sha512-tvN1iuT03kHgOFnLPfLJ8V95eijteveqdOSk+srqfePtQvqCExB8eHOYnlilbOcyJyKnYkr1vJvf7YqotAJu1A==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' @@ -2656,12 +2668,6 @@ packages: peerDependencies: react: ^16.3.0 || ^17.0.0 || ^18.0.0 - react-use-measure@2.1.1: - resolution: {integrity: sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==} - peerDependencies: - react: '>=16.13' - react-dom: '>=16.13' - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -2673,6 +2679,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.0.2: + resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} + engines: {node: '>= 14.16.0'} + reflect.getprototypeof@1.0.6: resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} engines: {node: '>= 0.4'} @@ -2684,8 +2694,8 @@ packages: resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} engines: {node: '>= 0.4'} - regexp.prototype.flags@1.5.2: - resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + regexp.prototype.flags@1.5.3: + resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} engines: {node: '>= 0.4'} require-directory@2.1.1: @@ -2714,9 +2724,9 @@ packages: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true - restore-cursor@4.0.0: - resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} @@ -2740,8 +2750,8 @@ packages: rollup: optional: true - rollup@4.18.0: - resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} + rollup@4.24.0: + resolution: {integrity: sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2756,8 +2766,8 @@ packages: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} - sass@1.77.6: - resolution: {integrity: sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==} + sass@1.79.4: + resolution: {integrity: sha512-K0QDSNPXgyqO4GZq2HO5Q70TLxTH6cIT59RdoCHMivrC8rqzaTw5ab9prjz9KUN1El4FLXrBXJhik61JR4HcGg==} engines: {node: '>=14.0.0'} hasBin: true @@ -2771,8 +2781,8 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.6.2: - resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true @@ -2831,8 +2841,8 @@ packages: solarxr-protocol@file:solarxr-protocol: resolution: {directory: solarxr-protocol, type: directory} - source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} source-map-support@0.5.21: @@ -2855,8 +2865,8 @@ packages: spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - spdx-license-ids@3.0.18: - resolution: {integrity: sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==} + spdx-license-ids@3.0.20: + resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} spdx-ranges@2.1.1: resolution: {integrity: sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==} @@ -2886,14 +2896,20 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} - string-width@7.1.0: - resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} + string.prototype.includes@2.0.0: + resolution: {integrity: sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==} + string.prototype.matchall@4.0.11: resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} engines: {node: '>= 0.4'} + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + string.prototype.trim@1.2.9: resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} @@ -2954,8 +2970,8 @@ packages: tailwind-gradient-mask-image@1.2.0: resolution: {integrity: sha512-tUJaGhvqbJFiVKJu6EU5n//KvGdVvY3L3VOFNqjztk13+ifAk00pcSNHBTgHfUiBGOEzDn0gFRbSmsftUV1lXA==} - tailwindcss@3.4.4: - resolution: {integrity: sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==} + tailwindcss@3.4.13: + resolution: {integrity: sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==} engines: {node: '>=14.0.0'} hasBin: true @@ -2978,13 +2994,14 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - three-mesh-bvh@0.7.5: - resolution: {integrity: sha512-WDd77RklE52pZSKZx8sDXzrd2JCF/gL/hugFvsIBylpMRlJxxwesKn2rW7TcQZ809NocDVkQx1UJo9pJtVAPYg==} + three-mesh-bvh@0.7.8: + resolution: {integrity: sha512-BGEZTOIC14U0XIRw3tO4jY7IjP7n7v24nv9JXS1CyeVRWOCkcOMhRnmENUjuV39gktAw4Ofhr0OvIAiTspQrrw==} + deprecated: Deprecated due to three.js version incompatibility. Please use v0.8.0, instead. peerDependencies: three: '>= 0.151.0' - three-stdlib@2.30.3: - resolution: {integrity: sha512-rYr8PqMljMza+Ct8kQk90Y7y+YcWoPu1thfYv5YGCp0hytNRbxSQWXY4GpdTGymCj3bDggEBpxso53C3pPwhIw==} + three-stdlib@2.33.0: + resolution: {integrity: sha512-V/uycBuqQOP/3Z+FBtpMdj2Ds5PyfJ3VDfMzktEmG4niOIzv7q1y5uMSbMcng0+057m1l0N147FQxsodQo9zBg==} peerDependencies: three: '>=0.128.0' @@ -3034,14 +3051,14 @@ packages: peerDependencies: typescript: '>=2.7' - ts-pattern@5.2.0: - resolution: {integrity: sha512-aGaSpOlDcns7ZoeG/OMftWyQG1KqPVhgplhJxNCvyIXqWrumM5uIoOSarw/hmmi/T1PnuQ/uD8NaFHvLpHicDg==} + ts-pattern@5.4.0: + resolution: {integrity: sha512-hgfOMfjlrARCnYtGD/xEAkFHDXuSyuqjzFSltyQCbN689uNvoQL20TVN2XFcLMjfNuwSsQGU+xtH6MrjIwhwUg==} tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - tslib@2.6.3: - resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} tunnel-rat@0.1.2: resolution: {integrity: sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==} @@ -3075,8 +3092,8 @@ packages: engines: {node: '>=4.2.0'} hasBin: true - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} hasBin: true @@ -3089,8 +3106,8 @@ packages: unplugin@1.0.1: resolution: {integrity: sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==} - update-browserslist-db@1.0.16: - resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} + update-browserslist-db@1.1.1: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -3098,8 +3115,13 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - use-sync-external-store@1.2.0: - resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + use-double-tap@1.3.6: + resolution: {integrity: sha512-zWmzlihSTuLJpT+YJqhVUySV8UNvmdmaXokBEIh+FxR4m/vaSk2cS5hlqEPDj64rmkHlL7zfRTrJPw30Jd0OZA==} + peerDependencies: + react: '>=16.8.0' + + use-sync-external-store@1.2.2: + resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -3114,8 +3136,8 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - vite@5.3.1: - resolution: {integrity: sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==} + vite@5.4.8: + resolution: {integrity: sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -3123,6 +3145,7 @@ packages: less: '*' lightningcss: ^1.21.0 sass: '*' + sass-embedded: '*' stylus: '*' sugarss: '*' terser: ^5.4.0 @@ -3135,6 +3158,8 @@ packages: optional: true sass: optional: true + sass-embedded: + optional: true stylus: optional: true sugarss: @@ -3167,8 +3192,8 @@ packages: which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - which-builtin-type@1.1.3: - resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + which-builtin-type@1.1.4: + resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==} engines: {node: '>= 0.4'} which-collection@1.0.1: @@ -3217,8 +3242,8 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.4.5: - resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==} + yaml@2.5.1: + resolution: {integrity: sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==} engines: {node: '>= 14'} hasBin: true @@ -3255,8 +3280,8 @@ packages: react: optional: true - zustand@4.5.2: - resolution: {integrity: sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==} + zustand@4.5.5: + resolution: {integrity: sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==} engines: {node: '>=12.7.0'} peerDependencies: '@types/react': '>=16.8' @@ -3279,153 +3304,132 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@babel/code-frame@7.24.7': + '@babel/code-frame@7.25.7': dependencies: - '@babel/highlight': 7.24.7 - picocolors: 1.0.1 + '@babel/highlight': 7.25.7 + picocolors: 1.1.0 - '@babel/compat-data@7.24.7': {} + '@babel/compat-data@7.25.7': {} - '@babel/core@7.24.7': + '@babel/core@7.25.7': dependencies: '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.24.7 - '@babel/generator': 7.24.7 - '@babel/helper-compilation-targets': 7.24.7 - '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) - '@babel/helpers': 7.24.7 - '@babel/parser': 7.24.7 - '@babel/template': 7.24.7 - '@babel/traverse': 7.24.7 - '@babel/types': 7.24.7 + '@babel/code-frame': 7.25.7 + '@babel/generator': 7.25.7 + '@babel/helper-compilation-targets': 7.25.7 + '@babel/helper-module-transforms': 7.25.7(@babel/core@7.25.7) + '@babel/helpers': 7.25.7 + '@babel/parser': 7.25.7 + '@babel/template': 7.25.7 + '@babel/traverse': 7.25.7 + '@babel/types': 7.25.7 convert-source-map: 2.0.0 - debug: 4.3.5 + debug: 4.3.7 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/generator@7.24.7': + '@babel/generator@7.25.7': dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.25.7 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - jsesc: 2.5.2 + jsesc: 3.0.2 - '@babel/helper-compilation-targets@7.24.7': + '@babel/helper-compilation-targets@7.25.7': dependencies: - '@babel/compat-data': 7.24.7 - '@babel/helper-validator-option': 7.24.7 - browserslist: 4.23.1 + '@babel/compat-data': 7.25.7 + '@babel/helper-validator-option': 7.25.7 + browserslist: 4.24.0 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-environment-visitor@7.24.7': + '@babel/helper-module-imports@7.25.7': dependencies: - '@babel/types': 7.24.7 - - '@babel/helper-function-name@7.24.7': - dependencies: - '@babel/template': 7.24.7 - '@babel/types': 7.24.7 - - '@babel/helper-hoist-variables@7.24.7': - dependencies: - '@babel/types': 7.24.7 - - '@babel/helper-module-imports@7.24.7': - dependencies: - '@babel/traverse': 7.24.7 - '@babel/types': 7.24.7 + '@babel/traverse': 7.25.7 + '@babel/types': 7.25.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7)': + '@babel/helper-module-transforms@7.25.7(@babel/core@7.25.7)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-simple-access': 7.24.7 - '@babel/helper-split-export-declaration': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 + '@babel/core': 7.25.7 + '@babel/helper-module-imports': 7.25.7 + '@babel/helper-simple-access': 7.25.7 + '@babel/helper-validator-identifier': 7.25.7 + '@babel/traverse': 7.25.7 transitivePeerDependencies: - supports-color - '@babel/helper-plugin-utils@7.24.7': {} + '@babel/helper-plugin-utils@7.25.7': {} - '@babel/helper-simple-access@7.24.7': + '@babel/helper-simple-access@7.25.7': dependencies: - '@babel/traverse': 7.24.7 - '@babel/types': 7.24.7 + '@babel/traverse': 7.25.7 + '@babel/types': 7.25.7 transitivePeerDependencies: - supports-color - '@babel/helper-split-export-declaration@7.24.7': + '@babel/helper-string-parser@7.25.7': {} + + '@babel/helper-validator-identifier@7.25.7': {} + + '@babel/helper-validator-option@7.25.7': {} + + '@babel/helpers@7.25.7': dependencies: - '@babel/types': 7.24.7 + '@babel/template': 7.25.7 + '@babel/types': 7.25.7 - '@babel/helper-string-parser@7.24.7': {} - - '@babel/helper-validator-identifier@7.24.7': {} - - '@babel/helper-validator-option@7.24.7': {} - - '@babel/helpers@7.24.7': + '@babel/highlight@7.25.7': dependencies: - '@babel/template': 7.24.7 - '@babel/types': 7.24.7 - - '@babel/highlight@7.24.7': - dependencies: - '@babel/helper-validator-identifier': 7.24.7 + '@babel/helper-validator-identifier': 7.25.7 chalk: 2.4.2 js-tokens: 4.0.0 - picocolors: 1.0.1 + picocolors: 1.1.0 - '@babel/parser@7.24.7': + '@babel/parser@7.25.7': dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.25.7 - '@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.24.7)': + '@babel/plugin-transform-react-jsx-self@7.25.7(@babel/core@7.25.7)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.25.7 + '@babel/helper-plugin-utils': 7.25.7 - '@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.24.7)': + '@babel/plugin-transform-react-jsx-source@7.25.7(@babel/core@7.25.7)': dependencies: - '@babel/core': 7.24.7 - '@babel/helper-plugin-utils': 7.24.7 + '@babel/core': 7.25.7 + '@babel/helper-plugin-utils': 7.25.7 - '@babel/runtime@7.24.7': + '@babel/runtime@7.25.7': dependencies: regenerator-runtime: 0.14.1 - '@babel/template@7.24.7': + '@babel/template@7.25.7': dependencies: - '@babel/code-frame': 7.24.7 - '@babel/parser': 7.24.7 - '@babel/types': 7.24.7 + '@babel/code-frame': 7.25.7 + '@babel/parser': 7.25.7 + '@babel/types': 7.25.7 - '@babel/traverse@7.24.7': + '@babel/traverse@7.25.7': dependencies: - '@babel/code-frame': 7.24.7 - '@babel/generator': 7.24.7 - '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-function-name': 7.24.7 - '@babel/helper-hoist-variables': 7.24.7 - '@babel/helper-split-export-declaration': 7.24.7 - '@babel/parser': 7.24.7 - '@babel/types': 7.24.7 - debug: 4.3.5 + '@babel/code-frame': 7.25.7 + '@babel/generator': 7.25.7 + '@babel/parser': 7.25.7 + '@babel/template': 7.25.7 + '@babel/types': 7.25.7 + debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/types@7.24.7': + '@babel/types@7.25.7': dependencies: - '@babel/helper-string-parser': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 + '@babel/helper-string-parser': 7.25.7 + '@babel/helper-validator-identifier': 7.25.7 to-fast-properties: 2.0.0 '@dword-design/dedent@0.7.0': @@ -3440,7 +3444,7 @@ snapshots: '@dword-design/eslint-plugin-import-alias@4.0.9': dependencies: - '@babel/core': 7.24.7 + '@babel/core': 7.25.7 '@dword-design/functions': 5.0.27 babel-plugin-module-resolver: 5.0.2 deepmerge: 4.3.1 @@ -3524,20 +3528,20 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.1)': dependencies: - eslint: 8.57.0 + eslint: 8.57.1 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.10.1': {} + '@eslint-community/regexpp@4.11.1': {} '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.5 + debug: 4.3.7 espree: 9.6.1 globals: 13.24.0 - ignore: 5.3.1 + ignore: 5.3.2 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -3545,7 +3549,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.57.0': {} + '@eslint/js@8.57.1': {} '@fluent/bundle@0.18.0': {} @@ -3560,16 +3564,16 @@ snapshots: dependencies: '@fluent/bundle': 0.18.0 - '@fontsource/poppins@5.0.14': {} + '@fontsource/poppins@5.1.0': {} '@formatjs/intl-localematcher@0.2.32': dependencies: - tslib: 2.6.3 + tslib: 2.7.0 - '@humanwhocodes/config-array@0.11.14': + '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.5 + debug: 4.3.7 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -3590,7 +3594,7 @@ snapshots: '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.2': {} @@ -3603,12 +3607,12 @@ snapshots: '@jridgewell/trace-mapping': 0.3.25 optional: true - '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.5.0': {} '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@mediapipe/tasks-vision@0.10.8': {} @@ -3624,7 +3628,7 @@ snapshots: typescript: 4.8.4 yargs: 16.2.0 - '@monogrid/gainmap-js@3.0.5(three@0.163.0)': + '@monogrid/gainmap-js@3.0.6(three@0.163.0)': dependencies: promise-worker-transferable: 1.0.4 three: 0.163.0 @@ -3641,6 +3645,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 + '@nolyfill/is-core-module@1.0.39': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -3666,32 +3672,32 @@ snapshots: '@react-spring/types': 9.6.1 react: 18.3.1 - '@react-spring/three@9.6.1(@react-three/fiber@8.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(react@18.3.1)(three@0.163.0)': + '@react-spring/three@9.6.1(@react-three/fiber@8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(react@18.3.1)(three@0.163.0)': dependencies: '@react-spring/animated': 9.6.1(react@18.3.1) '@react-spring/core': 9.6.1(react@18.3.1) '@react-spring/shared': 9.6.1(react@18.3.1) '@react-spring/types': 9.6.1 - '@react-three/fiber': 8.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) + '@react-three/fiber': 8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) react: 18.3.1 three: 0.163.0 '@react-spring/types@9.6.1': {} - '@react-three/drei@9.107.0(@react-three/fiber@8.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(@types/react@18.3.3)(@types/three@0.163.0)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0)': + '@react-three/drei@9.114.3(@react-three/fiber@8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(@types/react@18.3.11)(@types/three@0.163.0)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.7 '@mediapipe/tasks-vision': 0.10.8 - '@monogrid/gainmap-js': 3.0.5(three@0.163.0) - '@react-spring/three': 9.6.1(@react-three/fiber@8.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(react@18.3.1)(three@0.163.0) - '@react-three/fiber': 8.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) + '@monogrid/gainmap-js': 3.0.6(three@0.163.0) + '@react-spring/three': 9.6.1(@react-three/fiber@8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(react@18.3.1)(three@0.163.0) + '@react-three/fiber': 8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) '@use-gesture/react': 10.3.1(react@18.3.1) - camera-controls: 2.8.5(three@0.163.0) + camera-controls: 2.9.0(three@0.163.0) cross-env: 7.0.3 - detect-gpu: 5.0.38 + detect-gpu: 5.0.51 glsl-noise: 0.0.0 hls.js: 1.3.5 - maath: 0.10.7(@types/three@0.163.0)(three@0.163.0) + maath: 0.10.8(@types/three@0.163.0)(three@0.163.0) meshline: 3.3.1(three@0.163.0) react: 18.3.1 react-composer: 5.0.3(react@18.3.1) @@ -3699,10 +3705,10 @@ snapshots: stats.js: 0.17.0 suspend-react: 0.1.3(react@18.3.1) three: 0.163.0 - three-mesh-bvh: 0.7.5(three@0.163.0) - three-stdlib: 2.30.3(three@0.163.0) + three-mesh-bvh: 0.7.8(three@0.163.0) + three-stdlib: 2.33.0(three@0.163.0) troika-three-text: 0.49.1(three@0.163.0) - tunnel-rat: 0.1.2(@types/react@18.3.3)(immer@9.0.21)(react@18.3.1) + tunnel-rat: 0.1.2(@types/react@18.3.11)(immer@9.0.21)(react@18.3.1) utility-types: 3.11.0 uuid: 9.0.1 zustand: 3.7.2(react@18.3.1) @@ -3713,17 +3719,18 @@ snapshots: - '@types/three' - immer - '@react-three/fiber@8.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0)': + '@react-three/fiber@8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0)': dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.7 + '@types/debounce': 1.2.4 '@types/react-reconciler': 0.26.7 - '@types/webxr': 0.5.16 + '@types/webxr': 0.5.20 base64-js: 1.5.1 buffer: 6.0.3 + debounce: 1.2.1 its-fine: 1.2.5(react@18.3.1) react: 18.3.1 react-reconciler: 0.27.0(react@18.3.1) - react-use-measure: 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) scheduler: 0.21.0 suspend-react: 0.1.3(react@18.3.1) three: 0.163.0 @@ -3731,99 +3738,91 @@ snapshots: optionalDependencies: react-dom: 18.3.1(react@18.3.1) - '@remix-run/router@1.16.1': {} + '@remix-run/router@1.19.2': {} - '@rollup/rollup-android-arm-eabi@4.18.0': + '@rollup/rollup-android-arm-eabi@4.24.0': optional: true - '@rollup/rollup-android-arm64@4.18.0': + '@rollup/rollup-android-arm64@4.24.0': optional: true - '@rollup/rollup-darwin-arm64@4.18.0': + '@rollup/rollup-darwin-arm64@4.24.0': optional: true - '@rollup/rollup-darwin-x64@4.18.0': + '@rollup/rollup-darwin-x64@4.24.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.18.0': + '@rollup/rollup-linux-arm-gnueabihf@4.24.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.18.0': + '@rollup/rollup-linux-arm-musleabihf@4.24.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.18.0': + '@rollup/rollup-linux-arm64-gnu@4.24.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.18.0': + '@rollup/rollup-linux-arm64-musl@4.24.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.18.0': + '@rollup/rollup-linux-riscv64-gnu@4.24.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.18.0': + '@rollup/rollup-linux-s390x-gnu@4.24.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.18.0': + '@rollup/rollup-linux-x64-gnu@4.24.0': optional: true - '@rollup/rollup-linux-x64-musl@4.18.0': + '@rollup/rollup-linux-x64-musl@4.24.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.18.0': + '@rollup/rollup-win32-arm64-msvc@4.24.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.18.0': + '@rollup/rollup-win32-ia32-msvc@4.24.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.18.0': + '@rollup/rollup-win32-x64-msvc@4.24.0': optional: true - '@sentry-internal/browser-utils@8.26.0': + '@rtsao/scc@1.1.0': {} + + '@sentry-internal/browser-utils@8.44.0': dependencies: - '@sentry/core': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@sentry/core': 8.44.0 - '@sentry-internal/feedback@8.26.0': + '@sentry-internal/feedback@8.44.0': dependencies: - '@sentry/core': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@sentry/core': 8.44.0 - '@sentry-internal/replay-canvas@8.26.0': + '@sentry-internal/replay-canvas@8.44.0': dependencies: - '@sentry-internal/replay': 8.26.0 - '@sentry/core': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@sentry-internal/replay': 8.44.0 + '@sentry/core': 8.44.0 - '@sentry-internal/replay@8.26.0': + '@sentry-internal/replay@8.44.0': dependencies: - '@sentry-internal/browser-utils': 8.26.0 - '@sentry/core': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@sentry-internal/browser-utils': 8.44.0 + '@sentry/core': 8.44.0 - '@sentry/babel-plugin-component-annotate@2.22.2': {} + '@sentry/babel-plugin-component-annotate@2.22.7': {} - '@sentry/browser@8.26.0': + '@sentry/browser@8.44.0': dependencies: - '@sentry-internal/browser-utils': 8.26.0 - '@sentry-internal/feedback': 8.26.0 - '@sentry-internal/replay': 8.26.0 - '@sentry-internal/replay-canvas': 8.26.0 - '@sentry/core': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@sentry-internal/browser-utils': 8.44.0 + '@sentry-internal/feedback': 8.44.0 + '@sentry-internal/replay': 8.44.0 + '@sentry-internal/replay-canvas': 8.44.0 + '@sentry/core': 8.44.0 - '@sentry/bundler-plugin-core@2.22.2': + '@sentry/bundler-plugin-core@2.22.7': dependencies: - '@babel/core': 7.24.7 - '@sentry/babel-plugin-component-annotate': 2.22.2 - '@sentry/cli': 2.33.1 + '@babel/core': 7.25.7 + '@sentry/babel-plugin-component-annotate': 2.22.7 + '@sentry/cli': 2.39.1 dotenv: 16.4.5 find-up: 5.0.0 glob: 9.3.5 @@ -3833,28 +3832,28 @@ snapshots: - encoding - supports-color - '@sentry/cli-darwin@2.33.1': + '@sentry/cli-darwin@2.39.1': optional: true - '@sentry/cli-linux-arm64@2.33.1': + '@sentry/cli-linux-arm64@2.39.1': optional: true - '@sentry/cli-linux-arm@2.33.1': + '@sentry/cli-linux-arm@2.39.1': optional: true - '@sentry/cli-linux-i686@2.33.1': + '@sentry/cli-linux-i686@2.39.1': optional: true - '@sentry/cli-linux-x64@2.33.1': + '@sentry/cli-linux-x64@2.39.1': optional: true - '@sentry/cli-win32-i686@2.33.1': + '@sentry/cli-win32-i686@2.39.1': optional: true - '@sentry/cli-win32-x64@2.33.1': + '@sentry/cli-win32-x64@2.39.1': optional: true - '@sentry/cli@2.33.1': + '@sentry/cli@2.39.1': dependencies: https-proxy-agent: 5.0.1 node-fetch: 2.7.0 @@ -3862,141 +3861,132 @@ snapshots: proxy-from-env: 1.1.0 which: 2.0.2 optionalDependencies: - '@sentry/cli-darwin': 2.33.1 - '@sentry/cli-linux-arm': 2.33.1 - '@sentry/cli-linux-arm64': 2.33.1 - '@sentry/cli-linux-i686': 2.33.1 - '@sentry/cli-linux-x64': 2.33.1 - '@sentry/cli-win32-i686': 2.33.1 - '@sentry/cli-win32-x64': 2.33.1 + '@sentry/cli-darwin': 2.39.1 + '@sentry/cli-linux-arm': 2.39.1 + '@sentry/cli-linux-arm64': 2.39.1 + '@sentry/cli-linux-i686': 2.39.1 + '@sentry/cli-linux-x64': 2.39.1 + '@sentry/cli-win32-i686': 2.39.1 + '@sentry/cli-win32-x64': 2.39.1 transitivePeerDependencies: - encoding - supports-color - '@sentry/core@8.26.0': - dependencies: - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@sentry/core@8.44.0': {} - '@sentry/react@8.26.0(react@18.3.1)': + '@sentry/react@8.44.0(react@18.3.1)': dependencies: - '@sentry/browser': 8.26.0 - '@sentry/core': 8.26.0 - '@sentry/types': 8.26.0 - '@sentry/utils': 8.26.0 + '@sentry/browser': 8.44.0 + '@sentry/core': 8.44.0 hoist-non-react-statics: 3.3.2 react: 18.3.1 - '@sentry/types@8.26.0': {} - - '@sentry/utils@8.26.0': + '@sentry/vite-plugin@2.22.7': dependencies: - '@sentry/types': 8.26.0 - - '@sentry/vite-plugin@2.22.2': - dependencies: - '@sentry/bundler-plugin-core': 2.22.2 + '@sentry/bundler-plugin-core': 2.22.7 unplugin: 1.0.1 transitivePeerDependencies: - encoding - supports-color - '@tailwindcss/forms@0.5.7(tailwindcss@3.4.4(ts-node@9.1.1(typescript@5.4.5)))': + '@tailwindcss/forms@0.5.9(tailwindcss@3.4.13(ts-node@9.1.1(typescript@5.6.3)))': dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 3.4.4(ts-node@9.1.1(typescript@5.4.5)) + tailwindcss: 3.4.13(ts-node@9.1.1(typescript@5.6.3)) - '@tauri-apps/api@2.0.0-beta.14': {} + '@tauri-apps/api@2.0.2': {} - '@tauri-apps/cli-darwin-arm64@2.0.0-beta.21': + '@tauri-apps/cli-darwin-arm64@2.0.2': optional: true - '@tauri-apps/cli-darwin-x64@2.0.0-beta.21': + '@tauri-apps/cli-darwin-x64@2.0.2': optional: true - '@tauri-apps/cli-linux-arm-gnueabihf@2.0.0-beta.21': + '@tauri-apps/cli-linux-arm-gnueabihf@2.0.2': optional: true - '@tauri-apps/cli-linux-arm64-gnu@2.0.0-beta.21': + '@tauri-apps/cli-linux-arm64-gnu@2.0.2': optional: true - '@tauri-apps/cli-linux-arm64-musl@2.0.0-beta.21': + '@tauri-apps/cli-linux-arm64-musl@2.0.2': optional: true - '@tauri-apps/cli-linux-x64-gnu@2.0.0-beta.21': + '@tauri-apps/cli-linux-x64-gnu@2.0.2': optional: true - '@tauri-apps/cli-linux-x64-musl@2.0.0-beta.21': + '@tauri-apps/cli-linux-x64-musl@2.0.2': optional: true - '@tauri-apps/cli-win32-arm64-msvc@2.0.0-beta.21': + '@tauri-apps/cli-win32-arm64-msvc@2.0.2': optional: true - '@tauri-apps/cli-win32-ia32-msvc@2.0.0-beta.21': + '@tauri-apps/cli-win32-ia32-msvc@2.0.2': optional: true - '@tauri-apps/cli-win32-x64-msvc@2.0.0-beta.21': + '@tauri-apps/cli-win32-x64-msvc@2.0.2': optional: true - '@tauri-apps/cli@2.0.0-beta.21': + '@tauri-apps/cli@2.0.2': optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.0.0-beta.21 - '@tauri-apps/cli-darwin-x64': 2.0.0-beta.21 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.0.0-beta.21 - '@tauri-apps/cli-linux-arm64-gnu': 2.0.0-beta.21 - '@tauri-apps/cli-linux-arm64-musl': 2.0.0-beta.21 - '@tauri-apps/cli-linux-x64-gnu': 2.0.0-beta.21 - '@tauri-apps/cli-linux-x64-musl': 2.0.0-beta.21 - '@tauri-apps/cli-win32-arm64-msvc': 2.0.0-beta.21 - '@tauri-apps/cli-win32-ia32-msvc': 2.0.0-beta.21 - '@tauri-apps/cli-win32-x64-msvc': 2.0.0-beta.21 + '@tauri-apps/cli-darwin-arm64': 2.0.2 + '@tauri-apps/cli-darwin-x64': 2.0.2 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.0.2 + '@tauri-apps/cli-linux-arm64-gnu': 2.0.2 + '@tauri-apps/cli-linux-arm64-musl': 2.0.2 + '@tauri-apps/cli-linux-x64-gnu': 2.0.2 + '@tauri-apps/cli-linux-x64-musl': 2.0.2 + '@tauri-apps/cli-win32-arm64-msvc': 2.0.2 + '@tauri-apps/cli-win32-ia32-msvc': 2.0.2 + '@tauri-apps/cli-win32-x64-msvc': 2.0.2 - '@tauri-apps/plugin-dialog@2.0.0-beta.6': + '@tauri-apps/plugin-dialog@2.0.0': dependencies: - '@tauri-apps/api': 2.0.0-beta.14 + '@tauri-apps/api': 2.0.2 - '@tauri-apps/plugin-fs@2.0.0-beta.6': + '@tauri-apps/plugin-fs@2.0.0': dependencies: - '@tauri-apps/api': 2.0.0-beta.14 + '@tauri-apps/api': 2.0.2 - '@tauri-apps/plugin-os@2.0.0-beta.6': + '@tauri-apps/plugin-os@2.0.0': dependencies: - '@tauri-apps/api': 2.0.0-beta.14 + '@tauri-apps/api': 2.0.2 - '@tauri-apps/plugin-shell@2.0.0-beta.7': + '@tauri-apps/plugin-shell@2.0.0': dependencies: - '@tauri-apps/api': 2.0.0-beta.14 + '@tauri-apps/api': 2.0.2 - '@tauri-apps/plugin-store@2.0.0-beta.6': + '@tauri-apps/plugin-store@2.0.0': dependencies: - '@tauri-apps/api': 2.0.0-beta.14 + '@tauri-apps/api': 2.0.2 - '@tweenjs/tween.js@23.1.2': {} + '@tweenjs/tween.js@23.1.3': {} '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.24.7 - '@babel/types': 7.24.7 + '@babel/parser': 7.25.7 + '@babel/types': 7.25.7 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.6 '@types/babel__generator@7.6.8': dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.25.7 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.24.7 - '@babel/types': 7.24.7 + '@babel/parser': 7.25.7 + '@babel/types': 7.25.7 '@types/babel__traverse@7.20.6': dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.25.7 + + '@types/debounce@1.2.4': {} '@types/draco3d@1.4.10': {} - '@types/estree@1.0.5': {} + '@types/estree@1.0.6': {} '@types/file-saver@2.0.7': {} @@ -4009,31 +3999,31 @@ snapshots: '@types/offscreencanvas@2019.7.3': {} - '@types/prop-types@15.7.12': {} + '@types/prop-types@15.7.13': {} '@types/react-dom@18.3.0': dependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.11 '@types/react-helmet@6.1.11': dependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.11 '@types/react-modal@3.16.3': dependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.11 '@types/react-reconciler@0.26.7': dependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.11 '@types/react-reconciler@0.28.8': dependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.11 - '@types/react@18.3.3': + '@types/react@18.3.11': dependencies: - '@types/prop-types': 15.7.12 + '@types/prop-types': 15.7.13 csstype: 3.1.3 '@types/semver@7.5.8': {} @@ -4042,93 +4032,93 @@ snapshots: '@types/three@0.163.0': dependencies: - '@tweenjs/tween.js': 23.1.2 + '@tweenjs/tween.js': 23.1.3 '@types/stats.js': 0.17.3 - '@types/webxr': 0.5.16 + '@types/webxr': 0.5.20 fflate: 0.8.2 meshoptimizer: 0.18.1 - '@types/webxr@0.5.16': {} + '@types/webxr@0.5.20': {} - '@typescript-eslint/eslint-plugin@7.13.0(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@eslint-community/regexpp': 4.10.1 - '@typescript-eslint/parser': 7.13.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/type-utils': 7.13.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.13.0 - eslint: 8.57.0 + '@eslint-community/regexpp': 4.11.1 + '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/type-utils': 7.18.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 7.18.0 + eslint: 8.57.1 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.13.0 - debug: 4.3.5 - eslint: 8.57.0 + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 7.18.0 + debug: 4.3.7 + eslint: 8.57.1 optionalDependencies: - typescript: 5.4.5 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@7.13.0': + '@typescript-eslint/scope-manager@7.18.0': dependencies: - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/visitor-keys': 7.13.0 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/visitor-keys': 7.18.0 - '@typescript-eslint/type-utils@7.13.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/type-utils@7.18.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@8.57.0)(typescript@5.4.5) - debug: 4.3.5 - eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) + '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.6.3) + debug: 4.3.7 + eslint: 8.57.1 + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@7.13.0': {} + '@typescript-eslint/types@7.18.0': {} - '@typescript-eslint/typescript-estree@7.13.0(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@7.18.0(typescript@5.6.3)': dependencies: - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/visitor-keys': 7.13.0 - debug: 4.3.5 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/visitor-keys': 7.18.0 + debug: 4.3.7 globby: 11.1.0 is-glob: 4.0.3 - minimatch: 9.0.4 - semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.4.5) + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.4.5 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@7.13.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/utils@7.18.0(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - eslint: 8.57.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) + eslint: 8.57.1 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/visitor-keys@7.13.0': + '@typescript-eslint/visitor-keys@7.18.0': dependencies: - '@typescript-eslint/types': 7.13.0 + '@typescript-eslint/types': 7.18.0 eslint-visitor-keys: 3.4.3 '@ungap/structured-clone@1.2.0': {} @@ -4140,26 +4130,26 @@ snapshots: '@use-gesture/core': 10.3.1 react: 18.3.1 - '@vitejs/plugin-react@4.3.1(vite@5.3.1(@types/node@20.14.2)(sass@1.77.6)(terser@5.31.1))': + '@vitejs/plugin-react@4.3.2(vite@5.4.8(@types/node@20.14.2)(sass@1.79.4)(terser@5.31.1))': dependencies: - '@babel/core': 7.24.7 - '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.24.7) - '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.24.7) + '@babel/core': 7.25.7 + '@babel/plugin-transform-react-jsx-self': 7.25.7(@babel/core@7.25.7) + '@babel/plugin-transform-react-jsx-source': 7.25.7(@babel/core@7.25.7) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.3.1(@types/node@20.14.2)(sass@1.77.6)(terser@5.31.1) + vite: 5.4.8(@types/node@20.14.2)(sass@1.79.4)(terser@5.31.1) transitivePeerDependencies: - supports-color - acorn-jsx@5.3.2(acorn@8.12.0): + acorn-jsx@5.3.2(acorn@8.12.1): dependencies: - acorn: 8.12.0 + acorn: 8.12.1 - acorn@8.12.0: {} + acorn@8.12.1: {} agent-base@6.0.2: dependencies: - debug: 4.3.5 + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -4170,7 +4160,9 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ansi-escapes@6.2.1: {} + ansi-escapes@7.0.0: + dependencies: + environment: 1.1.0 ansi-regex@5.0.1: {} @@ -4199,9 +4191,9 @@ snapshots: argparse@2.0.1: {} - aria-query@5.3.0: + aria-query@5.1.3: dependencies: - dequal: 2.0.3 + deep-equal: 2.2.3 array-buffer-byte-length@1.0.0: dependencies: @@ -4258,13 +4250,6 @@ snapshots: es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 - array.prototype.toreversed@1.1.2: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-shim-unscopables: 1.0.2 - array.prototype.tosorted@1.1.4: dependencies: call-bind: 1.0.7 @@ -4286,14 +4271,14 @@ snapshots: ast-types-flow@0.0.8: {} - autoprefixer@10.4.19(postcss@8.4.38): + autoprefixer@10.4.20(postcss@8.4.47): dependencies: - browserslist: 4.23.1 - caniuse-lite: 1.0.30001636 + browserslist: 4.24.0 + caniuse-lite: 1.0.30001667 fraction.js: 4.3.7 normalize-range: 0.1.2 - picocolors: 1.0.1 - postcss: 8.4.38 + picocolors: 1.1.0 + postcss: 8.4.47 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.5: {} @@ -4302,17 +4287,15 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 - axe-core@4.7.0: {} + axe-core@4.10.0: {} - axobject-query@3.2.1: - dependencies: - dequal: 2.0.3 + axobject-query@4.1.0: {} babel-plugin-add-module-exports@1.0.4: {} babel-plugin-module-resolver@5.0.2: dependencies: - find-babel-config: 2.1.1 + find-babel-config: 2.1.2 glob: 9.3.5 pkg-up: 3.1.0 reselect: 4.1.8 @@ -4343,12 +4326,12 @@ snapshots: browser-fs-access@0.35.0: {} - browserslist@4.23.1: + browserslist@4.24.0: dependencies: - caniuse-lite: 1.0.30001636 - electron-to-chromium: 1.4.803 - node-releases: 2.0.14 - update-browserslist-db: 1.0.16(browserslist@4.23.1) + caniuse-lite: 1.0.30001667 + electron-to-chromium: 1.5.34 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.0) buffer-from@1.1.2: {} @@ -4376,11 +4359,11 @@ snapshots: camelcase-css@2.0.1: {} - camera-controls@2.8.5(three@0.163.0): + camera-controls@2.9.0(three@0.163.0): dependencies: three: 0.163.0 - caniuse-lite@1.0.30001636: {} + caniuse-lite@1.0.30001667: {} chalk@2.4.2: dependencies: @@ -4407,16 +4390,20 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@4.0.1: + dependencies: + readdirp: 4.0.2 + classnames@2.5.1: {} - cli-cursor@4.0.0: + cli-cursor@5.0.0: dependencies: - restore-cursor: 4.0.0 + restore-cursor: 5.1.0 cli-truncate@4.0.0: dependencies: slice-ansi: 5.0.0 - string-width: 7.1.0 + string-width: 7.2.0 cliui@7.0.4: dependencies: @@ -4501,9 +4488,9 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.3.5: + debug@4.3.7: dependencies: - ms: 2.1.2 + ms: 2.1.3 deep-equal@2.2.2: dependencies: @@ -4526,6 +4513,27 @@ snapshots: which-collection: 1.0.1 which-typed-array: 1.1.11 + deep-equal@2.2.3: + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + es-get-iterator: 1.1.3 + get-intrinsic: 1.2.4 + is-arguments: 1.1.1 + is-array-buffer: 3.0.4 + is-date-object: 1.0.5 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + isarray: 2.0.5 + object-is: 1.1.6 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.3 + side-channel: 1.0.6 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.2 + which-typed-array: 1.1.15 + deep-is@0.1.4: {} deepmerge@4.3.1: {} @@ -4546,9 +4554,7 @@ snapshots: delay@5.0.0: {} - dequal@2.0.3: {} - - detect-gpu@5.0.38: + detect-gpu@5.0.51: dependencies: webgl-constants: 1.1.1 @@ -4580,9 +4586,9 @@ snapshots: ebnf@1.9.1: {} - electron-to-chromium@1.4.803: {} + electron-to-chromium@1.5.34: {} - emoji-regex@10.3.0: {} + emoji-regex@10.4.0: {} emoji-regex@8.0.0: {} @@ -4592,11 +4598,13 @@ snapshots: dependencies: once: 1.4.0 - enhanced-resolve@5.17.0: + enhanced-resolve@5.17.1: dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 + environment@1.1.0: {} + es-abstract@1.23.3: dependencies: array-buffer-byte-length: 1.0.1 @@ -4630,10 +4638,10 @@ snapshots: is-string: 1.0.7 is-typed-array: 1.1.13 is-weakref: 1.0.2 - object-inspect: 1.13.1 + object-inspect: 1.13.2 object-keys: 1.1.1 object.assign: 4.1.5 - regexp.prototype.flags: 1.5.2 + regexp.prototype.flags: 1.5.3 safe-array-concat: 1.1.2 safe-regex-test: 1.0.3 string.prototype.trim: 1.2.9 @@ -4664,7 +4672,7 @@ snapshots: isarray: 2.0.5 stop-iteration-iterator: 1.0.0 - es-iterator-helpers@1.0.19: + es-iterator-helpers@1.1.0: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -4678,7 +4686,7 @@ snapshots: has-proto: 1.0.3 has-symbols: 1.0.3 internal-slot: 1.0.7 - iterator.prototype: 1.1.2 + iterator.prototype: 1.1.3 safe-array-concat: 1.1.2 es-object-atoms@1.0.0: @@ -4729,140 +4737,144 @@ snapshots: escalade@3.1.1: {} - escalade@3.1.2: {} + escalade@3.2.0: {} escape-string-regexp@1.0.5: {} escape-string-regexp@4.0.0: {} - eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: confusing-browser-globals: 1.0.11 - eslint: 8.57.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint: 8.57.1 + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) object.assign: 4.1.5 object.entries: 1.1.8 semver: 6.3.1 - eslint-config-airbnb@19.0.4(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.34.2(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.31.0)(eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.1(eslint@8.57.1))(eslint@8.57.1): dependencies: - eslint: 8.57.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) - eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) - eslint-plugin-react: 7.34.2(eslint@8.57.0) - eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) + eslint: 8.57.1 + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1) + eslint-plugin-react: 7.37.1(eslint@8.57.1) + eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) object.assign: 4.1.5 object.entries: 1.1.8 eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 - is-core-module: 2.13.1 + is-core-module: 2.15.1 resolve: 1.22.8 transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: - debug: 4.3.5 - enhanced-resolve: 5.17.0 - eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + '@nolyfill/is-core-module': 1.0.39 + debug: 4.3.7 + enhanced-resolve: 5.17.1 + eslint: 8.57.1 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) fast-glob: 3.3.2 - get-tsconfig: 4.7.5 - is-core-module: 2.13.1 + get-tsconfig: 4.8.1 + is-bun-module: 1.2.1 is-glob: 4.0.3 + optionalDependencies: + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 7.13.0(eslint@8.57.0)(typescript@5.4.5) - eslint: 8.57.0 + '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.6.3) + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: + '@rtsao/scc': 1.1.0 array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.0 + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) hasown: 2.0.2 - is-core-module: 2.13.1 + is-core-module: 2.15.1 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 object.groupby: 1.0.3 object.values: 1.2.0 semver: 6.3.1 + string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 7.13.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.6.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0): + eslint-plugin-jsx-a11y@6.10.0(eslint@8.57.1): dependencies: - '@babel/runtime': 7.24.7 - aria-query: 5.3.0 + aria-query: 5.1.3 array-includes: 3.1.8 array.prototype.flatmap: 1.3.2 ast-types-flow: 0.0.8 - axe-core: 4.7.0 - axobject-query: 3.2.1 + axe-core: 4.10.0 + axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - es-iterator-helpers: 1.0.19 - eslint: 8.57.0 + es-iterator-helpers: 1.1.0 + eslint: 8.57.1 hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 minimatch: 3.1.2 - object.entries: 1.1.8 object.fromentries: 2.0.8 + safe-regex-test: 1.0.3 + string.prototype.includes: 2.0.0 - eslint-plugin-react-hooks@4.6.2(eslint@8.57.0): + eslint-plugin-react-hooks@4.6.2(eslint@8.57.1): dependencies: - eslint: 8.57.0 + eslint: 8.57.1 - eslint-plugin-react@7.34.2(eslint@8.57.0): + eslint-plugin-react@7.37.1(eslint@8.57.1): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 array.prototype.flatmap: 1.3.2 - array.prototype.toreversed: 1.1.2 array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.0.19 - eslint: 8.57.0 + es-iterator-helpers: 1.1.0 + eslint: 8.57.1 estraverse: 5.3.0 + hasown: 2.0.2 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 object.entries: 1.1.8 object.fromentries: 2.0.8 - object.hasown: 1.1.4 object.values: 1.2.0 prop-types: 15.8.1 resolve: 2.0.0-next.5 semver: 6.3.1 string.prototype.matchall: 4.0.11 + string.prototype.repeat: 1.0.0 eslint-scope@7.2.2: dependencies: @@ -4871,26 +4883,26 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint@8.57.0: + eslint@8.57.1: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.10.1 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) + '@eslint-community/regexpp': 4.11.1 '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.5 + debug: 4.3.7 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.5.0 + esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 @@ -4898,7 +4910,7 @@ snapshots: glob-parent: 6.0.2 globals: 13.24.0 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -4916,11 +4928,11 @@ snapshots: espree@9.6.1: dependencies: - acorn: 8.12.0 - acorn-jsx: 5.3.2(acorn@8.12.0) + acorn: 8.12.1 + acorn-jsx: 5.3.2(acorn@8.12.1) eslint-visitor-keys: 3.4.3 - esquery@1.5.0: + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -4968,7 +4980,7 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.7 + micromatch: 4.0.8 fast-json-parse@1.0.3: {} @@ -4992,10 +5004,9 @@ snapshots: dependencies: to-regex-range: 5.0.1 - find-babel-config@2.1.1: + find-babel-config@2.1.2: dependencies: json5: 2.2.3 - path-exists: 4.0.0 find-up@3.0.0: dependencies: @@ -5024,7 +5035,7 @@ snapshots: dependencies: is-callable: 1.2.7 - foreground-child@3.2.1: + foreground-child@3.3.0: dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 @@ -5080,7 +5091,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.2.4 - get-tsconfig@4.7.5: + get-tsconfig@4.8.1: dependencies: resolve-pkg-maps: 1.0.0 @@ -5092,12 +5103,13 @@ snapshots: dependencies: is-glob: 4.0.3 - glob@10.4.1: + glob@10.4.5: dependencies: - foreground-child: 3.2.1 - jackspeak: 3.4.0 - minimatch: 9.0.4 + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 minipass: 7.1.2 + package-json-from-dist: 1.0.1 path-scurry: 1.11.1 glob@7.2.3: @@ -5132,7 +5144,7 @@ snapshots: array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.3.2 - ignore: 5.3.1 + ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0 @@ -5185,7 +5197,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.5 + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -5193,20 +5205,20 @@ snapshots: human-signals@5.0.0: {} - husky@9.0.11: {} + husky@9.1.6: {} hyphenate-style-name@1.1.0: {} ieee754@1.2.1: {} - ignore@5.3.1: {} + ignore@5.3.2: {} immediate@3.0.6: {} immer@9.0.21: optional: true - immutable@4.3.6: {} + immutable@4.3.7: {} import-fresh@3.3.0: dependencies: @@ -5265,9 +5277,13 @@ snapshots: call-bind: 1.0.2 has-tostringtag: 1.0.0 + is-bun-module@1.2.1: + dependencies: + semver: 7.6.3 + is-callable@1.2.7: {} - is-core-module@2.13.1: + is-core-module@2.15.1: dependencies: hasown: 2.0.2 @@ -5382,7 +5398,7 @@ snapshots: isexe@2.0.0: {} - iterator.prototype@1.1.2: + iterator.prototype@1.1.3: dependencies: define-properties: 1.2.1 get-intrinsic: 1.2.4 @@ -5395,7 +5411,7 @@ snapshots: '@types/react-reconciler': 0.28.8 react: 18.3.1 - jackspeak@3.4.0: + jackspeak@3.4.3: dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: @@ -5409,7 +5425,7 @@ snapshots: dependencies: argparse: 2.0.1 - jsesc@2.5.2: {} + jsesc@3.0.2: {} json-buffer@3.0.1: {} @@ -5457,27 +5473,27 @@ snapshots: lines-and-columns@1.2.4: {} - lint-staged@15.2.7: + lint-staged@15.2.10: dependencies: chalk: 5.3.0 commander: 12.1.0 - debug: 4.3.5 + debug: 4.3.7 execa: 8.0.1 lilconfig: 3.1.2 - listr2: 8.2.1 - micromatch: 4.0.7 + listr2: 8.2.5 + micromatch: 4.0.8 pidtree: 0.6.0 string-argv: 0.3.2 - yaml: 2.4.5 + yaml: 2.5.1 transitivePeerDependencies: - supports-color - listr2@8.2.1: + listr2@8.2.5: dependencies: cli-truncate: 4.0.0 colorette: 2.0.20 eventemitter3: 5.0.1 - log-update: 6.0.0 + log-update: 6.1.0 rfdc: 1.4.1 wrap-ansi: 9.0.0 @@ -5494,10 +5510,10 @@ snapshots: lodash@4.17.21: {} - log-update@6.0.0: + log-update@6.1.0: dependencies: - ansi-escapes: 6.2.1 - cli-cursor: 4.0.0 + ansi-escapes: 7.0.0 + cli-cursor: 5.0.0 slice-ansi: 7.1.0 strip-ansi: 7.1.0 wrap-ansi: 9.0.0 @@ -5506,20 +5522,20 @@ snapshots: dependencies: js-tokens: 4.0.0 - lru-cache@10.2.2: {} + lru-cache@10.4.3: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 - maath@0.10.7(@types/three@0.163.0)(three@0.163.0): + maath@0.10.8(@types/three@0.163.0)(three@0.163.0): dependencies: '@types/three': 0.163.0 three: 0.163.0 magic-string@0.30.8: dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 make-error@1.3.6: {} @@ -5537,7 +5553,7 @@ snapshots: meshoptimizer@0.18.1: {} - micromatch@4.0.7: + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 @@ -5546,6 +5562,8 @@ snapshots: mimic-fn@4.0.0: {} + mimic-function@5.0.1: {} + mini-svg-data-uri@1.4.4: {} minimatch@3.1.2: @@ -5556,7 +5574,7 @@ snapshots: dependencies: brace-expansion: 2.0.1 - minimatch@9.0.4: + minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -5566,8 +5584,6 @@ snapshots: minipass@7.1.2: {} - ms@2.1.2: {} - ms@2.1.3: {} mz@2.7.0: @@ -5584,7 +5600,7 @@ snapshots: dependencies: whatwg-url: 5.0.0 - node-releases@2.0.14: {} + node-releases@2.0.18: {} normalize-path@3.0.0: {} @@ -5604,13 +5620,18 @@ snapshots: object-inspect@1.12.3: {} - object-inspect@1.13.1: {} + object-inspect@1.13.2: {} object-is@1.1.5: dependencies: call-bind: 1.0.2 define-properties: 1.2.1 + object-is@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + object-keys@1.1.1: {} object.assign@4.1.5: @@ -5639,12 +5660,6 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.3 - object.hasown@1.1.4: - dependencies: - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 - object.values@1.2.0: dependencies: call-bind: 1.0.7 @@ -5665,6 +5680,10 @@ snapshots: dependencies: mimic-fn: 4.0.0 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + open@8.4.2: dependencies: define-lazy-prop: 2.0.0 @@ -5698,6 +5717,8 @@ snapshots: p-try@2.2.0: {} + package-json-from-dist@1.0.1: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -5716,14 +5737,14 @@ snapshots: path-scurry@1.11.1: dependencies: - lru-cache: 10.2.2 + lru-cache: 10.4.3 minipass: 7.1.2 path-type@4.0.0: {} pegjs@0.10.0: {} - picocolors@1.0.1: {} + picocolors@1.1.0: {} picomatch@2.3.1: {} @@ -5739,49 +5760,49 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-import@15.1.0(postcss@8.4.38): + postcss-import@15.1.0(postcss@8.4.47): dependencies: - postcss: 8.4.38 + postcss: 8.4.47 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.8 - postcss-js@4.0.1(postcss@8.4.38): + postcss-js@4.0.1(postcss@8.4.47): dependencies: camelcase-css: 2.0.1 - postcss: 8.4.38 + postcss: 8.4.47 - postcss-load-config@4.0.2(postcss@8.4.38)(ts-node@9.1.1(typescript@5.4.5)): + postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@9.1.1(typescript@5.6.3)): dependencies: lilconfig: 3.1.2 - yaml: 2.4.5 + yaml: 2.5.1 optionalDependencies: - postcss: 8.4.38 - ts-node: 9.1.1(typescript@5.4.5) + postcss: 8.4.47 + ts-node: 9.1.1(typescript@5.6.3) - postcss-nested@6.0.1(postcss@8.4.38): + postcss-nested@6.2.0(postcss@8.4.47): dependencies: - postcss: 8.4.38 - postcss-selector-parser: 6.1.0 + postcss: 8.4.47 + postcss-selector-parser: 6.1.2 - postcss-selector-parser@6.1.0: + postcss-selector-parser@6.1.2: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 postcss-value-parser@4.2.0: {} - postcss@8.4.38: + postcss@8.4.47: dependencies: nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 + picocolors: 1.1.0 + source-map-js: 1.2.1 potpack@1.0.2: {} prelude-ls@1.2.1: {} - prettier@3.3.2: {} + prettier@3.3.3: {} progress@2.0.3: {} @@ -5825,7 +5846,7 @@ snapshots: react-error-boundary@4.0.13(react@18.3.1): dependencies: - '@babel/runtime': 7.24.7 + '@babel/runtime': 7.25.7 react: 18.3.1 react-fast-compare@3.2.2: {} @@ -5838,7 +5859,7 @@ snapshots: react-fast-compare: 3.2.2 react-side-effect: 2.1.2(react@18.3.1) - react-hook-form@7.52.0(react@18.3.1): + react-hook-form@7.53.0(react@18.3.1): dependencies: react: 18.3.1 @@ -5871,28 +5892,22 @@ snapshots: react: 18.3.1 shallow-equal: 3.1.0 - react-router-dom@6.23.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-router-dom@6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@remix-run/router': 1.16.1 + '@remix-run/router': 1.19.2 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-router: 6.23.1(react@18.3.1) + react-router: 6.26.2(react@18.3.1) - react-router@6.23.1(react@18.3.1): + react-router@6.26.2(react@18.3.1): dependencies: - '@remix-run/router': 1.16.1 + '@remix-run/router': 1.19.2 react: 18.3.1 react-side-effect@2.1.2(react@18.3.1): dependencies: react: 18.3.1 - react-use-measure@2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - debounce: 1.2.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -5905,6 +5920,8 @@ snapshots: dependencies: picomatch: 2.3.1 + readdirp@4.0.2: {} + reflect.getprototypeof@1.0.6: dependencies: call-bind: 1.0.7 @@ -5913,7 +5930,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.2.4 globalthis: 1.0.4 - which-builtin-type: 1.1.3 + which-builtin-type: 1.1.4 regenerator-runtime@0.14.1: {} @@ -5923,7 +5940,7 @@ snapshots: define-properties: 1.2.1 set-function-name: 2.0.1 - regexp.prototype.flags@1.5.2: + regexp.prototype.flags@1.5.3: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -5942,20 +5959,20 @@ snapshots: resolve@1.22.8: dependencies: - is-core-module: 2.13.1 + is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 resolve@2.0.0-next.5: dependencies: - is-core-module: 2.13.1 + is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - restore-cursor@4.0.0: + restore-cursor@5.1.0: dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 + onetime: 7.0.0 + signal-exit: 4.1.0 reusify@1.0.4: {} @@ -5965,35 +5982,35 @@ snapshots: dependencies: glob: 7.2.3 - rollup-plugin-visualizer@5.12.0(rollup@4.18.0): + rollup-plugin-visualizer@5.12.0(rollup@4.24.0): dependencies: open: 8.4.2 picomatch: 2.3.1 source-map: 0.7.4 yargs: 17.7.2 optionalDependencies: - rollup: 4.18.0 + rollup: 4.24.0 - rollup@4.18.0: + rollup@4.24.0: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.18.0 - '@rollup/rollup-android-arm64': 4.18.0 - '@rollup/rollup-darwin-arm64': 4.18.0 - '@rollup/rollup-darwin-x64': 4.18.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.18.0 - '@rollup/rollup-linux-arm-musleabihf': 4.18.0 - '@rollup/rollup-linux-arm64-gnu': 4.18.0 - '@rollup/rollup-linux-arm64-musl': 4.18.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0 - '@rollup/rollup-linux-riscv64-gnu': 4.18.0 - '@rollup/rollup-linux-s390x-gnu': 4.18.0 - '@rollup/rollup-linux-x64-gnu': 4.18.0 - '@rollup/rollup-linux-x64-musl': 4.18.0 - '@rollup/rollup-win32-arm64-msvc': 4.18.0 - '@rollup/rollup-win32-ia32-msvc': 4.18.0 - '@rollup/rollup-win32-x64-msvc': 4.18.0 + '@rollup/rollup-android-arm-eabi': 4.24.0 + '@rollup/rollup-android-arm64': 4.24.0 + '@rollup/rollup-darwin-arm64': 4.24.0 + '@rollup/rollup-darwin-x64': 4.24.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.24.0 + '@rollup/rollup-linux-arm-musleabihf': 4.24.0 + '@rollup/rollup-linux-arm64-gnu': 4.24.0 + '@rollup/rollup-linux-arm64-musl': 4.24.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.24.0 + '@rollup/rollup-linux-riscv64-gnu': 4.24.0 + '@rollup/rollup-linux-s390x-gnu': 4.24.0 + '@rollup/rollup-linux-x64-gnu': 4.24.0 + '@rollup/rollup-linux-x64-musl': 4.24.0 + '@rollup/rollup-win32-arm64-msvc': 4.24.0 + '@rollup/rollup-win32-ia32-msvc': 4.24.0 + '@rollup/rollup-win32-x64-msvc': 4.24.0 fsevents: 2.3.3 run-parallel@1.2.0: @@ -6013,11 +6030,11 @@ snapshots: es-errors: 1.3.0 is-regex: 1.1.4 - sass@1.77.6: + sass@1.79.4: dependencies: - chokidar: 3.6.0 - immutable: 4.3.6 - source-map-js: 1.2.0 + chokidar: 4.0.1 + immutable: 4.3.7 + source-map-js: 1.2.1 scheduler@0.21.0: dependencies: @@ -6029,7 +6046,7 @@ snapshots: semver@6.3.1: {} - semver@7.6.2: {} + semver@7.6.3: {} set-function-length@1.2.2: dependencies: @@ -6072,7 +6089,7 @@ snapshots: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 - object-inspect: 1.13.1 + object-inspect: 1.13.2 signal-exit@3.0.7: {} @@ -6096,7 +6113,7 @@ snapshots: dependencies: flatbuffers: 22.10.26 - source-map-js@1.2.0: {} + source-map-js@1.2.1: {} source-map-support@0.5.21: dependencies: @@ -6118,9 +6135,9 @@ snapshots: spdx-expression-parse@3.0.1: dependencies: spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.18 + spdx-license-ids: 3.0.20 - spdx-license-ids@3.0.18: {} + spdx-license-ids@3.0.20: {} spdx-ranges@2.1.1: {} @@ -6154,12 +6171,17 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 - string-width@7.1.0: + string-width@7.2.0: dependencies: - emoji-regex: 10.3.0 + emoji-regex: 10.4.0 get-east-asian-width: 1.2.0 strip-ansi: 7.1.0 + string.prototype.includes@2.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.3 + string.prototype.matchall@4.0.11: dependencies: call-bind: 1.0.7 @@ -6171,10 +6193,15 @@ snapshots: gopd: 1.0.1 has-symbols: 1.0.3 internal-slot: 1.0.7 - regexp.prototype.flags: 1.5.2 + regexp.prototype.flags: 1.5.3 set-function-name: 2.0.2 side-channel: 1.0.6 + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.3 + string.prototype.trim@1.2.9: dependencies: call-bind: 1.0.7 @@ -6214,7 +6241,7 @@ snapshots: dependencies: '@jridgewell/gen-mapping': 0.3.5 commander: 4.1.1 - glob: 10.4.1 + glob: 10.4.5 lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.6 @@ -6236,7 +6263,7 @@ snapshots: tailwind-gradient-mask-image@1.2.0: {} - tailwindcss@3.4.4(ts-node@9.1.1(typescript@5.4.5)): + tailwindcss@3.4.13(ts-node@9.1.1(typescript@5.6.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -6248,16 +6275,16 @@ snapshots: is-glob: 4.0.3 jiti: 1.21.6 lilconfig: 2.1.0 - micromatch: 4.0.7 + micromatch: 4.0.8 normalize-path: 3.0.0 object-hash: 3.0.0 - picocolors: 1.0.1 - postcss: 8.4.38 - postcss-import: 15.1.0(postcss@8.4.38) - postcss-js: 4.0.1(postcss@8.4.38) - postcss-load-config: 4.0.2(postcss@8.4.38)(ts-node@9.1.1(typescript@5.4.5)) - postcss-nested: 6.0.1(postcss@8.4.38) - postcss-selector-parser: 6.1.0 + picocolors: 1.1.0 + postcss: 8.4.47 + postcss-import: 15.1.0(postcss@8.4.47) + postcss-js: 4.0.1(postcss@8.4.47) + postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@9.1.1(typescript@5.6.3)) + postcss-nested: 6.2.0(postcss@8.4.47) + postcss-selector-parser: 6.1.2 resolve: 1.22.8 sucrase: 3.35.0 transitivePeerDependencies: @@ -6268,7 +6295,7 @@ snapshots: terser@5.31.1: dependencies: '@jridgewell/source-map': 0.3.6 - acorn: 8.12.0 + acorn: 8.12.1 commander: 2.20.3 source-map-support: 0.5.21 optional: true @@ -6283,15 +6310,15 @@ snapshots: dependencies: any-promise: 1.3.0 - three-mesh-bvh@0.7.5(three@0.163.0): + three-mesh-bvh@0.7.8(three@0.163.0): dependencies: three: 0.163.0 - three-stdlib@2.30.3(three@0.163.0): + three-stdlib@2.33.0(three@0.163.0): dependencies: '@types/draco3d': 1.4.10 '@types/offscreencanvas': 2019.7.3 - '@types/webxr': 0.5.16 + '@types/webxr': 0.5.20 draco3d: 1.5.7 fflate: 0.6.10 potpack: 1.0.2 @@ -6323,9 +6350,9 @@ snapshots: troika-worker-utils@0.49.0: {} - ts-api-utils@1.3.0(typescript@5.4.5): + ts-api-utils@1.3.0(typescript@5.6.3): dependencies: - typescript: 5.4.5 + typescript: 5.6.3 ts-interface-checker@0.1.13: {} @@ -6339,18 +6366,18 @@ snapshots: typescript: 4.8.4 yn: 3.1.1 - ts-node@9.1.1(typescript@5.4.5): + ts-node@9.1.1(typescript@5.6.3): dependencies: arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 source-map-support: 0.5.21 - typescript: 5.4.5 + typescript: 5.6.3 yn: 3.1.1 optional: true - ts-pattern@5.2.0: {} + ts-pattern@5.4.0: {} tsconfig-paths@3.15.0: dependencies: @@ -6359,11 +6386,11 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tslib@2.6.3: {} + tslib@2.7.0: {} - tunnel-rat@0.1.2(@types/react@18.3.3)(immer@9.0.21)(react@18.3.1): + tunnel-rat@0.1.2(@types/react@18.3.11)(immer@9.0.21)(react@18.3.1): dependencies: - zustand: 4.5.2(@types/react@18.3.3)(immer@9.0.21)(react@18.3.1) + zustand: 4.5.5(@types/react@18.3.11)(immer@9.0.21)(react@18.3.1) transitivePeerDependencies: - '@types/react' - immer @@ -6409,7 +6436,7 @@ snapshots: typescript@4.8.4: {} - typescript@5.4.5: {} + typescript@5.6.3: {} unbox-primitive@1.0.2: dependencies: @@ -6423,22 +6450,26 @@ snapshots: unplugin@1.0.1: dependencies: - acorn: 8.12.0 + acorn: 8.12.1 chokidar: 3.6.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.5.0 - update-browserslist-db@1.0.16(browserslist@4.23.1): + update-browserslist-db@1.1.1(browserslist@4.24.0): dependencies: - browserslist: 4.23.1 - escalade: 3.1.2 - picocolors: 1.0.1 + browserslist: 4.24.0 + escalade: 3.2.0 + picocolors: 1.1.0 uri-js@4.4.1: dependencies: punycode: 2.3.1 - use-sync-external-store@1.2.0(react@18.3.1): + use-double-tap@1.3.6(react@18.3.1): + dependencies: + react: 18.3.1 + + use-sync-external-store@1.2.2(react@18.3.1): dependencies: react: 18.3.1 @@ -6448,15 +6479,15 @@ snapshots: uuid@9.0.1: {} - vite@5.3.1(@types/node@20.14.2)(sass@1.77.6)(terser@5.31.1): + vite@5.4.8(@types/node@20.14.2)(sass@1.79.4)(terser@5.31.1): dependencies: esbuild: 0.21.5 - postcss: 8.4.38 - rollup: 4.18.0 + postcss: 8.4.47 + rollup: 4.24.0 optionalDependencies: '@types/node': 20.14.2 fsevents: 2.3.3 - sass: 1.77.6 + sass: 1.79.4 terser: 5.31.1 warning@4.0.3: @@ -6486,7 +6517,7 @@ snapshots: is-string: 1.0.7 is-symbol: 1.0.4 - which-builtin-type@1.1.3: + which-builtin-type@1.1.4: dependencies: function.prototype.name: 1.1.6 has-tostringtag: 1.0.2 @@ -6552,7 +6583,7 @@ snapshots: wrap-ansi@9.0.0: dependencies: ansi-styles: 6.2.1 - string-width: 7.1.0 + string-width: 7.2.0 strip-ansi: 7.1.0 wrappy@1.0.2: {} @@ -6561,7 +6592,7 @@ snapshots: yallist@3.1.1: {} - yaml@2.4.5: {} + yaml@2.5.1: {} yargs-parser@20.2.9: {} @@ -6580,7 +6611,7 @@ snapshots: yargs@17.7.2: dependencies: cliui: 8.0.1 - escalade: 3.1.2 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -6595,10 +6626,10 @@ snapshots: optionalDependencies: react: 18.3.1 - zustand@4.5.2(@types/react@18.3.3)(immer@9.0.21)(react@18.3.1): + zustand@4.5.5(@types/react@18.3.11)(immer@9.0.21)(react@18.3.1): dependencies: - use-sync-external-store: 1.2.0(react@18.3.1) + use-sync-external-store: 1.2.2(react@18.3.1) optionalDependencies: - '@types/react': 18.3.3 + '@types/react': 18.3.11 immer: 9.0.21 react: 18.3.1 diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5bf5c4ff1..a64ba1d57 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.79" +channel = "1.81" profile = "default" components = ["rustc", "cargo", "clippy", "rustfmt", "rust-analyzer", "rust-src"] diff --git a/server/.gitignore b/server/.gitignore index e97171823..89916e7f5 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -19,3 +19,7 @@ Load AutoBone Recordings *.log.lck *.log logs/ + +android/release +android/debug + diff --git a/server/android/build.gradle.kts b/server/android/build.gradle.kts index 524b45ce9..7dd94c33a 100644 --- a/server/android/build.gradle.kts +++ b/server/android/build.gradle.kts @@ -5,6 +5,7 @@ * For more details take a look at the Java Libraries chapter in the Gradle * User Manual available at https://docs.gradle.org/6.3/userguide/java_library_plugin.html */ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { @@ -12,7 +13,7 @@ plugins { kotlin("plugin.serialization") id("com.github.gmazzo.buildconfig") - id("com.android.application") version "8.0.2" + id("com.android.application") version "8.6.1" id("org.ajoberstar.grgit") } @@ -39,8 +40,10 @@ tasks.preBuild { } tasks.withType { - kotlinOptions.jvmTarget = "17" - kotlinOptions.freeCompilerArgs += "-Xvalue-classes" + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + freeCompilerArgs.set(listOf("-Xvalue-classes")) + } } // Set compiler to use UTF-8 @@ -65,21 +68,21 @@ allprojects { dependencies { implementation(project(":server:core")) - implementation("commons-cli:commons-cli:1.5.0") - implementation("org.apache.commons:commons-lang3:3.12.0") + implementation("commons-cli:commons-cli:1.8.0") + implementation("org.apache.commons:commons-lang3:3.15.0") // Android stuff - implementation("androidx.appcompat:appcompat:1.6.1") - implementation("androidx.core:core-ktx:1.10.1") - implementation("com.google.android.material:material:1.9.0") + implementation("androidx.appcompat:appcompat:1.7.0") + implementation("androidx.core:core-ktx:1.13.1") + implementation("com.google.android.material:material:1.12.0") implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) - androidTestImplementation("androidx.test.ext:junit:1.1.5") - androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + androidTestImplementation("androidx.test.ext:junit:1.2.1") + androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") // For hosting web GUI - implementation("io.ktor:ktor-server-core:2.3.0") - implementation("io.ktor:ktor-server-netty:2.3.0") - implementation("io.ktor:ktor-server-caching-headers:2.3.0") + implementation("io.ktor:ktor-server-core:2.3.12") + implementation("io.ktor:ktor-server-netty:2.3.10") + implementation("io.ktor:ktor-server-caching-headers:2.3.12") // Serial implementation("com.github.mik3y:usb-serial-for-android:3.7.0") @@ -99,7 +102,7 @@ android { compile your app. This means your app can use the API features included in this API level and lower. */ - compileSdk = 33 + compileSdk = 35 /* The defaultConfig block encapsulates default settings and entries for all build variants and can override some attributes in main/AndroidManifest.xml @@ -119,13 +122,16 @@ android { minSdk = 26 // Specifies the API level used to test the app. - targetSdk = 33 + targetSdk = 35 + // adds an offset of the version code as we might do apk releases in the middle of actual + // releases if we failed on bundling or stuff + val versionCodeOffset = 1 // Defines the version number of your app. - versionCode = extra["gitVersionCode"] as? Int + versionCode = (extra["gitVersionCode"] as? Int)?.plus(versionCodeOffset) ?: 0 // Defines a user-friendly version name for your app. - versionName = extra["gitVersionName"] as? String + versionName = extra["gitVersionName"] as? String ?: "v0.0.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/server/android/proguard-rules.pro b/server/android/proguard-rules.pro index d2177735e..d57ca20d4 100644 --- a/server/android/proguard-rules.pro +++ b/server/android/proguard-rules.pro @@ -1,16 +1,3 @@ --dontwarn io.netty.internal.tcnative.AsyncSSLPrivateKeyMethod --dontwarn io.netty.internal.tcnative.AsyncTask --dontwarn io.netty.internal.tcnative.Buffer --dontwarn io.netty.internal.tcnative.CertificateCallback --dontwarn io.netty.internal.tcnative.CertificateCompressionAlgo --dontwarn io.netty.internal.tcnative.CertificateVerifier --dontwarn io.netty.internal.tcnative.Library --dontwarn io.netty.internal.tcnative.SSL --dontwarn io.netty.internal.tcnative.SSLContext --dontwarn io.netty.internal.tcnative.SSLPrivateKeyMethod --dontwarn io.netty.internal.tcnative.SSLSessionCache --dontwarn io.netty.internal.tcnative.SessionTicketKey --dontwarn io.netty.internal.tcnative.SniHostNameMatcher -dontwarn java.awt.Color -dontwarn java.beans.BeanInfo -dontwarn java.beans.IntrospectionException @@ -37,3 +24,12 @@ -dontwarn org.jetbrains.annotations.Async$Execute -dontwarn org.jetbrains.annotations.Async$Schedule -dontwarn reactor.blockhound.integration.BlockHoundIntegration + +-keep class io.ktor.** { *; } +-keep class io.netty.** {*; } +-keep class kotlin.reflect.jvm.internal.** { *; } +-keep class kotlinx.coroutines.** { *; } +-dontwarn kotlinx.atomicfu.** +-dontwarn io.netty.** +-dontwarn com.typesafe.** +-dontwarn org.slf4j.** diff --git a/server/android/src/main/AndroidManifest.xml b/server/android/src/main/AndroidManifest.xml index 164f46383..4bfcf931f 100644 --- a/server/android/src/main/AndroidManifest.xml +++ b/server/android/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ + diff --git a/server/android/src/main/java/dev/slimevr/android/ForegroundService.kt b/server/android/src/main/java/dev/slimevr/android/ForegroundService.kt index 76f39a85f..faa6998d3 100644 --- a/server/android/src/main/java/dev/slimevr/android/ForegroundService.kt +++ b/server/android/src/main/java/dev/slimevr/android/ForegroundService.kt @@ -1,12 +1,15 @@ package dev.slimevr.android -import android.app.Notification -import android.app.NotificationChannel -import android.app.NotificationManager -import android.app.Service +import android.app.* import android.content.Intent +import android.content.pm.ServiceInfo +import android.os.Build import android.os.IBinder +import androidx.core.app.NotificationChannelCompat import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import androidx.core.app.ServiceCompat +import io.eiren.util.logging.LogManager /** * ForegroundService helps to keep the SlimeVR Server on Android from being killed. @@ -35,9 +38,26 @@ class ForegroundService : Service() { } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - val notification = createNotification() - startForeground(NOTIFICATION_ID, notification) - + try { + val notification = createNotification() + ServiceCompat.startForeground( + this, + NOTIFICATION_ID, // Cannot be 0 + notification, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE + } else { + 0 + }, + ) + } catch (e: Exception) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && + e is ForegroundServiceStartNotAllowedException + ) { + LogManager.severe("Tried to start foreground service when not allowed:", e) + } + // ... + } /* * Currently being a foreground process should be enough to keep the server running. * If it turns out to not be enough then the next option would be to return sticky here @@ -51,13 +71,12 @@ class ForegroundService : Service() { override fun onBind(intent: Intent?): IBinder? = null private fun createNotificationChannel() { - val serviceChannel = NotificationChannel( - CHANNEL_ID, - "SlimeVR Foreground Service Channel", - NotificationManager.IMPORTANCE_LOW, - ) - val manager = getSystemService(NotificationManager::class.java) - manager.createNotificationChannel(serviceChannel) + val serviceChannel = NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManager.IMPORTANCE_LOW) + .setName("SlimeVR Foreground Service Channel") + .build() + NotificationManagerCompat + .from(this) + .createNotificationChannel(serviceChannel) } private fun createNotification(): Notification = NotificationCompat.Builder(this, CHANNEL_ID) diff --git a/server/build.gradle.kts b/server/build.gradle.kts index 2c6f41398..645f9c383 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -37,7 +37,7 @@ configure { "java.util.*,kotlin.math.*,dev.slimevr.autobone.errors.*" + ",io.github.axisangles.ktmath.*,kotlinx.atomicfu.*" + ",dev.slimevr.tracking.trackers.*,dev.slimevr.desktop.platform.ProtobufMessages.*" + - ",com.illposed.osc.*", + ",solarxr_protocol.rpc.*,kotlinx.coroutines.*,com.illposed.osc.*,android.app.*", "ij_kotlin_allow_trailing_comma" to true, ) val ktlintVersion = "1.2.1" diff --git a/server/core/build.gradle.kts b/server/core/build.gradle.kts index 8f6bb3577..cc400bc2e 100644 --- a/server/core/build.gradle.kts +++ b/server/core/build.gradle.kts @@ -5,6 +5,7 @@ * For more details take a look at the Java Libraries chapter in the Gradle * User Manual available at https://docs.gradle.org/6.3/userguide/java_library_plugin.html */ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { @@ -25,8 +26,10 @@ java { } } tasks.withType { - kotlinOptions.jvmTarget = "17" - kotlinOptions.freeCompilerArgs += "-Xvalue-classes" + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + freeCompilerArgs.set(listOf("-Xvalue-classes")) + } } // Set compiler to use UTF-8 @@ -60,27 +63,27 @@ dependencies { // This dependency is used internally, // and not exposed to consumers on their own compile classpath. implementation("com.google.flatbuffers:flatbuffers-java:22.10.26") - implementation("commons-cli:commons-cli:1.5.0") + implementation("commons-cli:commons-cli:1.8.0") implementation("com.fasterxml.jackson.core:jackson-databind:2.15.1") implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.1") implementation("com.github.jonpeterson:jackson-module-model-versioning:1.2.2") implementation("org.apache.commons:commons-math3:3.6.1") - implementation("org.apache.commons:commons-lang3:3.12.0") + implementation("org.apache.commons:commons-lang3:3.15.0") implementation("org.apache.commons:commons-collections4:4.4") implementation("com.illposed.osc:javaosc-core:0.8") implementation("org.java-websocket:Java-WebSocket:1.+") implementation("com.melloware:jintellitype:1.+") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") - implementation("it.unimi.dsi:fastutil:8.5.12") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1") // Jitpack implementation("com.github.SlimeVR:oscquery-kt:566a0cba58") testImplementation(kotlin("test")) // Use JUnit test framework - testImplementation(platform("org.junit:junit-bom:5.9.0")) + testImplementation(platform("org.junit:junit-bom:5.10.3")) testImplementation("org.junit.jupiter:junit-jupiter") testImplementation("org.junit.platform:junit-platform-launcher") } diff --git a/server/core/src/main/java/dev/slimevr/VRServer.kt b/server/core/src/main/java/dev/slimevr/VRServer.kt index 4bd35390e..6ae919fe8 100644 --- a/server/core/src/main/java/dev/slimevr/VRServer.kt +++ b/server/core/src/main/java/dev/slimevr/VRServer.kt @@ -102,8 +102,6 @@ class VRServer @JvmOverloads constructor( init { // UwU - instance = this - configManager = ConfigManager(configPath) configManager.loadConfig() deviceManager = DeviceManager(this) @@ -163,6 +161,7 @@ class VRServer @JvmOverloads constructor( for (tracker in computedTrackers) { registerTracker(tracker) } + instance = this } fun hasBridge(bridgeClass: Class): Boolean { diff --git a/server/core/src/main/java/dev/slimevr/autobone/AutoBone.kt b/server/core/src/main/java/dev/slimevr/autobone/AutoBone.kt index 965db74ff..d8f4f2868 100644 --- a/server/core/src/main/java/dev/slimevr/autobone/AutoBone.kt +++ b/server/core/src/main/java/dev/slimevr/autobone/AutoBone.kt @@ -167,7 +167,7 @@ class AutoBone(server: VRServer) { // Otherwise if there is no skeleton available, attempt to get the // max HMD height from the recording val hmdHeight = frames.maxHmdHeight - if (hmdHeight <= 0.4f) { + if (hmdHeight <= MIN_HEIGHT) { LogManager .warning( "[AutoBone] Max headset height detected (Value seems too low, did you not stand up straight while measuring?): $hmdHeight", @@ -195,6 +195,9 @@ class AutoBone(server: VRServer) { config: AutoBoneConfig = globalConfig, epochCallback: Consumer? = null, ): AutoBoneResults { + check(frames.frameHolders.isNotEmpty()) { "Recording has no trackers." } + check(frames.maxFrameCount > 0) { "Recording has no frames." } + // Load current values for adjustable configs loadConfigValues() @@ -209,6 +212,7 @@ class AutoBone(server: VRServer) { } else { targetHmdHeight / BodyProportionError.eyeHeightToHeightRatio } + check(targetHmdHeight > MIN_HEIGHT) { "Configured height ($targetHmdHeight) is too small (<= $MIN_HEIGHT)." } // Set up the current state, making all required players and setting up the // skeletons appropriately @@ -316,6 +320,9 @@ class AutoBone(server: VRServer) { .info( "[AutoBone] Target height: ${trainingStep.targetHmdHeight}, Final height: $estimatedHeight", ) + if (trainingStep.errorStats.mean > config.maxFinalError) { + throw AutoBoneException("The final epoch error value (${trainingStep.errorStats.mean}) has exceeded the maximum allowed value (${config.maxFinalError}).") + } return AutoBoneResults( estimatedHeight, @@ -746,6 +753,7 @@ class AutoBone(server: VRServer) { } companion object { + const val MIN_HEIGHT = 0.4f const val AUTOBONE_FOLDER = "AutoBone Recordings" const val LOADAUTOBONE_FOLDER = "Load AutoBone Recordings" diff --git a/server/core/src/main/java/dev/slimevr/autobone/AutoBoneHandler.kt b/server/core/src/main/java/dev/slimevr/autobone/AutoBoneHandler.kt index 0b6564ae2..091c8784b 100644 --- a/server/core/src/main/java/dev/slimevr/autobone/AutoBoneHandler.kt +++ b/server/core/src/main/java/dev/slimevr/autobone/AutoBoneHandler.kt @@ -189,8 +189,8 @@ class AutoBoneHandler(private val server: VRServer) { if (framesFuture != null) { announceProcessStatus(AutoBoneProcessType.SAVE, "Waiting for recording...") val frames = framesFuture.get() - check(frames.frameHolders.isNotEmpty()) { "Recording has no trackers" } - check(frames.maxFrameCount > 0) { "Recording has no frames" } + check(frames.frameHolders.isNotEmpty()) { "Recording has no trackers." } + check(frames.maxFrameCount > 0) { "Recording has no frames." } announceProcessStatus(AutoBoneProcessType.SAVE, "Saving recording...") autoBone.saveRecording(frames) announceProcessStatus( @@ -243,8 +243,6 @@ class AutoBoneHandler(private val server: VRServer) { if (framesFuture != null) { announceProcessStatus(AutoBoneProcessType.PROCESS, "Waiting for recording...") val frames = framesFuture.get() - check(frames.frameHolders.isNotEmpty()) { "Recording has no trackers" } - check(frames.maxFrameCount > 0) { "Recording has no frames" } frameRecordings.add(Pair.of("", frames)) } else { announceProcessStatus( diff --git a/server/core/src/main/java/dev/slimevr/config/AutoBoneConfig.kt b/server/core/src/main/java/dev/slimevr/config/AutoBoneConfig.kt index 6529f64f9..7c6c13672 100644 --- a/server/core/src/main/java/dev/slimevr/config/AutoBoneConfig.kt +++ b/server/core/src/main/java/dev/slimevr/config/AutoBoneConfig.kt @@ -26,4 +26,5 @@ class AutoBoneConfig { var useSkeletonHeight = false var randSeed = 4L var useFrameFiltering = false + var maxFinalError = 0.03f } diff --git a/server/core/src/main/java/dev/slimevr/config/ConfigManager.java b/server/core/src/main/java/dev/slimevr/config/ConfigManager.java index f9a207d5f..574696b99 100644 --- a/server/core/src/main/java/dev/slimevr/config/ConfigManager.java +++ b/server/core/src/main/java/dev/slimevr/config/ConfigManager.java @@ -16,6 +16,8 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.*; +import java.util.Comparator; +import java.util.stream.Stream; public class ConfigManager { @@ -115,6 +117,32 @@ public class ConfigManager { // Serialize config try { + // delete accidental folder caused by PR + // https://github.com/SlimeVR/SlimeVR-Server/pull/1176 + var cfgFileMaybeFolder = cfgFile.toFile(); + if (cfgFileMaybeFolder.isDirectory()) { + try (Stream pathStream = Files.walk(cfgFile)) { + var list = pathStream.sorted(Comparator.reverseOrder()).toList(); + for (var path : list) { + Files.delete(path); + } + } catch (IOException e) { + LogManager + .severe( + "Unable to delete folder that has same name as the config file on path \"" + + cfgFile + + "\"" + ); + return; + } + + } + var cfgFolder = cfgFile.toAbsolutePath().getParent().toFile(); + if (!cfgFolder.exists() && !cfgFolder.mkdirs()) { + LogManager + .severe("Unable to create folders for config on path \"" + cfgFile + "\""); + return; + } om.writeValue(tmpCfgFile.toFile(), this.vrConfig); } catch (IOException e) { LogManager.severe("Unable to write serialized config to \"" + tmpCfgFile + "\"", e); @@ -133,6 +161,11 @@ public class ConfigManager { } } + public void resetConfig() { + this.vrConfig = new VRConfig(); + saveConfig(); + } + public VRConfig getVrConfig() { return vrConfig; } diff --git a/server/core/src/main/java/dev/slimevr/config/DriftCompensationConfig.kt b/server/core/src/main/java/dev/slimevr/config/DriftCompensationConfig.kt index e8944e581..adced65a4 100644 --- a/server/core/src/main/java/dev/slimevr/config/DriftCompensationConfig.kt +++ b/server/core/src/main/java/dev/slimevr/config/DriftCompensationConfig.kt @@ -7,6 +7,9 @@ class DriftCompensationConfig { // Is drift compensation enabled var enabled = false + // Is drift prediction enabled + var prediction = false + // Amount of drift compensation applied var amount = 0.8f diff --git a/server/core/src/main/java/dev/slimevr/config/ServerConfig.java b/server/core/src/main/java/dev/slimevr/config/ServerConfig.java deleted file mode 100644 index 2daf2a749..000000000 --- a/server/core/src/main/java/dev/slimevr/config/ServerConfig.java +++ /dev/null @@ -1,10 +0,0 @@ -package dev.slimevr.config; - -public class ServerConfig { - - private int trackerPort = 6969; - - public int getTrackerPort() { - return trackerPort; - } -} diff --git a/server/core/src/main/java/dev/slimevr/config/ServerConfig.kt b/server/core/src/main/java/dev/slimevr/config/ServerConfig.kt new file mode 100644 index 000000000..cc3346829 --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/config/ServerConfig.kt @@ -0,0 +1,65 @@ +package dev.slimevr.config + +import dev.slimevr.VRServer +import dev.slimevr.tracking.trackers.udp.MagnetometerStatus +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.sync.Mutex + +class ServerConfig { + val trackerPort: Int = 6969 + + var useMagnetometerOnAllTrackers: Boolean = false + private set + + private val magMutex = Mutex() + suspend fun defineMagOnAllTrackers(state: Boolean) = coroutineScope { + magMutex.lock() + try { + if (useMagnetometerOnAllTrackers == state) return@coroutineScope + + VRServer.instance.deviceManager.devices.filter { it.magSupport }.map { + async { + // Not using 255 as it sometimes could make one of the sensors go into + // error mode (if there is more than one sensor inside the device) + if (!state) { + val trackers = it.trackers.filterValues { + it.magStatus != MagnetometerStatus.NOT_SUPPORTED + } +// if(trackers.size == it.trackers.size) { +// it.setMag(false) +// } else { + trackers.map { (_, t) -> + async { it.setMag(false, t.trackerNum) } + }.awaitAll() +// } + return@async + } + +// val every = it.trackers.all { (_, t) -> t.config.shouldHaveMagEnabled == true +// && t.magStatus != MagnetometerStatus.NOT_SUPPORTED } +// if (every) { +// it.setMag(true) +// return@async +// } + + it.trackers.filterValues { + it.config.shouldHaveMagEnabled == true && + it.magStatus != MagnetometerStatus.NOT_SUPPORTED + } + .map { (_, t) -> + async { + // FIXME: Tracker gets restarted after each setMag, what will happen for devices with 3 trackers? + it.setMag(true, t.trackerNum) + } + }.awaitAll() + } + }.awaitAll() + + useMagnetometerOnAllTrackers = state + } finally { + magMutex.unlock() + } + } +} diff --git a/server/core/src/main/java/dev/slimevr/config/TrackerConfig.kt b/server/core/src/main/java/dev/slimevr/config/TrackerConfig.kt index 122abc5c1..7770bec6b 100644 --- a/server/core/src/main/java/dev/slimevr/config/TrackerConfig.kt +++ b/server/core/src/main/java/dev/slimevr/config/TrackerConfig.kt @@ -2,6 +2,7 @@ package dev.slimevr.config import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.node.JsonNodeFactory +import dev.slimevr.VRServer import dev.slimevr.tracking.trackers.Tracker import io.github.axisangles.ktmath.ObjectQuaternion @@ -16,12 +17,18 @@ class TrackerConfig { var mountingResetOrientation: ObjectQuaternion? = null var allowDriftCompensation: Boolean? = null + /** + * Only checked if [ServerConfig.useMagnetometerOnAllTrackers] enabled + */ + var shouldHaveMagEnabled: Boolean? = null + constructor() constructor(tracker: Tracker) { this.designation = if (tracker.trackerPosition != null) tracker.trackerPosition!!.designation else null this.customName = tracker.customName allowDriftCompensation = tracker.isImu() + shouldHaveMagEnabled = tracker.isImu() } companion object { @@ -37,3 +44,6 @@ class TrackerConfig { } } } + +val Tracker.config: TrackerConfig + get() = VRServer.instance.configManager.vrConfig.getTracker(this) diff --git a/server/core/src/main/java/dev/slimevr/filtering/QuaternionMovingAverage.kt b/server/core/src/main/java/dev/slimevr/filtering/QuaternionMovingAverage.kt index b695037aa..f86c4525d 100644 --- a/server/core/src/main/java/dev/slimevr/filtering/QuaternionMovingAverage.kt +++ b/server/core/src/main/java/dev/slimevr/filtering/QuaternionMovingAverage.kt @@ -1,5 +1,6 @@ package dev.slimevr.filtering +import com.jme3.system.NanoTimer import dev.slimevr.VRServer import io.github.axisangles.ktmath.Quaternion import io.github.axisangles.ktmath.Quaternion.Companion.IDENTITY @@ -17,25 +18,25 @@ private const val PREDICT_BUFFER = 6 class QuaternionMovingAverage( val type: TrackerFilters, - var amount: Float, - initialRotation: Quaternion, + var amount: Float = 0f, + initialRotation: Quaternion = IDENTITY, ) { - var filteredQuaternion = IDENTITY private var smoothFactor = 0f private var predictFactor = 0f private lateinit var rotBuffer: CircularArrayList private var latestQuaternion = IDENTITY private var smoothingQuaternion = IDENTITY - private val fpsTimer = VRServer.instance.fpsTimer + private val fpsTimer = if (VRServer.instanceInitialized) VRServer.instance.fpsTimer else NanoTimer() private var frameCounter = 0 private var lastAmt = 0f + var filteredQuaternion = IDENTITY init { // amount should range from 0 to 1. // GUI should clamp it from 0.01 (1%) or 0.1 (10%) // to 1 (100%). amount = amount.coerceAtLeast(0f) - if (type === TrackerFilters.SMOOTHING) { + if (type == TrackerFilters.SMOOTHING) { // lower smoothFactor = more smoothing smoothFactor = SMOOTH_MULTIPLIER * (1 - amount.coerceAtMost(1f)) + SMOOTH_MIN // Totally a hack @@ -43,14 +44,12 @@ class QuaternionMovingAverage( smoothFactor /= amount } } - if (type === TrackerFilters.PREDICTION) { + if (type == TrackerFilters.PREDICTION) { // higher predictFactor = more prediction predictFactor = PREDICT_MULTIPLIER * amount + PREDICT_MIN rotBuffer = CircularArrayList(PREDICT_BUFFER) } - filteredQuaternion = initialRotation - latestQuaternion = initialRotation - smoothingQuaternion = initialRotation + resetQuats(initialRotation) } // Runs at up to 1000hz. We use a timer to make it framerate-independent @@ -70,7 +69,7 @@ class QuaternionMovingAverage( // Slerps the target rotation to that predicted rotation by amt filteredQuaternion = filteredQuaternion.interpR(quatBuf, amt) } - } else { // Smoothing + } else if (type == TrackerFilters.SMOOTHING) { // Increase every update for linear interpolation frameCounter++ @@ -90,24 +89,35 @@ class QuaternionMovingAverage( // Smooth towards the target rotation by the slerp factor filteredQuaternion = smoothingQuaternion.interpR(latestQuaternion, amt) + } else { + // No filtering; just keep track of rotations (for going over 180 degrees) + filteredQuaternion = latestQuaternion.twinNearest(smoothingQuaternion) } } @Synchronized fun addQuaternion(q: Quaternion) { - if (type === TrackerFilters.PREDICTION) { + if (type == TrackerFilters.PREDICTION) { if (rotBuffer.size == rotBuffer.capacity()) { rotBuffer.removeLast() } // Gets and stores the rotation between the last 2 quaternions rotBuffer.add(latestQuaternion.inv().times(q)) - } else { // Smoothing + } else if (type == TrackerFilters.SMOOTHING) { frameCounter = 0 lastAmt = 0f smoothingQuaternion = filteredQuaternion + } else { + smoothingQuaternion = filteredQuaternion } latestQuaternion = q } + + fun resetQuats(q: Quaternion) { + filteredQuaternion = q + latestQuaternion = q + smoothingQuaternion = q + } } diff --git a/server/core/src/main/java/dev/slimevr/osc/UnityArmature.kt b/server/core/src/main/java/dev/slimevr/osc/UnityArmature.kt index 6d1011192..36916f85c 100644 --- a/server/core/src/main/java/dev/slimevr/osc/UnityArmature.kt +++ b/server/core/src/main/java/dev/slimevr/osc/UnityArmature.kt @@ -12,9 +12,12 @@ import io.github.axisangles.ktmath.Vector3 */ class UnityArmature(localRot: Boolean) { + // Head private val headNode = TransformNode(localRotation = localRot) private val neckTailNode = TransformNode(localRotation = localRot) private val neckHeadNode = TransformNode(localRotation = localRot) + + // Spine private val upperChestNode = TransformNode(localRotation = localRot) private val chestNode = TransformNode(localRotation = localRot) private val spineTailNode = TransformNode(localRotation = localRot) @@ -22,12 +25,16 @@ class UnityArmature(localRot: Boolean) { private val hipsNode = TransformNode(localRotation = localRot) private val leftHipNode = TransformNode(localRotation = localRot) private val rightHipNode = TransformNode(localRotation = localRot) + + // Legs private val leftKneeNode = TransformNode(localRotation = localRot) private val leftAnkleNode = TransformNode(localRotation = localRot) private val leftFootNode = TransformNode(localRotation = localRot) private val rightKneeNode = TransformNode(localRotation = localRot) private val rightAnkleNode = TransformNode(localRotation = localRot) private val rightFootNode = TransformNode(localRotation = localRot) + + // Arms private val leftShoulderHeadNode = TransformNode(localRotation = localRot) private val rightShoulderHeadNode = TransformNode(localRotation = localRot) private val leftShoulderTailNode = TransformNode(localRotation = localRot) @@ -36,8 +43,50 @@ class UnityArmature(localRot: Boolean) { private val rightElbowNode = TransformNode(localRotation = localRot) private val leftWristNode = TransformNode(localRotation = localRot) private val rightWristNode = TransformNode(localRotation = localRot) - private val leftHandNode = TransformNode(localRotation = localRot) - private val rightHandNode = TransformNode(localRotation = localRot) + private val leftHandNode = TransformNode(localRotation = !localRot) + private val rightHandNode = TransformNode(localRotation = !localRot) + + // Fingers + val leftThumbProximalHeadNode = TransformNode(localRotation = localRot) + val leftThumbProximalTailNode = TransformNode(localRotation = localRot) + val leftThumbIntermediateNode = TransformNode(localRotation = localRot) + val leftThumbDistalNode = TransformNode(localRotation = localRot) + val leftIndexProximalHeadNode = TransformNode(localRotation = localRot) + val leftIndexProximalTailNode = TransformNode(localRotation = localRot) + val leftIndexIntermediateNode = TransformNode(localRotation = localRot) + val leftIndexDistalNode = TransformNode(localRotation = localRot) + val leftMiddleProximalHeadNode = TransformNode(localRotation = localRot) + val leftMiddleProximalTailNode = TransformNode(localRotation = localRot) + val leftMiddleIntermediateNode = TransformNode(localRotation = localRot) + val leftMiddleDistalNode = TransformNode(localRotation = localRot) + val leftRingProximalHeadNode = TransformNode(localRotation = localRot) + val leftRingProximalTailNode = TransformNode(localRotation = localRot) + val leftRingIntermediateNode = TransformNode(localRotation = localRot) + val leftRingDistalNode = TransformNode(localRotation = localRot) + val leftLittleProximalHeadNode = TransformNode(localRotation = localRot) + val leftLittleProximalTailNode = TransformNode(localRotation = localRot) + val leftLittleIntermediateNode = TransformNode(localRotation = localRot) + val leftLittleDistalNode = TransformNode(localRotation = localRot) + val rightThumbProximalHeadNode = TransformNode(localRotation = localRot) + val rightThumbProximalTailNode = TransformNode(localRotation = localRot) + val rightThumbIntermediateNode = TransformNode(localRotation = localRot) + val rightThumbDistalNode = TransformNode(localRotation = localRot) + val rightIndexProximalHeadNode = TransformNode(localRotation = localRot) + val rightIndexProximalTailNode = TransformNode(localRotation = localRot) + val rightIndexIntermediateNode = TransformNode(localRotation = localRot) + val rightIndexDistalNode = TransformNode(localRotation = localRot) + val rightMiddleProximalHeadNode = TransformNode(localRotation = localRot) + val rightMiddleProximalTailNode = TransformNode(localRotation = localRot) + val rightMiddleIntermediateNode = TransformNode(localRotation = localRot) + val rightMiddleDistalNode = TransformNode(localRotation = localRot) + val rightRingProximalHeadNode = TransformNode(localRotation = localRot) + val rightRingProximalTailNode = TransformNode(localRotation = localRot) + val rightRingIntermediateNode = TransformNode(localRotation = localRot) + val rightRingDistalNode = TransformNode(localRotation = localRot) + val rightLittleProximalHeadNode = TransformNode(localRotation = localRot) + val rightLittleProximalTailNode = TransformNode(localRotation = localRot) + val rightLittleIntermediateNode = TransformNode(localRotation = localRot) + val rightLittleDistalNode = TransformNode(localRotation = localRot) private var rootPosition = Vector3.NULL private var rootRotation = Quaternion.IDENTITY @@ -74,6 +123,48 @@ class UnityArmature(localRot: Boolean) { rightElbowNode.attachChild(rightWristNode) leftWristNode.attachChild(leftHandNode) rightWristNode.attachChild(rightHandNode) + + // Fingers + leftHandNode.attachChild(leftThumbProximalHeadNode) + leftThumbProximalHeadNode.attachChild(leftThumbProximalTailNode) + leftThumbProximalTailNode.attachChild(leftThumbIntermediateNode) + leftThumbIntermediateNode.attachChild(leftThumbDistalNode) + leftHandNode.attachChild(leftIndexProximalHeadNode) + leftIndexProximalHeadNode.attachChild(leftIndexProximalTailNode) + leftIndexProximalTailNode.attachChild(leftIndexIntermediateNode) + leftIndexIntermediateNode.attachChild(leftIndexDistalNode) + leftHandNode.attachChild(leftMiddleProximalHeadNode) + leftMiddleProximalHeadNode.attachChild(leftMiddleProximalTailNode) + leftMiddleProximalTailNode.attachChild(leftMiddleIntermediateNode) + leftMiddleIntermediateNode.attachChild(leftMiddleDistalNode) + leftHandNode.attachChild(leftRingProximalHeadNode) + leftRingProximalHeadNode.attachChild(leftRingProximalTailNode) + leftRingProximalTailNode.attachChild(leftRingIntermediateNode) + leftRingIntermediateNode.attachChild(leftRingDistalNode) + leftHandNode.attachChild(leftLittleProximalHeadNode) + leftLittleProximalHeadNode.attachChild(leftLittleProximalTailNode) + leftLittleProximalTailNode.attachChild(leftLittleIntermediateNode) + leftLittleIntermediateNode.attachChild(leftLittleDistalNode) + rightHandNode.attachChild(rightThumbProximalHeadNode) + rightThumbProximalHeadNode.attachChild(rightThumbProximalTailNode) + rightThumbProximalTailNode.attachChild(rightThumbIntermediateNode) + rightThumbIntermediateNode.attachChild(rightThumbDistalNode) + rightHandNode.attachChild(rightIndexProximalHeadNode) + rightIndexProximalHeadNode.attachChild(rightIndexProximalTailNode) + rightIndexProximalTailNode.attachChild(rightIndexIntermediateNode) + rightIndexIntermediateNode.attachChild(rightIndexDistalNode) + rightHandNode.attachChild(rightMiddleProximalHeadNode) + rightMiddleProximalHeadNode.attachChild(rightMiddleProximalTailNode) + rightMiddleProximalTailNode.attachChild(rightMiddleIntermediateNode) + rightMiddleIntermediateNode.attachChild(rightMiddleDistalNode) + rightHandNode.attachChild(rightRingProximalHeadNode) + rightRingProximalHeadNode.attachChild(rightRingProximalTailNode) + rightRingProximalTailNode.attachChild(rightRingIntermediateNode) + rightRingIntermediateNode.attachChild(rightRingDistalNode) + rightHandNode.attachChild(rightLittleProximalHeadNode) + rightLittleProximalHeadNode.attachChild(rightLittleProximalTailNode) + rightLittleProximalTailNode.attachChild(rightLittleIntermediateNode) + rightLittleIntermediateNode.attachChild(rightLittleDistalNode) } fun update() { @@ -91,10 +182,12 @@ class UnityArmature(localRot: Boolean) { fun setGlobalRotationForBone(unityBone: UnityBone, globalRot: Quaternion) { val node = getHeadNodeOfBone(unityBone) if (node != null) { - node.localTransform.rotation = when (unityBone) { - UnityBone.LEFT_UPPER_ARM, UnityBone.LEFT_LOWER_ARM, UnityBone.LEFT_HAND -> globalRot * LEFT_SHOULDER_OFFSET - UnityBone.RIGHT_UPPER_ARM, UnityBone.RIGHT_LOWER_ARM, UnityBone.RIGHT_HAND -> globalRot * RIGHT_SHOULDER_OFFSET - else -> globalRot + node.localTransform.rotation = if (UnityBone.isLeftArmBone(unityBone)) { + globalRot * LEFT_SHOULDER_OFFSET + } else if (UnityBone.isRightArmBone(unityBone)) { + globalRot * RIGHT_SHOULDER_OFFSET + } else { + globalRot } } } @@ -102,13 +195,15 @@ class UnityArmature(localRot: Boolean) { fun setLocalRotationForBone(unityBone: UnityBone, localRot: Quaternion) { val node = getHeadNodeOfBone(unityBone) if (node != null) { - if (unityBone === UnityBone.HIPS) { + if (unityBone == UnityBone.HIPS) { node.worldTransform.rotation = localRot } else { - node.localTransform.rotation = when (unityBone) { - UnityBone.LEFT_UPPER_ARM -> localRot * RIGHT_SHOULDER_OFFSET - UnityBone.RIGHT_UPPER_ARM -> localRot * LEFT_SHOULDER_OFFSET - else -> localRot + node.localTransform.rotation = if (UnityBone.isLeftStartOfArmOrFingerBone(unityBone)) { + localRot * RIGHT_SHOULDER_OFFSET + } else if (UnityBone.isRightStartOfArmOrFingerBone(unityBone)) { + localRot * LEFT_SHOULDER_OFFSET + } else { + localRot } } } @@ -117,7 +212,7 @@ class UnityArmature(localRot: Boolean) { fun getGlobalTranslationForBone(unityBone: UnityBone): Vector3 { val node = getHeadNodeOfBone(unityBone) return if (node != null) { - if (unityBone === UnityBone.HIPS) { + if (unityBone == UnityBone.HIPS) { val hipsAverage = ( leftHipNode.worldTransform.translation + rightHipNode.worldTransform.translation @@ -134,7 +229,7 @@ class UnityArmature(localRot: Boolean) { fun getLocalTranslationForBone(unityBone: UnityBone): Vector3 { val node = getHeadNodeOfBone(unityBone) return if (node != null) { - if (unityBone === UnityBone.HIPS) { + if (unityBone == UnityBone.HIPS) { val hipsAverage = ( leftHipNode.worldTransform.translation + rightHipNode.worldTransform.translation @@ -160,7 +255,7 @@ class UnityArmature(localRot: Boolean) { fun getLocalRotationForBone(unityBone: UnityBone): Quaternion { val node = getHeadNodeOfBone(unityBone) return if (node != null) { - if (unityBone === UnityBone.HIPS) { + if (unityBone == UnityBone.HIPS) { node.worldTransform.rotation * rootRotation } else { node.parent!!.worldTransform.rotation.inv() * node.worldTransform.rotation @@ -194,6 +289,36 @@ class UnityArmature(localRot: Boolean) { UnityBone.RIGHT_LOWER_ARM -> rightElbowNode UnityBone.LEFT_HAND -> leftWristNode UnityBone.RIGHT_HAND -> rightWristNode + UnityBone.LEFT_THUMB_PROXIMAL -> leftThumbProximalHeadNode + UnityBone.LEFT_THUMB_INTERMEDIATE -> leftThumbProximalTailNode + UnityBone.LEFT_THUMB_DISTAL -> leftThumbIntermediateNode + UnityBone.LEFT_INDEX_PROXIMAL -> leftIndexProximalHeadNode + UnityBone.LEFT_INDEX_INTERMEDIATE -> leftIndexProximalTailNode + UnityBone.LEFT_INDEX_DISTAL -> leftIndexIntermediateNode + UnityBone.LEFT_MIDDLE_PROXIMAL -> leftMiddleProximalHeadNode + UnityBone.LEFT_MIDDLE_INTERMEDIATE -> leftMiddleProximalTailNode + UnityBone.LEFT_MIDDLE_DISTAL -> leftMiddleIntermediateNode + UnityBone.LEFT_RING_PROXIMAL -> leftRingProximalHeadNode + UnityBone.LEFT_RING_INTERMEDIATE -> leftRingProximalTailNode + UnityBone.LEFT_RING_DISTAL -> leftRingIntermediateNode + UnityBone.LEFT_LITTLE_PROXIMAL -> leftLittleProximalHeadNode + UnityBone.LEFT_LITTLE_INTERMEDIATE -> leftLittleProximalTailNode + UnityBone.LEFT_LITTLE_DISTAL -> leftLittleIntermediateNode + UnityBone.RIGHT_THUMB_PROXIMAL -> rightThumbProximalHeadNode + UnityBone.RIGHT_THUMB_INTERMEDIATE -> rightThumbProximalTailNode + UnityBone.RIGHT_THUMB_DISTAL -> rightThumbIntermediateNode + UnityBone.RIGHT_INDEX_PROXIMAL -> rightIndexProximalHeadNode + UnityBone.RIGHT_INDEX_INTERMEDIATE -> rightIndexProximalTailNode + UnityBone.RIGHT_INDEX_DISTAL -> rightIndexIntermediateNode + UnityBone.RIGHT_MIDDLE_PROXIMAL -> rightMiddleProximalHeadNode + UnityBone.RIGHT_MIDDLE_INTERMEDIATE -> rightMiddleProximalTailNode + UnityBone.RIGHT_MIDDLE_DISTAL -> rightMiddleIntermediateNode + UnityBone.RIGHT_RING_PROXIMAL -> rightRingProximalHeadNode + UnityBone.RIGHT_RING_INTERMEDIATE -> rightRingProximalTailNode + UnityBone.RIGHT_RING_DISTAL -> rightRingIntermediateNode + UnityBone.RIGHT_LITTLE_PROXIMAL -> rightLittleProximalHeadNode + UnityBone.RIGHT_LITTLE_INTERMEDIATE -> rightLittleProximalTailNode + UnityBone.RIGHT_LITTLE_DISTAL -> rightLittleIntermediateNode else -> null } } diff --git a/server/core/src/main/java/dev/slimevr/osc/UnityBone.kt b/server/core/src/main/java/dev/slimevr/osc/UnityBone.kt index fe549bd4a..0bec9285d 100644 --- a/server/core/src/main/java/dev/slimevr/osc/UnityBone.kt +++ b/server/core/src/main/java/dev/slimevr/osc/UnityBone.kt @@ -38,36 +38,36 @@ enum class UnityBone( LEFT_EYE("LeftEye", null, null), RIGHT_EYE("RightEye", null, null), JAW("Jaw", null, null), - LEFT_THUMB_PROXIMAL("LeftThumbProximal", null, null), - LEFT_THUMB_INTERMEDIATE("LeftThumbIntermediate", null, null), - LEFT_THUMB_DISTAL("LeftThumbDistal", null, null), - LEFT_INDEX_PROXIMAL("LeftIndexProximal", null, null), - LEFT_INDEX_INTERMEDIATE("LeftIndexIntermediate", null, null), - LEFT_INDEX_DISTAL("LeftIndexDistal", null, null), - LEFT_MIDDLE_PROXIMAL("LeftMiddleProximal", null, null), - LEFT_MIDDLE_INTERMEDIATE("LeftMiddleIntermediate", null, null), - LEFT_MIDDLE_DISTAL("LeftMiddleDistal", null, null), - LEFT_RING_PROXIMAL("LeftRingProximal", null, null), - LEFT_RING_INTERMEDIATE("LeftRingIntermediate", null, null), - LEFT_RING_DISTAL("LeftRingDistal", null, null), - LEFT_LITTLE_PROXIMAL("LeftLittleProximal", null, null), - LEFT_LITTLE_INTERMEDIATE("LeftLittleIntermediate", null, null), - LEFT_LITTLE_DISTAL("LeftLittleDistal", null, null), - RIGHT_THUMB_PROXIMAL("RightThumbProximal", null, null), - RIGHT_THUMB_INTERMEDIATE("RightThumbIntermediate", null, null), - RIGHT_THUMB_DISTAL("RightThumbDistal", null, null), - RIGHT_INDEX_PROXIMAL("RightIndexProximal", null, null), - RIGHT_INDEX_INTERMEDIATE("RightIndexIntermediate", null, null), - RIGHT_INDEX_DISTAL("RightIndexDistal", null, null), - RIGHT_MIDDLE_PROXIMAL("RightMiddleProximal", null, null), - RIGHT_MIDDLE_INTERMEDIATE("RightMiddleIntermediate", null, null), - RIGHT_MIDDLE_DISTAL("RightMiddleDistal", null, null), - RIGHT_RING_PROXIMAL("RightRingProximal", null, null), - RIGHT_RING_INTERMEDIATE("RightRingIntermediate", null, null), - RIGHT_RING_DISTAL("RightRingDistal", null, null), - RIGHT_LITTLE_PROXIMAL("RightLittleProximal", null, null), - RIGHT_LITTLE_INTERMEDIATE("RightLittleIntermediate", null, null), - RIGHT_LITTLE_DISTAL("RightLittleDistal", null, null), + LEFT_THUMB_PROXIMAL("LeftThumbProximal", BoneType.LEFT_THUMB_METACARPAL, TrackerPosition.LEFT_THUMB_METACARPAL), + LEFT_THUMB_INTERMEDIATE("LeftThumbIntermediate", BoneType.LEFT_THUMB_PROXIMAL, TrackerPosition.LEFT_THUMB_PROXIMAL), + LEFT_THUMB_DISTAL("LeftThumbDistal", BoneType.LEFT_THUMB_DISTAL, TrackerPosition.LEFT_THUMB_DISTAL), + LEFT_INDEX_PROXIMAL("LeftIndexProximal", BoneType.LEFT_INDEX_PROXIMAL, TrackerPosition.LEFT_INDEX_PROXIMAL), + LEFT_INDEX_INTERMEDIATE("LeftIndexIntermediate", BoneType.LEFT_INDEX_INTERMEDIATE, TrackerPosition.LEFT_INDEX_INTERMEDIATE), + LEFT_INDEX_DISTAL("LeftIndexDistal", BoneType.LEFT_INDEX_DISTAL, TrackerPosition.LEFT_INDEX_DISTAL), + LEFT_MIDDLE_PROXIMAL("LeftMiddleProximal", BoneType.LEFT_MIDDLE_PROXIMAL, TrackerPosition.LEFT_MIDDLE_PROXIMAL), + LEFT_MIDDLE_INTERMEDIATE("LeftMiddleIntermediate", BoneType.LEFT_MIDDLE_INTERMEDIATE, TrackerPosition.LEFT_MIDDLE_INTERMEDIATE), + LEFT_MIDDLE_DISTAL("LeftMiddleDistal", BoneType.LEFT_MIDDLE_DISTAL, TrackerPosition.LEFT_MIDDLE_DISTAL), + LEFT_RING_PROXIMAL("LeftRingProximal", BoneType.LEFT_RING_PROXIMAL, TrackerPosition.LEFT_RING_PROXIMAL), + LEFT_RING_INTERMEDIATE("LeftRingIntermediate", BoneType.LEFT_RING_INTERMEDIATE, TrackerPosition.LEFT_RING_INTERMEDIATE), + LEFT_RING_DISTAL("LeftRingDistal", BoneType.LEFT_RING_DISTAL, TrackerPosition.LEFT_RING_DISTAL), + LEFT_LITTLE_PROXIMAL("LeftLittleProximal", BoneType.LEFT_LITTLE_PROXIMAL, TrackerPosition.LEFT_LITTLE_PROXIMAL), + LEFT_LITTLE_INTERMEDIATE("LeftLittleIntermediate", BoneType.LEFT_LITTLE_INTERMEDIATE, TrackerPosition.LEFT_LITTLE_INTERMEDIATE), + LEFT_LITTLE_DISTAL("LeftLittleDistal", BoneType.LEFT_LITTLE_DISTAL, TrackerPosition.LEFT_LITTLE_DISTAL), + RIGHT_THUMB_PROXIMAL("RightThumbProximal", BoneType.RIGHT_THUMB_METACARPAL, TrackerPosition.RIGHT_THUMB_METACARPAL), + RIGHT_THUMB_INTERMEDIATE("RightThumbIntermediate", BoneType.RIGHT_THUMB_PROXIMAL, TrackerPosition.RIGHT_THUMB_PROXIMAL), + RIGHT_THUMB_DISTAL("RightThumbDistal", BoneType.RIGHT_THUMB_DISTAL, TrackerPosition.RIGHT_THUMB_DISTAL), + RIGHT_INDEX_PROXIMAL("RightIndexProximal", BoneType.RIGHT_INDEX_PROXIMAL, TrackerPosition.RIGHT_INDEX_PROXIMAL), + RIGHT_INDEX_INTERMEDIATE("RightIndexIntermediate", BoneType.RIGHT_INDEX_INTERMEDIATE, TrackerPosition.RIGHT_INDEX_INTERMEDIATE), + RIGHT_INDEX_DISTAL("RightIndexDistal", BoneType.RIGHT_INDEX_DISTAL, TrackerPosition.RIGHT_INDEX_DISTAL), + RIGHT_MIDDLE_PROXIMAL("RightMiddleProximal", BoneType.RIGHT_MIDDLE_PROXIMAL, TrackerPosition.RIGHT_MIDDLE_PROXIMAL), + RIGHT_MIDDLE_INTERMEDIATE("RightMiddleIntermediate", BoneType.RIGHT_MIDDLE_INTERMEDIATE, TrackerPosition.RIGHT_MIDDLE_INTERMEDIATE), + RIGHT_MIDDLE_DISTAL("RightMiddleDistal", BoneType.RIGHT_MIDDLE_DISTAL, TrackerPosition.RIGHT_MIDDLE_DISTAL), + RIGHT_RING_PROXIMAL("RightRingProximal", BoneType.RIGHT_RING_PROXIMAL, TrackerPosition.RIGHT_RING_PROXIMAL), + RIGHT_RING_INTERMEDIATE("RightRingIntermediate", BoneType.RIGHT_RING_INTERMEDIATE, TrackerPosition.RIGHT_RING_INTERMEDIATE), + RIGHT_RING_DISTAL("RightRingDistal", BoneType.RIGHT_RING_DISTAL, TrackerPosition.RIGHT_RING_DISTAL), + RIGHT_LITTLE_PROXIMAL("RightLittleProximal", BoneType.RIGHT_LITTLE_PROXIMAL, TrackerPosition.RIGHT_LITTLE_PROXIMAL), + RIGHT_LITTLE_INTERMEDIATE("RightLittleIntermediate", BoneType.RIGHT_LITTLE_INTERMEDIATE, TrackerPosition.RIGHT_LITTLE_INTERMEDIATE), + RIGHT_LITTLE_DISTAL("RightLittleDistal", BoneType.RIGHT_LITTLE_DISTAL, TrackerPosition.RIGHT_LITTLE_DISTAL), LAST_BONE("LastBone", null, null), ; @@ -76,5 +76,107 @@ enum class UnityBone( @JvmStatic fun getByStringVal(stringVal: String): UnityBone? = byStringVal[stringVal.lowercase()] + + /** + * Returns the bone on the opposite limb, or the original bone if + * it not a limb bone. + */ + fun tryGetOppositeArmBone(bone: UnityBone): UnityBone = when (bone) { + LEFT_SHOULDER -> RIGHT_SHOULDER + LEFT_UPPER_ARM -> RIGHT_UPPER_ARM + LEFT_LOWER_ARM -> RIGHT_LOWER_ARM + LEFT_HAND -> RIGHT_HAND + RIGHT_SHOULDER -> LEFT_SHOULDER + RIGHT_UPPER_ARM -> LEFT_UPPER_ARM + RIGHT_LOWER_ARM -> LEFT_LOWER_ARM + RIGHT_HAND -> LEFT_HAND + LEFT_UPPER_LEG -> RIGHT_UPPER_LEG + LEFT_LOWER_LEG -> RIGHT_LOWER_LEG + LEFT_FOOT -> RIGHT_FOOT + RIGHT_UPPER_LEG -> LEFT_UPPER_LEG + RIGHT_LOWER_LEG -> LEFT_LOWER_LEG + RIGHT_FOOT -> LEFT_FOOT + LEFT_THUMB_PROXIMAL -> RIGHT_THUMB_PROXIMAL + LEFT_THUMB_INTERMEDIATE -> RIGHT_THUMB_INTERMEDIATE + LEFT_THUMB_DISTAL -> RIGHT_THUMB_DISTAL + LEFT_INDEX_PROXIMAL -> RIGHT_INDEX_PROXIMAL + LEFT_INDEX_INTERMEDIATE -> RIGHT_INDEX_INTERMEDIATE + LEFT_INDEX_DISTAL -> RIGHT_INDEX_DISTAL + LEFT_MIDDLE_PROXIMAL -> RIGHT_MIDDLE_PROXIMAL + LEFT_MIDDLE_INTERMEDIATE -> RIGHT_MIDDLE_INTERMEDIATE + LEFT_MIDDLE_DISTAL -> RIGHT_MIDDLE_DISTAL + LEFT_RING_PROXIMAL -> RIGHT_RING_PROXIMAL + LEFT_RING_INTERMEDIATE -> RIGHT_RING_INTERMEDIATE + LEFT_RING_DISTAL -> RIGHT_RING_DISTAL + LEFT_LITTLE_PROXIMAL -> RIGHT_LITTLE_PROXIMAL + LEFT_LITTLE_INTERMEDIATE -> RIGHT_LITTLE_INTERMEDIATE + LEFT_LITTLE_DISTAL -> RIGHT_LITTLE_DISTAL + RIGHT_THUMB_PROXIMAL -> LEFT_THUMB_PROXIMAL + RIGHT_THUMB_INTERMEDIATE -> LEFT_THUMB_INTERMEDIATE + RIGHT_THUMB_DISTAL -> LEFT_THUMB_DISTAL + RIGHT_INDEX_PROXIMAL -> LEFT_INDEX_PROXIMAL + RIGHT_INDEX_INTERMEDIATE -> LEFT_INDEX_INTERMEDIATE + RIGHT_INDEX_DISTAL -> LEFT_INDEX_DISTAL + RIGHT_MIDDLE_PROXIMAL -> LEFT_MIDDLE_PROXIMAL + RIGHT_MIDDLE_INTERMEDIATE -> LEFT_MIDDLE_INTERMEDIATE + RIGHT_MIDDLE_DISTAL -> LEFT_MIDDLE_DISTAL + RIGHT_RING_PROXIMAL -> LEFT_RING_PROXIMAL + RIGHT_RING_INTERMEDIATE -> LEFT_RING_INTERMEDIATE + RIGHT_RING_DISTAL -> LEFT_RING_DISTAL + RIGHT_LITTLE_PROXIMAL -> LEFT_LITTLE_PROXIMAL + RIGHT_LITTLE_INTERMEDIATE -> LEFT_LITTLE_INTERMEDIATE + RIGHT_LITTLE_DISTAL -> LEFT_LITTLE_DISTAL + else -> bone + } + + /** + * Returns true if the bone is part of the left arm (incl. fingers, excl. shoulder) + */ + fun isLeftArmBone(bone: UnityBone): Boolean = bone == LEFT_UPPER_ARM || bone == LEFT_LOWER_ARM || bone == LEFT_HAND || + bone == LEFT_THUMB_PROXIMAL || bone == LEFT_THUMB_INTERMEDIATE || bone == LEFT_THUMB_DISTAL || + bone == LEFT_INDEX_PROXIMAL || bone == LEFT_INDEX_INTERMEDIATE || bone == LEFT_INDEX_DISTAL || + bone == LEFT_MIDDLE_PROXIMAL || bone == LEFT_MIDDLE_INTERMEDIATE || bone == LEFT_MIDDLE_DISTAL || + bone == LEFT_RING_PROXIMAL || bone == LEFT_RING_INTERMEDIATE || bone == LEFT_RING_DISTAL || + bone == LEFT_LITTLE_PROXIMAL || bone == LEFT_LITTLE_INTERMEDIATE || bone == LEFT_LITTLE_DISTAL + + /** + * Returns true if the bone is part of the right arm (incl. fingers, excl. shoulder) + */ + fun isRightArmBone(bone: UnityBone): Boolean = bone == RIGHT_UPPER_ARM || bone == RIGHT_LOWER_ARM || bone == RIGHT_HAND || + bone == RIGHT_THUMB_PROXIMAL || bone == RIGHT_THUMB_INTERMEDIATE || bone == RIGHT_THUMB_DISTAL || + bone == RIGHT_INDEX_PROXIMAL || bone == RIGHT_INDEX_INTERMEDIATE || bone == RIGHT_INDEX_DISTAL || + bone == RIGHT_MIDDLE_PROXIMAL || bone == RIGHT_MIDDLE_INTERMEDIATE || bone == RIGHT_MIDDLE_DISTAL || + bone == RIGHT_RING_PROXIMAL || bone == RIGHT_RING_INTERMEDIATE || bone == RIGHT_RING_DISTAL || + bone == RIGHT_LITTLE_PROXIMAL || bone == RIGHT_LITTLE_INTERMEDIATE || bone == RIGHT_LITTLE_DISTAL + + /** + * Returns true if the bone is the left upper arm or proximal left finger bone + */ + fun isLeftStartOfArmOrFingerBone(bone: UnityBone): Boolean = bone == LEFT_UPPER_ARM || bone == LEFT_THUMB_PROXIMAL || + bone == LEFT_INDEX_PROXIMAL || bone == LEFT_MIDDLE_PROXIMAL || bone == LEFT_RING_PROXIMAL || bone == LEFT_LITTLE_PROXIMAL + + /** + * Returns true if the bone is the right upper arm or proximal right finger bone + */ + fun isRightStartOfArmOrFingerBone(bone: UnityBone): Boolean = bone == RIGHT_UPPER_ARM || bone == RIGHT_THUMB_PROXIMAL || + bone == RIGHT_INDEX_PROXIMAL || bone == RIGHT_MIDDLE_PROXIMAL || bone == RIGHT_RING_PROXIMAL || bone == RIGHT_LITTLE_PROXIMAL + + /** + * Returns true if the bone is part of the left fingers + */ + fun isLeftFingerBone(bone: UnityBone): Boolean = bone == LEFT_THUMB_PROXIMAL || bone == LEFT_THUMB_INTERMEDIATE || bone == LEFT_THUMB_DISTAL || + bone == LEFT_INDEX_PROXIMAL || bone == LEFT_INDEX_INTERMEDIATE || bone == LEFT_INDEX_DISTAL || + bone == LEFT_MIDDLE_PROXIMAL || bone == LEFT_MIDDLE_INTERMEDIATE || bone == LEFT_MIDDLE_DISTAL || + bone == LEFT_RING_PROXIMAL || bone == LEFT_RING_INTERMEDIATE || bone == LEFT_RING_DISTAL || + bone == LEFT_LITTLE_PROXIMAL || bone == LEFT_LITTLE_INTERMEDIATE || bone == LEFT_LITTLE_DISTAL + + /** + * Returns true if the bone part of the right fingers + */ + fun isRightFingerBone(bone: UnityBone): Boolean = bone == RIGHT_THUMB_PROXIMAL || bone == RIGHT_THUMB_INTERMEDIATE || bone == RIGHT_THUMB_DISTAL || + bone == RIGHT_INDEX_PROXIMAL || bone == RIGHT_INDEX_INTERMEDIATE || bone == RIGHT_INDEX_DISTAL || + bone == RIGHT_MIDDLE_PROXIMAL || bone == RIGHT_MIDDLE_INTERMEDIATE || bone == RIGHT_MIDDLE_DISTAL || + bone == RIGHT_RING_PROXIMAL || bone == RIGHT_RING_INTERMEDIATE || bone == RIGHT_RING_DISTAL || + bone == RIGHT_LITTLE_PROXIMAL || bone == RIGHT_LITTLE_INTERMEDIATE || bone == RIGHT_LITTLE_DISTAL } } diff --git a/server/core/src/main/java/dev/slimevr/osc/VMCHandler.kt b/server/core/src/main/java/dev/slimevr/osc/VMCHandler.kt index c9047d60c..473a94a25 100644 --- a/server/core/src/main/java/dev/slimevr/osc/VMCHandler.kt +++ b/server/core/src/main/java/dev/slimevr/osc/VMCHandler.kt @@ -169,7 +169,7 @@ class VMCHandler( try { val addr = InetAddress.getByName(ip) oscSender = OSCPortOut(InetSocketAddress(addr, portOut)) - if ((lastPortOut != portOut && lastAddress !== addr) || !wasConnected) { + if ((lastPortOut != portOut && lastAddress != addr) || !wasConnected) { LogManager .info( "[VMCHandler] Sending to port $portOut at address $ip", @@ -345,13 +345,13 @@ class VMCHandler( oscBundle.addPacket(OSCMessage("/VMC/Ext/Root/Pos", oscArgs.clone())) for (unityBone in UnityBone.entries) { - if (unityBone.boneType == null) continue - // Get opposite bone if tracking must be mirrored - val boneType = (if (mirrorTracking) tryGetOppositeArmBone(unityBone) else unityBone).boneType + val boneType = (if (mirrorTracking) UnityBone.tryGetOppositeArmBone(unityBone) else unityBone).boneType + + if (boneType == null) continue // Get SlimeVR bone - val bone = humanPoseManager.getBone(boneType!!) + val bone = humanPoseManager.getBone(boneType) // Update unity hierarchy from bone's global rotation val boneRotation = if (mirrorTracking) { @@ -368,7 +368,7 @@ class VMCHandler( // Anchor from head outputUnityArmature?.let { unityArmature -> // Scale the SlimeVR head position with the VRM model - val slimevrScaledHeadPos = humanPoseManager.getBone(BoneType.HEAD).getPosition() * + val slimevrScaledHeadPos = humanPoseManager.getBone(BoneType.HEAD).getTailPosition() * (vrmHeight / humanPoseManager.userHeightFromConfig) // Get the VRM head and hip positions @@ -384,20 +384,28 @@ class VMCHandler( } // Update Unity skeleton - outputUnityArmature!!.update() + outputUnityArmature?.update() // Add Unity humanoid bones transforms - for (bone in UnityBone.entries) { - if (bone.boneType != null && - !(humanPoseManager.isTrackingLeftArmFromController && isLeftArmUnityBone(bone)) && - !(humanPoseManager.isTrackingRightArmFromController && isRightArmUnityBone(bone)) + for (unityBone in UnityBone.entries) { + // Don't send bones for which we don't have an equivalent + // Don't send fingers if we don't have any tracker for them + // Don't send arm bones if we're tracking from the controller + if (unityBone.boneType != null && + (!UnityBone.isLeftFingerBone(unityBone) || humanPoseManager.skeleton.hasLeftFingerTracker || (mirrorTracking && humanPoseManager.skeleton.hasRightFingerTracker)) && + (!UnityBone.isRightFingerBone(unityBone) || humanPoseManager.skeleton.hasRightFingerTracker || (mirrorTracking && humanPoseManager.skeleton.hasLeftFingerTracker)) && + !(humanPoseManager.isTrackingLeftArmFromController && (UnityBone.isLeftArmBone(unityBone) || unityBone == UnityBone.LEFT_SHOULDER)) && + !(humanPoseManager.isTrackingRightArmFromController && (UnityBone.isRightArmBone(unityBone) || unityBone == UnityBone.RIGHT_SHOULDER)) ) { oscArgs.clear() - oscArgs.add(bone.stringVal) - addTransformToArgs( - outputUnityArmature!!.getLocalTranslationForBone(bone), - outputUnityArmature!!.getLocalRotationForBone(bone), - ) + oscArgs.add(unityBone.stringVal) + outputUnityArmature?.let { + addTransformToArgs( + it.getLocalTranslationForBone(unityBone), + it.getLocalRotationForBone(unityBone), + ) + } + oscBundle.addPacket(OSCMessage("/VMC/Ext/Bone/Pos", oscArgs.clone())) } } @@ -491,32 +499,6 @@ class VMCHandler( oscArgs.add(-rot.w) } - /** - * Returns the bone on the opposite limb, or the original bone if - * it not a limb bone. - */ - private fun tryGetOppositeArmBone(bone: UnityBone): UnityBone = when (bone) { - UnityBone.LEFT_SHOULDER -> UnityBone.RIGHT_SHOULDER - UnityBone.LEFT_UPPER_ARM -> UnityBone.RIGHT_UPPER_ARM - UnityBone.LEFT_LOWER_ARM -> UnityBone.RIGHT_LOWER_ARM - UnityBone.LEFT_HAND -> UnityBone.RIGHT_HAND - UnityBone.RIGHT_SHOULDER -> UnityBone.LEFT_SHOULDER - UnityBone.RIGHT_UPPER_ARM -> UnityBone.LEFT_UPPER_ARM - UnityBone.RIGHT_LOWER_ARM -> UnityBone.LEFT_LOWER_ARM - UnityBone.RIGHT_HAND -> UnityBone.LEFT_HAND - UnityBone.LEFT_UPPER_LEG -> UnityBone.RIGHT_UPPER_LEG - UnityBone.LEFT_LOWER_LEG -> UnityBone.RIGHT_LOWER_LEG - UnityBone.LEFT_FOOT -> UnityBone.RIGHT_FOOT - UnityBone.RIGHT_UPPER_LEG -> UnityBone.LEFT_UPPER_LEG - UnityBone.RIGHT_LOWER_LEG -> UnityBone.LEFT_LOWER_LEG - UnityBone.RIGHT_FOOT -> UnityBone.LEFT_FOOT - else -> bone - } - - private fun isLeftArmUnityBone(bone: UnityBone): Boolean = bone == UnityBone.LEFT_SHOULDER || bone == UnityBone.LEFT_UPPER_ARM || bone == UnityBone.LEFT_LOWER_ARM || bone == UnityBone.LEFT_HAND - - private fun isRightArmUnityBone(bone: UnityBone): Boolean = bone == UnityBone.RIGHT_SHOULDER || bone == UnityBone.RIGHT_UPPER_ARM || bone == UnityBone.RIGHT_LOWER_ARM || bone == UnityBone.RIGHT_HAND - override fun getOscSender(): OSCPortOut = oscSender!! override fun getPortOut(): Int = lastPortOut diff --git a/server/core/src/main/java/dev/slimevr/osc/VRCOSCHandler.kt b/server/core/src/main/java/dev/slimevr/osc/VRCOSCHandler.kt index e8109a886..85ae4a6a1 100644 --- a/server/core/src/main/java/dev/slimevr/osc/VRCOSCHandler.kt +++ b/server/core/src/main/java/dev/slimevr/osc/VRCOSCHandler.kt @@ -12,6 +12,7 @@ import com.jme3.math.FastMath import com.jme3.system.NanoTimer import dev.slimevr.VRServer import dev.slimevr.config.VRCOSCConfig +import dev.slimevr.protocol.rpc.setup.RPCUtil import dev.slimevr.tracking.trackers.Device import dev.slimevr.tracking.trackers.Tracker import dev.slimevr.tracking.trackers.TrackerPosition @@ -36,7 +37,7 @@ class VRCOSCHandler( private val config: VRCOSCConfig, private val computedTrackers: List, ) : OSCHandler { - private val localIp = InetAddress.getLocalHost().hostAddress + private val localIp = RPCUtil.getLocalIp() private val loopbackIp = InetAddress.getLoopbackAddress().hostAddress private val vrsystemTrackersAddresses = arrayOf( "/tracking/vrsystem/head/pose", @@ -79,7 +80,7 @@ class VRCOSCHandler( override fun refreshSettings(refreshRouterSettings: Boolean) { // Sets which trackers are enabled and force head and hands to false for (i in computedTrackers.indices) { - if (computedTrackers[i].trackerPosition !== TrackerPosition.HEAD || computedTrackers[i].trackerPosition !== TrackerPosition.LEFT_HAND || computedTrackers[i].trackerPosition !== TrackerPosition.RIGHT_HAND) { + if (computedTrackers[i].trackerPosition != TrackerPosition.HEAD || computedTrackers[i].trackerPosition != TrackerPosition.LEFT_HAND || computedTrackers[i].trackerPosition != TrackerPosition.RIGHT_HAND) { trackersEnabled[i] = config .getOSCTrackerRole( computedTrackers[i].trackerPosition!!.trackerRole!!, @@ -94,7 +95,11 @@ class VRCOSCHandler( updateOscSender(config.portOut, config.address) if (vrcOscQueryHandler == null && config.enabled) { - vrcOscQueryHandler = VRCOSCQueryHandler(this) + try { + vrcOscQueryHandler = VRCOSCQueryHandler(this) + } catch (e: Throwable) { + LogManager.severe("Unable to initialize OSCQuery: $e", e) + } } else if (vrcOscQueryHandler != null && !config.enabled) { vrcOscQueryHandler?.close() vrcOscQueryHandler = null @@ -194,7 +199,7 @@ class VRCOSCHandler( try { val addr = InetAddress.getByName(ip) oscSender = OSCPortOut(InetSocketAddress(addr, portOut)) - if (oscPortOut != portOut && oscIp !== addr || !wasConnected) { + if (oscPortOut != portOut && oscIp != addr || !wasConnected) { LogManager.info("[VRCOSCHandler] Sending to port $portOut at address $ip") } oscPortOut = portOut @@ -458,7 +463,7 @@ class VRCOSCHandler( ), ) } - if (computedTrackers[i].trackerPosition === TrackerPosition.HEAD) { + if (computedTrackers[i].trackerPosition == TrackerPosition.HEAD) { // Send HMD position val (x, y, z) = computedTrackers[i].position oscArgs.clear() diff --git a/server/core/src/main/java/dev/slimevr/osc/VRCOSCQueryHandler.kt b/server/core/src/main/java/dev/slimevr/osc/VRCOSCQueryHandler.kt index 67bde3a7b..827d597a3 100644 --- a/server/core/src/main/java/dev/slimevr/osc/VRCOSCQueryHandler.kt +++ b/server/core/src/main/java/dev/slimevr/osc/VRCOSCQueryHandler.kt @@ -23,7 +23,7 @@ class VRCOSCQueryHandler( init { // Request data - val localIp = RPCUtil.getLocalIp() + val localIp = RPCUtil.getLocalIp() ?: throw IllegalStateException("No local IP address found for OSCQuery to bind to") val httpPort = randomFreePort() oscQueryServer = OSCQueryServer( "SlimeVR-Server-$httpPort", diff --git a/server/core/src/main/java/dev/slimevr/poseframeformat/PoseFrameIO.kt b/server/core/src/main/java/dev/slimevr/poseframeformat/PoseFrameIO.kt index b0aa23216..706abfba5 100644 --- a/server/core/src/main/java/dev/slimevr/poseframeformat/PoseFrameIO.kt +++ b/server/core/src/main/java/dev/slimevr/poseframeformat/PoseFrameIO.kt @@ -73,30 +73,26 @@ object PoseFrameIO { } } - fun tryWriteFrames(outputStream: DataOutputStream, frames: PoseFrames): Boolean { - try { - writeFrames(outputStream, frames) - } catch (e: Exception) { - LogManager.severe("Error writing frame to stream", e) - return false - } - return true + fun tryWriteFrames(outputStream: DataOutputStream, frames: PoseFrames): Boolean = try { + writeFrames(outputStream, frames) + true + } catch (e: Exception) { + LogManager.severe("Error writing frame to stream.", e) + false } fun writeToFile(file: File, frames: PoseFrames) { DataOutputStream( BufferedOutputStream(FileOutputStream(file)), - ).use { outputStream -> writeFrames(outputStream, frames) } + ).use { writeFrames(it, frames) } } - fun tryWriteToFile(file: File, frames: PoseFrames): Boolean { - try { - writeToFile(file, frames) - } catch (e: Exception) { - LogManager.severe("Error writing frames to file", e) - return false - } - return true + fun tryWriteToFile(file: File, frames: PoseFrames): Boolean = try { + writeToFile(file, frames) + true + } catch (e: Exception) { + LogManager.severe("Error writing frames to file.", e) + false } @Throws(IOException::class) @@ -166,27 +162,20 @@ object PoseFrameIO { return PoseFrames(trackers) } - fun tryReadFrames(inputStream: DataInputStream): PoseFrames? { - return try { - return readFrames(inputStream) - } catch (e: Exception) { - LogManager.severe("Error reading frames from stream", e) - null - } + fun tryReadFrames(inputStream: DataInputStream): PoseFrames? = try { + readFrames(inputStream) + } catch (e: Exception) { + LogManager.severe("Error reading frames from stream.", e) + null } - fun readFromFile(file: File): PoseFrames = readFrames( - DataInputStream(BufferedInputStream(FileInputStream(file))), - ) + fun readFromFile(file: File): PoseFrames = + DataInputStream(BufferedInputStream(FileInputStream(file))).use { readFrames(it) } - fun tryReadFromFile(file: File): PoseFrames? { - return try { - return readFrames( - DataInputStream(BufferedInputStream(FileInputStream(file))), - ) - } catch (e: Exception) { - LogManager.severe("Error reading frames from file", e) - null - } + fun tryReadFromFile(file: File): PoseFrames? = try { + readFromFile(file) + } catch (e: Exception) { + LogManager.severe("Error reading frames from file.", e) + null } } diff --git a/server/core/src/main/java/dev/slimevr/poseframeformat/PoseRecorder.kt b/server/core/src/main/java/dev/slimevr/poseframeformat/PoseRecorder.kt index 6cd6fca91..c7cd59f32 100644 --- a/server/core/src/main/java/dev/slimevr/poseframeformat/PoseRecorder.kt +++ b/server/core/src/main/java/dev/slimevr/poseframeformat/PoseRecorder.kt @@ -83,12 +83,11 @@ class PoseRecorder(private val server: VRServer) { trackers: List = server.allTrackers, frameCallback: Consumer? = null, ): Future { - require(numFrames >= 1) { "numFrames must at least have a value of 1" } - require(intervalMs >= 1) { "intervalMs must at least have a value of 1" } - require(trackers.isNotEmpty()) { "trackers must have at least one entry" } - check(isReadyToRecord) { "PoseRecorder isn't ready to record!" } + require(numFrames >= 1) { "numFrames must at least have a value of 1." } + require(intervalMs >= 1) { "intervalMs must at least have a value of 1." } + require(trackers.isNotEmpty()) { "trackers must have at least one entry." } cancelFrameRecording() - poseFrame = PoseFrames(trackers.size) + val poseFrame = PoseFrames(trackers.size) // Update tracker list this.trackers.ensureCapacity(trackers.size) @@ -100,12 +99,14 @@ class PoseRecorder(private val server: VRServer) { // Create a tracker recording val trackerFrames = TrackerFrames(tracker, numFrames) - poseFrame?.frameHolders?.add(trackerFrames) + poseFrame.frameHolders.add(trackerFrames) // Pair tracker with recording this.trackers.add(Pair.of(tracker, trackerFrames)) } + require(this.trackers.isNotEmpty()) { "trackers must have at least one valid tracker." } + this.poseFrame = poseFrame frameCursor = 0 this.numFrames = numFrames frameRecordingInterval = intervalMs diff --git a/server/core/src/main/java/dev/slimevr/protocol/datafeed/DataFeedBuilder.java b/server/core/src/main/java/dev/slimevr/protocol/datafeed/DataFeedBuilder.java index bd6089862..2945e5289 100644 --- a/server/core/src/main/java/dev/slimevr/protocol/datafeed/DataFeedBuilder.java +++ b/server/core/src/main/java/dev/slimevr/protocol/datafeed/DataFeedBuilder.java @@ -59,7 +59,7 @@ public class DataFeedBuilder { ) ); - HardwareInfo.addNetworkProtocolVersion(fbb, udpDevice.firmwareBuild); + HardwareInfo.addNetworkProtocolVersion(fbb, udpDevice.protocolVersion); } // BRUH MOMENT @@ -139,8 +139,11 @@ public class DataFeedBuilder { TrackerInfo.addMountingResetOrientation(fbb, createQuat(fbb, mountResetFix)); } + TrackerInfo.addMagnetometer(fbb, tracker.getMagStatus().getSolarType()); TrackerInfo.addIsHmd(fbb, tracker.isHmd()); + TrackerInfo.addDataSupport(fbb, tracker.getTrackerDataType().getSolarType()); + return TrackerInfo.endTrackerInfo(fbb); } diff --git a/server/core/src/main/java/dev/slimevr/protocol/rpc/RPCHandler.kt b/server/core/src/main/java/dev/slimevr/protocol/rpc/RPCHandler.kt index a17940a26..d9995f647 100644 --- a/server/core/src/main/java/dev/slimevr/protocol/rpc/RPCHandler.kt +++ b/server/core/src/main/java/dev/slimevr/protocol/rpc/RPCHandler.kt @@ -2,9 +2,11 @@ package dev.slimevr.protocol.rpc import com.google.flatbuffers.FlatBufferBuilder import dev.slimevr.autobone.errors.BodyProportionError +import dev.slimevr.config.config import dev.slimevr.protocol.GenericConnection import dev.slimevr.protocol.ProtocolAPI import dev.slimevr.protocol.ProtocolHandler +import dev.slimevr.protocol.datafeed.DataFeedBuilder import dev.slimevr.protocol.rpc.autobone.RPCAutoBoneHandler import dev.slimevr.protocol.rpc.reset.RPCResetHandler import dev.slimevr.protocol.rpc.serial.RPCProvisioningHandler @@ -20,33 +22,14 @@ import dev.slimevr.tracking.trackers.TrackerPosition.Companion.getByBodyPart import dev.slimevr.tracking.trackers.TrackerUtils.getTrackerForSkeleton import io.eiren.util.logging.LogManager import io.github.axisangles.ktmath.Quaternion +import kotlinx.coroutines.* import solarxr_protocol.MessageBundle import solarxr_protocol.datatypes.TransactionId -import solarxr_protocol.rpc.AssignTrackerRequest -import solarxr_protocol.rpc.ChangeSkeletonConfigRequest -import solarxr_protocol.rpc.ClearDriftCompensationRequest -import solarxr_protocol.rpc.ClearMountingResetRequest -import solarxr_protocol.rpc.HeightResponse -import solarxr_protocol.rpc.LegTweaksTmpChange -import solarxr_protocol.rpc.LegTweaksTmpClear -import solarxr_protocol.rpc.OverlayDisplayModeChangeRequest -import solarxr_protocol.rpc.OverlayDisplayModeResponse -import solarxr_protocol.rpc.RecordBVHRequest -import solarxr_protocol.rpc.RecordBVHStatus -import solarxr_protocol.rpc.ResetRequest -import solarxr_protocol.rpc.ResetType -import solarxr_protocol.rpc.RpcMessage -import solarxr_protocol.rpc.RpcMessageHeader -import solarxr_protocol.rpc.ServerInfosResponse -import solarxr_protocol.rpc.SetPauseTrackingRequest -import solarxr_protocol.rpc.SkeletonConfigRequest -import solarxr_protocol.rpc.SkeletonResetAllRequest -import solarxr_protocol.rpc.StatusSystemRequest -import solarxr_protocol.rpc.StatusSystemResponse -import solarxr_protocol.rpc.StatusSystemResponseT +import solarxr_protocol.rpc.* class RPCHandler(private val api: ProtocolAPI) : ProtocolHandler() { private var currTransactionId: Long = 0 + private val mainScope = CoroutineScope(SupervisorJob()) init { RPCResetHandler(this, api) @@ -197,6 +180,18 @@ class RPCHandler(private val api: ProtocolAPI) : ProtocolHandler + this.onMagToggleRequest(conn, messageHeader) + } + + registerPacketListener( + RpcMessage.ChangeMagToggleRequest, + ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> + this.onChangeMagToggleRequest(conn, messageHeader) + } } private fun onServerInfosRequest( @@ -205,7 +200,7 @@ class RPCHandler(private val api: ProtocolAPI) : ProtocolHandler + this.onSettingsResetRequest(conn, messageHeader) + } } fun onSettingsRequest(conn: GenericConnection, messageHeader: RpcMessageHeader?) { @@ -84,6 +87,7 @@ class RPCSettingsHandler(var rpcHandler: RPCHandler, var api: ProtocolAPI) { .vrConfig .driftCompensation driftCompensationConfig.enabled = req.driftCompensation().enabled() + driftCompensationConfig.prediction = req.driftCompensation().prediction() driftCompensationConfig.amount = req.driftCompensation().amount() driftCompensationConfig.maxResets = req.driftCompensation().maxResets() driftCompensationConfig.updateTrackersDriftCompensation() @@ -149,7 +153,9 @@ class RPCSettingsHandler(var rpcHandler: RPCHandler, var api: ProtocolAPI) { vmcConfig.portOut = osc.portOut() vmcConfig.address = osc.address() } - if (req.vmcOsc().vrmJson() != null) vmcConfig.vrmJson = req.vmcOsc().vrmJson() + if (req.vmcOsc().vrmJson() != null) { + vmcConfig.vrmJson = req.vmcOsc().vrmJson().ifEmpty { null } + } vmcConfig.anchorHip = req.vmcOsc().anchorHip() vmcConfig.mirrorTracking = req.vmcOsc().mirrorTracking() @@ -344,6 +350,10 @@ class RPCSettingsHandler(var rpcHandler: RPCHandler, var api: ProtocolAPI) { api.server.configManager.saveConfig() } + fun onSettingsResetRequest(conn: GenericConnection, messageHeader: RpcMessageHeader?) { + api.server.configManager.resetConfig() + } + companion object { fun sendSteamVRUpdatedSettings(api: ProtocolAPI, rpcHandler: RPCHandler) { val fbb = FlatBufferBuilder(32) @@ -353,7 +363,7 @@ class RPCSettingsHandler(var rpcHandler: RPCHandler, var api: ProtocolAPI) { val settings = SettingsResponse .createSettingsResponse( fbb, - RPCSettingsBuilder.createSteamVRSettings(fbb, bridge), 0, 0, 0, 0, 0, 0, 0, 0, 0, + RPCSettingsBuilder.createSteamVRSettings(fbb, bridge), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ) val outbound = rpcHandler.createRPCMessage(fbb, RpcMessage.SettingsResponse, settings) diff --git a/server/core/src/main/java/dev/slimevr/protocol/rpc/setup/RPCUtil.kt b/server/core/src/main/java/dev/slimevr/protocol/rpc/setup/RPCUtil.kt index dd3d73827..ef46f2a6c 100644 --- a/server/core/src/main/java/dev/slimevr/protocol/rpc/setup/RPCUtil.kt +++ b/server/core/src/main/java/dev/slimevr/protocol/rpc/setup/RPCUtil.kt @@ -4,10 +4,16 @@ import java.net.NetworkInterface object RPCUtil { @JvmStatic - fun getLocalIp(): String = - NetworkInterface.getNetworkInterfaces().asSequence().first { netInt -> - netInt.isUp && !netInt.isLoopback && !netInt.isVirtual && netInt.interfaceAddresses.any { it.address.isSiteLocalAddress && it.broadcast != null } - }.interfaceAddresses.first { - it.address.isSiteLocalAddress && it.broadcast != null - }.address.hostAddress + fun getLocalIp(): String? { + for (netInt in NetworkInterface.getNetworkInterfaces()) { + if (netInt.isUp && !netInt.isLoopback && !netInt.isVirtual) { + for (netAddr in netInt.interfaceAddresses) { + if (netAddr.address.isSiteLocalAddress && netAddr.broadcast != null) { + return netAddr.address.hostAddress + } + } + } + } + return null + } } diff --git a/server/core/src/main/java/dev/slimevr/status/StatusSystem.kt b/server/core/src/main/java/dev/slimevr/status/StatusSystem.kt index 7dd38930d..d7723a450 100644 --- a/server/core/src/main/java/dev/slimevr/status/StatusSystem.kt +++ b/server/core/src/main/java/dev/slimevr/status/StatusSystem.kt @@ -1,7 +1,5 @@ package dev.slimevr.status -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap -import it.unimi.dsi.fastutil.ints.IntOpenHashSet import solarxr_protocol.rpc.StatusDataUnion import solarxr_protocol.rpc.StatusMessageT import java.util.concurrent.CopyOnWriteArrayList @@ -9,8 +7,8 @@ import java.util.concurrent.atomic.AtomicInteger class StatusSystem { private val listeners: MutableList = CopyOnWriteArrayList() - private val statuses: MutableMap = Int2ObjectOpenHashMap() - private val prioritizedStatuses: MutableSet = IntOpenHashSet() + private val statuses: MutableMap = HashMap() + private val prioritizedStatuses: MutableSet = HashSet() private val idCounter = AtomicInteger(1) fun addListener(listener: StatusListener) { @@ -58,6 +56,10 @@ class StatusSystem { it.onStatusRemoved(id) } } + + fun hasStatusType(dataType: Byte): Boolean = statuses.any { + it.value.type == dataType + } } interface StatusListener { diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/BoneType.java b/server/core/src/main/java/dev/slimevr/tracking/processor/BoneType.java index 146311747..0e263992b 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/processor/BoneType.java +++ b/server/core/src/main/java/dev/slimevr/tracking/processor/BoneType.java @@ -39,7 +39,37 @@ public enum BoneType { LEFT_HAND(BodyPart.LEFT_HAND), RIGHT_HAND(BodyPart.RIGHT_HAND), LEFT_HAND_TRACKER, - RIGHT_HAND_TRACKER; + RIGHT_HAND_TRACKER, + LEFT_THUMB_METACARPAL(BodyPart.LEFT_THUMB_METACARPAL), + LEFT_THUMB_PROXIMAL(BodyPart.LEFT_THUMB_PROXIMAL), + LEFT_THUMB_DISTAL(BodyPart.LEFT_THUMB_DISTAL), + LEFT_INDEX_PROXIMAL(BodyPart.LEFT_INDEX_PROXIMAL), + LEFT_INDEX_INTERMEDIATE(BodyPart.LEFT_INDEX_INTERMEDIATE), + LEFT_INDEX_DISTAL(BodyPart.LEFT_INDEX_DISTAL), + LEFT_MIDDLE_PROXIMAL(BodyPart.LEFT_MIDDLE_PROXIMAL), + LEFT_MIDDLE_INTERMEDIATE(BodyPart.LEFT_MIDDLE_INTERMEDIATE), + LEFT_MIDDLE_DISTAL(BodyPart.LEFT_MIDDLE_DISTAL), + LEFT_RING_PROXIMAL(BodyPart.LEFT_RING_PROXIMAL), + LEFT_RING_INTERMEDIATE(BodyPart.LEFT_RING_INTERMEDIATE), + LEFT_RING_DISTAL(BodyPart.LEFT_RING_DISTAL), + LEFT_LITTLE_PROXIMAL(BodyPart.LEFT_LITTLE_PROXIMAL), + LEFT_LITTLE_INTERMEDIATE(BodyPart.LEFT_LITTLE_INTERMEDIATE), + LEFT_LITTLE_DISTAL(BodyPart.LEFT_LITTLE_DISTAL), + RIGHT_THUMB_METACARPAL(BodyPart.RIGHT_THUMB_METACARPAL), + RIGHT_THUMB_PROXIMAL(BodyPart.RIGHT_THUMB_PROXIMAL), + RIGHT_THUMB_DISTAL(BodyPart.RIGHT_THUMB_DISTAL), + RIGHT_INDEX_PROXIMAL(BodyPart.RIGHT_INDEX_PROXIMAL), + RIGHT_INDEX_INTERMEDIATE(BodyPart.RIGHT_INDEX_INTERMEDIATE), + RIGHT_INDEX_DISTAL(BodyPart.RIGHT_INDEX_DISTAL), + RIGHT_MIDDLE_PROXIMAL(BodyPart.RIGHT_MIDDLE_PROXIMAL), + RIGHT_MIDDLE_INTERMEDIATE(BodyPart.RIGHT_MIDDLE_INTERMEDIATE), + RIGHT_MIDDLE_DISTAL(BodyPart.RIGHT_MIDDLE_DISTAL), + RIGHT_RING_PROXIMAL(BodyPart.RIGHT_RING_PROXIMAL), + RIGHT_RING_INTERMEDIATE(BodyPart.RIGHT_RING_INTERMEDIATE), + 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); public static final BoneType[] values = values(); diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/config/SkeletonConfigManager.kt b/server/core/src/main/java/dev/slimevr/tracking/processor/config/SkeletonConfigManager.kt index 8d43d07ce..9da33ef75 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/processor/config/SkeletonConfigManager.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/processor/config/SkeletonConfigManager.kt @@ -111,7 +111,7 @@ class SkeletonConfigManager( fun setToggle(config: SkeletonConfigToggles, newValue: Boolean?) { if (newValue != null) { - if (configToggles[config] != null && (newValue !== configToggles[config])) { + if (configToggles[config] != null && (newValue != configToggles[config])) { changedToggles[config.id - 1] = true } configToggles[config] = newValue @@ -287,6 +287,51 @@ class SkeletonConfigManager( 0f, ) + BoneType.LEFT_THUMB_METACARPAL, BoneType.LEFT_THUMB_PROXIMAL, BoneType.LEFT_THUMB_DISTAL, + BoneType.RIGHT_THUMB_METACARPAL, BoneType.RIGHT_THUMB_PROXIMAL, BoneType.RIGHT_THUMB_DISTAL, + -> setNodeOffset( + nodeOffset, + 0f, + -getOffset(SkeletonConfigOffsets.HAND_Y) * 0.2f, + -getOffset(SkeletonConfigOffsets.HAND_Y) * 0.1f, + ) + + BoneType.LEFT_INDEX_PROXIMAL, BoneType.LEFT_INDEX_INTERMEDIATE, BoneType.LEFT_INDEX_DISTAL, + BoneType.RIGHT_INDEX_PROXIMAL, BoneType.RIGHT_INDEX_INTERMEDIATE, BoneType.RIGHT_INDEX_DISTAL, + -> setNodeOffset( + nodeOffset, + 0f, + -getOffset(SkeletonConfigOffsets.HAND_Y) * 0.25f, + 0f, + ) + + BoneType.LEFT_MIDDLE_PROXIMAL, BoneType.LEFT_MIDDLE_INTERMEDIATE, BoneType.LEFT_MIDDLE_DISTAL, + BoneType.RIGHT_MIDDLE_PROXIMAL, BoneType.RIGHT_MIDDLE_INTERMEDIATE, BoneType.RIGHT_MIDDLE_DISTAL, + -> setNodeOffset( + nodeOffset, + 0f, + -getOffset(SkeletonConfigOffsets.HAND_Y) * 0.3f, + 0f, + ) + + BoneType.LEFT_RING_PROXIMAL, BoneType.LEFT_RING_INTERMEDIATE, BoneType.LEFT_RING_DISTAL, + BoneType.RIGHT_RING_PROXIMAL, BoneType.RIGHT_RING_INTERMEDIATE, BoneType.RIGHT_RING_DISTAL, + -> setNodeOffset( + nodeOffset, + 0f, + -getOffset(SkeletonConfigOffsets.HAND_Y) * 0.28f, + 0f, + ) + + BoneType.LEFT_LITTLE_PROXIMAL, BoneType.LEFT_LITTLE_INTERMEDIATE, BoneType.LEFT_LITTLE_DISTAL, + BoneType.RIGHT_LITTLE_PROXIMAL, BoneType.RIGHT_LITTLE_INTERMEDIATE, BoneType.RIGHT_LITTLE_DISTAL, + -> setNodeOffset( + nodeOffset, + 0f, + -getOffset(SkeletonConfigOffsets.HAND_Y) * 0.2f, + 0f, + ) + else -> {} } } diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/HumanSkeleton.kt b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/HumanSkeleton.kt index 3c2c0b5ca..adbe0cfce 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/HumanSkeleton.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/HumanSkeleton.kt @@ -12,6 +12,7 @@ import dev.slimevr.tracking.trackers.TrackerPosition import dev.slimevr.tracking.trackers.TrackerRole import dev.slimevr.tracking.trackers.TrackerUtils.getFirstAvailableTracker import dev.slimevr.tracking.trackers.TrackerUtils.getTrackerForSkeleton +import dev.slimevr.tracking.trackers.udp.TrackerDataType import dev.slimevr.util.ann.VRServerThread import io.eiren.util.ann.ThreadSafe import io.eiren.util.collections.FastList @@ -26,6 +27,7 @@ import io.github.axisangles.ktmath.Vector3 import io.github.axisangles.ktmath.Vector3.Companion.NEG_Y import io.github.axisangles.ktmath.Vector3.Companion.NULL import io.github.axisangles.ktmath.Vector3.Companion.POS_Y +import solarxr_protocol.rpc.StatusData import java.lang.IllegalArgumentException import kotlin.properties.Delegates @@ -60,6 +62,38 @@ class HumanSkeleton( val leftHandBone = Bone(BoneType.LEFT_HAND) val rightHandBone = Bone(BoneType.RIGHT_HAND) + // Finger bones + val leftThumbMetacarpalBone = Bone(BoneType.LEFT_THUMB_METACARPAL) + val leftThumbProximalBone = Bone(BoneType.LEFT_THUMB_PROXIMAL) + val leftThumbDistalBone = Bone(BoneType.LEFT_THUMB_DISTAL) + val leftIndexProximalBone = Bone(BoneType.LEFT_INDEX_PROXIMAL) + val leftIndexIntermediateBone = Bone(BoneType.LEFT_INDEX_INTERMEDIATE) + val leftIndexDistalBone = Bone(BoneType.LEFT_INDEX_DISTAL) + val leftMiddleProximalBone = Bone(BoneType.LEFT_MIDDLE_PROXIMAL) + val leftMiddleIntermediateBone = Bone(BoneType.LEFT_MIDDLE_INTERMEDIATE) + val leftMiddleDistalBone = Bone(BoneType.LEFT_MIDDLE_DISTAL) + val leftRingProximalBone = Bone(BoneType.LEFT_RING_PROXIMAL) + val leftRingIntermediateBone = Bone(BoneType.LEFT_RING_INTERMEDIATE) + val leftRingDistalBone = Bone(BoneType.LEFT_RING_DISTAL) + val leftLittleProximalBone = Bone(BoneType.LEFT_LITTLE_PROXIMAL) + val leftLittleIntermediateBone = Bone(BoneType.LEFT_LITTLE_INTERMEDIATE) + val leftLittleDistalBone = Bone(BoneType.LEFT_LITTLE_DISTAL) + val rightThumbMetacarpalBone = Bone(BoneType.RIGHT_THUMB_METACARPAL) + val rightThumbProximalBone = Bone(BoneType.RIGHT_THUMB_PROXIMAL) + val rightThumbDistalBone = Bone(BoneType.RIGHT_THUMB_DISTAL) + val rightIndexProximalBone = Bone(BoneType.RIGHT_INDEX_PROXIMAL) + val rightIndexIntermediateBone = Bone(BoneType.RIGHT_INDEX_INTERMEDIATE) + val rightIndexDistalBone = Bone(BoneType.RIGHT_INDEX_DISTAL) + val rightMiddleProximalBone = Bone(BoneType.RIGHT_MIDDLE_PROXIMAL) + val rightMiddleIntermediateBone = Bone(BoneType.RIGHT_MIDDLE_INTERMEDIATE) + val rightMiddleDistalBone = Bone(BoneType.RIGHT_MIDDLE_DISTAL) + val rightRingProximalBone = Bone(BoneType.RIGHT_RING_PROXIMAL) + val rightRingIntermediateBone = Bone(BoneType.RIGHT_RING_INTERMEDIATE) + val rightRingDistalBone = Bone(BoneType.RIGHT_RING_DISTAL) + val rightLittleProximalBone = Bone(BoneType.RIGHT_LITTLE_PROXIMAL) + val rightLittleIntermediateBone = Bone(BoneType.RIGHT_LITTLE_INTERMEDIATE) + val rightLittleDistalBone = Bone(BoneType.RIGHT_LITTLE_DISTAL) + // Tracker bones val headTrackerBone = Bone(BoneType.HEAD_TRACKER) val chestTrackerBone = Bone(BoneType.CHEST_TRACKER) @@ -76,12 +110,10 @@ class HumanSkeleton( // Buffers var hasSpineTracker = false var hasKneeTrackers = false - var hasLeftLegTracker = false - var hasRightLegTracker = false - var hasLeftFootTracker = false - var hasRightFootTracker = false var hasLeftArmTracker = false var hasRightArmTracker = false + var hasLeftFingerTracker = false + var hasRightFingerTracker = false // Input trackers var headTracker: Tracker? by Delegates.observable(null) { _, old, new -> @@ -109,6 +141,36 @@ class HumanSkeleton( var rightHandTracker: Tracker? = null var leftShoulderTracker: Tracker? = null var rightShoulderTracker: Tracker? = null + var leftThumbMetacarpalTracker: Tracker? = null + var leftThumbProximalTracker: Tracker? = null + var leftThumbDistalTracker: Tracker? = null + var leftIndexProximalTracker: Tracker? = null + var leftIndexIntermediateTracker: Tracker? = null + var leftIndexDistalTracker: Tracker? = null + var leftMiddleProximalTracker: Tracker? = null + var leftMiddleIntermediateTracker: Tracker? = null + var leftMiddleDistalTracker: Tracker? = null + var leftRingProximalTracker: Tracker? = null + var leftRingIntermediateTracker: Tracker? = null + var leftRingDistalTracker: Tracker? = null + var leftLittleProximalTracker: Tracker? = null + var leftLittleIntermediateTracker: Tracker? = null + var leftLittleDistalTracker: Tracker? = null + var rightThumbMetacarpalTracker: Tracker? = null + var rightThumbProximalTracker: Tracker? = null + var rightThumbDistalTracker: Tracker? = null + var rightIndexProximalTracker: Tracker? = null + var rightIndexIntermediateTracker: Tracker? = null + var rightIndexDistalTracker: Tracker? = null + var rightMiddleProximalTracker: Tracker? = null + var rightMiddleIntermediateTracker: Tracker? = null + var rightMiddleDistalTracker: Tracker? = null + var rightRingProximalTracker: Tracker? = null + var rightRingIntermediateTracker: Tracker? = null + var rightRingDistalTracker: Tracker? = null + var rightLittleProximalTracker: Tracker? = null + var rightLittleIntermediateTracker: Tracker? = null + var rightLittleDistalTracker: Tracker? = null // Output trackers var computedHeadTracker: Tracker? = null @@ -258,24 +320,63 @@ class HumanSkeleton( rightLowerArmBone.attachChild(rightHandBone) rightHandBone.attachChild(rightHandTrackerBone) } + + // Fingers + leftHandBone.attachChild(leftThumbMetacarpalBone) + leftThumbMetacarpalBone.attachChild(leftThumbProximalBone) + leftThumbProximalBone.attachChild(leftThumbDistalBone) + leftHandBone.attachChild(leftIndexProximalBone) + leftIndexProximalBone.attachChild(leftIndexIntermediateBone) + leftIndexIntermediateBone.attachChild(leftIndexDistalBone) + leftHandBone.attachChild(leftMiddleProximalBone) + leftMiddleProximalBone.attachChild(leftMiddleIntermediateBone) + leftMiddleIntermediateBone.attachChild(leftMiddleDistalBone) + leftHandBone.attachChild(leftRingProximalBone) + leftRingProximalBone.attachChild(leftRingIntermediateBone) + leftRingIntermediateBone.attachChild(leftRingDistalBone) + leftHandBone.attachChild(leftLittleProximalBone) + leftLittleProximalBone.attachChild(leftLittleIntermediateBone) + leftLittleIntermediateBone.attachChild(leftLittleDistalBone) + rightHandBone.attachChild(rightThumbMetacarpalBone) + rightThumbMetacarpalBone.attachChild(rightThumbProximalBone) + rightThumbProximalBone.attachChild(rightThumbDistalBone) + rightHandBone.attachChild(rightIndexProximalBone) + rightIndexProximalBone.attachChild(rightIndexIntermediateBone) + rightIndexIntermediateBone.attachChild(rightIndexDistalBone) + rightHandBone.attachChild(rightMiddleProximalBone) + rightMiddleProximalBone.attachChild(rightMiddleIntermediateBone) + rightMiddleIntermediateBone.attachChild(rightMiddleDistalBone) + rightHandBone.attachChild(rightRingProximalBone) + rightRingProximalBone.attachChild(rightRingIntermediateBone) + rightRingIntermediateBone.attachChild(rightRingDistalBone) + rightHandBone.attachChild(rightLittleProximalBone) + rightLittleProximalBone.attachChild(rightLittleIntermediateBone) + rightLittleIntermediateBone.attachChild(rightLittleDistalBone) } /** * Set input trackers from a list */ fun setTrackersFromList(trackers: List) { + // Head headTracker = getTrackerForSkeleton(trackers, TrackerPosition.HEAD) neckTracker = getTrackerForSkeleton(trackers, TrackerPosition.NECK) + + // Spine upperChestTracker = getTrackerForSkeleton(trackers, TrackerPosition.UPPER_CHEST) chestTracker = getTrackerForSkeleton(trackers, TrackerPosition.CHEST) waistTracker = getTrackerForSkeleton(trackers, TrackerPosition.WAIST) hipTracker = getTrackerForSkeleton(trackers, TrackerPosition.HIP) + + // Legs leftUpperLegTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_UPPER_LEG) leftLowerLegTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_LOWER_LEG) leftFootTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_FOOT) rightUpperLegTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_UPPER_LEG) rightLowerLegTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_LOWER_LEG) rightFootTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_FOOT) + + // Arms leftLowerArmTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_LOWER_ARM) rightLowerArmTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_LOWER_ARM) leftUpperArmTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_UPPER_ARM) @@ -285,15 +386,53 @@ class HumanSkeleton( leftShoulderTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_SHOULDER) rightShoulderTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_SHOULDER) - // Check for specific conditions and store them in booleans. + // Fingers + leftThumbMetacarpalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_THUMB_METACARPAL) + leftThumbProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_THUMB_PROXIMAL) + leftThumbDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_THUMB_DISTAL) + leftIndexProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_INDEX_PROXIMAL) + leftIndexIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_INDEX_INTERMEDIATE) + leftIndexDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_INDEX_DISTAL) + leftMiddleProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_MIDDLE_PROXIMAL) + leftMiddleIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_MIDDLE_INTERMEDIATE) + leftMiddleDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_MIDDLE_DISTAL) + leftRingProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_RING_PROXIMAL) + leftRingIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_RING_INTERMEDIATE) + leftRingDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_RING_DISTAL) + leftLittleProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_LITTLE_PROXIMAL) + leftLittleIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_LITTLE_INTERMEDIATE) + leftLittleDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_LITTLE_DISTAL) + rightThumbMetacarpalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_THUMB_METACARPAL) + rightThumbProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_THUMB_PROXIMAL) + rightThumbDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_THUMB_DISTAL) + rightIndexProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_INDEX_PROXIMAL) + rightIndexIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_INDEX_INTERMEDIATE) + rightIndexDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_INDEX_DISTAL) + rightMiddleProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_MIDDLE_PROXIMAL) + rightMiddleIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_MIDDLE_INTERMEDIATE) + rightMiddleDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_MIDDLE_DISTAL) + rightRingProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_RING_PROXIMAL) + rightRingIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_RING_INTERMEDIATE) + rightRingDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_RING_DISTAL) + rightLittleProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_LITTLE_PROXIMAL) + rightLittleIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_LITTLE_INTERMEDIATE) + rightLittleDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_LITTLE_DISTAL) + + // Check for specific conditions and cache them hasSpineTracker = upperChestTracker != null || chestTracker != null || waistTracker != null || hipTracker != null hasKneeTrackers = leftUpperLegTracker != null && rightUpperLegTracker != null - hasLeftLegTracker = leftUpperLegTracker != null || leftLowerLegTracker != null || leftFootTracker != null - hasRightLegTracker = rightUpperLegTracker != null || rightLowerLegTracker != null || rightFootTracker != null - hasLeftFootTracker = leftFootTracker != null - hasRightFootTracker = rightFootTracker != null hasLeftArmTracker = leftLowerArmTracker != null || leftUpperArmTracker != null hasRightArmTracker = rightLowerArmTracker != null || rightUpperArmTracker != null + hasLeftFingerTracker = leftThumbMetacarpalTracker != null || leftThumbProximalTracker != null || leftThumbDistalTracker != null || + leftIndexProximalTracker != null || leftIndexIntermediateTracker != null || leftIndexDistalTracker != null || + leftMiddleProximalTracker != null || leftMiddleIntermediateTracker != null || leftMiddleDistalTracker != null || + leftRingProximalTracker != null || leftRingIntermediateTracker != null || leftRingDistalTracker != null || + leftLittleProximalTracker != null || leftLittleIntermediateTracker != null || leftLittleDistalTracker != null + hasRightFingerTracker = rightThumbMetacarpalTracker != null || rightThumbProximalTracker != null || rightThumbDistalTracker != null || + rightIndexProximalTracker != null || rightIndexIntermediateTracker != null || rightIndexDistalTracker != null || + rightMiddleProximalTracker != null || rightMiddleIntermediateTracker != null || rightMiddleDistalTracker != null || + rightRingProximalTracker != null || rightRingIntermediateTracker != null || rightRingDistalTracker != null || + rightLittleProximalTracker != null || rightLittleIntermediateTracker != null || rightLittleDistalTracker != null // Rebuilds the arm skeleton nodes attachments assembleSkeletonArms(true) @@ -393,6 +532,7 @@ class HumanSkeleton( // Spine updateSpineTransforms() + // Left leg updateLegTransforms( leftUpperLegBone, @@ -404,6 +544,7 @@ class HumanSkeleton( leftLowerLegTracker, leftFootTracker, ) + // Right leg updateLegTransforms( rightUpperLegBone, @@ -415,6 +556,7 @@ class HumanSkeleton( rightLowerLegTracker, rightFootTracker, ) + // Left arm updateArmTransforms( isTrackingLeftArmFromController, @@ -429,6 +571,7 @@ class HumanSkeleton( leftLowerArmTracker, leftHandTracker, ) + // Right arm updateArmTransforms( isTrackingRightArmFromController, @@ -443,6 +586,116 @@ class HumanSkeleton( rightLowerArmTracker, rightHandTracker, ) + + // Left thumb + updateFingerTransforms( + leftHandTrackerBone.getGlobalRotation(), + leftThumbMetacarpalBone, + leftThumbProximalBone, + leftThumbDistalBone, + leftThumbMetacarpalTracker, + leftThumbProximalTracker, + leftThumbDistalTracker, + ) + + // Left index + updateFingerTransforms( + leftHandTrackerBone.getGlobalRotation(), + leftIndexProximalBone, + leftIndexIntermediateBone, + leftIndexDistalBone, + leftIndexProximalTracker, + leftIndexIntermediateTracker, + leftIndexDistalTracker, + ) + + // Left middle + updateFingerTransforms( + leftHandTrackerBone.getGlobalRotation(), + leftMiddleProximalBone, + leftMiddleIntermediateBone, + leftMiddleDistalBone, + leftMiddleProximalTracker, + leftMiddleIntermediateTracker, + leftMiddleDistalTracker, + ) + + // Left ring + updateFingerTransforms( + leftHandTrackerBone.getGlobalRotation(), + leftRingProximalBone, + leftRingIntermediateBone, + leftRingDistalBone, + leftRingProximalTracker, + leftRingIntermediateTracker, + leftRingDistalTracker, + ) + + // Left little + updateFingerTransforms( + leftHandTrackerBone.getGlobalRotation(), + leftLittleProximalBone, + leftLittleIntermediateBone, + leftLittleDistalBone, + leftLittleProximalTracker, + leftLittleIntermediateTracker, + leftLittleDistalTracker, + ) + + // Right thumb + updateFingerTransforms( + rightHandTrackerBone.getGlobalRotation(), + rightThumbMetacarpalBone, + rightThumbProximalBone, + rightThumbDistalBone, + rightThumbMetacarpalTracker, + rightThumbProximalTracker, + rightThumbDistalTracker, + ) + + // Right index + updateFingerTransforms( + rightHandTrackerBone.getGlobalRotation(), + rightIndexProximalBone, + rightIndexIntermediateBone, + rightIndexDistalBone, + rightIndexProximalTracker, + rightIndexIntermediateTracker, + rightIndexDistalTracker, + ) + + // Right middle + updateFingerTransforms( + rightHandTrackerBone.getGlobalRotation(), + rightMiddleProximalBone, + rightMiddleIntermediateBone, + rightMiddleDistalBone, + rightMiddleProximalTracker, + rightMiddleIntermediateTracker, + rightMiddleDistalTracker, + ) + + // Right ring + updateFingerTransforms( + rightHandTrackerBone.getGlobalRotation(), + rightRingProximalBone, + rightRingIntermediateBone, + rightRingDistalBone, + rightRingProximalTracker, + rightRingIntermediateTracker, + rightRingDistalTracker, + ) + + // Right little + updateFingerTransforms( + rightHandTrackerBone.getGlobalRotation(), + rightLittleProximalBone, + rightLittleIntermediateBone, + rightLittleDistalBone, + rightLittleProximalTracker, + rightLittleIntermediateTracker, + rightLittleDistalTracker, + ) } /** @@ -625,11 +878,10 @@ class HumanSkeleton( val extendedPelvisRot = extendedPelvisYawRoll(leftLegRot, rightLegRot, hipRot) // Interpolate between the hipRot and extendedPelvisRot - val newHipRot = if (extendedPelvisRot.lenSq() != 0.0f) { - hipRot.interpR(extendedPelvisRot, hipLegsAveraging) - } else { - Quaternion.IDENTITY - } + val newHipRot = hipRot.interpR( + if (extendedPelvisRot.lenSq() != 0.0f) extendedPelvisRot else IDENTITY, + hipLegsAveraging, + ) // Set new hip rotation hipBone.setRotation(newHipRot) @@ -766,6 +1018,70 @@ class HumanSkeleton( } } + /** + * Update a finger's 3 bones' transforms + */ + private fun updateFingerTransforms( + handRotation: Quaternion, + proximalBone: Bone, + intermediateBone: Bone, + distalBone: Bone, + proximalTracker: Tracker?, + intermediateTracker: Tracker?, + distalTracker: Tracker?, + ) { + if (distalTracker == null && intermediateTracker == null && proximalTracker == null) { + // Set fingers' rotations to the hand's if no finger tracker + proximalBone.setRotation(handRotation) + intermediateBone.setRotation(handRotation) + distalBone.setRotation(handRotation) + } + + // Note: we use interpQ instead of interpR in order to slerp over 180 degrees. + // Start of finger + proximalTracker?.let { + val fingerRot = if (it.trackerDataType == TrackerDataType.FLEX_RESISTANCE || + it.trackerDataType == TrackerDataType.FLEX_ANGLE + ) { + handRotation * it.getRotation() + } else { + it.getRotation() + } + + proximalBone.setRotation(fingerRot) + if (intermediateTracker == null) intermediateBone.setRotation(handRotation.interpQ(fingerRot, 2.12f)) + if (distalTracker == null) distalBone.setRotation(handRotation.interpQ(fingerRot, 3.03f)) + } + // Middle of finger + intermediateTracker?.let { + val fingerRot = if (it.trackerDataType == TrackerDataType.FLEX_RESISTANCE || + it.trackerDataType == TrackerDataType.FLEX_ANGLE + ) { + handRotation * it.getRotation() + } else { + it.getRotation() + } + + if (proximalTracker == null) proximalBone.setRotation(handRotation.interpQ(fingerRot, 0.47f)) + intermediateBone.setRotation(fingerRot) + if (distalTracker == null) distalBone.setRotation(handRotation.interpQ(fingerRot, 1.43f)) + } + // Tip of finger + distalTracker?.let { + val fingerRot = if (it.trackerDataType == TrackerDataType.FLEX_RESISTANCE || + it.trackerDataType == TrackerDataType.FLEX_ANGLE + ) { + handRotation * it.getRotation() + } else { + it.getRotation() + } + + if (proximalTracker == null && intermediateTracker == null) proximalBone.setRotation(handRotation.interpQ(fingerRot, 0.33f)) + if (intermediateTracker == null) intermediateBone.setRotation(handRotation.interpQ(fingerRot, 0.7f)) + distalBone.setRotation(fingerRot) + } + } + /** * Rotates the first Quaternion to match its yaw and roll to the rotation of * the second Quaternion @@ -958,6 +1274,36 @@ class HumanSkeleton( BoneType.RIGHT_HAND -> rightHandBone BoneType.LEFT_HAND_TRACKER -> leftHandTrackerBone BoneType.RIGHT_HAND_TRACKER -> rightHandTrackerBone + BoneType.LEFT_THUMB_METACARPAL -> leftThumbMetacarpalBone + BoneType.LEFT_THUMB_PROXIMAL -> leftThumbProximalBone + BoneType.LEFT_THUMB_DISTAL -> leftThumbDistalBone + BoneType.LEFT_INDEX_PROXIMAL -> leftIndexProximalBone + BoneType.LEFT_INDEX_INTERMEDIATE -> leftIndexIntermediateBone + BoneType.LEFT_INDEX_DISTAL -> leftIndexDistalBone + BoneType.LEFT_MIDDLE_PROXIMAL -> leftMiddleProximalBone + BoneType.LEFT_MIDDLE_INTERMEDIATE -> leftMiddleIntermediateBone + BoneType.LEFT_MIDDLE_DISTAL -> leftMiddleDistalBone + BoneType.LEFT_RING_PROXIMAL -> leftRingProximalBone + BoneType.LEFT_RING_INTERMEDIATE -> leftRingIntermediateBone + BoneType.LEFT_RING_DISTAL -> leftRingDistalBone + BoneType.LEFT_LITTLE_PROXIMAL -> leftLittleProximalBone + BoneType.LEFT_LITTLE_INTERMEDIATE -> leftLittleIntermediateBone + BoneType.LEFT_LITTLE_DISTAL -> leftLittleDistalBone + BoneType.RIGHT_THUMB_METACARPAL -> rightThumbMetacarpalBone + BoneType.RIGHT_THUMB_PROXIMAL -> rightThumbProximalBone + BoneType.RIGHT_THUMB_DISTAL -> rightThumbDistalBone + BoneType.RIGHT_INDEX_PROXIMAL -> rightIndexProximalBone + BoneType.RIGHT_INDEX_INTERMEDIATE -> rightIndexIntermediateBone + BoneType.RIGHT_INDEX_DISTAL -> rightIndexDistalBone + BoneType.RIGHT_MIDDLE_PROXIMAL -> rightMiddleProximalBone + BoneType.RIGHT_MIDDLE_INTERMEDIATE -> rightMiddleIntermediateBone + BoneType.RIGHT_MIDDLE_DISTAL -> rightMiddleDistalBone + BoneType.RIGHT_RING_PROXIMAL -> rightRingProximalBone + BoneType.RIGHT_RING_INTERMEDIATE -> rightRingIntermediateBone + BoneType.RIGHT_RING_DISTAL -> rightRingDistalBone + BoneType.RIGHT_LITTLE_PROXIMAL -> rightLittleProximalBone + BoneType.RIGHT_LITTLE_INTERMEDIATE -> rightLittleIntermediateBone + BoneType.RIGHT_LITTLE_DISTAL -> rightLittleDistalBone } /** @@ -987,6 +1333,36 @@ class HumanSkeleton( rightLowerArmBone, leftHandBone, rightHandBone, + leftThumbMetacarpalBone, + leftThumbProximalBone, + leftThumbDistalBone, + leftIndexProximalBone, + leftIndexIntermediateBone, + leftIndexDistalBone, + leftMiddleProximalBone, + leftMiddleIntermediateBone, + leftMiddleDistalBone, + leftRingProximalBone, + leftRingIntermediateBone, + leftRingDistalBone, + leftLittleProximalBone, + leftLittleIntermediateBone, + leftLittleDistalBone, + rightThumbMetacarpalBone, + rightThumbProximalBone, + rightThumbDistalBone, + rightIndexProximalBone, + rightIndexIntermediateBone, + rightIndexDistalBone, + rightMiddleProximalBone, + rightMiddleIntermediateBone, + rightMiddleDistalBone, + rightRingProximalBone, + rightRingIntermediateBone, + rightRingDistalBone, + rightLittleProximalBone, + rightLittleIntermediateBone, + rightLittleDistalBone, ) /** @@ -1006,6 +1382,36 @@ class HumanSkeleton( rightHandBone, leftHandTrackerBone, rightHandTrackerBone, + leftThumbMetacarpalBone, + leftThumbProximalBone, + leftThumbDistalBone, + leftIndexProximalBone, + leftIndexIntermediateBone, + leftIndexDistalBone, + leftMiddleProximalBone, + leftMiddleIntermediateBone, + leftMiddleDistalBone, + leftRingProximalBone, + leftRingIntermediateBone, + leftRingDistalBone, + leftLittleProximalBone, + leftLittleIntermediateBone, + leftLittleDistalBone, + rightThumbMetacarpalBone, + rightThumbProximalBone, + rightThumbDistalBone, + rightIndexProximalBone, + rightIndexIntermediateBone, + rightIndexDistalBone, + rightMiddleProximalBone, + rightMiddleIntermediateBone, + rightMiddleDistalBone, + rightRingProximalBone, + rightRingIntermediateBone, + rightRingDistalBone, + rightLittleProximalBone, + rightLittleIntermediateBone, + rightLittleDistalBone, ) val hmdHeight: Float @@ -1052,6 +1458,36 @@ class HumanSkeleton( rightHandTracker, leftShoulderTracker, rightShoulderTracker, + leftThumbMetacarpalTracker, + leftThumbProximalTracker, + leftThumbDistalTracker, + leftIndexProximalTracker, + leftIndexIntermediateTracker, + leftIndexDistalTracker, + leftMiddleProximalTracker, + leftMiddleIntermediateTracker, + leftMiddleDistalTracker, + leftRingProximalTracker, + leftRingIntermediateTracker, + leftRingDistalTracker, + leftLittleProximalTracker, + leftLittleIntermediateTracker, + leftLittleDistalTracker, + rightThumbMetacarpalTracker, + rightThumbProximalTracker, + rightThumbDistalTracker, + rightIndexProximalTracker, + rightIndexIntermediateTracker, + rightIndexDistalTracker, + rightMiddleProximalTracker, + rightMiddleIntermediateTracker, + rightMiddleDistalTracker, + rightRingProximalTracker, + rightRingIntermediateTracker, + rightRingDistalTracker, + rightLittleProximalTracker, + rightLittleIntermediateTracker, + rightLittleDistalTracker, ) fun resetTrackersFull(resetSourceName: String?) { @@ -1102,6 +1538,12 @@ class HumanSkeleton( @VRServerThread fun resetTrackersMounting(resetSourceName: String?) { + val server = humanPoseManager.server + if (server != null && server.statusSystem.hasStatusType(StatusData.StatusTrackerReset)) { + LogManager.info("[HumanSkeleton] Reset: mounting ($resetSourceName) failed, reset required") + return + } + // Resets the mounting orientation of the trackers with the HMD as reference. var referenceRotation = IDENTITY headTracker?.let { diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/Localizer.kt b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/Localizer.kt index 7a92814c1..f047df854 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/Localizer.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/Localizer.kt @@ -210,7 +210,7 @@ class Localizer(humanSkeleton: HumanSkeleton) { // update the target position of the foot private fun updateTargetPos(loc: Vector3, foot: MovementStates) { if (foot == plantedFoot) { - if (worldReference === MovementStates.FOLLOW_COM) { + if (worldReference == MovementStates.FOLLOW_COM) { targetFoot = loc } } else { @@ -255,16 +255,16 @@ class Localizer(humanSkeleton: HumanSkeleton) { // update how long the COM has been the reference and how long the foot // has been - comFrames = if (worldReference === MovementStates.FOLLOW_COM) comFrames + 1 else 0 - footFrames = if (worldReference === MovementStates.FOLLOW_FOOT) footFrames + 1 else 0 - sittingFrames = if (worldReference === MovementStates.FOLLOW_SITTING) sittingFrames + 1 else 0 + comFrames = if (worldReference == MovementStates.FOLLOW_COM) comFrames + 1 else 0 + footFrames = if (worldReference == MovementStates.FOLLOW_FOOT) footFrames + 1 else 0 + sittingFrames = if (worldReference == MovementStates.FOLLOW_SITTING) sittingFrames + 1 else 0 } // gets the position the COM should be at based on the velocity of the com and // the location of the floor private fun updateTargetCOM() { // if not in COM tracking mode, just use the current COM - if (worldReference === MovementStates.FOLLOW_FOOT || worldReference === MovementStates.FOLLOW_SITTING) { + if (worldReference == MovementStates.FOLLOW_FOOT || worldReference == MovementStates.FOLLOW_SITTING) { targetCOM = bufCur.centerOfMass } else { currentCOM = targetCOM @@ -293,7 +293,7 @@ class Localizer(humanSkeleton: HumanSkeleton) { val comPosStart: Vector3 = buf.centerOfMass // get the buffer that occurred VELOCITY_SAMPLE_RATE ago in time - while (buf.timeOfFrame > timeEnd && buf.parent !== null) { + while (buf.timeOfFrame > timeEnd && buf.parent != null) { buf = buf.parent!! } diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetection.kt b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetection.kt index 20f9c223e..71f5e50c2 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetection.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetection.kt @@ -73,7 +73,7 @@ class TapDetection { accelList.add(listval) // remove old values from the list (if they are too old) - while (time - accelList.first[1] > CLUMP_TIME_NS) { + while (time - accelList.first()[1] > CLUMP_TIME_NS) { accelList.removeFirst() } @@ -93,7 +93,7 @@ class TapDetection { // remove old taps from the list (if they are too old) if (!tapTimes.isEmpty()) { - while (time - tapTimes.first > timeWindowNS) { + while (time - tapTimes.first() > timeWindowNS) { tapTimes.removeFirst() if (tapTimes.isEmpty()) return } diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetectionManager.java b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetectionManager.java index 298b8459a..6e32e2693 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetectionManager.java +++ b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetectionManager.java @@ -1,12 +1,14 @@ package dev.slimevr.tracking.processor.skeleton; +import dev.slimevr.VRServer; 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; +import solarxr_protocol.rpc.StatusData; import java.util.ArrayList; import java.util.List; @@ -192,6 +194,13 @@ public class TapDetectionManager { } private void checkMountingReset() { + // Don't allow mounting if tracker needs reset + VRServer server = humanPoseManager.getServer(); + if (server != null && server.statusSystem.hasStatusType(StatusData.StatusTrackerReset)) { + mountingResetDetector.resetDetector(); + return; + } + boolean tapped = (mountingResetTaps <= mountingResetDetector.getTaps()); if (tapped && mountingResetAllowPlaySound) { diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/Device.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/Device.kt index 71d6db17b..4fca49688 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/Device.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/Device.kt @@ -2,10 +2,14 @@ package dev.slimevr.tracking.trackers import dev.slimevr.tracking.trackers.udp.BoardType import dev.slimevr.tracking.trackers.udp.MCUType +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicInteger -open class Device { +open class Device(val magSupport: Boolean = false) { open val id: Int = nextLocalDeviceId.incrementAndGet() open var name: String? = null open var firmwareVersion: String? = null @@ -24,6 +28,22 @@ open class Device { val isOpenVrDevice: Boolean get() = manufacturer == "OpenVR" + init { + CoroutineScope(Job()).launch { + // Wait a little for device to get configured + delay(1000) + } + } + + /** + * Enables or disables magnetometers in all the trackers of the device + * if `sensorId` null or in the specified tracker + * @param sensorId If null, every sensor will be modified + */ + open suspend fun setMag(state: Boolean, sensorId: Int = 255) { + TODO("Not implemented because no mag support: $magSupport") + } + companion object { @JvmStatic protected val nextLocalDeviceId = AtomicInteger() diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt index 564dd4b85..b0d60d475 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt @@ -4,6 +4,8 @@ import dev.slimevr.VRServer import dev.slimevr.config.TrackerConfig import dev.slimevr.tracking.trackers.TrackerPosition.Companion.getByDesignation import dev.slimevr.tracking.trackers.udp.IMUType +import dev.slimevr.tracking.trackers.udp.MagnetometerStatus +import dev.slimevr.tracking.trackers.udp.TrackerDataType import io.eiren.util.BufferedTimer import io.github.axisangles.ktmath.Quaternion import io.github.axisangles.ktmath.Vector3 @@ -65,6 +67,12 @@ class Tracker @JvmOverloads constructor( val needsReset: Boolean = false, val needsMounting: Boolean = false, val isHmd: Boolean = false, + magStatus: MagnetometerStatus = MagnetometerStatus.NOT_SUPPORTED, + /** + * Rotation by default. + * NOT the same as hasRotation (other data types emulate rotation) + */ + val trackerDataType: TrackerDataType = TrackerDataType.ROTATION, ) { private val timer = BufferedTimer(1f) private var timeAtLastUpdate: Long = System.currentTimeMillis() @@ -73,12 +81,15 @@ class Tracker @JvmOverloads constructor( var position = Vector3.NULL val resetsHandler: TrackerResetsHandler = TrackerResetsHandler(this) val filteringHandler: TrackerFilteringHandler = TrackerFilteringHandler() + val trackerFlexHandler: TrackerFlexHandler = TrackerFlexHandler(this) var batteryVoltage: Float? = null var batteryLevel: Float? = null var ping: Int? = null var signalStrength: Int? = null var temperature: Float? = null var customName: String? = null + var magStatus: MagnetometerStatus = magStatus + private set /** * If the tracker has gotten disconnected after it was initialized first time @@ -146,7 +157,7 @@ class Tracker @JvmOverloads constructor( fun checkReportRequireReset() { if (needsReset && trackerPosition != null && lastResetStatus == 0u && - !status.reset && (isImu() || !statusResetRecently) + !status.reset && (isImu() || !statusResetRecently && trackerDataType != TrackerDataType.FLEX_ANGLE) ) { reportRequireReset() } else if (lastResetStatus != 0u && (trackerPosition == null || status.reset)) { @@ -315,15 +326,16 @@ class Tracker @JvmOverloads constructor( * it too much should be avoided for performance reasons. */ fun getRotation(): Quaternion { - var rot = if (allowFiltering && filteringHandler.enabled) { + var rot = if (allowFiltering && filteringHandler.filteringEnabled) { // Get filtered rotation filteringHandler.getFilteredRotation() } else { // Get unfiltered rotation - _rotation + filteringHandler.getTrackedRotation() } - if (needsReset || (isComputed && !isInternal)) { + // Reset if needed and is not computed and internal + if (needsReset && !(isComputed && isInternal) && trackerDataType == TrackerDataType.ROTATION) { // Adjust to reset, mounting and drift compensation rot = resetsHandler.getReferenceAdjustedDriftRotationFrom(rot) } @@ -346,15 +358,16 @@ class Tracker @JvmOverloads constructor( * This is used for debugging/visualizing tracker data */ fun getIdentityAdjustedRotation(): Quaternion { - var rot = if (filteringHandler.enabled) { + var rot = if (filteringHandler.filteringEnabled) { // Get filtered rotation filteringHandler.getFilteredRotation() } else { // Get unfiltered rotation - _rotation + filteringHandler.getTrackedRotation() } - if (needsReset || (isComputed && trackerPosition == TrackerPosition.HEAD)) { + // Reset if needed or is a computed tracker besides head + if (needsReset && !(isComputed && trackerPosition != TrackerPosition.HEAD) && trackerDataType == TrackerDataType.ROTATION) { // Adjust to reset and mounting rot = resetsHandler.getIdentityAdjustedDriftRotationFrom(rot) } @@ -366,7 +379,7 @@ class Tracker @JvmOverloads constructor( * Gets the raw (unadjusted) rotation of the tracker. * If this is an IMU, this will be the raw sensor rotation. */ - fun getRawRotation(): Quaternion = _rotation + fun getRawRotation() = _rotation /** * Sets the raw (unadjusted) rotation of the tracker. @@ -382,11 +395,33 @@ class Tracker @JvmOverloads constructor( this._acceleration = vec } - fun isImu(): Boolean = imuType != null + /** + * True if the raw rotation is coming directly from an IMU (no cameras or lighthouses) + * For example, flex sensor trackers are not considered as IMU trackers (see TrackerDataType) + */ + fun isImu(): Boolean = imuType != null && trackerDataType == TrackerDataType.ROTATION + + /** + * Please don't use this and instead set it via [Device.setMag] + */ + internal fun setMagPrivate(mag: Boolean) { + magStatus = if (mag) { + MagnetometerStatus.ENABLED + } else { + MagnetometerStatus.DISABLED + } + } /** * Gets the current TPS of the tracker */ val tps: Float get() = timer.averageFPS + + /** + * Call when doing a full reset to reset the tracking of rotations >180 degrees + */ + fun resetFilteringQuats() { + filteringHandler.resetQuats(_rotation) + } } diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerFilteringHandler.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerFilteringHandler.kt index 5e7a8ca12..e00f06b8a 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerFilteringHandler.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerFilteringHandler.kt @@ -12,8 +12,9 @@ import io.github.axisangles.ktmath.Quaternion */ class TrackerFilteringHandler { - private var movingAverage: QuaternionMovingAverage? = null - var enabled = false + private var filteringMovingAverage: QuaternionMovingAverage? = null + private var trackingMovingAverage = QuaternionMovingAverage(TrackerFilters.NONE) + var filteringEnabled = false /** * Reads/loads filtering settings from given config @@ -21,15 +22,15 @@ class TrackerFilteringHandler { fun readFilteringConfig(config: FiltersConfig, currentRawRotation: Quaternion) { val type = TrackerFilters.getByConfigkey(config.type) if (type == TrackerFilters.SMOOTHING || type == TrackerFilters.PREDICTION) { - movingAverage = QuaternionMovingAverage( + filteringMovingAverage = QuaternionMovingAverage( type, config.amount, currentRawRotation, ) - enabled = true + filteringEnabled = true } else { - movingAverage = null - enabled = false + filteringMovingAverage = null + filteringEnabled = false } } @@ -37,18 +38,33 @@ class TrackerFilteringHandler { * Update the moving average to make it smooth */ fun update() { - movingAverage?.update() + trackingMovingAverage.update() + filteringMovingAverage?.update() } /** * Updates the latest rotation */ fun dataTick(currentRawRotation: Quaternion) { - movingAverage?.addQuaternion(currentRawRotation) + trackingMovingAverage.addQuaternion(currentRawRotation) + filteringMovingAverage?.addQuaternion(currentRawRotation) } + /** + * Call when doing a full reset to reset the tracking of rotations >180 degrees + */ + fun resetQuats(currentRawRotation: Quaternion) { + trackingMovingAverage.resetQuats(currentRawRotation) + filteringMovingAverage?.resetQuats(currentRawRotation) + } + + /** + * Gets the tracked rotation from the moving average (allows >180 degrees) + */ + fun getTrackedRotation() = trackingMovingAverage.filteredQuaternion + /** * Get the filtered rotation from the moving average */ - fun getFilteredRotation(): Quaternion = movingAverage?.filteredQuaternion ?: Quaternion.IDENTITY + fun getFilteredRotation() = filteringMovingAverage?.filteredQuaternion ?: Quaternion.IDENTITY } diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerFlexHandler.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerFlexHandler.kt new file mode 100644 index 000000000..653292cfb --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerFlexHandler.kt @@ -0,0 +1,176 @@ +package dev.slimevr.tracking.trackers + +import com.jme3.math.FastMath +import io.github.axisangles.ktmath.EulerAngles +import io.github.axisangles.ktmath.EulerOrder +import kotlin.math.* + +/** + * Class handling flex sensor data (angle and resistance) + * Resistance is expected to go up with bend by default, but a mounting reset allows the contrary + */ +class TrackerFlexHandler(val tracker: Tracker) { + private var minResistance = Float.MIN_VALUE + private var maxResistance = Float.MAX_VALUE + + // Used to support resistance going both ways. + // Default is higher = more bend, but can change after a full and mounting reset. + private var lastMinResetResistance = Float.MIN_VALUE + private var resistanceReversed = false + private var lastResistance = 0f + private val thumbInitialOffset = FastMath.PI / 8 // 22.5 deg + + /** + * Resets the min resistance from the last resistance value received. + * Triggered from full reset + */ + fun resetMin() { + minResistance = lastResistance + lastMinResetResistance = lastResistance + + setFlexResistance(lastResistance) + tracker.dataTick() + } + + /** + * Resets the max resistance from the last resistance value received. + * Triggered from mounting reset + */ + fun resetMax() { + // Account for the resistance being able to be reversed + if (resistanceReversed != lastResistance < lastMinResetResistance) { + // Switching + resistanceReversed = lastResistance < lastMinResetResistance + minResistance = maxResistance + maxResistance = lastMinResetResistance + } else { + // Not switching + maxResistance = lastResistance + } + + setFlexResistance(lastResistance) + tracker.dataTick() + } + + /** + * Sets the flex resistance which is then calculated into an angle + */ + fun setFlexResistance(resistance: Float) { + // Dynamically calibrate the minimum resistance + minResistance = if (minResistance == Float.MIN_VALUE) { + resistance + } else if (!resistanceReversed) { + min(minResistance, resistance) + } else { + max(minResistance, resistance) + } + + // Dynamically calibrate the maximum resistance + maxResistance = if (maxResistance == Float.MAX_VALUE) { + resistance + } else if (!resistanceReversed) { + max(maxResistance, resistance) + } else { + min(maxResistance, resistance) + } + + // Get max angle + val maxBend = getMaxAngleForTrackerPosition(tracker.trackerPosition) + + // Get angle and set it + val angle = if (minResistance == maxResistance) { + // Avoid division by 0 + 0f + } else { + maxBend * (resistance - minResistance) / (maxResistance - minResistance) + } + setFlexAngle(angle) + + lastResistance = resistance + } + + /** + * Sets an angle (rad) about the X axis + */ + fun setFlexAngle(angle: Float) { + // Sets the rotation of the tracker by the angle about a given axis depending on + // the tracker's TrackerPosition + when (tracker.trackerPosition) { + TrackerPosition.LEFT_INDEX_PROXIMAL, TrackerPosition.LEFT_INDEX_INTERMEDIATE, + TrackerPosition.LEFT_INDEX_DISTAL, TrackerPosition.LEFT_MIDDLE_PROXIMAL, + TrackerPosition.LEFT_MIDDLE_INTERMEDIATE, TrackerPosition.LEFT_MIDDLE_DISTAL, + TrackerPosition.LEFT_RING_PROXIMAL, TrackerPosition.LEFT_RING_INTERMEDIATE, + TrackerPosition.LEFT_RING_DISTAL, TrackerPosition.LEFT_LITTLE_PROXIMAL, + TrackerPosition.LEFT_LITTLE_INTERMEDIATE, TrackerPosition.LEFT_LITTLE_DISTAL, + TrackerPosition.RIGHT_SHOULDER, + -> tracker.setRotation(EulerAngles(EulerOrder.YZX, 0f, 0f, angle).toQuaternion()) + + TrackerPosition.RIGHT_INDEX_PROXIMAL, TrackerPosition.RIGHT_INDEX_INTERMEDIATE, + TrackerPosition.RIGHT_INDEX_DISTAL, TrackerPosition.RIGHT_MIDDLE_PROXIMAL, + TrackerPosition.RIGHT_MIDDLE_INTERMEDIATE, TrackerPosition.RIGHT_MIDDLE_DISTAL, + TrackerPosition.RIGHT_RING_PROXIMAL, TrackerPosition.RIGHT_RING_INTERMEDIATE, + TrackerPosition.RIGHT_RING_DISTAL, TrackerPosition.RIGHT_LITTLE_PROXIMAL, + TrackerPosition.RIGHT_LITTLE_INTERMEDIATE, TrackerPosition.RIGHT_LITTLE_DISTAL, + TrackerPosition.LEFT_SHOULDER, + -> tracker.setRotation(EulerAngles(EulerOrder.YZX, 0f, 0f, -angle).toQuaternion()) + + TrackerPosition.LEFT_THUMB_METACARPAL, TrackerPosition.LEFT_THUMB_PROXIMAL, TrackerPosition.LEFT_THUMB_DISTAL, + -> tracker.setRotation(EulerAngles(EulerOrder.YZX, thumbInitialOffset - angle, -angle * 0.05f, angle * 0.1f).toQuaternion()) + + TrackerPosition.RIGHT_THUMB_METACARPAL, TrackerPosition.RIGHT_THUMB_PROXIMAL, TrackerPosition.RIGHT_THUMB_DISTAL, + -> tracker.setRotation(EulerAngles(EulerOrder.YZX, thumbInitialOffset - angle, angle * 0.05f, -angle * 0.1f).toQuaternion()) + + // Default to X axis (pitch) + else -> tracker.setRotation(EulerAngles(EulerOrder.YZX, angle, 0f, 0f).toQuaternion()) + } + } + + /** + * Gets the max angle for a TrackerPosition + */ + private fun getMaxAngleForTrackerPosition(trackerPosition: TrackerPosition?): Float { + if (trackerPosition == null) return FastMath.PI // 180 degrees + + return when (trackerPosition) { + // 270 degrees + TrackerPosition.LEFT_INDEX_DISTAL, TrackerPosition.LEFT_MIDDLE_DISTAL, + TrackerPosition.LEFT_RING_DISTAL, TrackerPosition.LEFT_LITTLE_DISTAL, + TrackerPosition.RIGHT_INDEX_DISTAL, TrackerPosition.RIGHT_MIDDLE_DISTAL, + TrackerPosition.RIGHT_RING_DISTAL, TrackerPosition.RIGHT_LITTLE_DISTAL, + -> FastMath.PI + FastMath.HALF_PI + + // 202.5 degrees + TrackerPosition.LEFT_THUMB_DISTAL, TrackerPosition.RIGHT_THUMB_DISTAL, + -> FastMath.PI + thumbInitialOffset + + // 180 degrees + TrackerPosition.LEFT_INDEX_INTERMEDIATE, TrackerPosition.LEFT_MIDDLE_INTERMEDIATE, + TrackerPosition.LEFT_RING_INTERMEDIATE, TrackerPosition.LEFT_LITTLE_INTERMEDIATE, + TrackerPosition.RIGHT_INDEX_INTERMEDIATE, TrackerPosition.RIGHT_MIDDLE_INTERMEDIATE, + TrackerPosition.RIGHT_RING_INTERMEDIATE, TrackerPosition.RIGHT_LITTLE_INTERMEDIATE, + -> FastMath.PI + + // 112.5 degrees + TrackerPosition.LEFT_THUMB_PROXIMAL, TrackerPosition.RIGHT_THUMB_PROXIMAL, + -> FastMath.HALF_PI + thumbInitialOffset + + // 90 degrees + TrackerPosition.LEFT_INDEX_PROXIMAL, TrackerPosition.LEFT_MIDDLE_PROXIMAL, + TrackerPosition.LEFT_RING_PROXIMAL, TrackerPosition.LEFT_LITTLE_PROXIMAL, + TrackerPosition.RIGHT_INDEX_PROXIMAL, TrackerPosition.RIGHT_MIDDLE_PROXIMAL, + TrackerPosition.RIGHT_RING_PROXIMAL, TrackerPosition.RIGHT_LITTLE_PROXIMAL, + -> FastMath.HALF_PI + + // 67.5 degrees + TrackerPosition.LEFT_THUMB_METACARPAL, TrackerPosition.RIGHT_THUMB_METACARPAL, + -> FastMath.QUARTER_PI + thumbInitialOffset + + // 45 degrees + TrackerPosition.LEFT_SHOULDER, TrackerPosition.RIGHT_SHOULDER, + -> FastMath.QUARTER_PI + + // 135 degrees + else -> FastMath.HALF_PI + FastMath.QUARTER_PI + } + } +} diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerPosition.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerPosition.kt index 559aea899..ba39a600b 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerPosition.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerPosition.kt @@ -13,39 +13,88 @@ enum class TrackerPosition( val designation: String, val trackerRole: TrackerRole?, val bodyPart: Int, + val id: Int, ) { // If updating BodyPart of a TrackerRole, // please also update SteamVRBridge#updateShareSettingsAutomatically() - HEAD("body:head", TrackerRole.HMD, BodyPart.HEAD), - NECK("body:neck", TrackerRole.NECK, BodyPart.NECK), - UPPER_CHEST("body:upper_chest", TrackerRole.CHEST, BodyPart.UPPER_CHEST), - CHEST("body:chest", null, BodyPart.CHEST), - WAIST("body:waist", null, BodyPart.WAIST), - HIP("body:hip", TrackerRole.WAIST, BodyPart.HIP), - LEFT_UPPER_LEG("body:left_upper_leg", TrackerRole.LEFT_KNEE, BodyPart.LEFT_UPPER_LEG), - RIGHT_UPPER_LEG("body:right_upper_leg", TrackerRole.RIGHT_KNEE, BodyPart.RIGHT_UPPER_LEG), - LEFT_LOWER_LEG("body:left_lower_leg", null, BodyPart.LEFT_LOWER_LEG), - RIGHT_LOWER_LEG("body:right_lower_leg", null, BodyPart.RIGHT_LOWER_LEG), - LEFT_FOOT("body:left_foot", TrackerRole.LEFT_FOOT, BodyPart.LEFT_FOOT), - RIGHT_FOOT("body:right_foot", TrackerRole.RIGHT_FOOT, BodyPart.RIGHT_FOOT), - LEFT_LOWER_ARM("body:left_lower_arm", null, BodyPart.LEFT_LOWER_ARM), - RIGHT_LOWER_ARM("body:right_lower_arm", null, BodyPart.RIGHT_LOWER_ARM), - LEFT_UPPER_ARM("body:left_upper_arm", TrackerRole.LEFT_ELBOW, BodyPart.LEFT_UPPER_ARM), - RIGHT_UPPER_ARM("body:right_upper_arm", TrackerRole.RIGHT_ELBOW, BodyPart.RIGHT_UPPER_ARM), - LEFT_HAND("body:left_hand", TrackerRole.LEFT_HAND, BodyPart.LEFT_HAND), - RIGHT_HAND("body:right_hand", TrackerRole.RIGHT_HAND, BodyPart.RIGHT_HAND), - LEFT_SHOULDER("body:left_shoulder", TrackerRole.LEFT_SHOULDER, BodyPart.LEFT_SHOULDER), - RIGHT_SHOULDER("body:right_shoulder", TrackerRole.RIGHT_SHOULDER, BodyPart.RIGHT_SHOULDER), + HEAD("body:head", TrackerRole.HMD, BodyPart.HEAD, 1), + NECK("body:neck", TrackerRole.NECK, BodyPart.NECK, 2), + UPPER_CHEST("body:upper_chest", TrackerRole.CHEST, BodyPart.UPPER_CHEST, 3), + CHEST("body:chest", null, BodyPart.CHEST, 4), + WAIST("body:waist", null, BodyPart.WAIST, 5), + HIP("body:hip", TrackerRole.WAIST, BodyPart.HIP, 6), + LEFT_UPPER_LEG("body:left_upper_leg", TrackerRole.LEFT_KNEE, BodyPart.LEFT_UPPER_LEG, 7), + RIGHT_UPPER_LEG("body:right_upper_leg", TrackerRole.RIGHT_KNEE, BodyPart.RIGHT_UPPER_LEG, 8), + LEFT_LOWER_LEG("body:left_lower_leg", null, BodyPart.LEFT_LOWER_LEG, 9), + RIGHT_LOWER_LEG("body:right_lower_leg", null, BodyPart.RIGHT_LOWER_LEG, 10), + LEFT_FOOT("body:left_foot", TrackerRole.LEFT_FOOT, BodyPart.LEFT_FOOT, 11), + RIGHT_FOOT("body:right_foot", TrackerRole.RIGHT_FOOT, BodyPart.RIGHT_FOOT, 12), + LEFT_LOWER_ARM("body:left_lower_arm", null, BodyPart.LEFT_LOWER_ARM, 13), + 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_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), + LEFT_THUMB_PROXIMAL("body:left_thumb_proximal", null, BodyPart.LEFT_THUMB_PROXIMAL, 22), + LEFT_THUMB_DISTAL("body:left_thumb_distal", null, BodyPart.LEFT_THUMB_DISTAL, 23), + LEFT_INDEX_PROXIMAL("body:left_index_proximal", null, BodyPart.LEFT_INDEX_PROXIMAL, 24), + LEFT_INDEX_INTERMEDIATE("body:left_index_intermediate", null, BodyPart.LEFT_INDEX_INTERMEDIATE, 25), + LEFT_INDEX_DISTAL("body:left_index_distal", null, BodyPart.LEFT_INDEX_DISTAL, 26), + LEFT_MIDDLE_PROXIMAL("body:left_middle_proximal", null, BodyPart.LEFT_MIDDLE_PROXIMAL, 27), + LEFT_MIDDLE_INTERMEDIATE("body:left_middle_intermediate", null, BodyPart.LEFT_MIDDLE_INTERMEDIATE, 28), + LEFT_MIDDLE_DISTAL("body:left_middle_distal", null, BodyPart.LEFT_MIDDLE_DISTAL, 29), + LEFT_RING_PROXIMAL("body:left_ring_proximal", null, BodyPart.LEFT_RING_PROXIMAL, 30), + LEFT_RING_INTERMEDIATE("body:left_ring_intermediate", null, BodyPart.LEFT_RING_INTERMEDIATE, 31), + LEFT_RING_DISTAL("body:left_ring_distal", null, BodyPart.LEFT_RING_DISTAL, 32), + LEFT_LITTLE_PROXIMAL("body:left_little_proximal", null, BodyPart.LEFT_LITTLE_PROXIMAL, 33), + LEFT_LITTLE_INTERMEDIATE("body:left_little_intermediate", null, BodyPart.LEFT_LITTLE_INTERMEDIATE, 34), + LEFT_LITTLE_DISTAL("body:left_little_distal", null, BodyPart.LEFT_LITTLE_DISTAL, 35), + RIGHT_THUMB_METACARPAL("body:right_thumb_metacarpal", null, BodyPart.RIGHT_THUMB_METACARPAL, 36), + RIGHT_THUMB_PROXIMAL("body:right_thumb_proximal", null, BodyPart.RIGHT_THUMB_PROXIMAL, 37), + RIGHT_THUMB_DISTAL("body:right_thumb_distal", null, BodyPart.RIGHT_THUMB_DISTAL, 38), + RIGHT_INDEX_PROXIMAL("body:right_index_proximal", null, BodyPart.RIGHT_INDEX_PROXIMAL, 39), + RIGHT_INDEX_INTERMEDIATE("body:right_index_intermediate", null, BodyPart.RIGHT_INDEX_INTERMEDIATE, 40), + RIGHT_INDEX_DISTAL("body:right_index_distal", null, BodyPart.RIGHT_INDEX_DISTAL, 41), + RIGHT_MIDDLE_PROXIMAL("body:right_middle_proximal", null, BodyPart.RIGHT_MIDDLE_PROXIMAL, 42), + RIGHT_MIDDLE_INTERMEDIATE("body:right_middle_intermediate", null, BodyPart.RIGHT_MIDDLE_INTERMEDIATE, 43), + RIGHT_MIDDLE_DISTAL("body:right_middle_distal", null, BodyPart.RIGHT_MIDDLE_DISTAL, 44), + RIGHT_RING_PROXIMAL("body:right_ring_proximal", null, BodyPart.RIGHT_RING_PROXIMAL, 45), + RIGHT_RING_INTERMEDIATE("body:right_ring_intermediate", null, BodyPart.RIGHT_RING_INTERMEDIATE, 46), + RIGHT_RING_DISTAL("body:right_ring_distal", null, BodyPart.RIGHT_RING_DISTAL, 47), + RIGHT_LITTLE_PROXIMAL("body:right_little_proximal", null, BodyPart.RIGHT_LITTLE_PROXIMAL, 48), + RIGHT_LITTLE_INTERMEDIATE("body:right_little_intermediate", null, BodyPart.RIGHT_LITTLE_INTERMEDIATE, 49), + RIGHT_LITTLE_DISTAL("body:right_little_distal", null, BodyPart.RIGHT_LITTLE_DISTAL, 50), ; /** * Returns the default mounting orientation for the body part */ fun defaultMounting(): Quaternion = when (this) { - LEFT_LOWER_ARM, LEFT_HAND -> Quaternion.SLIMEVR.LEFT - RIGHT_LOWER_ARM, RIGHT_HAND -> Quaternion.SLIMEVR.RIGHT + LEFT_LOWER_ARM, LEFT_HAND, + LEFT_INDEX_PROXIMAL, LEFT_INDEX_INTERMEDIATE, + LEFT_INDEX_DISTAL, LEFT_MIDDLE_PROXIMAL, + LEFT_MIDDLE_INTERMEDIATE, LEFT_MIDDLE_DISTAL, + LEFT_RING_PROXIMAL, LEFT_RING_INTERMEDIATE, + LEFT_RING_DISTAL, LEFT_LITTLE_PROXIMAL, + LEFT_LITTLE_INTERMEDIATE, LEFT_LITTLE_DISTAL, + -> Quaternion.SLIMEVR.LEFT + + RIGHT_LOWER_ARM, RIGHT_HAND, + RIGHT_INDEX_PROXIMAL, RIGHT_INDEX_INTERMEDIATE, + RIGHT_INDEX_DISTAL, RIGHT_MIDDLE_PROXIMAL, + RIGHT_MIDDLE_INTERMEDIATE, RIGHT_MIDDLE_DISTAL, + RIGHT_RING_PROXIMAL, RIGHT_RING_INTERMEDIATE, + RIGHT_RING_DISTAL, RIGHT_LITTLE_PROXIMAL, + RIGHT_LITTLE_INTERMEDIATE, RIGHT_LITTLE_DISTAL, + -> Quaternion.SLIMEVR.RIGHT + LEFT_UPPER_ARM, LEFT_LOWER_LEG -> Quaternion.SLIMEVR.FRONT_LEFT + RIGHT_UPPER_ARM, RIGHT_LOWER_LEG -> Quaternion.SLIMEVR.FRONT_RIGHT + else -> Quaternion.SLIMEVR.FRONT } @@ -56,6 +105,7 @@ enum class TrackerPosition( this[position.bodyPart] = position } } + private val byId = entries.associateBy { it.id } private val byDesignation = entries.associateBy { it.designation.lowercase() } private val byTrackerRole = entries.filter { it.trackerRole != null }.associateBy { it.trackerRole!! } @@ -82,5 +132,8 @@ enum class TrackerPosition( @JvmStatic fun getByBodyPart(bodyPart: Int): TrackerPosition? = byBodyPart[bodyPart] + + @JvmStatic + fun getById(id: Int): TrackerPosition? = byId[id] } } diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerResetsHandler.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerResetsHandler.kt index a47dbd0a6..c90414dd6 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerResetsHandler.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerResetsHandler.kt @@ -7,6 +7,7 @@ import dev.slimevr.config.ArmsResetModes import dev.slimevr.config.DriftCompensationConfig import dev.slimevr.config.ResetsConfig import dev.slimevr.filtering.CircularArrayList +import dev.slimevr.tracking.trackers.udp.TrackerDataType import io.eiren.math.FloatMath.animateEase import io.github.axisangles.ktmath.EulerAngles import io.github.axisangles.ktmath.EulerOrder @@ -37,6 +38,7 @@ class TrackerResetsHandler(val tracker: Tracker) { private var driftSince: Long = 0 private var timeAtLastReset: Long = 0 private var compensateDrift = false + private var driftPrediction = false private var driftCompensationEnabled = false private var resetMountingFeet = false private var armsResetMode = ArmsResetModes.BACK @@ -78,6 +80,7 @@ class TrackerResetsHandler(val tracker: Tracker) { */ fun readDriftCompensationConfig(config: DriftCompensationConfig) { compensateDrift = config.enabled + driftPrediction = config.prediction driftAmount = config.amount val maxResets = config.maxResets @@ -186,11 +189,11 @@ class TrackerResetsHandler(val tracker: Tracker) { */ private fun adjustToDrift(rotation: Quaternion): Quaternion { if (driftCompensationEnabled && totalDriftTime > 0) { - return rotation - .interpR( - averagedDriftQuat * rotation, - driftAmount * ((System.currentTimeMillis() - driftSince).toFloat() / totalDriftTime), - ) + var driftTimeRatio = ((System.currentTimeMillis() - driftSince).toFloat() / totalDriftTime) + if (!driftPrediction) { + driftTimeRatio = min(1.0f, driftTimeRatio) + } + return averagedDriftQuat.pow(driftAmount * driftTimeRatio) * rotation } return rotation } @@ -211,10 +214,19 @@ class TrackerResetsHandler(val tracker: Tracker) { * 0). This allows the tracker to be strapped to body at any pitch and roll. */ fun resetFull(reference: Quaternion) { + if (tracker.trackerDataType == TrackerDataType.FLEX_RESISTANCE) { + tracker.trackerFlexHandler.resetMin() + postProcessResetFull() + return + } else if (tracker.trackerDataType == TrackerDataType.FLEX_ANGLE) { + postProcessResetFull() + return + } + // Adjust for T-Pose (down) - tposeDownFix = if ((isLeftArmTracker() && armsResetMode == ArmsResetModes.TPOSE_DOWN)) { + tposeDownFix = if (((isLeftArmTracker() || isLeftFingerTracker()) && armsResetMode == ArmsResetModes.TPOSE_DOWN)) { EulerAngles(EulerOrder.YZX, 0f, 0f, -FastMath.HALF_PI).toQuaternion() - } else if ((isRightArmTracker() && armsResetMode == ArmsResetModes.TPOSE_DOWN)) { + } else if (((isRightArmTracker() || isRightFingerTracker()) && armsResetMode == ArmsResetModes.TPOSE_DOWN)) { EulerAngles(EulerOrder.YZX, 0f, 0f, FastMath.HALF_PI).toQuaternion() } else { Quaternion.IDENTITY @@ -274,10 +286,16 @@ class TrackerResetsHandler(val tracker: Tracker) { calculateDrift(oldRot) + postProcessResetFull() + } + + private fun postProcessResetFull() { if (this.tracker.lastResetStatus != 0u) { VRServer.instance.statusSystem.removeStatus(this.tracker.lastResetStatus) this.tracker.lastResetStatus = 0u } + + tracker.resetFilteringQuats() } /** @@ -287,6 +305,12 @@ class TrackerResetsHandler(val tracker: Tracker) { * position should be corrected in the source. */ fun resetYaw(reference: Quaternion) { + if (tracker.trackerDataType == TrackerDataType.FLEX_RESISTANCE || + tracker.trackerDataType == TrackerDataType.FLEX_ANGLE + ) { + return + } + // Old rot for drift compensation val oldRot = adjustToReference(tracker.getRawRotation()) lastResetQuaternion = oldRot @@ -312,6 +336,8 @@ class TrackerResetsHandler(val tracker: Tracker) { this.tracker.statusResetRecently = false this.tracker.lastResetStatus = 0u } + + tracker.resetFilteringQuats() } /** @@ -319,7 +345,15 @@ class TrackerResetsHandler(val tracker: Tracker) { * and stores it in mountRotFix, and adjusts yawFix */ fun resetMounting(reference: Quaternion) { - if (!resetMountingFeet && isFootTracker()) return + if (tracker.trackerDataType == TrackerDataType.FLEX_RESISTANCE) { + tracker.trackerFlexHandler.resetMax() + tracker.resetFilteringQuats() + return + } else if (tracker.trackerDataType == TrackerDataType.FLEX_ANGLE) { + return + } else if (!resetMountingFeet && isFootTracker()) { + return + } // Get the current calibrated rotation var rotBuf = adjustToDrift(tracker.getRawRotation() * mountingOrientation) @@ -336,15 +370,17 @@ class TrackerResetsHandler(val tracker: Tracker) { // Calculate the yaw angle using tan var yawAngle = atan2(rotVector.x, rotVector.z) - // Adjust for T-Pose + // Adjust for T-Pose and fingers if ((isLeftArmTracker() && armsResetMode == ArmsResetModes.TPOSE_DOWN) || - (isRightArmTracker() && armsResetMode == ArmsResetModes.TPOSE_UP) + (isRightArmTracker() && armsResetMode == ArmsResetModes.TPOSE_UP) || + isLeftFingerTracker() ) { // Tracker goes right yawAngle -= FastMath.HALF_PI } if ((isLeftArmTracker() && armsResetMode == ArmsResetModes.TPOSE_UP) || - (isRightArmTracker() && armsResetMode == ArmsResetModes.TPOSE_DOWN) + (isRightArmTracker() && armsResetMode == ArmsResetModes.TPOSE_DOWN) || + isRightFingerTracker() ) { // Tracker goes left yawAngle += FastMath.HALF_PI @@ -363,6 +399,8 @@ class TrackerResetsHandler(val tracker: Tracker) { // save mounting reset if (saveMountingReset) tracker.saveMountingResetOrientation(mountRotFix) + + tracker.resetFilteringQuats() } fun clearMounting() { @@ -571,4 +609,46 @@ class TrackerResetsHandler(val tracker: Tracker) { } return false } + + private fun isLeftFingerTracker(): Boolean { + tracker.trackerPosition?.let { + return it == TrackerPosition.LEFT_THUMB_METACARPAL || + it == TrackerPosition.LEFT_THUMB_PROXIMAL || + it == TrackerPosition.LEFT_THUMB_DISTAL || + it == TrackerPosition.LEFT_INDEX_PROXIMAL || + it == TrackerPosition.LEFT_INDEX_INTERMEDIATE || + it == TrackerPosition.LEFT_INDEX_DISTAL || + it == TrackerPosition.LEFT_MIDDLE_PROXIMAL || + it == TrackerPosition.LEFT_MIDDLE_INTERMEDIATE || + it == TrackerPosition.LEFT_MIDDLE_DISTAL || + it == TrackerPosition.LEFT_RING_PROXIMAL || + it == TrackerPosition.LEFT_RING_INTERMEDIATE || + it == TrackerPosition.LEFT_RING_DISTAL || + it == TrackerPosition.LEFT_LITTLE_PROXIMAL || + it == TrackerPosition.LEFT_LITTLE_INTERMEDIATE || + it == TrackerPosition.LEFT_LITTLE_DISTAL + } + return false + } + + private fun isRightFingerTracker(): Boolean { + tracker.trackerPosition?.let { + return it == TrackerPosition.RIGHT_THUMB_METACARPAL || + it == TrackerPosition.RIGHT_THUMB_PROXIMAL || + it == TrackerPosition.RIGHT_THUMB_DISTAL || + it == TrackerPosition.RIGHT_INDEX_PROXIMAL || + it == TrackerPosition.RIGHT_INDEX_INTERMEDIATE || + it == TrackerPosition.RIGHT_INDEX_DISTAL || + it == TrackerPosition.RIGHT_MIDDLE_PROXIMAL || + it == TrackerPosition.RIGHT_MIDDLE_INTERMEDIATE || + it == TrackerPosition.RIGHT_MIDDLE_DISTAL || + it == TrackerPosition.RIGHT_RING_PROXIMAL || + it == TrackerPosition.RIGHT_RING_INTERMEDIATE || + it == TrackerPosition.RIGHT_RING_DISTAL || + it == TrackerPosition.RIGHT_LITTLE_PROXIMAL || + it == TrackerPosition.RIGHT_LITTLE_INTERMEDIATE || + it == TrackerPosition.RIGHT_LITTLE_DISTAL + } + return false + } } diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerUtils.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerUtils.kt index 35927f2ca..2a40b6ed7 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerUtils.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerUtils.kt @@ -31,7 +31,7 @@ object TrackerUtils { position: TrackerPosition, ): Tracker? { val resetTrackers = allTrackers.filter { - it.trackerPosition === position && + it.trackerPosition == position && !it.isInternal && !it.status.reset } @@ -51,7 +51,7 @@ object TrackerUtils { position: TrackerPosition, ): Tracker? { val resetTrackers = allTrackers.filter { - it.trackerPosition === position && + it.trackerPosition == position && !it.isComputed && !it.isInternal && !it.status.reset @@ -72,7 +72,7 @@ object TrackerUtils { position: TrackerPosition, ): Tracker? { val resetTrackers = allTrackers.filter { - it.trackerPosition === position && + it.trackerPosition == position && !it.isImu() && !it.isInternal && !it.status.reset diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/FeatureFlags.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/FeatureFlags.kt index d639160ef..640af5807 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/FeatureFlags.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/FeatureFlags.kt @@ -12,6 +12,9 @@ class FirmwareFeatures { // EXAMPLE_FEATURE, // Add new flags here + REMOTE_COMMAND, + B64_WIFI_SCANNING, + SENSOR_CONFIG, BITS_TOTAL, } @@ -32,7 +35,7 @@ class FirmwareFeatures { fun from(received: ByteBuffer, length: Int): FirmwareFeatures { val res = FirmwareFeatures() res.available = true - received.get(res.flags, 0, Math.min(res.flags.size, length)) + received.get(res.flags, 0, res.flags.size.coerceAtMost(length)) return res } } diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/FirmwareConstants.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/FirmwareConstants.kt index 1e0877ec5..57f0a47d0 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/FirmwareConstants.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/FirmwareConstants.kt @@ -23,7 +23,7 @@ enum class IMUType(val id: UInt) { fun getSolarType(): Int = this.id.toInt() companion object { - private val byId = IMUType.values().associateBy { it.id } + private val byId = entries.associateBy { it.id } @JvmStatic fun getById(id: UInt): IMUType? = byId[id] @@ -77,7 +77,7 @@ enum class BoardType(val id: UInt) { } companion object { - private val byId = BoardType.values().associateBy { it.id } + private val byId = entries.associateBy { it.id } @JvmStatic fun getById(id: UInt): BoardType? = byId[id] @@ -100,9 +100,57 @@ enum class MCUType(val id: UInt) { fun getSolarType(): Int = this.id.toInt() companion object { - private val byId = MCUType.values().associateBy { it.id } + private val byId = entries.associateBy { it.id } @JvmStatic fun getById(id: UInt): MCUType? = byId[id] } } + +enum class TrackerDataType(val id: UInt) { + ROTATION(0u), + FLEX_RESISTANCE(1u), + FLEX_ANGLE(2u), + ; + + fun getSolarType(): Int = this.id.toInt() + + companion object { + private val byId = entries.associateBy { it.id } + + @JvmStatic + fun getById(id: UInt): TrackerDataType? = byId[id] + } +} + +@JvmInline +value class ConfigTypeId(val v: UShort) + +enum class MagnetometerStatus { + NOT_SUPPORTED, + DISABLED, + ENABLED, + ; + + fun getSolarType(): Int = this.ordinal + + companion object { + private val byId = entries.associateBy { it.ordinal.toUByte() } + + @JvmStatic + fun getById(id: UByte): MagnetometerStatus? = byId[id] + } +} + +@JvmInline +value class SensorConfig(val v: UShort) { + val magStatus + get(): MagnetometerStatus { + if ((v.toUInt() shr 1) and 1u == 0u) return MagnetometerStatus.NOT_SUPPORTED + return if ((v and 1u) == 1u.toUShort()) { + MagnetometerStatus.ENABLED + } else { + MagnetometerStatus.DISABLED + } + } +} diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/TrackersUDPServer.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/TrackersUDPServer.kt index ea19fb6f2..484e11583 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/TrackersUDPServer.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/TrackersUDPServer.kt @@ -3,13 +3,15 @@ package dev.slimevr.tracking.trackers.udp import com.jme3.math.FastMath import dev.slimevr.NetworkProtocol import dev.slimevr.VRServer -import dev.slimevr.tracking.trackers.Tracker -import dev.slimevr.tracking.trackers.TrackerStatus +import dev.slimevr.config.config +import dev.slimevr.protocol.rpc.MAG_TIMEOUT +import dev.slimevr.tracking.trackers.* import io.eiren.util.Util import io.eiren.util.collections.FastList import io.eiren.util.logging.LogManager import io.github.axisangles.ktmath.Quaternion.Companion.fromRotationVector import io.github.axisangles.ktmath.Vector3 +import kotlinx.coroutines.* import org.apache.commons.lang3.ArrayUtils import solarxr_protocol.rpc.ResetType import java.net.DatagramPacket @@ -20,8 +22,12 @@ import java.net.SocketAddress import java.net.SocketTimeoutException import java.nio.ByteBuffer import java.nio.ByteOrder -import java.util.Random +import java.util.* +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.ConcurrentLinkedDeque import java.util.function.Consumer +import kotlin.collections.HashMap +import kotlin.coroutines.resume /** * Receives trackers data by UDP using extended owoTrack protocol. @@ -80,7 +86,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker ipAddress = addr name = handshake.macString?.let { "udp://$it" } descriptiveName = "udp:/$addr" - firmwareBuild = handshake.firmwareBuild + protocolVersion = handshake.protocolVersion firmwareVersion = handshake.firmware connectionsByAddress[address] = this @@ -90,8 +96,8 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker """ [TrackerServer] Tracker $i handed over to address $socketAddr. Board type: ${handshake.boardType}, - imu type: ${handshake.imuType}, - firmware: ${handshake.firmware} ($firmwareBuild), + firmware name: ${handshake.firmware}, + protocol version: $protocolVersion, mac: ${handshake.macString}, name: $name """.trimIndent(), @@ -104,7 +110,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker name = handshake.macString?.let { "udp://$it" } ?: "udp:/$addr" descriptiveName = "udp:/$addr" - firmwareBuild = handshake.firmwareBuild + protocolVersion = handshake.protocolVersion firmwareVersion = handshake.firmware val i = connections.indexOf(this) LogManager @@ -112,8 +118,8 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker """ [TrackerServer] Tracker $i reconnected from address $socketAddr. Board type: ${handshake.boardType}, - imu type: ${handshake.imuType}, - firmware: ${handshake.firmware} ($firmwareBuild), + firmware name: ${handshake.firmware}, + protocol version: $protocolVersion, mac: ${handshake.macString}, name: $name """.trimIndent(), @@ -130,7 +136,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker handshake.mcuType, ) VRServer.instance.deviceManager.addDevice(connection) - connection.firmwareBuild = handshake.firmwareBuild + connection.protocolVersion = handshake.protocolVersion connection.protocol = if (handshake.firmware?.isEmpty() == true) { // Only old owoTrack doesn't report firmware and have different packet IDs with SlimeVR NetworkProtocol.OWO_LEGACY @@ -158,18 +164,18 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker """ [TrackerServer] Tracker $i connected from address $socketAddr. Board type: ${handshake.boardType}, - imu type: ${handshake.imuType}, - firmware: ${handshake.firmware} (${connection.firmwareBuild}), + firmware name: ${handshake.firmware}, + protocol version: ${connection.protocolVersion}, mac: ${handshake.macString}, name: ${connection.name} """.trimIndent(), ) } - if (connection.protocol == NetworkProtocol.OWO_LEGACY || connection.firmwareBuild < 9) { + if (connection.protocol == NetworkProtocol.OWO_LEGACY || connection.protocolVersion < 9) { // Set up new sensor for older firmware. // Firmware after 7 should send sensor status packet and sensor // will be created when it's received - setUpSensor(connection, 0, handshake.imuType, 1) + setUpSensor(connection, 0, handshake.imuType, 1, MagnetometerStatus.NOT_SUPPORTED, null, TrackerDataType.ROTATION) } connection } @@ -180,7 +186,8 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker socket.send(DatagramPacket(rcvBuffer, bb.position(), connection.address)) } - private fun setUpSensor(connection: UDPDevice, trackerId: Int, sensorType: IMUType, sensorStatus: Int) { + private val mainScope = CoroutineScope(SupervisorJob()) + private fun setUpSensor(connection: UDPDevice, trackerId: Int, sensorType: IMUType, sensorStatus: Int, magStatus: MagnetometerStatus, trackerPosition: TrackerPosition?, trackerDataType: TrackerDataType) { LogManager.info("[TrackerServer] Sensor $trackerId for ${connection.name} status: $sensorStatus") var imuTracker = connection.getTracker(trackerId) if (imuTracker == null) { @@ -194,23 +201,73 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker VRServer.getNextLocalTrackerId(), connection.name + "/" + trackerId, "IMU Tracker $formattedHWID", - null, + trackerPosition, trackerNum = trackerId, hasRotation = true, hasAcceleration = true, userEditable = true, - imuType = sensorType, + imuType = if (trackerDataType == TrackerDataType.ROTATION) sensorType else null, allowFiltering = true, needsReset = true, needsMounting = true, usesTimeout = true, + magStatus = magStatus, + trackerDataType = trackerDataType, ) connection.trackers[trackerId] = imuTracker trackersConsumer.accept(imuTracker) - LogManager.info("[TrackerServer] Added sensor $trackerId for ${connection.name}, type $sensorType") + LogManager.info("[TrackerServer] Added sensor $trackerId for ${connection.name}, ImuType $sensorType, DataType $trackerDataType, default TrackerPosition $trackerPosition") } val status = UDPPacket15SensorInfo.getStatus(sensorStatus) if (status != null) imuTracker.status = status + + if (magStatus == MagnetometerStatus.NOT_SUPPORTED) return + if (magStatus == MagnetometerStatus.ENABLED && + (!VRServer.instance.configManager.vrConfig.server.useMagnetometerOnAllTrackers || imuTracker.config.shouldHaveMagEnabled == false) + ) { + mainScope.launch { + withTimeoutOrNull(MAG_TIMEOUT) { + connection.setMag(false, trackerId) + } + } + } else if (magStatus == MagnetometerStatus.DISABLED && + VRServer.instance.configManager.vrConfig.server.useMagnetometerOnAllTrackers && imuTracker.config.shouldHaveMagEnabled == true + ) { + mainScope.launch { + withTimeoutOrNull(MAG_TIMEOUT) { + connection.setMag(true, trackerId) + } + } + } + } + + private data class ConfigStateWaiter( + val expectedState: Boolean, + val channel: CancellableContinuation, + var ran: Boolean = false, + ) + + private val queues: MutableMap, Deque> = ConcurrentHashMap() + suspend fun setConfigFlag(device: UDPDevice, configTypeId: ConfigTypeId, state: Boolean, sensorId: Int = 255) { + if (device.timedOut) return + val triple = Triple(device.address, configTypeId, sensorId) + val queue = queues.computeIfAbsent(triple) { _ -> ConcurrentLinkedDeque() } + + suspendCancellableCoroutine { + val waiter = ConfigStateWaiter(state, it) + queue.add(waiter) + it.invokeOnCancellation { + queue.remove(waiter) + } + } + } + + private fun actualSetConfigFlag(device: UDPDevice, configTypeId: ConfigTypeId, state: Boolean, sensorId: Int) { + val packet = UDPPacket25SetConfigFlag(sensorId, configTypeId, state) + bb.limit(bb.capacity()) + bb.rewind() + parser.write(bb, null, packet) + socket.send(DatagramPacket(rcvBuffer, bb.position(), device.address)) } override fun run() { @@ -243,6 +300,19 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker parser.parse(bb, connection) .filterNotNull() .forEach { processPacket(received, it, connection) } + + queues.forEach { (t, p) -> + val q = p.firstOrNull() ?: return@forEach + if (q.ran) return@forEach + + val device = connectionsByAddress[t.first] ?: run { + p.removeFirst() + LogManager.info("[TrackerServer] Device ${t.first} not connected, so can't communicate with it") + return@forEach + } + actualSetConfigFlag(device, t.second, q.expectedState, t.third) + if (!device.timedOut) q.ran = true + } } catch (ignored: SocketTimeoutException) { } catch (e: Exception) { LogManager.warning( @@ -311,7 +381,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker private fun processPacket(received: DatagramPacket, packet: UDPPacket, connection: UDPDevice?) { val tracker: Tracker? when (packet) { - is UDPPacket0Heartbeat, is UDPPacket1Heartbeat -> {} + is UDPPacket0Heartbeat, is UDPPacket1Heartbeat, is UDPPacket25SetConfigFlag -> {} is UDPPacket3Handshake -> setUpNewConnection(received, packet) @@ -402,14 +472,23 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker is UDPPacket15SensorInfo -> { if (connection == null) return - setUpSensor(connection, packet.sensorId, packet.sensorType, packet.sensorStatus) + val magStatus = packet.sensorConfig?.magStatus ?: MagnetometerStatus.NOT_SUPPORTED + setUpSensor( + connection, + packet.sensorId, + packet.sensorType, + packet.sensorStatus, + magStatus, + packet.trackerPosition, + packet.trackerDataType, + ) // Send ack bb.limit(bb.capacity()) bb.rewind() parser.writeSensorInfoResponse(bb, connection, packet) socket.send(DatagramPacket(rcvBuffer, bb.position(), connection.address)) LogManager.info( - "[TrackerServer] Sensor info for ${connection.descriptiveName}/${packet.sensorId}: ${packet.sensorStatus}", + "[TrackerServer] Sensor info for ${connection.descriptiveName}/${packet.sensorId}: ${packet.sensorStatus}, mag $magStatus", ) } @@ -418,8 +497,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker } is UDPPacket20Temperature -> { - tracker = connection?.getTracker(packet.sensorId) - if (tracker == null) return + tracker = connection?.getTracker(packet.sensorId) ?: return tracker.temperature = packet.temperature } @@ -455,7 +533,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker } LogManager.info( - "[TrackerServer] User action from ${connection.descriptiveName } received. $name performed.", + "[TrackerServer] User action from ${connection.descriptiveName} received. $name performed.", ) } @@ -469,6 +547,33 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker connection.firmwareFeatures = packet.firmwareFeatures } + is UDPPacket24AckConfigChange -> { + if (connection == null) return + val queue = queues[Triple(connection.address, packet.configType, packet.sensorId)] ?: run { + LogManager.severe("[TrackerServer] Error, acknowledgment of config change that we don't have in our queue.") + return + } + val changed = queue.removeFirst() + changed.channel.resume(true) + val trackers = if (SensorSpecificPacket.isGlobal(packet.sensorId)) { + connection.trackers.values.toList() + } else { + listOf(connection.getTracker(packet.sensorId) ?: return) + } + LogManager.info("[TrackerServer] Acknowledged config change on ${connection.descriptiveName} (${trackers.map { it.trackerNum }.joinToString()}). Config changed on ${packet.configType}") + } + + is UDPPacket26FlexData -> { + tracker = connection?.getTracker(packet.sensorId) + if (tracker == null) return + if (tracker.trackerDataType == TrackerDataType.FLEX_RESISTANCE) { + tracker.trackerFlexHandler.setFlexResistance(packet.flexData) + } else if (tracker.trackerDataType == TrackerDataType.FLEX_ANGLE) { + tracker.trackerFlexHandler.setFlexAngle(packet.flexData) + } + tracker.dataTick() + } + is UDPPacket200ProtocolChange -> {} } } diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/UDPDevice.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/UDPDevice.kt index afc0a56d7..bed58741c 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/UDPDevice.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/UDPDevice.kt @@ -1,6 +1,7 @@ package dev.slimevr.tracking.trackers.udp import dev.slimevr.NetworkProtocol +import dev.slimevr.VRServer import dev.slimevr.tracking.trackers.Device import dev.slimevr.tracking.trackers.Tracker import java.net.InetAddress @@ -13,7 +14,7 @@ class UDPDevice( override val hardwareIdentifier: String, override val boardType: BoardType = BoardType.UNKNOWN, override val mcuType: MCUType = MCUType.UNKNOWN, -) : Device() { +) : Device(true) { override val id: Int = nextLocalDeviceId.incrementAndGet() @@ -47,12 +48,23 @@ class UDPDevice( var protocol: NetworkProtocol? = null @JvmField - var firmwareBuild = 0 + var protocolVersion = 0 @JvmField var timedOut = false override val trackers = ConcurrentHashMap() + override suspend fun setMag(state: Boolean, sensorId: Int) { + if (sensorId == 255) { + VRServer.instance.trackersServer.setConfigFlag(this, ConfigTypeId(1u), state) + trackers.forEach { (_, t) -> t.setMagPrivate(state) } + } else { + require(trackers[sensorId] != null) { "There is no tracker $sensorId in device ${toString()}" } + VRServer.instance.trackersServer.setConfigFlag(this, ConfigTypeId(1u), state, sensorId) + trackers[sensorId]!!.setMagPrivate(state) + } + } + var firmwareFeatures = FirmwareFeatures() fun isNextPacket(packetId: Long): Boolean { diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/UDPPacket.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/UDPPacket.kt index 6691602ac..3de607976 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/UDPPacket.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/UDPPacket.kt @@ -1,5 +1,6 @@ package dev.slimevr.tracking.trackers.udp +import dev.slimevr.tracking.trackers.TrackerPosition import dev.slimevr.tracking.trackers.TrackerStatus import io.github.axisangles.ktmath.Quaternion import io.github.axisangles.ktmath.Vector3 @@ -95,7 +96,7 @@ data class UDPPacket3Handshake( var boardType: BoardType = BoardType.UNKNOWN, var imuType: IMUType = IMUType.UNKNOWN, var mcuType: MCUType = MCUType.UNKNOWN, - var firmwareBuild: Int = 0, + var protocolVersion: Int = 0, var firmware: String? = null, var macString: String? = null, ) : UDPPacket(3) { @@ -115,7 +116,7 @@ data class UDPPacket3Handshake( buf.int buf.int // IMU info } - if (buf.remaining() > 3) firmwareBuild = buf.int + if (buf.remaining() > 3) protocolVersion = buf.int var length = 0 if (buf.remaining() > 0) length = buf.get().toInt() // firmware version length is 1 longer than @@ -223,6 +224,9 @@ data class UDPPacket14Error(var errorNumber: Int = 0) : data class UDPPacket15SensorInfo( var sensorStatus: Int = 0, var sensorType: IMUType = IMUType.UNKNOWN, + var sensorConfig: SensorConfig? = null, + var trackerDataType: TrackerDataType = TrackerDataType.ROTATION, + var trackerPosition: TrackerPosition? = null, ) : UDPPacket(15), SensorSpecificPacket { override var sensorId = 0 @@ -230,9 +234,13 @@ data class UDPPacket15SensorInfo( sensorId = buf.get().toInt() and 0xFF sensorStatus = buf.get().toInt() and 0xFF if (buf.remaining() > 0) { - sensorType = - IMUType.getById(buf.get().toUInt() and 0xFFu) ?: IMUType.UNKNOWN + sensorType = IMUType.getById(buf.get().toUInt() and 0xFFu) ?: IMUType.UNKNOWN } + if (buf.remaining() > 1) { + sensorConfig = SensorConfig(buf.getShort().toUShort()) + } + if (buf.remaining() > 0) trackerPosition = TrackerPosition.getById(buf.get().toInt() and 0xFF) + if (buf.remaining() > 0) trackerDataType = TrackerDataType.getById(buf.get().toUInt() and 0xFFu) ?: TrackerDataType.ROTATION } companion object { @@ -350,6 +358,42 @@ data class UDPPacket23RotationAndAcceleration( } } +data class UDPPacket24AckConfigChange( + override var sensorId: Int = 0, + var configType: ConfigTypeId = ConfigTypeId(0u), +) : UDPPacket(24), + SensorSpecificPacket { + override fun readData(buf: ByteBuffer) { + sensorId = buf.get().toInt() and 0xFF + configType = ConfigTypeId(buf.getShort().toUShort()) + } +} + +data class UDPPacket25SetConfigFlag( + override var sensorId: Int = 255, + var configType: ConfigTypeId, + var state: Boolean, +) : UDPPacket(25), + SensorSpecificPacket { + override fun writeData(buf: ByteBuffer) { + buf.put(sensorId.toByte()) + buf.putShort(configType.v.toShort()) + buf.put(if (state) 1 else 0) + } +} + +data class UDPPacket26FlexData( + var flexData: Float = 0f, +) : UDPPacket(26), + SensorSpecificPacket { + + override var sensorId = 0 + override fun readData(buf: ByteBuffer) { + sensorId = buf.get().toInt() and 0xFF + flexData = UDPUtils.getSafeBufferFloat(buf) + } +} + data class UDPPacket200ProtocolChange( var targetProtocol: Int = 0, var targetProtocolVersion: Int = 0, diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/UDPProtocolParser.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/UDPProtocolParser.kt index e0c7e3e0f..59d8c3b26 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/UDPProtocolParser.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/UDPProtocolParser.kt @@ -114,6 +114,8 @@ class UDPProtocolParser { PACKET_TEMPERATURE -> UDPPacket20Temperature() PACKET_USER_ACTION -> UDPPacket21UserAction() PACKET_FEATURE_FLAGS -> UDPPacket22FeatureFlags() + PACKET_ACK_CONFIG_CHANGE -> UDPPacket24AckConfigChange() + PACKET_FLEX_DATA -> UDPPacket26FlexData() PACKET_PROTOCOL_CHANGE -> UDPPacket200ProtocolChange() else -> null } @@ -147,6 +149,9 @@ class UDPProtocolParser { const val PACKET_USER_ACTION = 21 const val PACKET_FEATURE_FLAGS = 22 const val PACKET_ROTATION_AND_ACCELERATION = 23 + const val PACKET_ACK_CONFIG_CHANGE = 24 + const val PACKET_SET_CONFIG_FLAG = 25 + const val PACKET_FLEX_DATA = 26 const val PACKET_BUNDLE = 100 const val PACKET_BUNDLE_COMPACT = 101 const val PACKET_PROTOCOL_CHANGE = 200 diff --git a/server/core/src/main/java/io/github/axisangles/ktmath/Matrix3.kt b/server/core/src/main/java/io/github/axisangles/ktmath/Matrix3.kt index e1ef46f08..5d787fc3b 100644 --- a/server/core/src/main/java/io/github/axisangles/ktmath/Matrix3.kt +++ b/server/core/src/main/java/io/github/axisangles/ktmath/Matrix3.kt @@ -221,15 +221,15 @@ value class Matrix3 * finds the rotation matrix closest to all given rotation matrices. * multiply input matrices by a weight for weighted averaging. * WARNING: NOT ANGULAR - * @param others a variable number of additional matrices to average + * @param others a variable number of additional boxed matrices to average * @return the average rotation matrix */ - fun average(vararg others: Matrix3): Matrix3 { + fun average(vararg others: ObjectMatrix3): Matrix3 { var count = 1f var sum = this others.forEach { count += 1f - sum += it + sum += it.toValue() } return (sum / count).orthonormalize() } @@ -460,6 +460,16 @@ value class Matrix3 */ fun toEulerAngles(order: EulerOrder): EulerAngles = orthonormalize().toEulerAnglesAssumingOrthonormal(order) + + fun toObject() = ObjectMatrix3(xx, yx, zx, xy, yy, zy, xz, yz, zz) +} + +data class ObjectMatrix3( + val xx: Float, val yx: Float, val zx: Float, + val xy: Float, val yy: Float, val zy: Float, + val xz: Float, val yz: Float, val zz: Float +) { + fun toValue() = Matrix3(xx, yx, zx, xy, yy, zy, xz, yz, zz) } operator fun Float.times(that: Matrix3): Matrix3 = that * this diff --git a/server/desktop/build.gradle.kts b/server/desktop/build.gradle.kts index c983fccc1..9ebb84a73 100644 --- a/server/desktop/build.gradle.kts +++ b/server/desktop/build.gradle.kts @@ -5,12 +5,13 @@ * For more details take a look at the Java Libraries chapter in the Gradle * User Manual available at https://docs.gradle.org/6.3/userguide/java_library_plugin.html */ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { kotlin("jvm") application - id("com.github.johnrengelman.shadow") + id("com.gradleup.shadow") id("com.github.gmazzo.buildconfig") id("org.ajoberstar.grgit") } @@ -26,8 +27,10 @@ java { } } tasks.withType { - kotlinOptions.jvmTarget = "17" - kotlinOptions.freeCompilerArgs += "-Xvalue-classes" + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + freeCompilerArgs.set(listOf("-Xvalue-classes")) + } } // Set compiler to use UTF-8 @@ -54,8 +57,8 @@ dependencies { implementation(project(":server:core")) implementation(project(":solarxr-protocol")) - implementation("commons-cli:commons-cli:1.5.0") - implementation("org.apache.commons:commons-lang3:3.12.0") + implementation("commons-cli:commons-cli:1.8.0") + implementation("org.apache.commons:commons-lang3:3.15.0") implementation("com.google.protobuf:protobuf-java:3.21.12") implementation("net.java.dev.jna:jna:5.+") implementation("net.java.dev.jna:jna-platform:5.+") diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt b/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt index ce36aca4b..cc4662d70 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt +++ b/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt @@ -95,8 +95,7 @@ fun main(args: Array) { } try { // This is disabled because the config can't be read at this point - // new ServerSocket(6969).close(); - ServerSocket(35903).close() + // ServerSocket(6969).close() ServerSocket(21110).close() } catch (e: IOException) { LogManager diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/platform/SteamVRBridge.kt b/server/desktop/src/main/java/dev/slimevr/desktop/platform/SteamVRBridge.kt index 3f3d9bcd2..52fc93611 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/platform/SteamVRBridge.kt +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/SteamVRBridge.kt @@ -155,16 +155,16 @@ abstract class SteamVRBridge( // Display name, needsReset and isHmd val displayName: String - val (needsReset, isHmd) = if (trackerAdded.trackerId == 0) { + val isHmd = if (trackerAdded.trackerId == 0) { displayName = if (trackerAdded.trackerName == "HMD") { "SteamVR Driver HMD" } else { "Feeder App HMD" } - false to true + true } else { displayName = trackerAdded.trackerName - true to false + false } // trackerPosition @@ -187,7 +187,7 @@ abstract class SteamVRBridge( hasRotation = true, userEditable = true, isComputed = true, - needsReset = needsReset, + needsReset = true, isHmd = isHmd, ) diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/tracking/trackers/hid/HIDDevice.kt b/server/desktop/src/main/java/dev/slimevr/desktop/tracking/trackers/hid/HIDDevice.kt index 2af65cd6a..05a3f9165 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/tracking/trackers/hid/HIDDevice.kt +++ b/server/desktop/src/main/java/dev/slimevr/desktop/tracking/trackers/hid/HIDDevice.kt @@ -2,7 +2,12 @@ package dev.slimevr.desktop.tracking.trackers.hid import dev.slimevr.tracking.trackers.Device import dev.slimevr.tracking.trackers.Tracker +import dev.slimevr.tracking.trackers.udp.BoardType +import dev.slimevr.tracking.trackers.udp.MCUType class HIDDevice(val hidId: Int) : Device() { + override var hardwareIdentifier: String = "Unknown" + override var boardType: BoardType = BoardType.UNKNOWN + override var mcuType: MCUType = MCUType.UNKNOWN fun getTracker(id: Int): Tracker? = trackers[id] } diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/tracking/trackers/hid/TrackersHID.kt b/server/desktop/src/main/java/dev/slimevr/desktop/tracking/trackers/hid/TrackersHID.kt index 8e85c65af..dce94ec15 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/tracking/trackers/hid/TrackersHID.kt +++ b/server/desktop/src/main/java/dev/slimevr/desktop/tracking/trackers/hid/TrackersHID.kt @@ -5,12 +5,15 @@ import dev.slimevr.VRServer import dev.slimevr.tracking.trackers.Device import dev.slimevr.tracking.trackers.Tracker import dev.slimevr.tracking.trackers.TrackerStatus +import dev.slimevr.tracking.trackers.udp.BoardType import dev.slimevr.tracking.trackers.udp.IMUType +import dev.slimevr.tracking.trackers.udp.MCUType import io.eiren.util.logging.LogManager import io.github.axisangles.ktmath.Quaternion import io.github.axisangles.ktmath.Quaternion.Companion.fromRotationVector import io.github.axisangles.ktmath.Vector3 import org.hid4java.HidDevice +import org.hid4java.HidException import org.hid4java.HidManager import org.hid4java.HidServices import org.hid4java.HidServicesListener @@ -18,12 +21,16 @@ import org.hid4java.HidServicesSpecification import org.hid4java.event.HidServicesEvent import org.hid4java.jna.HidApi import org.hid4java.jna.HidDeviceInfoStructure +import java.nio.ByteBuffer import java.util.function.Consumer import kotlin.experimental.and +import kotlin.math.* private const val HID_TRACKER_RECEIVER_VID = 0x1209 private const val HID_TRACKER_RECEIVER_PID = 0x7690 +private const val PACKET_SIZE = 16 + /** * Receives trackers data by UDP using extended owoTrack protocol. */ @@ -34,22 +41,26 @@ class TrackersHID(name: String, private val trackersConsumer: Consumer) private val devicesBySerial: MutableMap> = HashMap() private val devicesByHID: MutableMap> = HashMap() private val hidServicesSpecification = HidServicesSpecification() - private val hidServices: HidServices + private var hidServices: HidServices? = null init { hidServicesSpecification.setAutoStart(false) - hidServices = HidManager.getHidServices(hidServicesSpecification) - hidServices.addHidServicesListener(this) - val dataReadThread = Thread(dataReadRunnable) - dataReadThread.isDaemon = true - dataReadThread.name = "hid4java data reader" - dataReadThread.start() - // We use hid4java but actually do not start the service ever, because it will just enumerate everything and cause problems - // Do enumeration ourself - val deviceEnumerateThread = Thread(deviceEnumerateRunnable) - deviceEnumerateThread.isDaemon = true - deviceEnumerateThread.name = "hid4java device enumerator" - deviceEnumerateThread.start() + try { + hidServices = HidManager.getHidServices(hidServicesSpecification) + hidServices?.addHidServicesListener(this) + val dataReadThread = Thread(dataReadRunnable) + dataReadThread.isDaemon = true + dataReadThread.name = "hid4java data reader" + dataReadThread.start() + // We use hid4java but actually do not start the service ever, because it will just enumerate everything and cause problems + // Do enumeration ourself + val deviceEnumerateThread = Thread(deviceEnumerateRunnable) + deviceEnumerateThread.isDaemon = true + deviceEnumerateThread.name = "hid4java device enumerator" + deviceEnumerateThread.start() + } catch (e: HidException) { + LogManager.severe("Error initializing HID services: ${e.message}", e) + } } private fun checkConfigureDevice(hidDevice: HidDevice) { @@ -134,14 +145,23 @@ class TrackersHID(name: String, private val trackersConsumer: Consumer) } } - private fun deviceIdLookup(hidDevice: HidDevice, deviceId: Int, deviceList: MutableList): HIDDevice { + private fun deviceIdLookup(hidDevice: HidDevice, deviceId: Int, deviceName: String? = null, deviceList: MutableList): HIDDevice? { synchronized(this.devices) { deviceList.map { this.devices[it] }.find { it.hidId == deviceId }?.let { return it } + if (deviceName == null) { // not registered yet + return null + } val device = HIDDevice(deviceId) - // server wants tracker to be unique, so use combination of hid serial and full id - device.name = hidDevice.serialNumber ?: "Unknown HID Device" - device.name += "-$deviceId" + // server wants tracker to be unique, so use combination of hid serial and full id // TODO: use the tracker "address" instead + // TODO: the server should not setup any device, only when the receiver associates the id with the tracker "address" and sends this packet (0xff?) which it will do occasionally + // device.name = hidDevice.serialNumber ?: "Unknown HID Device" + // device.name += "-$deviceId" + device.name = deviceName device.manufacturer = "HID Device" // TODO: + // device.manufacturer = hidDevice.manufacturer ?: "HID Device" +// device.hardwareIdentifier = hidDevice.serialNumber // hardwareIdentifier is not used to identify the tracker, so also display the receiver serial +// device.hardwareIdentifier += "-$deviceId/$deviceName" // receiver serial + assigned id in receiver + device address + device.hardwareIdentifier = deviceName // the rest of identifier wont fit in gui this.devices.add(device) deviceList.add(this.devices.size - 1) VRServer.instance.deviceManager.addDevice(device) // actually add device to the server @@ -186,81 +206,228 @@ class TrackersHID(name: String, private val trackersConsumer: Consumer) private fun dataRead() { synchronized(devicesByHID) { var devicesPresent = false + var devicesDataReceived = false val q = intArrayOf(0, 0, 0, 0) val a = intArrayOf(0, 0, 0) for ((hidDevice, deviceList) in devicesByHID) { - val dataReceived: Array = try { - hidDevice.read(80, 0) // Read up to 80 bytes + val dataReceived: ByteArray = try { + hidDevice.readAll(0) // multiples 64 bytes } catch (e: NegativeArraySizeException) { continue // Skip devices with read error (Maybe disconnected) } devicesPresent = true // Even if the device has no data if (dataReceived.isNotEmpty()) { // Process data - // TODO: make this less bad - if (dataReceived.size % 20 != 0) { + // The data is always received as 64 bytes, this check no longer works + if (dataReceived.size % PACKET_SIZE != 0) { LogManager.info("[TrackerServer] Malformed HID packet, ignoring") continue // Don't continue with this data } - val packetCount = dataReceived.size / 20 + devicesDataReceived = true // Data is received and is valid (not malformed) + val packetCount = dataReceived.size / PACKET_SIZE var i = 0 - while (i < packetCount * 20) { - if (i > 0) { - val currSlice: Array = dataReceived.copyOfRange(i, (i + 19)) - val prevSlice: Array = dataReceived.copyOfRange((i - 20), (i - 1)) - if (currSlice contentEquals prevSlice) { - i += 20 - continue + while (i < packetCount * PACKET_SIZE) { + // Common packet data + val packetType = dataReceived[i].toUByte().toInt() + val id = dataReceived[i + 1].toUByte().toInt() + val trackerId = 0 // no concept of extensions + val deviceId = id + + // Register device + if (packetType == 255) { // device register packet from receiver + val buffer = ByteBuffer.wrap(dataReceived, i + 2, 8) + buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN) + val addr = buffer.getLong() and 0xFFFFFFFFFFFF + val deviceName = String.format("%012X", addr) + deviceIdLookup(hidDevice, deviceId, deviceName, deviceList) // register device + // server wants tracker to be unique, so use combination of hid serial and full id + i += PACKET_SIZE + continue + } + + val device: HIDDevice? = deviceIdLookup(hidDevice, deviceId, null, deviceList) + if (device == null) { // not registered yet + i += PACKET_SIZE + continue + } + + // Register tracker + if (packetType == 0) { // Tracker register packet (device info) + val imu_id = dataReceived[i + 8].toUByte().toInt() + val sensorType = IMUType.getById(imu_id.toUInt()) + if (sensorType != null) { + setUpSensor(device, trackerId, sensorType!!, TrackerStatus.OK) } } - // dataReceived[i] //for later - val idCombination = dataReceived[i + 1].toInt() - val rssi = -dataReceived[i + 2].toInt() - val battery = dataReceived[i + 3].toInt() - // ushort big endian - val battery_mV = dataReceived[i + 5].toUByte().toInt() shl 8 or dataReceived[i + 4].toUByte().toInt() - // Q15: 1 is represented as 0x7FFF, -1 as 0x8000 - // The sender can use integer saturation to avoid overflow - for (j in 0..3) { // quat received as fixed Q15 - // Q15 as short big endian - q[j] = dataReceived[i + 6 + j * 2 + 1].toInt() shl 8 or dataReceived[i + 6 + j * 2].toUByte().toInt() + var tracker: Tracker? = device.getTracker(trackerId) + if (tracker == null) { // not registered yet + i += PACKET_SIZE + continue } - for (j in 0..2) { // accel received as fixed 7, in m/s - // Q15 as short big endian - a[j] = dataReceived[i + 14 + j * 2 + 1].toInt() shl 8 or dataReceived[i + 14 + j * 2].toUByte().toInt() - } - val trackerId = idCombination and 0b1111 - val deviceId = (idCombination shr 4) and 0b1111 - val device = deviceIdLookup(hidDevice, deviceId, deviceList) - // server wants tracker to be unique, so use combination of hid serial and full id - setUpSensor(device, trackerId, IMUType.UNKNOWN, TrackerStatus.OK) - val tracker = device.getTracker(trackerId)!! - tracker.signalStrength = rssi - // tracker.batteryVoltage = if (battery and 128 == 128) 5f else 0f // Charge status - tracker.batteryVoltage = battery_mV.toFloat() * 0.001f - tracker.batteryLevel = (battery and 127).toFloat() - // The data comes in the same order as in the UDP protocol - // x y z w -> w x y z - var rot = Quaternion(q[3].toFloat(), q[0].toFloat(), q[1].toFloat(), q[2].toFloat()) - val scaleRot = 1 / (1 shl 15).toFloat() // compile time evaluation - rot = AXES_OFFSET.times(scaleRot).times(rot) // no division - tracker.setRotation(rot) - // TODO: I think the acceleration is wrong??? - // Yes it was. And rotation was wrong too. - // At lease we have fixed the fixed point decoding. - val scaleAccel = 1 / (1 shl 7).toFloat() // compile time evaluation - var acceleration = Vector3(a[0].toFloat(), a[1].toFloat(), a[2].toFloat()).times(scaleAccel) // no division - tracker.setAcceleration(acceleration) - tracker.dataTick() - i += 20 + // Packet data + var batt: Int? = null + var batt_v: Int? = null + var temp: Int? = null + var brd_id: Int? = null + var mcu_id: Int? = null + // var imu_id: Int? = null + // var mag_id: Int? = null // not used currently + var fw_date: Int? = null + var fw_major: Int? = null + var fw_minor: Int? = null + var fw_patch: Int? = null + var svr_status: Int? = null + // var status: Int? = null // raw status from tracker + var rssi: Int? = null + + // Tracker packets + when (packetType) { + 0 -> { // device info + batt = dataReceived[i + 2].toUByte().toInt() + batt_v = dataReceived[i + 3].toUByte().toInt() + temp = dataReceived[i + 4].toUByte().toInt() + brd_id = dataReceived[i + 5].toUByte().toInt() + mcu_id = dataReceived[i + 6].toUByte().toInt() + // imu_id = dataReceived[i + 8].toUByte().toInt() + // mag_id = dataReceived[i + 9].toUByte().toInt() + // ushort big endian + fw_date = dataReceived[i + 11].toUByte().toInt() shl 8 or dataReceived[i + 10].toUByte().toInt() + fw_major = dataReceived[i + 12].toUByte().toInt() + fw_minor = dataReceived[i + 13].toUByte().toInt() + fw_patch = dataReceived[i + 14].toUByte().toInt() + rssi = dataReceived[i + 15].toUByte().toInt() + } + + 1 -> { // full precision quat and accel, no extra data + // Q15: 1 is represented as 0x7FFF, -1 as 0x8000 + // The sender can use integer saturation to avoid overflow + for (j in 0..3) { // quat received as fixed Q15 + // Q15 as short big endian + q[j] = dataReceived[i + 2 + j * 2 + 1].toInt() shl 8 or dataReceived[i + 2 + j * 2].toUByte().toInt() + } + for (j in 0..2) { // accel received as fixed 7, in m/s + // Q7 as short big endian + a[j] = dataReceived[i + 10 + j * 2 + 1].toInt() shl 8 or dataReceived[i + 10 + j * 2].toUByte().toInt() + } + } + + 2 -> { // reduced precision quat and accel with data + batt = dataReceived[i + 2].toUByte().toInt() + batt_v = dataReceived[i + 3].toUByte().toInt() + temp = dataReceived[i + 4].toUByte().toInt() + // quaternion is quantized as exponential map + // X = 10 bits, Y/Z = 11 bits + val buffer = ByteBuffer.wrap(dataReceived, i + 5, 4) + buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN) + val q_buf = buffer.getInt().toUInt() + q[0] = (q_buf and 1023u).toInt() + q[1] = (q_buf shr 10 and 2047u).toInt() + q[2] = (q_buf shr 21 and 2047u).toInt() + for (j in 0..2) { // accel received as fixed 7, in m/s + // Q7 as short big endian + a[j] = dataReceived[i + 9 + j * 2 + 1].toInt() shl 8 or dataReceived[i + 9 + j * 2].toUByte().toInt() + } + rssi = dataReceived[i + 15].toUByte().toInt() + } + + 3 -> { // status + svr_status = dataReceived[i + 2].toUByte().toInt() + // status = dataReceived[i + 3].toUByte().toInt() + rssi = dataReceived[i + 15].toUByte().toInt() + } + + else -> { + } + } + + // Assign data + if (batt != null) { + tracker.batteryLevel = if (batt == 128) 1f else (batt and 127).toFloat() + } + // Server still won't display battery at 0% at all + if (batt_v != null) { + tracker.batteryVoltage = (batt_v.toFloat() + 245f) / 100f + } + if (temp != null) { + tracker.temperature = if (temp > 0) temp.toFloat() / 2f - 39f else null + } + // Range 1 - 255 -> -38.5 - +88.5 C + if (brd_id != null) { + val boardType = BoardType.getById(brd_id.toUInt()) + if (boardType != null) { + device.boardType = boardType!! + } + } + if (mcu_id != null) { + val mcuType = MCUType.getById(mcu_id.toUInt()) + if (mcuType != null) { + device.mcuType = mcuType!! + } + } + if (fw_date != null && fw_major != null && fw_minor != null && fw_patch != null) { + val firmwareYear = 2020 + (fw_date shr 9 and 127) + val firmwareMonth = fw_date shr 5 and 15 + val firmwareDay = fw_date and 31 + val firmwareDate = String.format("%04d-%02d-%02d", firmwareYear, firmwareMonth, firmwareDay) + device.firmwareVersion = "$fw_major.$fw_minor.$fw_patch (Build $firmwareDate)" + } + if (svr_status != null) { + val status = TrackerStatus.getById(svr_status) + if (status != null) { + tracker.status = status!! + } + } + if (rssi != null) { + tracker.signalStrength = -rssi + } + + // Assign rotation and acceleration + if (packetType == 1) { + // The data comes in the same order as in the UDP protocol + // x y z w -> w x y z + var rot = Quaternion(q[3].toFloat(), q[0].toFloat(), q[1].toFloat(), q[2].toFloat()) + val scaleRot = 1 / (1 shl 15).toFloat() // compile time evaluation + rot = AXES_OFFSET.times(scaleRot).times(rot) // no division + tracker.setRotation(rot) + } + if (packetType == 2) { + val v = floatArrayOf(q[0].toFloat(), q[1].toFloat(), q[2].toFloat()) // used q array for quantized data + v[0] /= (1 shl 10).toFloat() + v[1] /= (1 shl 11).toFloat() + v[2] /= (1 shl 11).toFloat() + for (i in 0..2) { + v[i] = v[i] * 2 - 1 + } + // http://marc-b-reynolds.github.io/quaternions/2017/05/02/QuatQuantPart1.html#fnref:pos:3 + // https://github.com/Marc-B-Reynolds/Stand-alone-junk/blob/559bd78893a3a95cdee1845834c632141b945a45/src/Posts/quatquant0.c#L898 + val d = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + val invSqrtD = 1 / sqrt(d + 1e-6f) + val a = (PI.toFloat() / 2) * d * invSqrtD + val s = sin(a) + val k = s * invSqrtD + var rot = Quaternion(cos(a), k * v[0], k * v[1], k * v[2]) + rot = AXES_OFFSET.times(rot) // no division + tracker.setRotation(rot) + } + if (packetType == 1 || packetType == 2) { + // TODO: Acceleration "was" wrong + val scaleAccel = 1 / (1 shl 7).toFloat() // compile time evaluation + var acceleration = Vector3(a[0].toFloat(), a[1].toFloat(), a[2].toFloat()).times(scaleAccel) // no division + tracker.setAcceleration(acceleration) + tracker.dataTick() // only data tick if there is rotation data + } + + i += PACKET_SIZE } // LogManager.info("[TrackerServer] HID received $packetCount tracker packets") } } if (!devicesPresent) { sleep(10) // No hid device, "empty loop" so sleep to save the poor cpu + } else if (!devicesDataReceived) { + sleep(1) // read has no timeout, no data also causes an "empty loop" } } } diff --git a/settings.gradle.kts b/settings.gradle.kts index c6d119b82..e2691d0b8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,7 +26,7 @@ pluginManagement { kotlin("jvm") version kotlinVersion kotlin("android") version kotlinVersion id("com.diffplug.spotless") version spotlessVersion - id("com.github.johnrengelman.shadow") version shadowJarVersion + id("com.gradleup.shadow") version shadowJarVersion id("com.github.gmazzo.buildconfig") version buildconfigVersion id("org.ajoberstar.grgit") version grgitVersion } diff --git a/solarxr-protocol b/solarxr-protocol index b182bec2c..aa69fb6e5 160000 --- a/solarxr-protocol +++ b/solarxr-protocol @@ -1 +1 @@ -Subproject commit b182bec2cad042fdbfdeb27236a310cb0bd40617 +Subproject commit aa69fb6e56b88a206010d1cb75bfa0edde5b4582