A multiplayer VR framework w/voice chat

Compare changes

Choose any two refs to compare.

+3 -1
.gitignore
··· 1 target/ 2 - .env
··· 1 target/ 2 + .env 3 + *.assetbundle 4 + *.flx
+3
.vscode/settings.json
···
··· 1 + { 2 + "python.analysis.autoImportCompletions": true 3 + }
+359 -4
Cargo.lock
··· 104 ] 105 106 [[package]] 107 name = "alsa" 108 version = "0.9.1" 109 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 135 "bitflags 2.10.0", 136 "cc", 137 "cesu8", 138 - "jni", 139 "jni-sys", 140 "libc", 141 "log", ··· 181 dependencies = [ 182 "num-traits", 183 ] 184 185 [[package]] 186 name = "arrayref" ··· 987 checksum = "7ef8e4b7e61dfe7719bb03c884dc270cd46a82efb40f93e9933b990c5c190c59" 988 989 [[package]] 990 name = "bevy_pbr" 991 version = "0.17.3" 992 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1535 ] 1536 1537 [[package]] 1538 name = "bindgen" 1539 version = "0.72.1" 1540 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1553 ] 1554 1555 [[package]] 1556 name = "bit-set" 1557 version = "0.8.0" 1558 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1631 "futures-io", 1632 "futures-lite", 1633 "piper", 1634 ] 1635 1636 [[package]] ··· 1976 "core-foundation-sys", 1977 "coreaudio-rs 0.11.3", 1978 "dasp_sample", 1979 - "jni", 1980 "js-sys", 1981 "libc", 1982 "mach2", ··· 1998 "alsa", 1999 "coreaudio-rs 0.13.0", 2000 "dasp_sample", 2001 - "jni", 2002 "js-sys", 2003 "libc", 2004 "mach2", ··· 2016 ] 2017 2018 [[package]] 2019 name = "crc32fast" 2020 version = "1.5.0" 2021 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2304 ] 2305 2306 [[package]] 2307 name = "felix-audio" 2308 version = "0.1.0" 2309 dependencies = [ ··· 2322 dependencies = [ 2323 "anyhow", 2324 "bevy", 2325 "cpal 0.16.0", 2326 "dotenvy", 2327 "felix-audio", 2328 "felix-net", 2329 "tokio", 2330 ] 2331 ··· 2882 2883 [[package]] 2884 name = "jni" 2885 version = "0.21.1" 2886 source = "registry+https://github.com/rust-lang/crates.io-index" 2887 checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" ··· 3069 checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 3070 3071 [[package]] 3072 name = "mach2" 3073 version = "0.4.3" 3074 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3342 ] 3343 3344 [[package]] 3345 name = "num_enum" 3346 version = "0.7.5" 3347 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3657 source = "registry+https://github.com/rust-lang/crates.io-index" 3658 checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" 3659 dependencies = [ 3660 - "jni", 3661 "ndk 0.8.0", 3662 "ndk-context", 3663 "num-derive", ··· 3700 checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 3701 3702 [[package]] 3703 name = "opus" 3704 version = "0.3.0" 3705 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3735 dependencies = [ 3736 "ttf-parser 0.25.1", 3737 ] 3738 3739 [[package]] 3740 name = "parking" ··· 4316 ] 4317 4318 [[package]] 4319 name = "serde_core" 4320 version = "1.0.228" 4321 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4346 "ryu", 4347 "serde", 4348 "serde_core", 4349 ] 4350 4351 [[package]] ··· 5028 checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 5029 5030 [[package]] 5031 name = "uuid" 5032 version = "1.19.0" 5033 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 5294 "js-sys", 5295 "log", 5296 "naga", 5297 "portable-atomic", 5298 "profiling", 5299 "raw-window-handle", 5300 "smallvec", 5301 "static_assertions", 5302 "wasm-bindgen", 5303 "web-sys", 5304 "wgpu-core", 5305 "wgpu-hal", ··· 5331 "smallvec", 5332 "thiserror 2.0.17", 5333 "wgpu-core-deps-apple", 5334 "wgpu-core-deps-wasm", 5335 "wgpu-core-deps-windows-linux-android", 5336 "wgpu-hal", ··· 5342 version = "26.0.0" 5343 source = "registry+https://github.com/rust-lang/crates.io-index" 5344 checksum = "18ae5fbde6a4cbebae38358aa73fcd6e0f15c6144b67ef5dc91ded0db125dbdf" 5345 dependencies = [ 5346 "wgpu-hal", 5347 ]
··· 104 ] 105 106 [[package]] 107 + name = "alloc-no-stdlib" 108 + version = "2.0.4" 109 + source = "registry+https://github.com/rust-lang/crates.io-index" 110 + checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" 111 + 112 + [[package]] 113 + name = "alloc-stdlib" 114 + version = "0.2.2" 115 + source = "registry+https://github.com/rust-lang/crates.io-index" 116 + checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" 117 + dependencies = [ 118 + "alloc-no-stdlib", 119 + ] 120 + 121 + [[package]] 122 name = "alsa" 123 version = "0.9.1" 124 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 150 "bitflags 2.10.0", 151 "cc", 152 "cesu8", 153 + "jni 0.21.1", 154 "jni-sys", 155 "libc", 156 "log", ··· 196 dependencies = [ 197 "num-traits", 198 ] 199 + 200 + [[package]] 201 + name = "array-init" 202 + version = "2.1.0" 203 + source = "registry+https://github.com/rust-lang/crates.io-index" 204 + checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" 205 206 [[package]] 207 name = "arrayref" ··· 1008 checksum = "7ef8e4b7e61dfe7719bb03c884dc270cd46a82efb40f93e9933b990c5c190c59" 1009 1010 [[package]] 1011 + name = "bevy_mod_openxr" 1012 + version = "0.4.0" 1013 + source = "registry+https://github.com/rust-lang/crates.io-index" 1014 + checksum = "1ead3d12dc1c364bc8f5d063c8cd82df23a3d6261807abecfbbca70ca3cb2c15" 1015 + dependencies = [ 1016 + "android_system_properties", 1017 + "ash", 1018 + "bevy_app", 1019 + "bevy_camera", 1020 + "bevy_derive", 1021 + "bevy_ecs", 1022 + "bevy_log", 1023 + "bevy_math", 1024 + "bevy_mod_xr", 1025 + "bevy_platform", 1026 + "bevy_render", 1027 + "bevy_transform", 1028 + "jni 0.20.0", 1029 + "ndk-context", 1030 + "openxr", 1031 + "thiserror 2.0.17", 1032 + "wgpu", 1033 + "wgpu-hal", 1034 + ] 1035 + 1036 + [[package]] 1037 + name = "bevy_mod_xr" 1038 + version = "0.4.0" 1039 + source = "registry+https://github.com/rust-lang/crates.io-index" 1040 + checksum = "4107b79e3e3b38bc57a7c3fceb465300070b4bc3d2ebd839a9e04468b06cc11c" 1041 + dependencies = [ 1042 + "bevy_app", 1043 + "bevy_camera", 1044 + "bevy_color", 1045 + "bevy_derive", 1046 + "bevy_ecs", 1047 + "bevy_gizmos", 1048 + "bevy_log", 1049 + "bevy_math", 1050 + "bevy_render", 1051 + "bevy_transform", 1052 + ] 1053 + 1054 + [[package]] 1055 name = "bevy_pbr" 1056 version = "0.17.3" 1057 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1600 ] 1601 1602 [[package]] 1603 + name = "bevy_xr_utils" 1604 + version = "0.4.0" 1605 + source = "registry+https://github.com/rust-lang/crates.io-index" 1606 + checksum = "f82cd353262258aae6048ccad3544b8a978a301d9eb954d66efef6dccc91dfa9" 1607 + dependencies = [ 1608 + "bevy_app", 1609 + "bevy_color", 1610 + "bevy_derive", 1611 + "bevy_ecs", 1612 + "bevy_gizmos", 1613 + "bevy_log", 1614 + "bevy_math", 1615 + "bevy_mod_openxr", 1616 + "bevy_mod_xr", 1617 + "bevy_transform", 1618 + "openxr", 1619 + "openxr_mndx_xdev_space", 1620 + ] 1621 + 1622 + [[package]] 1623 name = "bindgen" 1624 version = "0.72.1" 1625 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1638 ] 1639 1640 [[package]] 1641 + name = "binrw" 1642 + version = "0.15.0" 1643 + source = "registry+https://github.com/rust-lang/crates.io-index" 1644 + checksum = "81419ff39e6ed10a92a7f125290859776ced35d9a08a665ae40b23e7ca702f30" 1645 + dependencies = [ 1646 + "array-init", 1647 + "binrw_derive", 1648 + "bytemuck", 1649 + ] 1650 + 1651 + [[package]] 1652 + name = "binrw_derive" 1653 + version = "0.15.0" 1654 + source = "registry+https://github.com/rust-lang/crates.io-index" 1655 + checksum = "376404e55ec40d0d6f8b4b7df3f87b87954bd987f0cf9a7207ea3b6ea5c9add4" 1656 + dependencies = [ 1657 + "either", 1658 + "owo-colors", 1659 + "proc-macro2", 1660 + "quote", 1661 + "syn", 1662 + ] 1663 + 1664 + [[package]] 1665 name = "bit-set" 1666 version = "0.8.0" 1667 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1740 "futures-io", 1741 "futures-lite", 1742 "piper", 1743 + ] 1744 + 1745 + [[package]] 1746 + name = "brotli" 1747 + version = "3.5.0" 1748 + source = "registry+https://github.com/rust-lang/crates.io-index" 1749 + checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" 1750 + dependencies = [ 1751 + "alloc-no-stdlib", 1752 + "alloc-stdlib", 1753 + "brotli-decompressor", 1754 + ] 1755 + 1756 + [[package]] 1757 + name = "brotli-decompressor" 1758 + version = "2.5.1" 1759 + source = "registry+https://github.com/rust-lang/crates.io-index" 1760 + checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" 1761 + dependencies = [ 1762 + "alloc-no-stdlib", 1763 + "alloc-stdlib", 1764 ] 1765 1766 [[package]] ··· 2106 "core-foundation-sys", 2107 "coreaudio-rs 0.11.3", 2108 "dasp_sample", 2109 + "jni 0.21.1", 2110 "js-sys", 2111 "libc", 2112 "mach2", ··· 2128 "alsa", 2129 "coreaudio-rs 0.13.0", 2130 "dasp_sample", 2131 + "jni 0.21.1", 2132 "js-sys", 2133 "libc", 2134 "mach2", ··· 2146 ] 2147 2148 [[package]] 2149 + name = "crc" 2150 + version = "3.4.0" 2151 + source = "registry+https://github.com/rust-lang/crates.io-index" 2152 + checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" 2153 + dependencies = [ 2154 + "crc-catalog", 2155 + ] 2156 + 2157 + [[package]] 2158 + name = "crc-catalog" 2159 + version = "2.4.0" 2160 + source = "registry+https://github.com/rust-lang/crates.io-index" 2161 + checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" 2162 + 2163 + [[package]] 2164 name = "crc32fast" 2165 version = "1.5.0" 2166 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2449 ] 2450 2451 [[package]] 2452 + name = "felix-assets" 2453 + version = "0.1.0" 2454 + dependencies = [ 2455 + "anyhow", 2456 + "bevy", 2457 + "unity-asset", 2458 + "unity-asset-binary", 2459 + "unity-asset-decode", 2460 + ] 2461 + 2462 + [[package]] 2463 name = "felix-audio" 2464 version = "0.1.0" 2465 dependencies = [ ··· 2478 dependencies = [ 2479 "anyhow", 2480 "bevy", 2481 + "bevy_mod_openxr", 2482 + "bevy_mod_xr", 2483 + "bevy_xr_utils", 2484 "cpal 0.16.0", 2485 "dotenvy", 2486 + "felix-assets", 2487 "felix-audio", 2488 "felix-net", 2489 + "openxr", 2490 "tokio", 2491 ] 2492 ··· 3043 3044 [[package]] 3045 name = "jni" 3046 + version = "0.20.0" 3047 + source = "registry+https://github.com/rust-lang/crates.io-index" 3048 + checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" 3049 + dependencies = [ 3050 + "cesu8", 3051 + "combine", 3052 + "jni-sys", 3053 + "log", 3054 + "thiserror 1.0.69", 3055 + "walkdir", 3056 + ] 3057 + 3058 + [[package]] 3059 + name = "jni" 3060 version = "0.21.1" 3061 source = "registry+https://github.com/rust-lang/crates.io-index" 3062 checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" ··· 3244 checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 3245 3246 [[package]] 3247 + name = "lz4_flex" 3248 + version = "0.12.0" 3249 + source = "registry+https://github.com/rust-lang/crates.io-index" 3250 + checksum = "ab6473172471198271ff72e9379150e9dfd70d8e533e0752a27e515b48dd375e" 3251 + dependencies = [ 3252 + "twox-hash", 3253 + ] 3254 + 3255 + [[package]] 3256 + name = "lzma-rs" 3257 + version = "0.3.0" 3258 + source = "registry+https://github.com/rust-lang/crates.io-index" 3259 + checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" 3260 + dependencies = [ 3261 + "byteorder", 3262 + "crc", 3263 + ] 3264 + 3265 + [[package]] 3266 name = "mach2" 3267 version = "0.4.3" 3268 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3536 ] 3537 3538 [[package]] 3539 + name = "num_cpus" 3540 + version = "1.17.0" 3541 + source = "registry+https://github.com/rust-lang/crates.io-index" 3542 + checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" 3543 + dependencies = [ 3544 + "hermit-abi", 3545 + "libc", 3546 + ] 3547 + 3548 + [[package]] 3549 name = "num_enum" 3550 version = "0.7.5" 3551 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3861 source = "registry+https://github.com/rust-lang/crates.io-index" 3862 checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" 3863 dependencies = [ 3864 + "jni 0.21.1", 3865 "ndk 0.8.0", 3866 "ndk-context", 3867 "num-derive", ··· 3904 checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 3905 3906 [[package]] 3907 + name = "openxr" 3908 + version = "0.19.0" 3909 + source = "registry+https://github.com/rust-lang/crates.io-index" 3910 + checksum = "2a2d6934d2508f94fd4cbda6c2a326f111f60ce59fd9136df6d478564397dd40" 3911 + dependencies = [ 3912 + "libc", 3913 + "libloading", 3914 + "ndk-context", 3915 + "openxr-sys", 3916 + ] 3917 + 3918 + [[package]] 3919 + name = "openxr-sys" 3920 + version = "0.11.0" 3921 + source = "registry+https://github.com/rust-lang/crates.io-index" 3922 + checksum = "f10e7e38c47f2175fc39363713b656db899fa0b4a14341029702cbdfa6f44d05" 3923 + dependencies = [ 3924 + "cmake", 3925 + "libc", 3926 + "mint", 3927 + ] 3928 + 3929 + [[package]] 3930 + name = "openxr_mndx_xdev_space" 3931 + version = "0.1.1" 3932 + source = "registry+https://github.com/rust-lang/crates.io-index" 3933 + checksum = "fc03c3948dceb287224eaa9079a5d4f690e91b43a2385da6c686edf0f850408a" 3934 + dependencies = [ 3935 + "openxr", 3936 + ] 3937 + 3938 + [[package]] 3939 name = "opus" 3940 version = "0.3.0" 3941 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3971 dependencies = [ 3972 "ttf-parser 0.25.1", 3973 ] 3974 + 3975 + [[package]] 3976 + name = "owo-colors" 3977 + version = "4.2.3" 3978 + source = "registry+https://github.com/rust-lang/crates.io-index" 3979 + checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" 3980 3981 [[package]] 3982 name = "parking" ··· 4558 ] 4559 4560 [[package]] 4561 + name = "serde_bytes" 4562 + version = "0.11.19" 4563 + source = "registry+https://github.com/rust-lang/crates.io-index" 4564 + checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" 4565 + dependencies = [ 4566 + "serde", 4567 + "serde_core", 4568 + ] 4569 + 4570 + [[package]] 4571 name = "serde_core" 4572 version = "1.0.228" 4573 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4598 "ryu", 4599 "serde", 4600 "serde_core", 4601 + ] 4602 + 4603 + [[package]] 4604 + name = "serde_yaml" 4605 + version = "0.9.34+deprecated" 4606 + source = "registry+https://github.com/rust-lang/crates.io-index" 4607 + checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" 4608 + dependencies = [ 4609 + "indexmap", 4610 + "itoa", 4611 + "ryu", 4612 + "serde", 4613 + "unsafe-libyaml", 4614 ] 4615 4616 [[package]] ··· 5293 checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 5294 5295 [[package]] 5296 + name = "unity-asset" 5297 + version = "0.2.0" 5298 + source = "registry+https://github.com/rust-lang/crates.io-index" 5299 + checksum = "6705b95fda449527055ff77fe5cff49f774dde7335ed92bc3d048fc74066ebaf" 5300 + dependencies = [ 5301 + "unity-asset-binary", 5302 + "unity-asset-core", 5303 + "unity-asset-yaml", 5304 + ] 5305 + 5306 + [[package]] 5307 + name = "unity-asset-binary" 5308 + version = "0.2.0" 5309 + source = "registry+https://github.com/rust-lang/crates.io-index" 5310 + checksum = "d739d1414c1732be1035417f83b1e60f234c7d5eb8abda0ee70d178a58137cb7" 5311 + dependencies = [ 5312 + "binrw", 5313 + "brotli", 5314 + "byteorder", 5315 + "flate2", 5316 + "indexmap", 5317 + "lz4_flex", 5318 + "lzma-rs", 5319 + "memmap2", 5320 + "num_cpus", 5321 + "once_cell", 5322 + "regex", 5323 + "serde", 5324 + "serde_json", 5325 + "thiserror 2.0.17", 5326 + "unity-asset-core", 5327 + ] 5328 + 5329 + [[package]] 5330 + name = "unity-asset-core" 5331 + version = "0.2.0" 5332 + source = "registry+https://github.com/rust-lang/crates.io-index" 5333 + checksum = "12903fd47e122b5e7e335fc9cb5540bb35ab0ffe5bb57a7741a8c7be8d361361" 5334 + dependencies = [ 5335 + "indexmap", 5336 + "lazy_static", 5337 + "serde", 5338 + "serde_bytes", 5339 + "thiserror 2.0.17", 5340 + ] 5341 + 5342 + [[package]] 5343 + name = "unity-asset-decode" 5344 + version = "0.2.0" 5345 + source = "registry+https://github.com/rust-lang/crates.io-index" 5346 + checksum = "9ea6e630cdefde54a88ca4fbae54cf3d3e5ba527fac96b085562da3b3834b77b" 5347 + dependencies = [ 5348 + "indexmap", 5349 + "serde", 5350 + "unity-asset-binary", 5351 + "unity-asset-core", 5352 + ] 5353 + 5354 + [[package]] 5355 + name = "unity-asset-yaml" 5356 + version = "0.2.0" 5357 + source = "registry+https://github.com/rust-lang/crates.io-index" 5358 + checksum = "b991e340c27b1578e657defee9f57de867d853b8f40448fb079d0ee3a5ebc77e" 5359 + dependencies = [ 5360 + "indexmap", 5361 + "serde", 5362 + "serde_yaml", 5363 + "thiserror 2.0.17", 5364 + "unity-asset-core", 5365 + ] 5366 + 5367 + [[package]] 5368 + name = "unsafe-libyaml" 5369 + version = "0.2.11" 5370 + source = "registry+https://github.com/rust-lang/crates.io-index" 5371 + checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" 5372 + 5373 + [[package]] 5374 name = "uuid" 5375 version = "1.19.0" 5376 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 5637 "js-sys", 5638 "log", 5639 "naga", 5640 + "parking_lot", 5641 "portable-atomic", 5642 "profiling", 5643 "raw-window-handle", 5644 "smallvec", 5645 "static_assertions", 5646 "wasm-bindgen", 5647 + "wasm-bindgen-futures", 5648 "web-sys", 5649 "wgpu-core", 5650 "wgpu-hal", ··· 5676 "smallvec", 5677 "thiserror 2.0.17", 5678 "wgpu-core-deps-apple", 5679 + "wgpu-core-deps-emscripten", 5680 "wgpu-core-deps-wasm", 5681 "wgpu-core-deps-windows-linux-android", 5682 "wgpu-hal", ··· 5688 version = "26.0.0" 5689 source = "registry+https://github.com/rust-lang/crates.io-index" 5690 checksum = "18ae5fbde6a4cbebae38358aa73fcd6e0f15c6144b67ef5dc91ded0db125dbdf" 5691 + dependencies = [ 5692 + "wgpu-hal", 5693 + ] 5694 + 5695 + [[package]] 5696 + name = "wgpu-core-deps-emscripten" 5697 + version = "26.0.0" 5698 + source = "registry+https://github.com/rust-lang/crates.io-index" 5699 + checksum = "d7670e390f416006f746b4600fdd9136455e3627f5bd763abf9a65daa216dd2d" 5700 dependencies = [ 5701 "wgpu-hal", 5702 ]
+4 -1
Cargo.toml
··· 1 [workspace] 2 resolver = "3" 3 - members = [ "audio", "client", "net", "server" ]
··· 1 [workspace] 2 resolver = "3" 3 + members = [ "audio", "client", "assets", "net", "server" ] 4 + 5 + [profile.dev.package."*"] 6 + opt-level = 3
+11
assets/Cargo.toml
···
··· 1 + [package] 2 + name = "felix-assets" 3 + version = "0.1.0" 4 + edition = "2024" 5 + 6 + [dependencies] 7 + anyhow = "1.0.100" 8 + unity-asset = "0.2.0" 9 + unity-asset-binary = "0.2.0" 10 + unity-asset-decode = { version = "0.2.0", features = [ "mesh" ] } 11 + bevy = "0.17.3"
+3
assets/examples/test.rs
···
··· 1 + fn main(){ 2 + felix_assets::load("test.flx").unwrap(); 3 + }
+62
assets/src/buffer.rs
···
··· 1 + use std::io::Read; 2 + 3 + use bevy::math::{Quat, Vec3}; 4 + 5 + pub struct StreamedBuffer{ 6 + stream: Box<dyn Read> 7 + } 8 + 9 + impl StreamedBuffer{ 10 + pub fn new( stream: impl Read + 'static ) -> Self{ 11 + Self { 12 + stream: Box::new(stream) 13 + } 14 + } 15 + 16 + pub fn get_u8(&mut self) -> u8{ 17 + let mut b = [0u8; 1]; 18 + self.stream.read(&mut b).unwrap(); 19 + 20 + b[0] 21 + } 22 + 23 + pub fn get_u8s(&mut self, count: usize) -> Vec<u8>{ 24 + let mut b = vec![0u8; count]; 25 + self.stream.read(&mut b).unwrap(); 26 + 27 + b 28 + } 29 + 30 + pub fn get_i32(&mut self) -> i32{ 31 + let b = self.get_u8s(4); 32 + i32::from_le_bytes([ b[0], b[1], b[2], b[3] ]) 33 + } 34 + 35 + pub fn get_u32(&mut self) -> u32{ 36 + let b = self.get_u8s(4); 37 + u32::from_le_bytes([ b[0], b[1], b[2], b[3] ]) 38 + } 39 + 40 + pub fn get_str(&mut self) -> String{ 41 + let length = self.get_u32(); 42 + let b = self.get_u8s(length as usize); 43 + 44 + let string = str::from_utf8(&b).unwrap(); 45 + string.to_owned() 46 + } 47 + 48 + 49 + pub fn get_vec3(&mut self) -> Vec3{ 50 + Vec3 { x: self.get_f32(), y: self.get_f32(), z: self.get_f32() } 51 + } 52 + 53 + pub fn get_quat(&mut self) -> Quat{ 54 + Quat::from_xyzw(self.get_f32(), self.get_f32(), self.get_f32(), self.get_f32()) 55 + } 56 + 57 + 58 + pub fn get_f32(&mut self) -> f32{ 59 + let b = self.get_u8s(4); 60 + f32::from_le_bytes([ b[0], b[1], b[2], b[3] ]) 61 + } 62 + }
+84
assets/src/felix/mod.rs
···
··· 1 + use std::fs::File; 2 + 3 + use bevy::{asset::RenderAssetUsages, mesh::{Indices, PrimitiveTopology}, prelude::*, transform::components::Transform}; 4 + 5 + use crate::{BevyObject, BevyObjectData, BevyObjectLightData, BevyObjectLightDataType, buffer::StreamedBuffer}; 6 + 7 + pub fn load( path: &'static str ) -> anyhow::Result<Vec<BevyObject>>{ 8 + // TODO: Material loading 9 + // TODO: UV Loading 10 + // TODO: Flat normals 11 + // TODO: Live updates directly from blender? 12 + 13 + let mut objs = vec![]; 14 + 15 + let decoder = File::open(path).unwrap(); 16 + let mut buf = StreamedBuffer::new(decoder); 17 + 18 + let obj_count = buf.get_u32(); 19 + 20 + for _ in 0..obj_count{ 21 + let name = buf.get_str(); 22 + let transform = Transform { 23 + translation: buf.get_vec3(), 24 + rotation: buf.get_quat(), 25 + scale: buf.get_vec3() 26 + }; 27 + 28 + match buf.get_u32(){ 29 + 0 => { // 0 - Mesh 30 + let mut vertices = vec![]; 31 + let mut normals = vec![]; 32 + let mut triangles = vec![]; 33 + 34 + let vertex_count = buf.get_u32(); 35 + for _ in 0..vertex_count{ 36 + vertices.push(buf.get_vec3()); 37 + normals.push(buf.get_vec3()); 38 + } 39 + 40 + let triangle_count = buf.get_u32(); 41 + for _ in 0..triangle_count{ 42 + triangles.push(buf.get_u32()); 43 + triangles.push(buf.get_u32()); 44 + triangles.push(buf.get_u32()); 45 + } 46 + 47 + objs.push(BevyObject { 48 + name, 49 + transform, 50 + data: BevyObjectData::Mesh(Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD) 51 + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vertices) 52 + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) 53 + .with_inserted_indices(Indices::U32(triangles))) 54 + }); 55 + } 56 + 57 + 1 => { // 1 - Light 58 + let light_type = match buf.get_u32(){ 59 + 0 => BevyObjectLightDataType::Point, 60 + 1 => BevyObjectLightDataType::Sun, 61 + 2 => BevyObjectLightDataType::Spot, 62 + 3 => BevyObjectLightDataType::Area, 63 + _ => BevyObjectLightDataType::Unknown 64 + }; 65 + 66 + let colour = buf.get_vec3(); 67 + 68 + objs.push(BevyObject { 69 + name, 70 + transform, 71 + data: BevyObjectData::Light(BevyObjectLightData { 72 + type_: light_type, 73 + colour: Color::linear_rgb(colour.x, colour.y, colour.z), 74 + power: buf.get_f32() 75 + }) 76 + }); 77 + } 78 + 79 + _ => {} 80 + } 81 + } 82 + 83 + Ok(objs) 84 + }
+38
assets/src/lib.rs
···
··· 1 + use bevy::{color::Color, mesh::Mesh, transform::components::Transform}; 2 + 3 + mod unity; 4 + mod felix; 5 + mod buffer; 6 + 7 + #[derive(Debug)] 8 + pub enum BevyObjectData{ 9 + Mesh(Mesh), 10 + Light(BevyObjectLightData) 11 + } 12 + 13 + #[derive(Debug)] 14 + pub struct BevyObject{ 15 + pub name: String, 16 + pub transform: Transform, 17 + pub data: BevyObjectData, 18 + } 19 + 20 + #[derive(Debug)] 21 + pub struct BevyObjectLightData{ 22 + pub type_: BevyObjectLightDataType, 23 + pub colour: Color, 24 + pub power: f32 25 + } 26 + 27 + #[derive(Debug)] 28 + pub enum BevyObjectLightDataType{ 29 + Point, 30 + Sun, 31 + Spot, 32 + Area, 33 + Unknown 34 + } 35 + 36 + pub fn load( path: &'static str ) -> anyhow::Result<Vec<BevyObject>>{ 37 + felix::load(path) 38 + }
+22
assets/src/unity/component/mesh_renderer.rs
···
··· 1 + use unity_asset_binary::object::UnityObject; 2 + 3 + use crate::unity::component::Component; 4 + 5 + #[derive(Debug)] 6 + pub struct MeshRenderer{ 7 + 8 + } 9 + 10 + impl Component for MeshRenderer{ 11 + 12 + } 13 + 14 + impl From<UnityObject> for MeshRenderer{ 15 + fn from(value: UnityObject) -> Self { 16 + // dbg!(value.property_names()); 17 + 18 + Self { 19 + 20 + } 21 + } 22 + }
+6
assets/src/unity/component/mod.rs
···
··· 1 + pub mod transform; 2 + pub mod mesh_renderer; 3 + 4 + pub trait Component{ 5 + 6 + }
+16
assets/src/unity/component/transform.rs
···
··· 1 + use bevy::transform::components::Transform; 2 + use unity_asset_binary::object::UnityObject; 3 + 4 + use crate::unity::unity_value::{unity_value_to_quat, unity_value_to_vec3}; 5 + 6 + pub fn into_bevy_transform(value: UnityObject) -> Transform { 7 + let position = value.get("m_LocalPosition").unwrap(); 8 + let rotation = value.get("m_LocalRotation").unwrap(); 9 + let scale = value.get("m_LocalScale").unwrap(); 10 + 11 + Transform { 12 + translation: unity_value_to_vec3(position), 13 + rotation: unity_value_to_quat(rotation), 14 + scale: unity_value_to_vec3(scale) 15 + } 16 + }
+111
assets/src/unity/mod.rs
···
··· 1 + // NOTE: Very WIP, Does not work!! 2 + 3 + use anyhow::bail; 4 + use bevy::{prelude::*, transform::components::Transform}; 5 + use unity_asset::environment::{Environment, EnvironmentObjectRef}; 6 + use unity_asset_binary::unity_version::UnityVersion; 7 + use unity_asset_decode::mesh::MeshParser; 8 + 9 + use crate::{BevyObject, BevyObjectData, unity::{component::{Component, mesh_renderer::MeshRenderer, transform::into_bevy_transform}, unity_value::try_unity_mesh_to_bevy}}; 10 + 11 + mod component; 12 + mod unity_value; 13 + 14 + #[derive(Debug)] 15 + pub struct UnityGameObject{ 16 + pub name: String, 17 + pub active: bool, 18 + 19 + pub transform: Transform, 20 + pub mesh_renderer: Option<MeshRenderer>, 21 + pub mesh_filter: Option<Mesh>, 22 + } 23 + 24 + pub fn load( path: &'static str ) -> anyhow::Result<Vec<BevyObject>>{ 25 + let mesh_parser = MeshParser::new(UnityVersion::parse_version("2020.3.12f1").unwrap()); 26 + 27 + let mut env = Environment::new(); 28 + env.load(path)?; 29 + 30 + let mut gameobjects = vec![]; 31 + 32 + for obj in env.objects(){ 33 + match obj{ 34 + EnvironmentObjectRef::Binary(v) => { 35 + if v.object.class_id() == 1{ 36 + let obj = v.object.read()?; 37 + let go = obj.as_gameobject().unwrap(); 38 + 39 + let mut components: Vec<Box<dyn Component>> = vec![]; 40 + 41 + let mut transform = None; 42 + let mut mesh_renderer = None; 43 + let mut mesh_filter = None; 44 + 45 + let comps = obj.get("m_Component").unwrap().as_array().unwrap(); 46 + 47 + for comp in comps{ 48 + let obj = comp.as_object().unwrap().get("component").unwrap(); 49 + let path_id = obj.as_object().unwrap().get("m_PathID").unwrap().as_i64().unwrap(); 50 + 51 + let comp = env.find_binary_object(path_id).unwrap(); 52 + let comp = comp.read().unwrap(); 53 + 54 + match comp.class_id(){ 55 + 4 => transform = Some(into_bevy_transform(comp)), // Normal Transform 56 + 224 => transform = Some(into_bevy_transform(comp)), // Rect Transform (gonna just treat it as normal) 57 + 58 + 23 => mesh_renderer = Some(MeshRenderer::from(comp)), 59 + 33 => { 60 + let mesh = comp.get("m_Mesh").unwrap(); 61 + let path_id = mesh.as_object().unwrap().get("m_PathID").unwrap().as_i64().unwrap(); 62 + 63 + let mesh = env.find_binary_object(path_id).unwrap(); 64 + let mesh_obj = mesh.read().unwrap(); 65 + 66 + if let Some(mesh) = try_unity_mesh_to_bevy(mesh_obj, &mesh_parser){ 67 + mesh_filter = Some(mesh); 68 + } else{ 69 + println!("[WARN] Failed to load mesh for: {}", go.name); 70 + } 71 + }, 72 + 73 + _ => {} 74 + } 75 + } 76 + 77 + if transform.is_none(){ bail!("Cannot find transform for object {}", go.name); } 78 + 79 + let gameobject = UnityGameObject { 80 + name: go.name, 81 + active: go.active, 82 + 83 + transform: transform.unwrap(), 84 + mesh_renderer, 85 + mesh_filter 86 + }; 87 + 88 + gameobjects.push(gameobject); 89 + break; 90 + } 91 + }, 92 + _ => {} 93 + } 94 + } 95 + 96 + let mut objs = vec![]; 97 + 98 + for go in gameobjects{ 99 + if go.active{ 100 + if let Some(mesh) = go.mesh_filter{ 101 + objs.push(BevyObject { 102 + name: go.name, 103 + transform: go.transform, 104 + data: BevyObjectData::Mesh(mesh) 105 + }); 106 + } 107 + } 108 + } 109 + 110 + Ok(objs) 111 + }
+467
assets/src/unity/unity_value.rs
···
··· 1 + use std::{fs::File, io::Write, mem}; 2 + 3 + use bevy::{asset::RenderAssetUsages, math::{Quat, Vec3}, mesh::{Indices, PrimitiveTopology}, prelude::*}; 4 + use unity_asset::UnityValue; 5 + use unity_asset_binary::object::UnityObject; 6 + use unity_asset_decode::mesh::MeshParser; 7 + 8 + pub fn unity_value_to_vec3( val: &UnityValue ) -> Vec3{ 9 + let obj = val.as_object().unwrap(); 10 + 11 + Vec3 { 12 + x: obj.get("x").unwrap().as_f64().unwrap() as f32, 13 + y: obj.get("y").unwrap().as_f64().unwrap() as f32, 14 + z: obj.get("z").unwrap().as_f64().unwrap() as f32 15 + } 16 + } 17 + 18 + pub fn unity_value_to_quat( val: &UnityValue ) -> Quat{ 19 + let obj = val.as_object().unwrap(); 20 + 21 + Quat::from_xyzw( 22 + obj.get("x").unwrap().as_f64().unwrap() as f32, 23 + obj.get("y").unwrap().as_f64().unwrap() as f32, 24 + obj.get("z").unwrap().as_f64().unwrap() as f32, 25 + obj.get("w").unwrap().as_f64().unwrap() as f32 26 + ) 27 + } 28 + 29 + fn get_channel_component_size( format: u8 ) -> usize{ 30 + match format{ 31 + 0 => 4, // kVertexFormatFloat 32 + 1 => 2, // kVertexFormatFloat16 33 + 2 => 1, // kVertexFormatUNorm8 34 + 3 => 1, // kVertexFormatSNorm8 35 + 4 => 2, // kVertexFormatUNorm16 36 + 5 => 2, // kVertexFormatSNorm16 37 + 6 => 1, // kVertexFormatUInt8 38 + 7 => 1, // kVertexFormatSInt8 39 + 8 => 2, // kVertexFormatUInt16 40 + 9 => 2, // kVertexFormatSInt16 41 + 10 => 4, // kVertexFormatUInt32 42 + 11 => 4, // kVertexFormatSInt32 43 + 44 + _ => 0 45 + } 46 + } 47 + 48 + enum UnityDataTypeArray{ 49 + kVertexFormatFloat(Vec<Vec<f32>>), 50 + kVertexFormatFloat16(Vec<Vec<f32>>), 51 + kVertexFormatUNorm8(Vec<Vec<u8>>), 52 + kVertexFormatSNorm8(Vec<Vec<i8>>), 53 + kVertexFormatUNorm16(Vec<Vec<u16>>), 54 + kVertexFormatSNorm16(Vec<Vec<i16>>), 55 + kVertexFormatUInt8(Vec<Vec<u8>>), 56 + kVertexFormatSInt8(Vec<Vec<i8>>), 57 + kVertexFormatUInt16(Vec<Vec<u16>>), 58 + kVertexFormatSInt16(Vec<Vec<i16>>), 59 + kVertexFormatUInt32(Vec<Vec<u32>>), 60 + kVertexFormatSInt32(Vec<Vec<i32>>), 61 + Unknown 62 + } 63 + 64 + impl UnityDataTypeArray{ 65 + pub fn as_vec3_array( &self ) -> Vec<Vec3>{ 66 + if let Self::kVertexFormatFloat(array) = self{ 67 + let mut vecs = vec![]; 68 + 69 + for val in array{ 70 + vecs.push(Vec3 { x: val[0], y: val[1], z: val[2] }); 71 + } 72 + 73 + vecs 74 + } else{ 75 + panic!("Not a float array"); 76 + } 77 + } 78 + } 79 + 80 + fn unpack_struct( dimension: usize, component_dtype: u8, bytes: Vec<u8> ) -> UnityDataTypeArray{ 81 + match component_dtype{ 82 + 0 => { 83 + let mut decoded: Vec<Vec<_>> = vec![]; 84 + let item_size = get_channel_component_size(component_dtype); 85 + let vec_size = item_size * dimension; 86 + 87 + for i in 0..( bytes.len() / vec_size ){ 88 + let indx = i * vec_size; 89 + let mut vec = vec![0.0; dimension]; 90 + 91 + for j in 0..dimension{ 92 + vec[j] = f32::from_le_bytes([ 93 + bytes[indx + (j * item_size)], 94 + bytes[indx + (j * item_size) + 1], 95 + bytes[indx + (j * item_size) + 2], 96 + bytes[indx + (j * item_size) + 3] 97 + ]); 98 + } 99 + decoded.push(vec); 100 + } 101 + 102 + UnityDataTypeArray::kVertexFormatFloat(decoded) 103 + }, 104 + 105 + 1 => { 106 + let mut decoded: Vec<Vec<_>> = vec![]; 107 + let item_size = get_channel_component_size(component_dtype); 108 + let vec_size = item_size * dimension; 109 + 110 + for i in 0..( bytes.len() / vec_size ){ 111 + let indx = i * vec_size; 112 + let mut vec = vec![0.0; dimension]; 113 + 114 + for j in 0..dimension{ 115 + vec[j] = f32::from_le_bytes([ 116 + bytes[indx + (j * item_size)], 117 + bytes[indx + (j * item_size) + 1], 118 + 0, 0 119 + ]); 120 + } 121 + decoded.push(vec); 122 + } 123 + 124 + UnityDataTypeArray::kVertexFormatFloat16(decoded) 125 + }, 126 + 127 + 2 => { 128 + let mut decoded: Vec<Vec<u8>> = vec![]; 129 + let item_size = get_channel_component_size(component_dtype); 130 + let vec_size = item_size * dimension; 131 + 132 + for i in 0..( bytes.len() / vec_size ){ 133 + let indx = i * vec_size; 134 + let mut vec = vec![0; vec_size]; 135 + 136 + for j in 0..vec_size{ vec[j] = u8::from_le_bytes([ bytes[indx + (j * item_size)] ]); } 137 + decoded.push(vec); 138 + } 139 + 140 + UnityDataTypeArray::kVertexFormatUNorm8(decoded) 141 + }, 142 + 143 + 3 => { 144 + let mut decoded: Vec<Vec<_>> = vec![]; 145 + let item_size = get_channel_component_size(component_dtype); 146 + let vec_size = item_size * dimension; 147 + 148 + for i in 0..( bytes.len() / vec_size ){ 149 + let indx = i * vec_size; 150 + let mut vec = vec![0; vec_size]; 151 + 152 + for j in 0..vec_size{ vec[j] = i8::from_le_bytes([ bytes[indx + (j * item_size)] ]); } 153 + decoded.push(vec); 154 + } 155 + 156 + UnityDataTypeArray::kVertexFormatSNorm8(decoded) 157 + }, 158 + 159 + 4 => { 160 + let mut decoded: Vec<Vec<_>> = vec![]; 161 + let item_size = get_channel_component_size(component_dtype); 162 + let vec_size = item_size * dimension; 163 + 164 + for i in 0..( bytes.len() / vec_size ){ 165 + let indx = i * vec_size; 166 + let mut vec = vec![0; vec_size]; 167 + 168 + for j in 0..vec_size{ 169 + vec[j] = u16::from_le_bytes([ 170 + bytes[indx + (j * item_size)], 171 + bytes[indx + (j * item_size) + 1] 172 + ]); 173 + } 174 + decoded.push(vec); 175 + } 176 + 177 + UnityDataTypeArray::kVertexFormatUNorm16(decoded) 178 + }, 179 + 180 + 5 => { 181 + let mut decoded: Vec<Vec<_>> = vec![]; 182 + let item_size = get_channel_component_size(component_dtype); 183 + let vec_size = item_size * dimension; 184 + 185 + for i in 0..( bytes.len() / vec_size ){ 186 + let indx = i * vec_size; 187 + let mut vec = vec![0; vec_size]; 188 + 189 + for j in 0..vec_size{ 190 + vec[j] = i16::from_le_bytes([ 191 + bytes[indx + (j * item_size)], 192 + bytes[indx + (j * item_size) + 1] 193 + ]); 194 + } 195 + decoded.push(vec); 196 + } 197 + 198 + UnityDataTypeArray::kVertexFormatSNorm16(decoded) 199 + }, 200 + 201 + 6 => { 202 + let mut decoded: Vec<Vec<u8>> = vec![]; 203 + let item_size = get_channel_component_size(component_dtype); 204 + let vec_size = item_size * dimension; 205 + 206 + for i in 0..( bytes.len() / vec_size ){ 207 + let indx = i * vec_size; 208 + let mut vec = vec![0; vec_size]; 209 + 210 + for j in 0..vec_size{ vec[j] = u8::from_le_bytes([ bytes[indx + (j * item_size)] ]); } 211 + decoded.push(vec); 212 + } 213 + 214 + UnityDataTypeArray::kVertexFormatUInt8(decoded) 215 + }, 216 + 217 + 7 => { 218 + let mut decoded: Vec<Vec<_>> = vec![]; 219 + let item_size = get_channel_component_size(component_dtype); 220 + let vec_size = item_size * dimension; 221 + 222 + for i in 0..( bytes.len() / vec_size ){ 223 + let indx = i * vec_size; 224 + let mut vec = vec![0; vec_size]; 225 + 226 + for j in 0..vec_size{ vec[j] = i8::from_le_bytes([ bytes[indx + (j * item_size)] ]); } 227 + decoded.push(vec); 228 + } 229 + 230 + UnityDataTypeArray::kVertexFormatSInt8(decoded) 231 + }, 232 + 233 + 8 => { 234 + let mut decoded: Vec<Vec<_>> = vec![]; 235 + let item_size = get_channel_component_size(component_dtype); 236 + let vec_size = item_size * dimension; 237 + 238 + for i in 0..( bytes.len() / vec_size ){ 239 + let indx = i * vec_size; 240 + let mut vec = vec![0; vec_size]; 241 + 242 + for j in 0..vec_size{ 243 + vec[j] = u16::from_le_bytes([ 244 + bytes[indx + (j * item_size)], 245 + bytes[indx + (j * item_size) + 1] 246 + ]); 247 + } 248 + decoded.push(vec); 249 + } 250 + 251 + UnityDataTypeArray::kVertexFormatUInt16(decoded) 252 + }, 253 + 254 + 9 => { 255 + let mut decoded: Vec<Vec<_>> = vec![]; 256 + let item_size = get_channel_component_size(component_dtype); 257 + let vec_size = item_size * dimension; 258 + 259 + for i in 0..( bytes.len() / vec_size ){ 260 + let indx = i * vec_size; 261 + let mut vec = vec![0; vec_size]; 262 + 263 + for j in 0..vec_size{ 264 + vec[j] = i16::from_le_bytes([ 265 + bytes[indx + (j * item_size)], 266 + bytes[indx + (j * item_size) + 1] 267 + ]); 268 + } 269 + decoded.push(vec); 270 + } 271 + 272 + UnityDataTypeArray::kVertexFormatSInt16(decoded) 273 + }, 274 + 275 + 10 => { 276 + let mut decoded: Vec<Vec<_>> = vec![]; 277 + let item_size = get_channel_component_size(component_dtype); 278 + let vec_size = item_size * dimension; 279 + 280 + for i in 0..( bytes.len() / vec_size ){ 281 + let indx = i * vec_size; 282 + let mut vec = vec![0; vec_size]; 283 + 284 + for j in 0..vec_size{ 285 + vec[j] = u32::from_le_bytes([ 286 + bytes[indx + (j * item_size)], 287 + bytes[indx + (j * item_size) + 1], 288 + bytes[indx + (j * item_size) + 2], 289 + bytes[indx + (j * item_size) + 3] 290 + ]); 291 + } 292 + decoded.push(vec); 293 + } 294 + 295 + UnityDataTypeArray::kVertexFormatUInt32(decoded) 296 + }, 297 + 298 + 11 => { 299 + let mut decoded: Vec<Vec<_>> = vec![]; 300 + let item_size = get_channel_component_size(component_dtype); 301 + let vec_size = item_size * dimension; 302 + 303 + for i in 0..( bytes.len() / vec_size ){ 304 + let indx = i * vec_size; 305 + let mut vec = vec![0; vec_size]; 306 + 307 + for j in 0..vec_size{ 308 + vec[j] = i32::from_le_bytes([ 309 + bytes[indx + (j * item_size)], 310 + bytes[indx + (j * item_size) + 1], 311 + bytes[indx + (j * item_size) + 2], 312 + bytes[indx + (j * item_size) + 3] 313 + ]); 314 + } 315 + decoded.push(vec); 316 + } 317 + 318 + UnityDataTypeArray::kVertexFormatSInt32(decoded) 319 + }, 320 + 321 + _ => { UnityDataTypeArray::Unknown } 322 + } 323 + } 324 + 325 + struct StreamInfo{ 326 + channel_mask: usize, 327 + offset: usize, 328 + stride: usize 329 + } 330 + 331 + pub fn try_unity_mesh_to_bevy( mesh_obj: UnityObject, mesh_parser: &MeshParser ) -> Option<Mesh>{ 332 + let mut vertices = None; 333 + let mut normals = None; 334 + let mut tangents = None; 335 + let mut uv0 = None; 336 + 337 + let mesh = mesh_parser.parse_from_unity_object(&mesh_obj).unwrap().mesh; 338 + let vertex_data = mesh.vertex_data; 339 + 340 + dbg!(&vertex_data.channels); 341 + 342 + let mut streams = vec![]; 343 + let stream_count = 1 + vertex_data.channels.iter().map(|x| x.stream).max()? as usize; 344 + 345 + let mut offset = 0; 346 + 347 + for s in 0..stream_count{ 348 + let mut chn_mask = 0; 349 + let mut stride = 0; 350 + 351 + let mut i = 0; 352 + for channel in &vertex_data.channels{ 353 + if channel.stream == s as u8 && channel.dimension > 0{ 354 + chn_mask |= 1 << i; 355 + 356 + let component_size = get_channel_component_size(channel.format); 357 + stride += channel.dimension as usize * component_size; 358 + } 359 + 360 + i += 1; 361 + } 362 + 363 + streams.push(StreamInfo { 364 + channel_mask: chn_mask, 365 + offset, 366 + stride 367 + }); 368 + 369 + offset += vertex_data.vertex_count as usize * stride; 370 + offset = ( offset + ( 16 - 1 ) ) & !(16 - 1); 371 + } 372 + 373 + let mut i = 0; 374 + for channel in vertex_data.channels{ 375 + let stream = &streams[channel.stream as usize]; 376 + 377 + if stream.channel_mask >> i & 1 == 1{ 378 + let component_byte_size = get_channel_component_size(channel.format); 379 + dbg!(&component_byte_size, &channel.format); 380 + let channel_dimension = channel.dimension as usize; 381 + 382 + let mut bytes = 383 + vec![0; vertex_data.vertex_count as usize * channel_dimension * component_byte_size]; 384 + 385 + for v in 0..vertex_data.vertex_count{ 386 + let vertex_offset = stream.offset + channel.offset as usize + stream.stride * v as usize; 387 + 388 + for d in 0..channel_dimension{ 389 + let component_offset = vertex_offset + component_byte_size * d as usize; 390 + let dst_offset = component_byte_size * (v as usize * channel.dimension as usize + d as usize); 391 + 392 + let slice = &vertex_data.data_size[component_offset..component_offset + component_byte_size]; 393 + bytes[dst_offset..dst_offset + component_byte_size].clone_from_slice(slice); 394 + } 395 + } 396 + 397 + let component_data = unpack_struct(channel_dimension, channel.format, bytes); 398 + 399 + match i{ 400 + 0 => vertices = Some(component_data), 401 + 1 => normals = Some(component_data), 402 + 2 => tangents = Some(component_data), 403 + 4 => uv0 = Some(component_data), 404 + 405 + _ => {} 406 + } 407 + } 408 + 409 + i += 1; 410 + } 411 + 412 + let mut triangles = vec![]; 413 + if mesh.index_buffer.len() > 0{ 414 + for submesh in mesh.sub_meshes{ 415 + let first_index = submesh.first_byte / 2; 416 + 417 + match submesh.topology{ 418 + 0 => { 419 + // for i in (0..submesh.index_count).step_by(3){ 420 + // triangles.push(mesh.index_buffer[(first_index + i) as usize] as u16); 421 + // triangles.push(mesh.index_buffer[(first_index + i + 1) as usize] as u16); 422 + // triangles.push(mesh.index_buffer[(first_index + i + 2) as usize] as u16); 423 + // } 424 + 425 + for i in (0..submesh.index_count).step_by(6){ 426 + triangles.push(u16::from_le_bytes([ 427 + mesh.index_buffer[(first_index + i) as usize], 428 + mesh.index_buffer[(first_index + i + 1) as usize] 429 + ])); 430 + 431 + triangles.push(u16::from_le_bytes([ 432 + mesh.index_buffer[(first_index + i + 2) as usize], 433 + mesh.index_buffer[(first_index + i + 3) as usize] 434 + ])); 435 + 436 + triangles.push(u16::from_le_bytes([ 437 + mesh.index_buffer[(first_index + i + 4) as usize], 438 + mesh.index_buffer[(first_index + i + 5) as usize] 439 + ])); 440 + } 441 + }, 442 + // TODO: Implement other topologys 443 + _ => {} 444 + } 445 + } 446 + } else{ 447 + return None; 448 + } 449 + 450 + if vertices.is_none(){ panic!("Cannot parse vertices") } 451 + let vertices = vertices.unwrap().as_vec3_array(); 452 + 453 + let mut file = File::create("test.obj").unwrap(); 454 + 455 + for vec in &vertices{ 456 + writeln!(file, "v {} {} {}", vec.x, vec.y, vec.z).unwrap(); 457 + } 458 + 459 + for i in 0..(triangles.len() / 3){ 460 + let indx = i * 3; 461 + writeln!(file, "f {} {} {}", triangles[indx] + 1, triangles[indx + 1] + 1, triangles[indx + 2] + 1).unwrap(); 462 + } 463 + 464 + Some(Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD) 465 + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vertices) 466 + .with_inserted_indices(Indices::U16(triangles))) 467 + }
+6 -13
audio/src/lib.rs
··· 1 use bevy::{app::{App, Plugin, Startup, Update}, ecs::{component::Component, system::{Commands, Query}}, math::{Quat, Vec3}, transform::components::Transform}; 2 - use cpal::{BufferSize, SampleRate, StreamConfig}; 3 - use kira::{AudioManager, AudioManagerSettings, DefaultBackend, Tween, backend::cpal::CpalBackendSettings, listener::ListenerHandle}; 4 5 use crate::source::FelixAudioSource; 6 ··· 12 pub mod source; 13 pub mod utils; 14 pub mod voice; 15 16 fn update_audio_system( 17 mut audio_system: Query<&mut FelixAudioComponent>, ··· 47 impl Plugin for FelixAudio{ 48 fn build(&self, app: &mut App) { 49 app.add_systems(Startup, move | mut commands: Commands | { 50 - let mut settings = AudioManagerSettings::default(); 51 - settings.backend_settings = CpalBackendSettings { 52 - config: Some(StreamConfig { 53 - channels: 2, 54 - sample_rate: SampleRate(48_000), 55 - buffer_size: BufferSize::Fixed(512) 56 - }), 57 - ..Default::default() 58 - }; 59 - 60 - let mut manager = AudioManager::<DefaultBackend>::new(settings).unwrap(); 61 let main_listener = manager.add_listener(Vec3::default(), Quat::default()).unwrap(); 62 63 let handle = FelixAudioComponent { manager, main_listener };
··· 1 use bevy::{app::{App, Plugin, Startup, Update}, ecs::{component::Component, system::{Commands, Query}}, math::{Quat, Vec3}, transform::components::Transform}; 2 + use kira::{AudioManager, AudioManagerSettings, DefaultBackend, Tween, listener::ListenerHandle}; 3 4 use crate::source::FelixAudioSource; 5 ··· 11 pub mod source; 12 pub mod utils; 13 pub mod voice; 14 + 15 + // TODO: Make this use HRTF at some point 16 + // Maybe revisit steam audio? 17 + // Or just find some other library that does HRTFs. 18 19 fn update_audio_system( 20 mut audio_system: Query<&mut FelixAudioComponent>, ··· 50 impl Plugin for FelixAudio{ 51 fn build(&self, app: &mut App) { 52 app.add_systems(Startup, move | mut commands: Commands | { 53 + let mut manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default()).unwrap(); 54 let main_listener = manager.add_listener(Vec3::default(), Quat::default()).unwrap(); 55 56 let handle = FelixAudioComponent { manager, main_listener };
+1 -6
audio/src/source/static_source.rs
··· 1 use std::{sync::{Arc, Mutex}, thread}; 2 3 use bevy::transform::components::Transform; 4 - use kira::{Decibels, Easing, Mapping, Mix, Tween, Value, effect::{filter::FilterBuilder, reverb::ReverbBuilder}, sound::static_sound::StaticSoundData, track::{SendTrackBuilder, SendTrackHandle, SpatialTrackBuilder, SpatialTrackHandle}}; 5 6 use crate::{FelixAudioComponent, source::AudioSource}; 7 ··· 52 .with_effect(FilterBuilder::new().cutoff(Value::FromListenerDistance(Mapping { 53 input_range: ( 0.0, 20.0 ), 54 output_range: ( 18000.0, 2000.0 ), 55 - easing: Easing::Linear 56 - }))) 57 - .with_effect(ReverbBuilder::new().mix(Value::FromListenerDistance(Mapping { 58 - input_range: ( 0.0, 100.0 ), 59 - output_range: ( Mix::DRY, Mix::WET ), 60 easing: Easing::Linear 61 }))) 62 .with_send(&send_track, Value::FromListenerDistance(Mapping {
··· 1 use std::{sync::{Arc, Mutex}, thread}; 2 3 use bevy::transform::components::Transform; 4 + use kira::{Decibels, Easing, Mapping, Tween, Value, effect::{filter::FilterBuilder}, sound::static_sound::StaticSoundData, track::{SendTrackBuilder, SendTrackHandle, SpatialTrackBuilder, SpatialTrackHandle}}; 5 6 use crate::{FelixAudioComponent, source::AudioSource}; 7 ··· 52 .with_effect(FilterBuilder::new().cutoff(Value::FromListenerDistance(Mapping { 53 input_range: ( 0.0, 20.0 ), 54 output_range: ( 18000.0, 2000.0 ), 55 easing: Easing::Linear 56 }))) 57 .with_send(&send_track, Value::FromListenerDistance(Mapping {
+1 -6
audio/src/source/stream_source.rs
··· 1 use bevy::transform::components::Transform; 2 - use kira::{Decibels, Easing, Mapping, Mix, Tween, Value, effect::{filter::FilterBuilder, reverb::ReverbBuilder}, track::{SendTrackBuilder, SendTrackHandle, SpatialTrackBuilder, SpatialTrackHandle}}; 3 4 use crate::{FelixAudioComponent, source::{AudioSource, stream_source::sound_data::StreamAudioSourceSoundData}}; 5 ··· 44 .with_effect(FilterBuilder::new().cutoff(Value::FromListenerDistance(Mapping { 45 input_range: ( 0.0, 20.0 ), 46 output_range: ( 18000.0, 2000.0 ), 47 - easing: Easing::Linear 48 - }))) 49 - .with_effect(ReverbBuilder::new().mix(Value::FromListenerDistance(Mapping { 50 - input_range: ( 0.0, 100.0 ), 51 - output_range: ( Mix::DRY, Mix::WET ), 52 easing: Easing::Linear 53 }))) 54 .with_send(&send_track, Value::FromListenerDistance(Mapping {
··· 1 use bevy::transform::components::Transform; 2 + use kira::{Decibels, Easing, Mapping, Tween, Value, effect::{filter::FilterBuilder}, track::{SendTrackBuilder, SendTrackHandle, SpatialTrackBuilder, SpatialTrackHandle}}; 3 4 use crate::{FelixAudioComponent, source::{AudioSource, stream_source::sound_data::StreamAudioSourceSoundData}}; 5 ··· 44 .with_effect(FilterBuilder::new().cutoff(Value::FromListenerDistance(Mapping { 45 input_range: ( 0.0, 20.0 ), 46 output_range: ( 18000.0, 2000.0 ), 47 easing: Easing::Linear 48 }))) 49 .with_send(&send_track, Value::FromListenerDistance(Mapping {
+18 -3
audio/src/voice/decoder.rs
··· 1 - use std::{collections::VecDeque, sync::{Arc, Mutex, mpsc::{Sender, channel}}, thread}; 2 3 use opus::{Channels, Decoder}; 4 5 use crate::{MONO_20MS, SAMPLE_RATE}; 6 7 pub struct VoiceChatDecoder{ 8 - stream_in: Sender<Vec<u8>> 9 } 10 11 impl VoiceChatDecoder{ ··· 13 let mut decoder = Decoder::new(SAMPLE_RATE as u32, Channels::Mono).unwrap(); 14 let ( stream_in, stream_out ) = channel(); 15 16 thread::spawn(move || { 17 let mut buffer = [0.0; MONO_20MS]; 18 ··· 20 let packet: Vec<u8> = stream_out.recv().unwrap(); 21 decoder.decode_float(&packet, &mut buffer, false).unwrap(); 22 23 let mut voice = queue.lock().unwrap(); 24 for sample in buffer{ voice.push_back(sample); } 25 } 26 }); 27 28 - Self { stream_in } 29 } 30 31 pub fn decode( &self, packet: Vec<u8> ){ 32 self.stream_in.send(packet).unwrap(); 33 } 34 }
··· 1 + use std::{collections::VecDeque, sync::{Arc, Mutex, RwLock, mpsc::{Sender, channel}}, thread}; 2 3 use opus::{Channels, Decoder}; 4 5 use crate::{MONO_20MS, SAMPLE_RATE}; 6 7 pub struct VoiceChatDecoder{ 8 + stream_in: Sender<Vec<u8>>, 9 + last_rms: Arc<RwLock<f32>> 10 } 11 12 impl VoiceChatDecoder{ ··· 14 let mut decoder = Decoder::new(SAMPLE_RATE as u32, Channels::Mono).unwrap(); 15 let ( stream_in, stream_out ) = channel(); 16 17 + let set_rms = Arc::new(RwLock::new(0.0)); 18 + let set_rms_1 = set_rms.clone(); 19 + 20 thread::spawn(move || { 21 let mut buffer = [0.0; MONO_20MS]; 22 ··· 24 let packet: Vec<u8> = stream_out.recv().unwrap(); 25 decoder.decode_float(&packet, &mut buffer, false).unwrap(); 26 27 + let mut total = 0.0; 28 + for sample in buffer{ total += sample.powi(2) } 29 + *set_rms.write().unwrap() = 20.0 * ( total / buffer.len() as f32 ).sqrt().log10(); 30 + 31 let mut voice = queue.lock().unwrap(); 32 for sample in buffer{ voice.push_back(sample); } 33 } 34 }); 35 36 + Self { 37 + stream_in, 38 + last_rms: set_rms_1 39 + } 40 } 41 42 pub fn decode( &self, packet: Vec<u8> ){ 43 self.stream_in.send(packet).unwrap(); 44 + } 45 + 46 + pub fn get_last_rms( &self ) -> f32{ 47 + *self.last_rms.read().unwrap() 48 } 49 }
+63 -18
audio/src/voice/microphone.rs
··· 1 - use std::{env, net::{ToSocketAddrs, UdpSocket}, sync::{Arc, Mutex}}; 2 3 use bevy::ecs::component::Component; 4 use cpal::{BufferSize, SampleRate, Stream, StreamConfig, traits::{DeviceTrait, HostTrait, StreamTrait}}; ··· 10 #[derive(Component)] 11 pub struct VoiceChatMicrophone{ 12 stream: Option<Stream>, 13 - udp: Option<UdpSocket>, 14 - muted: Arc<Mutex<bool>> 15 } 16 17 impl VoiceChatMicrophone{ 18 - pub fn new( socket: UdpSocket ) -> Self{ 19 Self { 20 stream: None, 21 - udp: Some(socket), 22 - muted: Arc::new(Mutex::new(false)) 23 } 24 } 25 ··· 33 let mut encoder = Encoder::new(SAMPLE_RATE as u32, Channels::Mono, Application::Voip)?; 34 35 let host = cpal::default_host(); 36 - let mic = host.default_input_device().unwrap(); 37 38 let mut output = [0; 512]; 39 ··· 41 let mut buffer = [0; MONO_20MS]; 42 43 let muted = self.muted.clone(); 44 - let udp = self.udp.take().unwrap(); 45 46 - let addr = env::var("HOST")?.to_socket_addrs()?.nth(0).unwrap(); 47 48 let stream = mic.build_input_stream( 49 &StreamConfig { 50 - channels: 1, 51 buffer_size: BufferSize::Fixed(BUFFER_SIZE as u32), 52 sample_rate: SampleRate(SAMPLE_RATE as u32) 53 }, ··· 58 buffer_indx = 0; 59 } else{ 60 for i in 0..data.len(){ 61 buffer[buffer_indx] = data[i]; 62 buffer_indx += 1; 63 64 if buffer_indx >= MONO_20MS{ 65 buffer_indx = 0; 66 67 - let len = encoder.encode(&buffer, &mut output).unwrap(); 68 - let buf_to_send = output[0..len].to_vec(); 69 70 - let packet = PlayerVoicePacket { 71 - id: "".into(), // NOTE: I know this kinda seems stupid but it's easier for me to get the player id on the server so imma just make the server fill this in. 72 - packet: buf_to_send 73 - }; 74 75 - let packet: Vec<u8> = packet.to_buf().into(); 76 - udp.send_to(&packet, addr).unwrap(); 77 } 78 } 79 } ··· 86 self.stream = Some(stream); 87 88 Ok(()) 89 } 90 }
··· 1 + use std::{env, net::{SocketAddr, UdpSocket}, sync::{Arc, Mutex, RwLock}}; 2 3 use bevy::ecs::component::Component; 4 use cpal::{BufferSize, SampleRate, Stream, StreamConfig, traits::{DeviceTrait, HostTrait, StreamTrait}}; ··· 10 #[derive(Component)] 11 pub struct VoiceChatMicrophone{ 12 stream: Option<Stream>, 13 + addr: SocketAddr, 14 + udp: UdpSocket, 15 + muted: Arc<Mutex<bool>>, 16 + last_rms: Arc<RwLock<f32>>, 17 + gate_level: Arc<RwLock<f32>> 18 } 19 20 impl VoiceChatMicrophone{ 21 + pub fn new( addr: SocketAddr, socket: UdpSocket ) -> Self{ 22 Self { 23 stream: None, 24 + addr, 25 + udp: socket, 26 + muted: Arc::new(Mutex::new(false)), // TODO: Default to muted 27 + last_rms: Arc::new(RwLock::new(0.0)), 28 + gate_level: Arc::new(RwLock::new(-65.0)) 29 } 30 } 31 ··· 39 let mut encoder = Encoder::new(SAMPLE_RATE as u32, Channels::Mono, Application::Voip)?; 40 41 let host = cpal::default_host(); 42 + 43 + let mut i = 0; 44 + let devices = host.input_devices().unwrap(); 45 + for device in devices{ 46 + println!("{}) {:?}", i, device.name()); 47 + i += 1; 48 + } 49 + 50 + let mut devices = host.input_devices().unwrap(); 51 + let mic = if let Ok(device_index) = env::var("MIC_INDEX"){ 52 + devices.nth(device_index.parse()?).unwrap() 53 + } else{ 54 + host.default_input_device().unwrap() 55 + }; 56 + 57 + println!("Using Device: {:?}", mic.name()); 58 59 let mut output = [0; 512]; 60 ··· 62 let mut buffer = [0; MONO_20MS]; 63 64 let muted = self.muted.clone(); 65 + 66 + let udp = self.udp.try_clone().unwrap(); 67 + let addr = self.addr.clone(); 68 + 69 + for conf in mic.supported_input_configs().unwrap(){ 70 + println!("{} {:?} {} {:?}", conf.channels(), conf.buffer_size(), conf.sample_format(), conf.with_max_sample_rate()); 71 + } 72 73 + let set_rms = self.last_rms.clone(); 74 + let gate_level = self.gate_level.clone(); 75 76 let stream = mic.build_input_stream( 77 &StreamConfig { 78 + channels: 2, 79 buffer_size: BufferSize::Fixed(BUFFER_SIZE as u32), 80 sample_rate: SampleRate(SAMPLE_RATE as u32) 81 }, ··· 86 buffer_indx = 0; 87 } else{ 88 for i in 0..data.len(){ 89 + if i % 2 == 1{ continue; } 90 + 91 buffer[buffer_indx] = data[i]; 92 buffer_indx += 1; 93 94 if buffer_indx >= MONO_20MS{ 95 buffer_indx = 0; 96 97 + let mut total = 0.0; 98 + for sample in buffer{ total += (sample as f32).powi(2) } 99 100 + let rms = 20.0 * ( ( total / buffer.len() as f32 ).sqrt() / i16::MAX as f32 ).log10(); 101 + *set_rms.write().unwrap() = rms; 102 103 + if rms > *gate_level.read().unwrap(){ 104 + let len = encoder.encode(&buffer, &mut output).unwrap(); 105 + let buf_to_send = output[0..len].to_vec(); 106 + 107 + let packet = PlayerVoicePacket { 108 + id: "".into(), // NOTE: I know this kinda seems stupid but it's easier for me to get the player id on the server so imma just make the server fill this in. 109 + packet: buf_to_send 110 + }; 111 + 112 + let packet: Vec<u8> = packet.to_buf().into(); 113 + udp.send_to(&packet, addr).unwrap(); 114 + } 115 } 116 } 117 } ··· 124 self.stream = Some(stream); 125 126 Ok(()) 127 + } 128 + 129 + pub fn get_rms_of_last_packet( &self ) -> ( f32, bool ){ 130 + let rms = *self.last_rms.read().unwrap(); 131 + let gate = *self.gate_level.read().unwrap(); 132 + 133 + ( rms, rms > gate ) 134 } 135 }
+3 -3
audio/src/voice/mod.rs
··· 1 - use std::net::UdpSocket; 2 3 use crate::voice::microphone::VoiceChatMicrophone; 4 5 pub mod decoder; 6 pub mod microphone; 7 8 - pub fn init_microphone( socket: UdpSocket ) -> anyhow::Result<VoiceChatMicrophone>{ 9 - let mut handle = VoiceChatMicrophone::new(socket); 10 handle.start_stream()?; 11 12 Ok(handle)
··· 1 + use std::net::{SocketAddr, UdpSocket}; 2 3 use crate::voice::microphone::VoiceChatMicrophone; 4 5 pub mod decoder; 6 pub mod microphone; 7 8 + pub fn init_microphone( addr: SocketAddr, socket: UdpSocket ) -> anyhow::Result<VoiceChatMicrophone>{ 9 + let mut handle = VoiceChatMicrophone::new(addr, socket); 10 handle.start_stream()?; 11 12 Ok(handle)
+5
client/Cargo.toml
··· 10 dotenvy = "0.15.7" 11 felix-net = { path = '../net' } 12 felix-audio = { path = '../audio' } 13 tokio = { version = "1.48.0", features = ["full"] }
··· 10 dotenvy = "0.15.7" 11 felix-net = { path = '../net' } 12 felix-audio = { path = '../audio' } 13 + felix-assets = { path = '../assets' } 14 tokio = { version = "1.48.0", features = ["full"] } 15 + bevy_mod_openxr = "0.4.0" 16 + openxr = "0.19.0" 17 + bevy_mod_xr = "0.4.0" 18 + bevy_xr_utils = "0.4.0"
+143 -28
client/src/components/debug_camera.rs
··· 1 use std::f32::consts::PI; 2 3 use bevy::{ input::mouse::MouseMotion, prelude::* }; 4 5 #[derive(Component)] 6 pub struct DebugCamera{ ··· 17 } 18 } 19 20 pub fn update( 21 mut query: Query<(&mut DebugCamera, &mut Transform)>, 22 - 23 time: Res<Time>, 24 25 keys: Res<ButtonInput<KeyCode>>, 26 mouse_buttons: Res<ButtonInput<MouseButton>>, 27 mut mouse_motion: MessageReader<MouseMotion>, 28 ){ 29 - let mut delta_time = time.delta_secs(); 30 - if keys.pressed(KeyCode::ShiftLeft){ delta_time *= 2.0; } 31 32 let ( mut debug, mut transform ) = query.single_mut().unwrap(); 33 34 - for ev in mouse_motion.read(){ 35 - if mouse_buttons.pressed(MouseButton::Right){ 36 - debug.pitch -= ev.delta.y * delta_time * 0.1; 37 - debug.yaw -= ev.delta.x * delta_time * 0.1; 38 } 39 - } 40 41 - transform.rotation = Quat::from_euler(EulerRot::YXZ, debug.yaw, debug.pitch, 0.0); 42 43 - if keys.pressed(KeyCode::KeyW){ 44 - let dir = transform.forward(); 45 - transform.translation += dir * delta_time; 46 - } else if keys.pressed(KeyCode::KeyS){ 47 - let dir = -transform.forward(); 48 - transform.translation += dir * delta_time; 49 } 50 51 - if keys.pressed(KeyCode::KeyA){ 52 - let dir = transform.left(); 53 - transform.translation += dir * delta_time; 54 - } else if keys.pressed(KeyCode::KeyD){ 55 - let dir = -transform.left(); 56 - transform.translation += dir * delta_time; 57 } 58 59 - if keys.pressed(KeyCode::KeyE){ 60 - let dir = transform.up(); 61 - transform.translation += dir * delta_time; 62 - } else if keys.pressed(KeyCode::KeyQ){ 63 - let dir = -transform.up(); 64 - transform.translation += dir * delta_time; 65 - } 66 }
··· 1 use std::f32::consts::PI; 2 3 use bevy::{ input::mouse::MouseMotion, prelude::* }; 4 + use bevy_mod_openxr::{helper_traits::ToQuat, resources::OxrViews}; 5 + use bevy_mod_xr::session::{XrState, XrTrackingRoot}; 6 + use felix_audio::voice::microphone::VoiceChatMicrophone; 7 + 8 + use crate::net::connection::Connection; 9 10 #[derive(Component)] 11 pub struct DebugCamera{ ··· 22 } 23 } 24 25 + pub fn vr_locomotion( // TODO: Move locomotion to controllers instead of keyboard 26 + views: ResMut<OxrViews>, 27 + mut position_query: Query<&mut Transform, With<XrTrackingRoot>>, 28 + keys: Res<ButtonInput<KeyCode>>, 29 + xr_state: Res<XrState>, 30 + time: Res<Time> 31 + ){ 32 + if *xr_state == XrState::Running{ 33 + let mut delta_time = time.delta_secs(); 34 + if keys.pressed(KeyCode::ShiftLeft){ delta_time *= 2.0; } 35 + 36 + let mut transform = position_query.single_mut().unwrap(); 37 + let view = views.first().unwrap(); 38 + 39 + let cam = view.pose.orientation.to_quat(); 40 + 41 + if keys.pressed(KeyCode::KeyW){ 42 + let mut dir = cam * -Vec3::Z * delta_time; 43 + dir.y = 0.0; 44 + 45 + transform.translation += dir; 46 + } else if keys.pressed(KeyCode::KeyS){ 47 + let mut dir = cam * Vec3::Z * delta_time; 48 + dir.y = 0.0; 49 + 50 + transform.translation += dir; 51 + } 52 + 53 + if keys.pressed(KeyCode::KeyA){ 54 + let mut dir = cam * -Vec3::X * delta_time; 55 + dir.y = 0.0; 56 + 57 + transform.translation += dir; 58 + } else if keys.pressed(KeyCode::KeyD){ 59 + let mut dir = cam * Vec3::X * delta_time; 60 + dir.y = 0.0; 61 + 62 + transform.translation += dir; 63 + } 64 + } 65 + } 66 + 67 pub fn update( 68 mut query: Query<(&mut DebugCamera, &mut Transform)>, 69 time: Res<Time>, 70 71 keys: Res<ButtonInput<KeyCode>>, 72 mouse_buttons: Res<ButtonInput<MouseButton>>, 73 mut mouse_motion: MessageReader<MouseMotion>, 74 + 75 + // Debug Text 76 + mut debug_text: Query<(&mut Text, &DebugText)>, 77 + voice: Query<&VoiceChatMicrophone>, 78 + networking: Query<&Connection>, 79 + xr_state: Res<XrState> 80 ){ 81 + let net_manager = networking.single().unwrap(); 82 + let xr_state = xr_state.into_inner(); 83 84 let ( mut debug, mut transform ) = query.single_mut().unwrap(); 85 86 + if *xr_state != XrState::Running{ 87 + let mut delta_time = time.delta_secs(); 88 + if keys.pressed(KeyCode::ShiftLeft){ delta_time *= 2.0; } 89 + 90 + for ev in mouse_motion.read(){ 91 + if mouse_buttons.pressed(MouseButton::Right){ 92 + debug.pitch -= ev.delta.y * delta_time * 0.1; 93 + debug.yaw -= ev.delta.x * delta_time * 0.1; 94 + } 95 + } 96 + 97 + transform.rotation = Quat::from_euler(EulerRot::YXZ, debug.yaw, debug.pitch, 0.0); 98 + 99 + if keys.pressed(KeyCode::KeyW){ 100 + let dir = transform.forward(); 101 + transform.translation += dir * delta_time; 102 + } else if keys.pressed(KeyCode::KeyS){ 103 + let dir = -transform.forward(); 104 + transform.translation += dir * delta_time; 105 } 106 107 + if keys.pressed(KeyCode::KeyA){ 108 + let dir = transform.left(); 109 + transform.translation += dir * delta_time; 110 + } else if keys.pressed(KeyCode::KeyD){ 111 + let dir = -transform.left(); 112 + transform.translation += dir * delta_time; 113 + } 114 115 + if keys.pressed(KeyCode::KeyE){ 116 + let dir = transform.up(); 117 + transform.translation += dir * delta_time; 118 + } else if keys.pressed(KeyCode::KeyQ){ 119 + let dir = -transform.up(); 120 + transform.translation += dir * delta_time; 121 + } 122 } 123 124 + let mut remote_rms = "".to_owned(); 125 + for id in net_manager.get_remote_player_voice_ids(){ 126 + remote_rms += format!( 127 + "{}: {:.4}db\n", 128 + id, 129 + net_manager.get_remote_player_voice_rms(&id) 130 + ).as_str(); 131 } 132 133 + let ( rms, mic_open ) = if let Ok(mic) = voice.single(){ 134 + mic.get_rms_of_last_packet() 135 + } else{ 136 + ( -1.0, false ) 137 + }; 138 + 139 + let ( mut text, _ ) = debug_text.single_mut().unwrap(); 140 + text.0 = format!( 141 + "Microphone RMS: {:.4}db Open: {} 142 + {}Position: X: {:.2} Y: {:.2} Z: {:.2} 143 + Rotation: X: {:.2} Y: {:.2} Z: {:.2} W: {:.2} 144 + XR State: {:#?}", 145 + rms, 146 + mic_open, 147 + 148 + remote_rms, 149 + 150 + transform.translation.x, 151 + transform.translation.y, 152 + transform.translation.z, 153 + 154 + transform.rotation.x, 155 + transform.rotation.y, 156 + transform.rotation.z, 157 + transform.rotation.w, 158 + 159 + xr_state 160 + ); 161 + } 162 + 163 + #[derive(Component)] 164 + pub struct DebugText; 165 + 166 + pub fn setup( 167 + mut commands: Commands 168 + ){ 169 + commands.spawn(( 170 + Node { 171 + position_type: PositionType::Absolute, 172 + bottom: px(5.0), 173 + right: px(5.0), 174 + ..default() 175 + }, 176 + Text::new("Here is some text"), 177 + TextColor(Color::WHITE), 178 + TextLayout::new_with_justify(Justify::Right), 179 + DebugText 180 + )); 181 }
+1 -1
client/src/components/network_interface.rs
··· 88 let mut lock = listener.lock().unwrap(); 89 90 for i in 0..buf.len(){ 91 - buf[i] = lock.pop_front().unwrap(); } 92 93 buf 94 }))
··· 88 let mut lock = listener.lock().unwrap(); 89 90 for i in 0..buf.len(){ 91 + buf[i] = lock.pop_front().unwrap_or(0.0); } 92 93 buf 94 }))
+48 -17
client/src/main.rs
··· 1 - use bevy::{DefaultPlugins, app::{App, FixedUpdate, Startup, Update}, ecs::system::Commands}; 2 use felix_audio::{FelixAudio, voice}; 3 4 use crate::{components::{debug_camera, network_interface, remote_player}, setup::setup}; ··· 8 mod net; 9 10 fn main() { 11 - dotenvy::dotenv().unwrap(); 12 13 - App::new() 14 - .add_plugins(( 15 - DefaultPlugins, 16 - FelixAudio 17 )) 18 - .add_systems(Startup, setup) 19 - .add_systems(Startup, move | mut commands: Commands |{ 20 - let ( comp, voice ) = net::handle_net().expect("Network Module Failed."); 21 22 - commands.spawn(comp); 23 - commands.spawn(voice::init_microphone(voice).expect("Failed to start microphone.")); 24 - }) 25 - .add_systems(Update, debug_camera::update) 26 - .add_systems(Update, remote_player::update) 27 - .add_systems(FixedUpdate, network_interface::fixed_update) 28 - .run(); 29 - }
··· 1 + use std::{env, net::ToSocketAddrs}; 2 + 3 + use bevy::{app::{App, FixedUpdate, Startup, Update}, ecs::system::Commands, prelude::*, render::pipelined_rendering::PipelinedRenderingPlugin}; 4 + use bevy_mod_openxr::{add_xr_plugins, resources::OxrSessionConfig}; 5 + use bevy_mod_xr::session::{XrSessionCreated, XrSessionPlugin, XrState}; 6 + use bevy_xr_utils::tracking_utils::TrackingUtilitiesPlugin; 7 use felix_audio::{FelixAudio, voice}; 8 9 use crate::{components::{debug_camera, network_interface, remote_player}, setup::setup}; ··· 13 mod net; 14 15 fn main() { 16 + if let Err(err) = dotenvy::dotenv(){ println!("[WARN] .ENV failed loading {:#?}", err); } 17 + let try_use_vr = env::var("DONT_USE_VR").is_err(); 18 19 + let mut app = App::new(); 20 + 21 + if try_use_vr{ 22 + app.add_plugins(( 23 + add_xr_plugins( 24 + DefaultPlugins 25 + .build() 26 + .disable::<PipelinedRenderingPlugin>(), 27 + ).set(XrSessionPlugin { auto_handle: true }), 28 + TrackingUtilitiesPlugin 29 )) 30 + .insert_resource(OxrSessionConfig { 31 + ..Default::default() 32 + }) 33 + .add_systems(XrSessionCreated, || { println!("[INFO] Started VR") }); 34 + } else{ 35 + app 36 + .add_plugins(DefaultPlugins) 37 + .insert_resource(XrState::Unavailable); 38 + } 39 40 + app.add_plugins(FelixAudio) 41 + .add_systems(Startup, setup) 42 + .add_systems(Startup, move | mut commands: Commands |{ 43 + let addr = env::var("HOST").unwrap().to_socket_addrs().unwrap().nth(0).unwrap(); 44 + 45 + let ( comp, voice ) = net::handle_net(addr.clone()).expect("Network Module Failed"); 46 + commands.spawn(comp); 47 + 48 + match voice::init_microphone(addr, voice){ 49 + Ok(voice) => { commands.spawn(voice); }, 50 + Err(err) => println!("[WARN] Failed to start microphone: {}", err) 51 + } 52 + }) 53 + .add_systems(Update, debug_camera::update) 54 + .add_systems(Update, debug_camera::vr_locomotion) 55 + .add_systems(Startup, debug_camera::setup) 56 + .add_systems(Update, remote_player::update) 57 + .add_systems(FixedUpdate, network_interface::fixed_update); 58 + 59 + app.run(); 60 + }
+52 -14
client/src/net/connection.rs
··· 1 - use std::{collections::{HashMap, VecDeque}, io::{Read, Write}, net::{SocketAddr, TcpStream, UdpSocket}, sync::{Arc, Mutex, RwLock}, thread}; 2 use bevy::ecs::component::Component; 3 use felix_audio::voice::decoder::VoiceChatDecoder; 4 use tokio::sync::broadcast::{self, Receiver, Sender}; ··· 14 udp: UdpSocket, 15 udp_server_address: SocketAddr, 16 17 net_recv: Receiver<NetClientCommand>, 18 19 voice_queues: Arc<RwLock<HashMap<String, VoiceChatDecoder>>>, 20 - pub id: String 21 } 22 23 impl Connection{ 24 pub fn new( stream: TcpStream, udp: UdpSocket, udp_server_address: SocketAddr ) -> Self{ 25 let ( event_sender, event_recv ) = broadcast::channel(32); 26 27 let mut conn = Self { 28 tcp: stream, ··· 30 udp, 31 udp_server_address, 32 33 net_recv: event_recv, 34 35 voice_queues: Arc::new(RwLock::new(HashMap::new())), 36 - id: "".to_owned() 37 }; 38 39 - conn.start_listener_thread(event_sender).unwrap(); 40 41 let packet = NotifyConnectionInfo { id: conn.id.clone() }; 42 conn.send_reliable(packet).unwrap(); ··· 44 conn 45 } 46 47 - fn start_listener_thread(&self, cmd: Sender<NetClientCommand>) -> anyhow::Result<()>{ 48 let mut tcp = self.tcp.try_clone()?; 49 let udp = self.udp.try_clone()?; 50 ··· 54 let srv_addr = self.udp_server_address.clone(); 55 let voice_queues = self.voice_queues.clone(); 56 57 thread::spawn(move || { // UDP RECV THREAD 58 let mut buf = [0; 1024]; 59 60 while let Ok((length, addr)) = udp_1.recv_from(&mut buf){ 61 if addr != srv_addr{ continue; } 62 63 let mut msg: Buffer = (&buf[0..length]).into(); 64 65 while msg.left() > 0{ 66 let packet = packet::parse(&mut msg); 67 - cmd_1.send(NetClientCommand::RecvPacket(packet)).unwrap(); 68 } 69 } 70 }); ··· 74 75 while let Ok(length) = tcp.read(&mut buf){ 76 if length == 0 { break; } 77 78 let mut msg: Buffer = (&buf[0..length]).into(); 79 ··· 87 let packet = LinkUDP { id: info.id }; 88 let packet: Vec<_> = packet.to_buf().into(); 89 90 - udp.send_to(&packet, "127.0.0.1:2603").unwrap(); 91 - }, 92 - PacketTypes::PlayerVoicePacket(packet) => { 93 - let voices = voice_queues.read().unwrap(); 94 - if let Some(decoder) = voices.get(&packet.id){ 95 - decoder.decode(packet.packet); } 96 }, 97 _ => { 98 cmd.send(NetClientCommand::RecvPacket(packet)).unwrap(); ··· 107 Ok(()) 108 } 109 110 - pub fn start_listening_for_player_voice( &mut self, id: &String ) -> Arc<Mutex<VecDeque<f32>>>{ 111 let voice_queue = Arc::new(Mutex::new(VecDeque::new())); 112 let decoder = VoiceChatDecoder::new(voice_queue.clone()); 113 ··· 117 voice_queue 118 } 119 120 - pub fn stop_listening_for_player_voice( &mut self, id: &String ){ 121 let mut voices = self.voice_queues.write().unwrap(); 122 voices.remove(id); 123 } ··· 138 self.udp.send_to(&buf, self.udp_server_address)?; 139 140 Ok(()) 141 } 142 }
··· 1 + use std::{collections::{HashMap, VecDeque}, io::{Read, Write}, net::{Shutdown, SocketAddr, TcpStream, UdpSocket}, sync::{Arc, Mutex, RwLock}, thread}; 2 use bevy::ecs::component::Component; 3 use felix_audio::voice::decoder::VoiceChatDecoder; 4 use tokio::sync::broadcast::{self, Receiver, Sender}; ··· 14 udp: UdpSocket, 15 udp_server_address: SocketAddr, 16 17 + net_send: Sender<NetClientCommand>, 18 net_recv: Receiver<NetClientCommand>, 19 20 voice_queues: Arc<RwLock<HashMap<String, VoiceChatDecoder>>>, 21 + pub id: String, 22 + 23 + killed_signal: broadcast::Sender<()> 24 } 25 26 impl Connection{ 27 pub fn new( stream: TcpStream, udp: UdpSocket, udp_server_address: SocketAddr ) -> Self{ 28 let ( event_sender, event_recv ) = broadcast::channel(32); 29 + let ( killed_signal_send, killed_signal ) = broadcast::channel(32); 30 31 let mut conn = Self { 32 tcp: stream, ··· 34 udp, 35 udp_server_address, 36 37 + net_send: event_sender.clone(), 38 net_recv: event_recv, 39 40 voice_queues: Arc::new(RwLock::new(HashMap::new())), 41 + id: "".to_owned(), 42 + 43 + killed_signal: killed_signal_send 44 }; 45 46 + conn.start_listener_thread(event_sender, killed_signal).unwrap(); 47 48 let packet = NotifyConnectionInfo { id: conn.id.clone() }; 49 conn.send_reliable(packet).unwrap(); ··· 51 conn 52 } 53 54 + fn start_listener_thread(&self, cmd: Sender<NetClientCommand>, mut signal: Receiver<()>) -> anyhow::Result<()>{ 55 let mut tcp = self.tcp.try_clone()?; 56 let udp = self.udp.try_clone()?; 57 ··· 61 let srv_addr = self.udp_server_address.clone(); 62 let voice_queues = self.voice_queues.clone(); 63 64 + let mut signal_1 = signal.resubscribe(); 65 + 66 thread::spawn(move || { // UDP RECV THREAD 67 let mut buf = [0; 1024]; 68 69 while let Ok((length, addr)) = udp_1.recv_from(&mut buf){ 70 if addr != srv_addr{ continue; } 71 + if signal_1.try_recv().is_ok(){ break; } 72 73 let mut msg: Buffer = (&buf[0..length]).into(); 74 75 while msg.left() > 0{ 76 let packet = packet::parse(&mut msg); 77 + 78 + match packet{ 79 + PacketTypes::PlayerVoicePacket(packet) => { 80 + let voices = voice_queues.try_read().unwrap(); 81 + if let Some(decoder) = voices.get(&packet.id){ 82 + decoder.decode(packet.packet); } 83 + }, 84 + _ => { 85 + cmd_1.send(NetClientCommand::RecvPacket(packet)).unwrap(); 86 + } 87 + } 88 } 89 } 90 }); ··· 94 95 while let Ok(length) = tcp.read(&mut buf){ 96 if length == 0 { break; } 97 + if signal.try_recv().is_ok(){ break; } 98 99 let mut msg: Buffer = (&buf[0..length]).into(); 100 ··· 108 let packet = LinkUDP { id: info.id }; 109 let packet: Vec<_> = packet.to_buf().into(); 110 111 + udp.send_to(&packet, srv_addr).unwrap(); 112 }, 113 _ => { 114 cmd.send(NetClientCommand::RecvPacket(packet)).unwrap(); ··· 123 Ok(()) 124 } 125 126 + pub fn get_remote_player_voice_ids( &self ) -> Vec<String>{ 127 + let voices = self.voice_queues.read().unwrap(); 128 + voices.iter().map(| x | x.0.clone()).collect() 129 + } 130 + 131 + pub fn get_remote_player_voice_rms( &self, id: &String ) -> f32{ 132 + let voices = self.voice_queues.read().unwrap(); 133 + let decoder = voices.get(id).unwrap(); 134 + 135 + decoder.get_last_rms() 136 + } 137 + 138 + pub fn start_listening_for_player_voice( &self, id: &String ) -> Arc<Mutex<VecDeque<f32>>>{ 139 let voice_queue = Arc::new(Mutex::new(VecDeque::new())); 140 let decoder = VoiceChatDecoder::new(voice_queue.clone()); 141 ··· 145 voice_queue 146 } 147 148 + pub fn stop_listening_for_player_voice( &self, id: &String ){ 149 let mut voices = self.voice_queues.write().unwrap(); 150 voices.remove(id); 151 } ··· 166 self.udp.send_to(&buf, self.udp_server_address)?; 167 168 Ok(()) 169 + } 170 + } 171 + 172 + impl Drop for Connection{ 173 + fn drop(&mut self) { 174 + println!("Killing connection to: {}", self.udp_server_address); 175 + self.net_send.send(NetClientCommand::Disconnected).unwrap(); 176 + 177 + self.killed_signal.send(()).unwrap(); 178 + self.tcp.shutdown(Shutdown::Both).unwrap(); 179 } 180 }
+2 -4
client/src/net/mod.rs
··· 1 - use std::{env, net::{TcpStream, ToSocketAddrs, UdpSocket}}; 2 3 use bevy::prelude::*; 4 use felix_net::packet::PacketTypes; ··· 14 RecvPacket(PacketTypes) 15 } 16 17 - pub fn handle_net() -> anyhow::Result<( Connection, UdpSocket )>{ 18 - let addr = env::var("HOST")?.to_socket_addrs()?.nth(0).unwrap(); 19 - 20 let tcp = TcpStream::connect(addr)?; 21 let udp = UdpSocket::bind("0.0.0.0:0")?; 22
··· 1 + use std::net::{SocketAddr, TcpStream, UdpSocket}; 2 3 use bevy::prelude::*; 4 use felix_net::packet::PacketTypes; ··· 14 RecvPacket(PacketTypes) 15 } 16 17 + pub fn handle_net( addr: SocketAddr ) -> anyhow::Result<( Connection, UdpSocket )>{ 18 let tcp = TcpStream::connect(addr)?; 19 let udp = UdpSocket::bind("0.0.0.0:0")?; 20
+74 -21
client/src/setup.rs
··· 1 use bevy::prelude::*; 2 use felix_audio::FelixAudioListener; 3 4 - use crate::debug_camera; 5 6 pub fn setup( 7 mut commands: Commands, 8 mut meshes: ResMut<Assets<Mesh>>, 9 mut materials: ResMut<Assets<StandardMaterial>> 10 ){ 11 - commands.spawn(( 12 - Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))), 13 - MeshMaterial3d(materials.add(Color::WHITE)), 14 - Transform::from_xyz(5.0, 0.0, 0.0), 15 - )); 16 17 commands.spawn(( 18 - Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))), 19 - MeshMaterial3d(materials.add(Color::WHITE)), 20 - Transform::from_xyz(-5.0, 0.0, 0.0) 21 )); 22 23 commands.spawn(( 24 - Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))), 25 - MeshMaterial3d(materials.add(Color::WHITE)), 26 - Transform::from_xyz(0.0, 0.0, 5.0) 27 )); 28 29 commands.spawn(( 30 - Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))), 31 - MeshMaterial3d(materials.add(Color::WHITE)), 32 - Transform::from_xyz(0.0, 0.0, -5.0) 33 )); 34 35 - commands.spawn(( 36 - debug_camera::DebugCamera::default(), 37 - Camera3d::default(), 38 - Transform::from_xyz(0.0, 0.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y), 39 - FelixAudioListener 40 - )); 41 }
··· 1 use bevy::prelude::*; 2 + use bevy_mod_xr::session::XrTracker; 3 + use bevy_xr_utils::tracking_utils::{XrTrackedLocalFloor, XrTrackedStage, XrTrackedView}; 4 + use felix_assets::{BevyObjectData, BevyObjectLightDataType}; 5 use felix_audio::FelixAudioListener; 6 7 + use crate::components::debug_camera::DebugCamera; 8 9 pub fn setup( 10 mut commands: Commands, 11 mut meshes: ResMut<Assets<Mesh>>, 12 mut materials: ResMut<Assets<StandardMaterial>> 13 ){ 14 + // TODO: World loading from server 15 + // TODO: UI and Menus 16 + 17 + // commands.spawn(( 18 + // Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))), 19 + // MeshMaterial3d(materials.add(Color::WHITE)), 20 + // Transform::from_xyz(5.0, 0.0, 0.0), 21 + // )); 22 + 23 + // commands.spawn(( 24 + // Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))), 25 + // MeshMaterial3d(materials.add(Color::WHITE)), 26 + // Transform::from_xyz(-5.0, 0.0, 0.0) 27 + // )); 28 + 29 + // commands.spawn(( 30 + // Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))), 31 + // MeshMaterial3d(materials.add(Color::WHITE)), 32 + // Transform::from_xyz(0.0, 0.0, 5.0) 33 + // )); 34 + 35 + // commands.spawn(( 36 + // Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))), 37 + // MeshMaterial3d(materials.add(Color::WHITE)), 38 + // Transform::from_xyz(0.0, 0.0, -5.0) 39 + // )); 40 41 commands.spawn(( 42 + DebugCamera::default(), // TODO: Build a proper player controller 43 + Camera3d::default(), 44 + Transform::from_xyz(0.0, 0.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y), 45 + FelixAudioListener, 46 + XrTracker, 47 + XrTrackedView 48 )); 49 50 commands.spawn(( 51 + Mesh3d(meshes.add(Cuboid::new(0.5, 0.1, 0.5))), 52 + MeshMaterial3d(materials.add(Color::srgb_u8(144, 255, 144))), 53 + Transform::from_xyz(0.0, 0.0, 0.0), 54 + XrTrackedLocalFloor, 55 + XrTracker, 56 )); 57 58 commands.spawn(( 59 + Mesh3d(meshes.add(Cuboid::new(0.5, 0.1, 0.5))), 60 + MeshMaterial3d(materials.add(Color::srgb_u8(144, 255, 255))), 61 + Transform::from_xyz(0.0, 0.0, 0.0), 62 + XrTrackedStage, 63 + XrTracker, 64 )); 65 66 + let gos = felix_assets::load("/home/phaze/Documents/rindo.flx").unwrap(); 67 + for go in gos{ 68 + match go.data{ 69 + BevyObjectData::Mesh(mesh) => { 70 + commands.spawn(( 71 + Mesh3d(meshes.add(mesh)), 72 + MeshMaterial3d(materials.add(Color::WHITE)), 73 + go.transform 74 + )); 75 + }, 76 + BevyObjectData::Light(light) => { 77 + match light.type_{ 78 + BevyObjectLightDataType::Point => { 79 + commands.spawn(( 80 + PointLight { 81 + color: light.colour, 82 + intensity: light.power, 83 + shadows_enabled: true, 84 + ..Default::default() 85 + }, 86 + go.transform 87 + )); 88 + }, 89 + _ => {} 90 + } 91 + } 92 + } 93 + } 94 }
-4
server/src/net/connection.rs
··· 74 self.position = packet.position; 75 self.rotation = packet.rotation; 76 }, 77 - PacketTypes::PlayerVoicePacket(mut voice) => { 78 - voice.id = self.id.clone(); // NOTE: See "audio/src/voice/microphone.rs:71" 79 - self.main_thread_sender.send(NetServerCommand::BroadcastVoice(voice)).unwrap(); 80 - }, 81 _ => {} 82 } 83
··· 74 self.position = packet.position; 75 self.rotation = packet.rotation; 76 }, 77 _ => {} 78 } 79
+19 -10
server/src/net/mod.rs
··· 1 use std::{collections::HashMap, env, net::{SocketAddr, TcpListener, TcpStream, UdpSocket}, thread, time::Duration}; 2 3 - use felix_net::{buffer::Buffer, packet::{self, PacketTypes}, packets::{player_join_packet::PlayerJoinPacket, player_leave_packet::PlayerLeavePacket, player_list_packet::PlayerListPacket, player_voice_packet::PlayerVoicePacket, update_clients_positions::UpdateClientsPositions}}; 4 5 use crate::net::connection::Connection; 6 ··· 13 SendOverUDP(Vec<u8>, SocketAddr), 14 RecvOverUDP(SocketAddr, PacketTypes), 15 RecvOverTCP(String, PacketTypes), 16 - BroadcastVoice(PlayerVoicePacket), 17 BroadcastPlayerPositions 18 } 19 20 pub fn handle_net() -> anyhow::Result<()>{ 21 let port = env::var("HOST_PORT")?; 22 23 let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", port))?; ··· 113 }, 114 NetServerCommand::RecvOverUDP(addr, packet) => { 115 if let Some(conn_id) = connections_by_address.get(&addr){ 116 - let conn = connections.get_mut(conn_id).unwrap(); 117 - conn.recv_packet(packet)?; 118 } 119 }, 120 NetServerCommand::RecvOverTCP(conn_id, packet) => { ··· 130 131 for (_, conn) in &mut connections{ 132 conn.try_send_unreliable(packet.clone())?; } 133 - }, 134 - NetServerCommand::BroadcastVoice(packet) => { 135 - for ( remote_id, conn ) in &mut connections{ 136 - if remote_id == &packet.id { continue; } 137 - conn.try_send_unreliable(packet.clone())?; 138 - } 139 } 140 } 141 }
··· 1 use std::{collections::HashMap, env, net::{SocketAddr, TcpListener, TcpStream, UdpSocket}, thread, time::Duration}; 2 3 + use felix_net::{buffer::Buffer, packet::{self, PacketTypes}, packets::{player_join_packet::PlayerJoinPacket, player_leave_packet::PlayerLeavePacket, player_list_packet::PlayerListPacket, update_clients_positions::UpdateClientsPositions}}; 4 5 use crate::net::connection::Connection; 6 ··· 13 SendOverUDP(Vec<u8>, SocketAddr), 14 RecvOverUDP(SocketAddr, PacketTypes), 15 RecvOverTCP(String, PacketTypes), 16 BroadcastPlayerPositions 17 } 18 19 pub fn handle_net() -> anyhow::Result<()>{ 20 + // TODO: Multiple instances 21 + // Need to decide if i want to run each instance on a seperate thread 22 + 23 let port = env::var("HOST_PORT")?; 24 25 let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", port))?; ··· 115 }, 116 NetServerCommand::RecvOverUDP(addr, packet) => { 117 if let Some(conn_id) = connections_by_address.get(&addr){ 118 + match packet { 119 + PacketTypes::PlayerVoicePacket(mut voice) => { // Keep voice stuff in one thread to avoid copying a lot of data all over the place 120 + voice.id = conn_id.clone(); // NOTE: See "audio/src/voice/microphone.rs:71" 121 + 122 + for ( remote_id, conn ) in &mut connections{ 123 + if remote_id == &voice.id { continue; } 124 + conn.try_send_unreliable(voice.clone())?; 125 + } 126 + }, 127 + _ => { 128 + let conn = connections.get_mut(conn_id).unwrap(); 129 + conn.recv_packet(packet)?; 130 + } 131 + } 132 + 133 } 134 }, 135 NetServerCommand::RecvOverTCP(conn_id, packet) => { ··· 145 146 for (_, conn) in &mut connections{ 147 conn.try_send_unreliable(packet.clone())?; } 148 } 149 } 150 }