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 + }
+259
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" ··· 181 dependencies = [ 182 "num-traits", 183 ] 184 185 [[package]] 186 name = "arrayref" ··· 1579 ] 1580 1581 [[package]] 1582 name = "bindgen" 1583 version = "0.72.1" 1584 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1593 "regex", 1594 "rustc-hash 2.1.1", 1595 "shlex", 1596 "syn", 1597 ] 1598 ··· 1678 ] 1679 1680 [[package]] 1681 name = "bumpalo" 1682 version = "3.19.1" 1683 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2060 ] 2061 2062 [[package]] 2063 name = "crc32fast" 2064 version = "1.5.0" 2065 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2348 ] 2349 2350 [[package]] 2351 name = "felix-audio" 2352 version = "0.1.0" 2353 dependencies = [ ··· 2368 "bevy", 2369 "bevy_mod_openxr", 2370 "bevy_mod_xr", 2371 "cpal 0.16.0", 2372 "dotenvy", 2373 "felix-audio", 2374 "felix-net", 2375 "openxr", ··· 3130 checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 3131 3132 [[package]] 3133 name = "mach2" 3134 version = "0.4.3" 3135 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3400 dependencies = [ 3401 "autocfg", 3402 "libm", 3403 ] 3404 3405 [[package]] ··· 3784 ] 3785 3786 [[package]] 3787 name = "opus" 3788 version = "0.3.0" 3789 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3819 dependencies = [ 3820 "ttf-parser 0.25.1", 3821 ] 3822 3823 [[package]] 3824 name = "parking" ··· 4400 ] 4401 4402 [[package]] 4403 name = "serde_core" 4404 version = "1.0.228" 4405 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4430 "ryu", 4431 "serde", 4432 "serde_core", 4433 ] 4434 4435 [[package]] ··· 5110 version = "0.2.6" 5111 source = "registry+https://github.com/rust-lang/crates.io-index" 5112 checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 5113 5114 [[package]] 5115 name = "uuid"
··· 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" ··· 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" ··· 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" ··· 1634 "regex", 1635 "rustc-hash 2.1.1", 1636 "shlex", 1637 + "syn", 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 ··· 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]] 1767 name = "bumpalo" 1768 version = "3.19.1" 1769 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 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 = [ ··· 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", ··· 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" ··· 3533 dependencies = [ 3534 "autocfg", 3535 "libm", 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]] ··· 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]] ··· 5291 version = "0.2.6" 5292 source = "registry+https://github.com/rust-lang/crates.io-index" 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"
+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 + }
+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 {
+1 -1
audio/src/voice/decoder.rs
··· 26 27 let mut total = 0.0; 28 for sample in buffer{ total += sample.powi(2) } 29 - *set_rms.write().unwrap() = ( total / buffer.len() as f32 ).sqrt(); 30 31 let mut voice = queue.lock().unwrap(); 32 for sample in buffer{ voice.push_back(sample); }
··· 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); }
+34 -22
audio/src/voice/microphone.rs
··· 1 - use std::{env, net::{ToSocketAddrs, 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 - udp: Option<UdpSocket>, 14 muted: Arc<Mutex<bool>>, 15 - last_rms: Arc<RwLock<isize>> 16 } 17 18 impl VoiceChatMicrophone{ 19 - pub fn new( socket: UdpSocket ) -> Self{ 20 Self { 21 stream: None, 22 - udp: Some(socket), 23 muted: Arc::new(Mutex::new(false)), // TODO: Default to muted 24 - last_rms: Arc::new(RwLock::new(0)) 25 } 26 } 27 ··· 58 let mut buffer = [0; MONO_20MS]; 59 60 let muted = self.muted.clone(); 61 - let udp = self.udp.take().unwrap(); 62 63 - let addr = env::var("HOST")?.to_socket_addrs()?.nth(0).unwrap(); 64 65 for conf in mic.supported_input_configs().unwrap(){ 66 println!("{} {:?} {} {:?}", conf.channels(), conf.buffer_size(), conf.sample_format(), conf.with_max_sample_rate()); 67 } 68 69 let set_rms = self.last_rms.clone(); 70 71 let stream = mic.build_input_stream( 72 &StreamConfig { ··· 81 buffer_indx = 0; 82 } else{ 83 for i in 0..data.len(){ 84 - if i % 2 == 0{ continue; } 85 86 buffer[buffer_indx] = data[i]; 87 buffer_indx += 1; ··· 89 if buffer_indx >= MONO_20MS{ 90 buffer_indx = 0; 91 92 - let mut total = 0; 93 - for sample in buffer{ total += (sample as isize).pow(2) } 94 - *set_rms.write().unwrap() = ( total / buffer.len() as isize ).isqrt(); 95 96 - let len = encoder.encode(&buffer, &mut output).unwrap(); 97 - let buf_to_send = output[0..len].to_vec(); 98 99 - let packet = PlayerVoicePacket { 100 - 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. 101 - packet: buf_to_send 102 - }; 103 104 - let packet: Vec<u8> = packet.to_buf().into(); 105 - udp.send_to(&packet, addr).unwrap(); 106 } 107 } 108 } ··· 117 Ok(()) 118 } 119 120 - pub fn get_rms_of_last_packet( &self ) -> f32{ 121 - *self.last_rms.read().unwrap() as f32 / i16::MAX as f32 122 } 123 }
··· 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 ··· 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 { ··· 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; ··· 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 } ··· 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)
+2
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"] } 14 bevy_mod_openxr = "0.4.0" 15 openxr = "0.19.0" 16 bevy_mod_xr = "0.4.0"
··· 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"
+88 -38
client/src/components/debug_camera.rs
··· 1 use std::f32::consts::PI; 2 3 use bevy::{ input::mouse::MouseMotion, prelude::* }; 4 - use bevy_mod_xr::session::XrState; 5 use felix_audio::voice::microphone::VoiceChatMicrophone; 6 7 use crate::net::connection::Connection; ··· 21 } 22 } 23 24 pub fn update( 25 mut query: Query<(&mut DebugCamera, &mut Transform)>, 26 - 27 time: Res<Time>, 28 29 keys: Res<ButtonInput<KeyCode>>, ··· 37 xr_state: Res<XrState> 38 ){ 39 let net_manager = networking.single().unwrap(); 40 41 - let mut delta_time = time.delta_secs(); 42 - if keys.pressed(KeyCode::ShiftLeft){ delta_time *= 2.0; } 43 44 - let ( mut debug, mut transform ) = query.single_mut().unwrap(); 45 46 - for ev in mouse_motion.read(){ 47 - if mouse_buttons.pressed(MouseButton::Right){ 48 - debug.pitch -= ev.delta.y * delta_time * 0.1; 49 - debug.yaw -= ev.delta.x * delta_time * 0.1; 50 } 51 - } 52 53 - transform.rotation = Quat::from_euler(EulerRot::YXZ, debug.yaw, debug.pitch, 0.0); 54 55 - if keys.pressed(KeyCode::KeyW){ 56 - let dir = transform.forward(); 57 - transform.translation += dir * delta_time; 58 - } else if keys.pressed(KeyCode::KeyS){ 59 - let dir = -transform.forward(); 60 - transform.translation += dir * delta_time; 61 - } 62 63 - if keys.pressed(KeyCode::KeyA){ 64 - let dir = transform.left(); 65 - transform.translation += dir * delta_time; 66 - } else if keys.pressed(KeyCode::KeyD){ 67 - let dir = -transform.left(); 68 - transform.translation += dir * delta_time; 69 - } 70 71 - if keys.pressed(KeyCode::KeyE){ 72 - let dir = transform.up(); 73 - transform.translation += dir * delta_time; 74 - } else if keys.pressed(KeyCode::KeyQ){ 75 - let dir = -transform.up(); 76 - transform.translation += dir * delta_time; 77 } 78 79 let mut remote_rms = "".to_owned(); 80 for id in net_manager.get_remote_player_voice_ids(){ 81 - remote_rms += format!("{}: {:.4}\n", id, net_manager.get_remote_player_voice_rms(&id)).as_str(); 82 } 83 84 - let rms = if let Ok(mic) = voice.single(){ 85 mic.get_rms_of_last_packet() 86 } else{ 87 - -1.0 88 }; 89 90 let ( mut text, _ ) = debug_text.single_mut().unwrap(); 91 text.0 = format!( 92 - "Microphone RMS: {:.4} 93 - {}Position: {:.2} {:.2} {:.2} 94 - Rotation: {:.2} {:.2} {:.2} {:.2} 95 XR State: {:#?}", 96 rms, 97 98 remote_rms, 99 ··· 106 transform.rotation.z, 107 transform.rotation.w, 108 109 - xr_state.into_inner() 110 ); 111 } 112
··· 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; ··· 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>>, ··· 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 ··· 156 transform.rotation.z, 157 transform.rotation.w, 158 159 + xr_state 160 ); 161 } 162
+37 -26
client/src/main.rs
··· 1 use bevy::{app::{App, FixedUpdate, Startup, Update}, ecs::system::Commands, prelude::*, render::pipelined_rendering::PipelinedRenderingPlugin}; 2 use bevy_mod_openxr::{add_xr_plugins, resources::OxrSessionConfig}; 3 - use bevy_mod_xr::session::{XrSessionCreated, XrSessionPlugin}; 4 use felix_audio::{FelixAudio, voice}; 5 - use openxr::EnvironmentBlendMode; 6 7 use crate::{components::{debug_camera, network_interface, remote_player}, setup::setup}; 8 ··· 12 13 fn main() { 14 if let Err(err) = dotenvy::dotenv(){ println!("[WARN] .ENV failed loading {:#?}", err); } 15 16 - App::new() 17 - .add_plugins(( 18 add_xr_plugins( 19 DefaultPlugins 20 .build() 21 .disable::<PipelinedRenderingPlugin>(), 22 ).set(XrSessionPlugin { auto_handle: true }), 23 - FelixAudio 24 )) 25 .insert_resource(OxrSessionConfig { 26 - blend_mode_preference: vec![ 27 - EnvironmentBlendMode::ALPHA_BLEND, 28 - EnvironmentBlendMode::ADDITIVE, 29 - EnvironmentBlendMode::OPAQUE 30 - ], 31 ..Default::default() 32 }) 33 - .add_systems(XrSessionCreated, || { println!("[INFO] Started VR") }) 34 - .add_systems(Startup, setup) 35 - .add_systems(Startup, move | mut commands: Commands |{ 36 - let ( comp, voice ) = net::handle_net().expect("Network Module Failed"); 37 - commands.spawn(comp); 38 39 - match voice::init_microphone(voice){ 40 - Ok(voice) => { commands.spawn(voice); }, 41 - Err(err) => println!("[WARN] Failed to start microphone: {}", err) 42 - } 43 - }) 44 - .add_systems(Update, debug_camera::update) 45 - .add_systems(Startup, debug_camera::setup) 46 - .add_systems(Update, remote_player::update) 47 - .add_systems(FixedUpdate, network_interface::fixed_update) 48 - .run(); 49 - }
··· 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}; 10 ··· 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 + }
+1 -1
client/src/net/connection.rs
··· 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();
··· 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();
+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
+69 -22
client/src/setup.rs
··· 1 use bevy::prelude::*; 2 use felix_audio::FelixAudioListener; 3 4 use crate::components::debug_camera::DebugCamera; ··· 9 mut materials: ResMut<Assets<StandardMaterial>> 10 ){ 11 // TODO: World loading from server 12 13 - // TODO: World loading format? Could build an asset bundle parser? 14 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 - )); 47 }
··· 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; ··· 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 }