Skip to content

Commit

Permalink
AvatarAttach (#45)
Browse files Browse the repository at this point in the history
features
- `AvatarAttach`
- `Visibility`
- `PointerResults`:
  - add normal
  - add position
  - add scene entity to hit result for events sent to scene roots
- collisions
  - add DisableCollisions marker, apply to `AvatarAttach`ed items
- mock js modules

bugfixes
- animations
  - fix path bug (inc bevy patch [#9407](bevyengine/bevy#9407)) that caused anims to play on the wrong nodes
  - play gltf first animation if no animator present
  - play animation resets the anim (only if not looping)
- fix main.crdt buffer overrun
- fix collider pipeline use-before-init crash
- system log chat tab now updates live without forcing reload
- chat tab wraps correctly
- send transform updates to scene only if they are changed
- don't validate the `main_file` for texture wearables, just look for pngs
- AudioSource 
  - only plays in current scene
  - use manual spatial calc to preserve requested volume
  
tweaks
- increase base move speed
- vsync off by default
- update to latest protobuf messages
  • Loading branch information
robtfm authored Aug 16, 2023
1 parent 9be1e3c commit 3d3a4d5
Show file tree
Hide file tree
Showing 68 changed files with 2,066 additions and 489 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,16 @@ jobs:
Add-Content $env:GITHUB_ENV "FFMPEG_DIR=${pwd}\ffmpeg`n"
Add-Content $env:GITHUB_PATH "${pwd}\ffmpeg\bin`n"
- uses: actions-rs/cargo@v1
if: runner.os == 'windows'
with:
command: test
args: --all --release
- uses: actions-rs/cargo@v1
if: runner.os != 'windows'
with:
command: test
args: --all

fmt:
name: Rustfmt
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,6 @@ pico-args = "0.5.0"
prost-build = "0.11.8"

[patch.crates-io]
bevy = { git = "https://github.com/robtfm/bevy", branch = "0.11-hotfix" }
bevy = { git = "https://github.com/robtfm/bevy", branch = "0.11.1-hotfix" }
bevy_kira_audio = { git = "https://github.com/robtfm/bevy_kira_audio", branch = "pub-manager" }
ffmpeg-next = { git = "https://github.com/robtfm/rust-ffmpeg", branch = "audio-linesize-0" }
102 changes: 89 additions & 13 deletions crates/av/src/audio_source.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
use std::time::Duration;

use bevy::prelude::*;
use bevy_kira_audio::{
prelude::{AudioEmitter, AudioReceiver},
AudioControl, AudioInstance, AudioTween,
};
use common::{structs::PrimaryCameraRes, util::TryInsertEx};
use dcl_component::proto_components::sdk::components::PbAudioSource;
use common::{
sets::{SceneSets, SetupSets},
structs::{PrimaryCameraRes, PrimaryUser},
util::TryInsertEx,
};
use dcl::interface::ComponentPosition;
use dcl_component::{proto_components::sdk::components::PbAudioSource, SceneComponentId};
use ipfs::IpfsLoaderExt;
use scene_runner::{renderer_context::RendererSceneContext, SceneEntity};
use scene_runner::{
renderer_context::RendererSceneContext, update_world::AddCrdtInterfaceExt, ContainingScene,
SceneEntity,
};

#[derive(Component, Debug)]
pub struct AudioSource(PbAudioSource);
Expand All @@ -19,12 +25,28 @@ impl From<PbAudioSource> for AudioSource {
}
}

pub(crate) fn setup_audio(mut commands: Commands, camera: Res<PrimaryCameraRes>) {
pub struct AudioSourcePlugin;

impl Plugin for AudioSourcePlugin {
fn build(&self, app: &mut App) {
app.add_crdt_lww_component::<PbAudioSource, AudioSource>(
SceneComponentId::AUDIO_SOURCE,
ComponentPosition::EntityOnly,
);
app.add_systems(
Update,
(update_audio, update_source_volume).in_set(SceneSets::PostLoop),
);
app.add_systems(Startup, setup_audio.in_set(SetupSets::Main));
}
}

fn setup_audio(mut commands: Commands, camera: Res<PrimaryCameraRes>) {
commands.entity(camera.0).try_insert(AudioReceiver);
}

#[allow(clippy::type_complexity)]
pub(crate) fn update_audio(
#[allow(clippy::type_complexity, clippy::too_many_arguments)]
fn update_audio(
mut commands: Commands,
mut query: Query<
(
Expand All @@ -40,7 +62,14 @@ pub(crate) fn update_audio(
audio: Res<bevy_kira_audio::Audio>,
asset_server: Res<AssetServer>,
mut audio_instances: ResMut<Assets<AudioInstance>>,
containing_scene: ContainingScene,
player: Query<Entity, With<PrimaryUser>>,
) {
let current_scene = player
.get_single()
.ok()
.and_then(|p| containing_scene.get(p));

for (ent, scene_ent, audio_source, maybe_source, maybe_emitter) in query.iter_mut() {
// preload clips
let h_audio = match maybe_source {
Expand Down Expand Up @@ -77,10 +106,13 @@ pub(crate) fn update_audio(
instance = instance.looped();
}

if let Some(volume) = audio_source.0.volume {
instance = instance
.with_volume(bevy_kira_audio::prelude::Volume::Amplitude(volume as f64));
}
let volume = if Some(scene_ent.root) == current_scene {
audio_source.0.volume.unwrap_or(1.0)
} else {
0.0
};
instance =
instance.with_volume(bevy_kira_audio::prelude::Volume::Amplitude(volume as f64));

let instance = instance.handle();
commands.entity(ent).try_insert(AudioEmitter {
Expand All @@ -90,10 +122,54 @@ pub(crate) fn update_audio(
// stop running
for h_instance in emitter.instances.iter() {
if let Some(instance) = audio_instances.get_mut(h_instance) {
instance.stop(AudioTween::linear(Duration::ZERO));
instance.stop(AudioTween::default());
}
}
emitter.instances.clear();
}
}
}

fn update_source_volume(
query: Query<(&SceneEntity, &AudioSource, &AudioEmitter, &GlobalTransform)>,
mut audio_instances: ResMut<Assets<AudioInstance>>,
containing_scene: ContainingScene,
player: Query<Entity, With<PrimaryUser>>,
mut prev_scene: Local<Option<Entity>>,
receiver: Query<&GlobalTransform, With<AudioReceiver>>,
) {
let current_scene = player
.get_single()
.ok()
.and_then(|p| containing_scene.get(p));

let Ok(receiver) = receiver.get_single() else {
return;
};

for (scene, source, emitter, transform) in query.iter() {
if current_scene == Some(scene.root) {
let sound_path = transform.translation() - receiver.translation();
let volume = (1. - sound_path.length() / 25.0).clamp(0., 1.).powi(2)
* source.0.volume.unwrap_or(1.0);

let right_ear_angle = receiver.right().angle_between(sound_path);
let panning = (right_ear_angle.cos() + 1.) / 2.;

for h_instance in &emitter.instances {
if let Some(instance) = audio_instances.get_mut(h_instance) {
instance.set_volume(volume as f64, AudioTween::default());
instance.set_panning(panning as f64, AudioTween::default());
}
}
} else if *prev_scene == Some(scene.root) {
for h_instance in &emitter.instances {
if let Some(instance) = audio_instances.get_mut(h_instance) {
instance.set_volume(0.0, AudioTween::default());
}
}
}
}

*prev_scene = current_scene;
}
15 changes: 2 additions & 13 deletions crates/av/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,9 @@ pub mod video_player;
pub mod video_stream;

use audio_sink::{spawn_and_locate_foreign_streams, spawn_audio_streams};
use audio_source::{setup_audio, update_audio};
use audio_source::AudioSourcePlugin;
use bevy::prelude::*;
use bevy_kira_audio::prelude::SpacialAudio;
use common::sets::{SceneSets, SetupSets};
use dcl::interface::ComponentPosition;
use dcl_component::{proto_components::sdk::components::PbAudioSource, SceneComponentId};
use microphone::MicPlugin;
use scene_runner::update_world::AddCrdtInterfaceExt;
use video_player::VideoPlayerPlugin;

pub struct AudioPlugin;
Expand All @@ -28,13 +23,7 @@ impl Plugin for AudioPlugin {
app.add_plugins(bevy_kira_audio::AudioPlugin);
app.add_plugins(VideoPlayerPlugin);
app.add_plugins(MicPlugin);
app.add_crdt_lww_component::<PbAudioSource, audio_source::AudioSource>(
SceneComponentId::AUDIO_SOURCE,
ComponentPosition::EntityOnly,
);
app.add_systems(Update, update_audio.in_set(SceneSets::PostLoop));
app.insert_resource(SpacialAudio { max_distance: 25. });
app.add_systems(Startup, setup_audio.in_set(SetupSets::Main));
app.add_plugins(AudioSourcePlugin);
app.add_systems(
PostUpdate,
(spawn_audio_streams, spawn_and_locate_foreign_streams),
Expand Down
74 changes: 74 additions & 0 deletions crates/avatar/src/attach.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use bevy::prelude::*;

use common::{
sets::SceneSets,
structs::{AttachPoints, PrimaryUser},
util::TryInsertEx,
};
use dcl::interface::ComponentPosition;
use dcl_component::{
proto_components::sdk::components::{AvatarAnchorPointType, PbAvatarAttach},
SceneComponentId,
};
use scene_runner::update_world::{
mesh_collider::DisableCollisions, transform_and_parent::ParentPositionSync, AddCrdtInterfaceExt,
};

pub struct AttachPlugin;

impl Plugin for AttachPlugin {
fn build(&self, app: &mut App) {
app.add_crdt_lww_component::<PbAvatarAttach, AvatarAttachment>(
SceneComponentId::AVATAR_ATTACHMENT,
ComponentPosition::Any,
);
app.add_systems(Update, update_attached.in_set(SceneSets::PostLoop));
}
}

#[derive(Component, Debug)]
pub struct AvatarAttachment(pub PbAvatarAttach);

impl From<PbAvatarAttach> for AvatarAttachment {
fn from(value: PbAvatarAttach) -> Self {
Self(value)
}
}

pub fn update_attached(
mut commands: Commands,
attachments: Query<(Entity, &AvatarAttachment), Changed<AvatarAttachment>>,
mut removed_attachments: RemovedComponents<AvatarAttachment>,
primary_user: Query<&AttachPoints, With<PrimaryUser>>,
) {
for removed in removed_attachments.iter() {
if let Some(mut commands) = commands.get_entity(removed) {
commands.remove::<(ParentPositionSync, DisableCollisions)>();
}
}

for (ent, attach) in attachments.iter() {
let attach_points = if attach.0.avatar_id.is_none() {
let Ok(data) = primary_user.get_single() else {
warn!("no primary user");
continue;
};
data
} else {
warn!("nope");
continue;
};

let sync_entity = match attach.0.anchor_point_id() {
AvatarAnchorPointType::AaptPosition => attach_points.position,
AvatarAnchorPointType::AaptNameTag => attach_points.nametag,
AvatarAnchorPointType::AaptLeftHand => attach_points.left_hand,
AvatarAnchorPointType::AaptRightHand => attach_points.right_hand,
};

commands
.entity(ent)
.try_insert((ParentPositionSync(sync_entity), DisableCollisions));
debug!("syncing {ent:?} to {sync_entity:?}");
}
}
Loading

0 comments on commit 3d3a4d5

Please sign in to comment.