A multiplayer VR framework w/voice chat
at main 3.3 kB view raw
1use std::collections::HashMap; 2 3use bevy::prelude::*; 4use felix_audio::{SAMPLE_RATE, source::{FelixAudioSource, stream_source::StreamAudioSource}}; 5use felix_net::{packet::PacketTypes, packets::update_server_position::UpdateServerPositions}; 6 7use crate::{debug_camera::DebugCamera, net::{NetClientCommand, connection::Connection}, remote_player::RemotePlayer}; 8 9pub fn fixed_update( 10 mut query: Query<(&mut DebugCamera, &mut Transform)>, 11 12 mut networking: Query<&mut Connection>, 13 14 mut commands: Commands, 15 mut meshes: ResMut<Assets<Mesh>>, 16 mut materials: ResMut<Assets<StandardMaterial>>, 17 18 players: Query<(Entity, &mut RemotePlayer)> 19){ 20 let ( _, transform ) = query.single_mut().unwrap(); 21 let mut net_manager = networking.single_mut().unwrap(); 22 23 let update_pos_packet = UpdateServerPositions { 24 position: transform.translation.clone(), 25 rotation: transform.rotation.clone() 26 }; 27 28 net_manager.try_send_unreliable(update_pos_packet).unwrap(); 29 30 if let Ok(ev) = net_manager.recv_event(){ 31 match ev{ 32 NetClientCommand::Connected(id) => { 33 println!("[INFO] Connected to server as {}", id); 34 } 35 NetClientCommand::Disconnected => { 36 println!("[WARN] Disconnected from server."); 37 } 38 NetClientCommand::RecvPacket(packet) => { 39 match packet{ 40 PacketTypes::PlayerJoinPacket(packet) => { 41 join_players(vec![packet.id], &mut commands, &mut meshes, &mut materials, &mut net_manager); 42 } 43 PacketTypes::PlayerListPacket(packet) => { 44 join_players(packet.ids, &mut commands, &mut meshes, &mut materials, &mut net_manager); 45 } 46 PacketTypes::PlayerLeavePacket(packet) => { 47 leave_player(packet.id, &mut commands, players, &mut net_manager); 48 } 49 PacketTypes::UpdateClientsPositions(packet) => { 50 let mut map = HashMap::new(); 51 52 for ( id, pos, rot ) in packet.players{ 53 map.insert(id, (pos, rot)); } 54 55 for ( _, mut player ) in players{ 56 let ( pos, rot ) = map.get(&player.id).unwrap(); 57 58 player.pos = *pos; 59 player.rot = *rot; 60 } 61 } 62 _ => {} 63 } 64 } 65 } 66 } 67} 68 69fn join_players( 70 players: Vec<String>, 71 72 commands: &mut Commands, 73 meshes: &mut ResMut<Assets<Mesh>>, 74 materials: &mut ResMut<Assets<StandardMaterial>>, 75 76 net_manager: &mut Connection 77){ 78 for id in players{ 79 let listener = net_manager.start_listening_for_player_voice(&id); 80 81 commands.spawn(( 82 Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))), 83 MeshMaterial3d(materials.add(Color::WHITE)), 84 Transform::from_xyz(0.0, 0.0, 0.0), 85 RemotePlayer { id, ..Default::default() }, 86 FelixAudioSource::from(StreamAudioSource::new(SAMPLE_RATE, move | len | { 87 let mut buf = vec![0.0; len]; 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 })) 95 )); 96 } 97} 98 99fn leave_player( 100 id: String, 101 commands: &mut Commands, 102 103 players: Query<(Entity, &mut RemotePlayer)>, 104 net_manager: &mut Connection 105){ 106 net_manager.stop_listening_for_player_voice(&id); 107 108 for ( entity, player ) in players{ 109 if id == player.id{ 110 commands.entity(entity).despawn(); 111 break; 112 } 113 } 114}