mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'DaforLynx/event-music' into 'master'
Event music can use more than one event at a time. Added test for soundtracks. See merge request veloren/veloren!3686
This commit is contained in:
commit
97f3fa56d3
13
assets/voxygen/audio/calendar/christmas/soundtrack.ron
Normal file
13
assets/voxygen/audio/calendar/christmas/soundtrack.ron
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Times: Some(Day or Night) or None [both]
|
||||||
|
// Weathers: Some(Clear, Cloudy, Rain, or Storm) or None [any weather]
|
||||||
|
// Biomes: Grassland, Forest, Desert, Snowland, Lake, Mountain, Ocean, Jungle, Savannah, Taiga
|
||||||
|
// planned biomes: Swamp
|
||||||
|
// Number after biome indicates weighting; higher numbers are less frequent
|
||||||
|
// Sites: Settlement(Default, Cliff, or Desert), Cave, Dungeon(Old or Gnarling), or Void [none]
|
||||||
|
// Music states: Activity(Explore or Combat)
|
||||||
|
// Combat music is looped. Needs three files: start, loop, and end. Start contains leadup to the loop.
|
||||||
|
// It's recommended to also have appropriate metadata for those who listen via the game files :)
|
||||||
|
|
||||||
|
(
|
||||||
|
tracks: []
|
||||||
|
)
|
@ -142,7 +142,7 @@
|
|||||||
"voxygen.audio.sfx.footsteps.stepdirt_4",
|
"voxygen.audio.sfx.footsteps.stepdirt_4",
|
||||||
"voxygen.audio.sfx.footsteps.stepdirt_5",
|
"voxygen.audio.sfx.footsteps.stepdirt_5",
|
||||||
],
|
],
|
||||||
threshold: 1.6,
|
threshold: 1.8,
|
||||||
),
|
),
|
||||||
QuadRun(Earth): (
|
QuadRun(Earth): (
|
||||||
files: [
|
files: [
|
||||||
@ -152,7 +152,7 @@
|
|||||||
"voxygen.audio.sfx.footsteps.stepdirt_4",
|
"voxygen.audio.sfx.footsteps.stepdirt_4",
|
||||||
"voxygen.audio.sfx.footsteps.stepdirt_5",
|
"voxygen.audio.sfx.footsteps.stepdirt_5",
|
||||||
],
|
],
|
||||||
threshold: 0.8,
|
threshold: 0.9,
|
||||||
),
|
),
|
||||||
Run(Grass): (
|
Run(Grass): (
|
||||||
files: [
|
files: [
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use chrono::{DateTime, Datelike, Local, TimeZone, Utc};
|
use chrono::{DateTime, Datelike, Local, TimeZone, Utc};
|
||||||
use chrono_tz::Tz;
|
use chrono_tz::Tz;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use strum::EnumIter;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, EnumIter)]
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
pub enum CalendarEvent {
|
pub enum CalendarEvent {
|
||||||
Christmas = 0,
|
Christmas = 0,
|
||||||
|
@ -56,7 +56,7 @@ use hashbrown::HashMap;
|
|||||||
use rand::{prelude::SliceRandom, thread_rng, Rng};
|
use rand::{prelude::SliceRandom, thread_rng, Rng};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use tracing::{debug, trace, warn};
|
use tracing::{debug, trace};
|
||||||
|
|
||||||
/// Collection of all the tracks
|
/// Collection of all the tracks
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -151,7 +151,7 @@ enum PlayState {
|
|||||||
/// Provides methods to control music playback
|
/// Provides methods to control music playback
|
||||||
pub struct MusicMgr {
|
pub struct MusicMgr {
|
||||||
/// Collection of all the tracks
|
/// Collection of all the tracks
|
||||||
soundtrack: AssetHandle<SoundtrackCollection<SoundtrackItem>>,
|
soundtrack: SoundtrackCollection<SoundtrackItem>,
|
||||||
/// Instant at which the current track began playing
|
/// Instant at which the current track began playing
|
||||||
began_playing: Instant,
|
began_playing: Instant,
|
||||||
/// Time until the next track should be played
|
/// Time until the next track should be played
|
||||||
@ -310,7 +310,7 @@ impl MusicMgr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if audio.music_enabled()
|
if audio.music_enabled()
|
||||||
&& !self.soundtrack.read().tracks.is_empty()
|
&& !self.soundtrack.tracks.is_empty()
|
||||||
&& (self.began_playing.elapsed().as_secs_f32() > self.next_track_change || interrupt)
|
&& (self.began_playing.elapsed().as_secs_f32() > self.next_track_change || interrupt)
|
||||||
{
|
{
|
||||||
if interrupt {
|
if interrupt {
|
||||||
@ -378,10 +378,10 @@ impl MusicMgr {
|
|||||||
// too many constraints. Returning Err(()) signals that we couldn't find
|
// too many constraints. Returning Err(()) signals that we couldn't find
|
||||||
// an appropriate track for the current state, and hence the state
|
// an appropriate track for the current state, and hence the state
|
||||||
// machine for the activity shouldn't be updated.
|
// machine for the activity shouldn't be updated.
|
||||||
let soundtrack = self.soundtrack.read();
|
|
||||||
// First, filter out tracks not matching the timing, site, biome, and current
|
// First, filter out tracks not matching the timing, site, biome, and current
|
||||||
// activity
|
// activity
|
||||||
let mut maybe_tracks = soundtrack
|
let mut maybe_tracks = self
|
||||||
|
.soundtrack
|
||||||
.tracks
|
.tracks
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|track| {
|
.filter(|track| {
|
||||||
@ -487,24 +487,60 @@ impl MusicMgr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_soundtrack_items(
|
/// Loads default soundtrack if no events are active. Otherwise, attempts to
|
||||||
calendar: &Calendar,
|
/// compile and load all active event soundtracks, falling back to default
|
||||||
) -> AssetHandle<SoundtrackCollection<SoundtrackItem>> {
|
/// if they are empty.
|
||||||
// Cannot fail: A default value is always provided
|
fn load_soundtrack_items(calendar: &Calendar) -> SoundtrackCollection<SoundtrackItem> {
|
||||||
let mut soundtrack = SoundtrackCollection::load_expect("voxygen.audio.soundtrack");
|
let mut soundtrack = SoundtrackCollection::default();
|
||||||
|
// Loads default soundtrack if no events are active
|
||||||
if calendar.events().len() == 0 {
|
if calendar.events().len() == 0 {
|
||||||
soundtrack
|
for track in SoundtrackCollection::load_expect("voxygen.audio.soundtrack")
|
||||||
|
.read()
|
||||||
|
.tracks
|
||||||
|
.clone()
|
||||||
|
{
|
||||||
|
soundtrack.tracks.push(track)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Compiles event-specific soundtracks if any are active
|
||||||
for event in calendar.events() {
|
for event in calendar.events() {
|
||||||
match event {
|
match event {
|
||||||
CalendarEvent::Halloween => {
|
CalendarEvent::Halloween => {
|
||||||
soundtrack = SoundtrackCollection::load_expect(
|
for track in SoundtrackCollection::load_expect(
|
||||||
"voxygen.audio.calendar.halloween.soundtrack",
|
"voxygen.audio.calendar.halloween.soundtrack",
|
||||||
);
|
)
|
||||||
|
.read()
|
||||||
|
.tracks
|
||||||
|
.clone()
|
||||||
|
{
|
||||||
|
soundtrack.tracks.push(track)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CalendarEvent::Christmas => {
|
||||||
|
for track in SoundtrackCollection::load_expect(
|
||||||
|
"voxygen.audio.calendar.christmas.soundtrack",
|
||||||
|
)
|
||||||
|
.read()
|
||||||
|
.tracks
|
||||||
|
.clone()
|
||||||
|
{
|
||||||
|
soundtrack.tracks.push(track)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => soundtrack = SoundtrackCollection::load_expect("voxygen.audio.soundtrack"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Fallback if events are active but give an empty tracklist
|
||||||
|
if soundtrack.tracks.is_empty() {
|
||||||
|
for track in SoundtrackCollection::load_expect("voxygen.audio.soundtrack")
|
||||||
|
.read()
|
||||||
|
.tracks
|
||||||
|
.clone()
|
||||||
|
{
|
||||||
|
soundtrack.tracks.push(track)
|
||||||
|
}
|
||||||
|
soundtrack
|
||||||
|
} else {
|
||||||
soundtrack
|
soundtrack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -517,13 +553,11 @@ impl assets::Asset for SoundtrackCollection<RawSoundtrackItem> {
|
|||||||
|
|
||||||
impl assets::Compound for SoundtrackCollection<SoundtrackItem> {
|
impl assets::Compound for SoundtrackCollection<SoundtrackItem> {
|
||||||
fn load(_: assets::AnyCache, id: &str) -> Result<Self, assets::BoxedError> {
|
fn load(_: assets::AnyCache, id: &str) -> Result<Self, assets::BoxedError> {
|
||||||
let inner = || -> Result<_, assets::Error> {
|
let manifest: AssetHandle<SoundtrackCollection<RawSoundtrackItem>> = AssetExt::load(id)?;
|
||||||
let manifest: AssetHandle<SoundtrackCollection<RawSoundtrackItem>> =
|
let mut soundtrack = SoundtrackCollection::default();
|
||||||
AssetExt::load(id)?;
|
|
||||||
let mut soundtracks = SoundtrackCollection::default();
|
|
||||||
for item in manifest.read().tracks.iter().cloned() {
|
for item in manifest.read().tracks.iter().cloned() {
|
||||||
match item {
|
match item {
|
||||||
RawSoundtrackItem::Individual(track) => soundtracks.tracks.push(track),
|
RawSoundtrackItem::Individual(track) => soundtrack.tracks.push(track),
|
||||||
RawSoundtrackItem::Segmented {
|
RawSoundtrackItem::Segmented {
|
||||||
title,
|
title,
|
||||||
timing,
|
timing,
|
||||||
@ -534,7 +568,7 @@ impl assets::Compound for SoundtrackCollection<SoundtrackItem> {
|
|||||||
artist,
|
artist,
|
||||||
} => {
|
} => {
|
||||||
for (path, length, music_state, activity_override) in segments.into_iter() {
|
for (path, length, music_state, activity_override) in segments.into_iter() {
|
||||||
soundtracks.tracks.push(SoundtrackItem {
|
soundtrack.tracks.push(SoundtrackItem {
|
||||||
title: title.clone(),
|
title: title.clone(),
|
||||||
path,
|
path,
|
||||||
length,
|
length,
|
||||||
@ -550,14 +584,34 @@ impl assets::Compound for SoundtrackCollection<SoundtrackItem> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(soundtracks)
|
Ok(soundtrack)
|
||||||
};
|
}
|
||||||
match inner() {
|
}
|
||||||
Ok(soundtracks) => Ok(soundtracks),
|
|
||||||
Err(e) => {
|
#[cfg(test)]
|
||||||
warn!("Error loading soundtracks: {:?}", e);
|
mod tests {
|
||||||
Ok(SoundtrackCollection::default())
|
use super::*;
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_soundtracks() {
|
||||||
|
let _: AssetHandle<SoundtrackCollection<SoundtrackItem>> =
|
||||||
|
SoundtrackCollection::load_expect("voxygen.audio.soundtrack");
|
||||||
|
for event in CalendarEvent::iter() {
|
||||||
|
match event {
|
||||||
|
CalendarEvent::Halloween => {
|
||||||
|
let _: AssetHandle<SoundtrackCollection<SoundtrackItem>> =
|
||||||
|
SoundtrackCollection::load_expect(
|
||||||
|
"voxygen.audio.calendar.halloween.soundtrack",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
CalendarEvent::Christmas => {
|
||||||
|
let _: AssetHandle<SoundtrackCollection<SoundtrackItem>> =
|
||||||
|
SoundtrackCollection::load_expect(
|
||||||
|
"voxygen.audio.calendar.christmas.soundtrack",
|
||||||
|
);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user