2020-11-14 00:27:09 +00:00
|
|
|
//! Handles ambient non-positional sounds
|
|
|
|
use crate::{
|
|
|
|
audio::{channel::AmbientChannelTag, AudioFrontend},
|
|
|
|
scene::Camera,
|
|
|
|
};
|
2020-11-07 01:55:59 +00:00
|
|
|
use client::Client;
|
2020-12-13 01:09:57 +00:00
|
|
|
use common::{
|
|
|
|
assets::{self, AssetExt, AssetHandle},
|
|
|
|
vol::ReadVol,
|
|
|
|
};
|
2021-04-06 15:47:03 +00:00
|
|
|
use common_state::State;
|
2020-11-07 01:55:59 +00:00
|
|
|
use serde::Deserialize;
|
|
|
|
use std::time::Instant;
|
|
|
|
use tracing::warn;
|
2020-11-17 00:38:48 +00:00
|
|
|
use vek::*;
|
2020-11-07 01:55:59 +00:00
|
|
|
|
|
|
|
#[derive(Debug, Default, Deserialize)]
|
2020-11-14 00:27:09 +00:00
|
|
|
struct AmbientCollection {
|
|
|
|
tracks: Vec<AmbientItem>,
|
2020-11-07 01:55:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Configuration for a single music track in the soundtrack
|
|
|
|
#[derive(Debug, Deserialize)]
|
2020-11-14 00:27:09 +00:00
|
|
|
pub struct AmbientItem {
|
2020-11-07 01:55:59 +00:00
|
|
|
path: String,
|
|
|
|
/// Length of the track in seconds
|
|
|
|
length: f32,
|
2020-11-17 00:38:48 +00:00
|
|
|
/// Specifies which ambient channel to play on
|
2020-11-14 00:27:09 +00:00
|
|
|
tag: AmbientChannelTag,
|
2020-11-07 01:55:59 +00:00
|
|
|
}
|
|
|
|
|
2020-11-14 00:27:09 +00:00
|
|
|
pub struct AmbientMgr {
|
2020-12-12 22:14:24 +00:00
|
|
|
soundtrack: AssetHandle<AmbientCollection>,
|
2020-11-07 01:55:59 +00:00
|
|
|
began_playing: Instant,
|
|
|
|
next_track_change: f32,
|
2020-11-08 05:26:20 +00:00
|
|
|
volume: f32,
|
|
|
|
tree_multiplier: f32,
|
2020-11-07 01:55:59 +00:00
|
|
|
}
|
|
|
|
|
2020-11-14 00:27:09 +00:00
|
|
|
impl Default for AmbientMgr {
|
2020-11-12 03:55:40 +00:00
|
|
|
fn default() -> Self {
|
2020-11-07 01:55:59 +00:00
|
|
|
Self {
|
|
|
|
soundtrack: Self::load_soundtrack_items(),
|
|
|
|
began_playing: Instant::now(),
|
|
|
|
next_track_change: 0.0,
|
2020-11-08 05:26:20 +00:00
|
|
|
volume: 0.0,
|
|
|
|
tree_multiplier: 0.0,
|
2020-11-07 01:55:59 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-12 03:55:40 +00:00
|
|
|
}
|
2020-11-07 01:55:59 +00:00
|
|
|
|
2020-11-14 00:27:09 +00:00
|
|
|
impl AmbientMgr {
|
2020-11-07 01:55:59 +00:00
|
|
|
/// Checks whether the previous track has completed. If so, sends a
|
|
|
|
/// request to play the next (random) track
|
2020-11-07 10:02:29 +00:00
|
|
|
pub fn maintain(
|
|
|
|
&mut self,
|
|
|
|
audio: &mut AudioFrontend,
|
|
|
|
state: &State,
|
|
|
|
client: &Client,
|
|
|
|
camera: &Camera,
|
|
|
|
) {
|
2020-12-12 22:14:24 +00:00
|
|
|
if audio.sfx_enabled() && !self.soundtrack.read().tracks.is_empty() {
|
2020-11-12 03:55:40 +00:00
|
|
|
let focus_off = camera.get_focus_pos().map(f32::trunc);
|
|
|
|
let cam_pos = camera.dependents().cam_pos + focus_off;
|
|
|
|
|
2020-11-17 00:38:48 +00:00
|
|
|
let (terrain_alt, tree_density) = if let Some(chunk) = client.current_chunk() {
|
|
|
|
(chunk.meta().alt(), chunk.meta().tree_density())
|
|
|
|
} else {
|
|
|
|
(0.0, 0.0)
|
|
|
|
};
|
2020-11-08 05:26:20 +00:00
|
|
|
|
2020-11-14 00:27:09 +00:00
|
|
|
// The following code is specifically for wind, as it is the only
|
|
|
|
// non-positional ambient sound in the game. Others can be added
|
|
|
|
// as seen fit.
|
|
|
|
|
2020-11-27 17:43:47 +00:00
|
|
|
let target_volume = {
|
|
|
|
// Wind volume increases with altitude
|
|
|
|
let alt_multiplier = (cam_pos.z / 1200.0).abs();
|
|
|
|
|
|
|
|
// Tree density factors into wind volume. The more trees,
|
|
|
|
// the lower wind volume. The trees make more of an impact
|
|
|
|
// the closer the camera is to the ground.
|
|
|
|
self.tree_multiplier = ((1.0 - tree_density)
|
|
|
|
+ ((cam_pos.z - terrain_alt).abs() / 150.0).powi(2))
|
|
|
|
.min(1.0);
|
|
|
|
|
|
|
|
let mut volume_multiplier = alt_multiplier * self.tree_multiplier;
|
|
|
|
|
|
|
|
// Checks if the camera is underwater to stop ambient sounds
|
|
|
|
if state
|
|
|
|
.terrain()
|
|
|
|
.get((cam_pos).map(|e| e.floor() as i32))
|
|
|
|
.map(|b| b.is_liquid())
|
|
|
|
.unwrap_or(false)
|
|
|
|
{
|
|
|
|
volume_multiplier *= 0.1;
|
|
|
|
}
|
|
|
|
if cam_pos.z < terrain_alt - 10.0 {
|
|
|
|
volume_multiplier = 0.0;
|
|
|
|
}
|
2020-11-07 01:55:59 +00:00
|
|
|
|
2020-11-27 17:43:47 +00:00
|
|
|
volume_multiplier.clamped(0.0, 1.0)
|
|
|
|
};
|
2020-11-08 05:26:20 +00:00
|
|
|
|
2020-11-14 00:27:09 +00:00
|
|
|
// Transitions the ambient sounds (more) smoothly
|
|
|
|
self.volume = audio.get_ambient_volume();
|
2020-11-17 00:38:48 +00:00
|
|
|
audio.set_ambient_volume(Lerp::lerp(self.volume, target_volume, 0.01));
|
2020-11-07 01:55:59 +00:00
|
|
|
|
|
|
|
if self.began_playing.elapsed().as_secs_f32() > self.next_track_change {
|
2020-11-17 00:38:48 +00:00
|
|
|
// Right now there is only wind non-positional sfx so it is always
|
|
|
|
// selected. Modify this variable assignment when adding other non-
|
|
|
|
// positional sfx
|
2020-12-12 22:14:24 +00:00
|
|
|
let soundtrack = self.soundtrack.read();
|
|
|
|
let track = &soundtrack
|
2020-11-14 00:27:09 +00:00
|
|
|
.tracks
|
|
|
|
.iter()
|
2020-11-17 00:38:48 +00:00
|
|
|
.find(|track| track.tag == AmbientChannelTag::Wind);
|
2020-11-14 00:27:09 +00:00
|
|
|
|
|
|
|
if let Some(track) = track {
|
|
|
|
self.began_playing = Instant::now();
|
|
|
|
self.next_track_change = track.length;
|
2020-11-07 01:55:59 +00:00
|
|
|
|
2020-11-27 17:43:47 +00:00
|
|
|
audio.play_ambient(AmbientChannelTag::Wind, &track.path, target_volume);
|
2020-11-14 00:27:09 +00:00
|
|
|
}
|
2020-11-07 01:55:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-12 22:14:24 +00:00
|
|
|
fn load_soundtrack_items() -> AssetHandle<AmbientCollection> {
|
2021-06-25 16:47:03 +00:00
|
|
|
AmbientCollection::load_or_insert_with("voxygen.audio.ambient", |error| {
|
|
|
|
warn!(
|
|
|
|
"Error reading ambience config file, ambience will not be available: {:#?}",
|
|
|
|
error
|
|
|
|
);
|
|
|
|
AmbientCollection::default()
|
|
|
|
})
|
2020-11-07 01:55:59 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-12 22:14:24 +00:00
|
|
|
|
|
|
|
impl assets::Asset for AmbientCollection {
|
|
|
|
type Loader = assets::RonLoader;
|
|
|
|
|
2020-12-13 01:09:57 +00:00
|
|
|
const EXTENSION: &'static str = "ron";
|
|
|
|
}
|