diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 249d5894a76..3936912e013 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -846,61 +846,91 @@ class SongDifficulty { var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : ''; + if (characters.playerVocals != null) + { + // The metadata explicitly defines the list of voices. + var playerIds:Array = characters?.playerVocals ?? [characters.player]; + var playerVoices:Array = playerIds.map((id) -> Paths.voices(this.song.id, '-$id$suffix')); + var validVoices:Bool = true; + + // Check if all voice paths exist before returning + // If not, fallback to the default method for resolving voices + for (voice in playerVoices) + { + if (voice == null || !Assets.exists(voice)) validVoices = false; + } + if (validVoices) return playerVoices; + } + // Automatically resolve voices by removing suffixes. // For example, if `Voices-bf-car-erect.ogg` does not exist, check for `Voices-bf-erect.ogg`. // Then, check for `Voices-bf-car.ogg`, then `Voices-bf.ogg`. + var playerId:String = characters.player; + var playerVoice:String = Paths.voices(this.song.id, '-${playerId}$suffix'); - if (characters.playerVocals == null) + while (playerVoice != null && !Assets.exists(playerVoice)) { - var playerId:String = characters.player; - var playerVoice:String = Paths.voices(this.song.id, '-${playerId}$suffix'); - + // Remove the last suffix. + // For example, bf-car becomes bf. + playerId = playerId.split('-').slice(0, -1).join('-'); + // Try again. + playerVoice = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix'); + } + if (playerVoice == null) + { + // Try again without $suffix. + playerId = characters.player; + playerVoice = Paths.voices(this.song.id, '-${playerId}'); while (playerVoice != null && !Assets.exists(playerVoice)) { // Remove the last suffix. - // For example, bf-car becomes bf. playerId = playerId.split('-').slice(0, -1).join('-'); // Try again. playerVoice = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix'); } - if (playerVoice == null) - { - // Try again without $suffix. - playerId = characters.player; - playerVoice = Paths.voices(this.song.id, '-${playerId}'); - while (playerVoice != null && !Assets.exists(playerVoice)) - { - // Remove the last suffix. - playerId = playerId.split('-').slice(0, -1).join('-'); - // Try again. - playerVoice = playerId == '' ? null : Paths.voices(this.song.id, '-${playerId}$suffix'); - } - } - - return playerVoice != null ? [playerVoice] : []; } - else - { - // The metadata explicitly defines the list of voices. - var playerIds:Array = characters?.playerVocals ?? [characters.player]; - var playerVoices:Array = playerIds.map((id) -> Paths.voices(this.song.id, '-$id$suffix')); - return playerVoices; - } + return playerVoice != null ? [playerVoice] : []; } public function buildOpponentVoiceList():Array { var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : ''; + if (characters.opponentVocals != null) + { + // The metadata explicitly defines the list of voices. + var opponentIds:Array = characters?.opponentVocals ?? [characters.opponent]; + var opponentVoices:Array = opponentIds.map((id) -> Paths.voices(this.song.id, '-$id$suffix')); + var validVoices:Bool = true; + + // Check if all voice paths exist before returning + // If not, fallback to the default method for resolving voices + for (voice in opponentVoices) + { + if (voice == null || !Assets.exists(voice)) validVoices = false; + } + if (validVoices) return opponentVoices; + } + // Automatically resolve voices by removing suffixes. // For example, if `Voices-bf-car-erect.ogg` does not exist, check for `Voices-bf-erect.ogg`. // Then, check for `Voices-bf-car.ogg`, then `Voices-bf.ogg`. - if (characters.opponentVocals == null) + var opponentId:String = characters.opponent; + var opponentVoice:String = Paths.voices(this.song.id, '-${opponentId}$suffix'); + while (opponentVoice != null && !Assets.exists(opponentVoice)) + { + // Remove the last suffix. + opponentId = opponentId.split('-').slice(0, -1).join('-'); + // Try again. + opponentVoice = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix'); + } + if (opponentVoice == null) { - var opponentId:String = characters.opponent; - var opponentVoice:String = Paths.voices(this.song.id, '-${opponentId}$suffix'); + // Try again without $suffix. + opponentId = characters.opponent; + opponentVoice = Paths.voices(this.song.id, '-${opponentId}'); while (opponentVoice != null && !Assets.exists(opponentVoice)) { // Remove the last suffix. @@ -908,30 +938,9 @@ class SongDifficulty // Try again. opponentVoice = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix'); } - if (opponentVoice == null) - { - // Try again without $suffix. - opponentId = characters.opponent; - opponentVoice = Paths.voices(this.song.id, '-${opponentId}'); - while (opponentVoice != null && !Assets.exists(opponentVoice)) - { - // Remove the last suffix. - opponentId = opponentId.split('-').slice(0, -1).join('-'); - // Try again. - opponentVoice = opponentId == '' ? null : Paths.voices(this.song.id, '-${opponentId}$suffix'); - } - } - - return opponentVoice != null ? [opponentVoice] : []; } - else - { - // The metadata explicitly defines the list of voices. - var opponentIds:Array = characters?.opponentVocals ?? [characters.opponent]; - var opponentVoices:Array = opponentIds.map((id) -> Paths.voices(this.song.id, '-$id$suffix')); - return opponentVoices; - } + return opponentVoice != null ? [opponentVoice] : []; } /**