Add more audio overrides

This commit is contained in:
D1GQ committed 2026-04-06 22:23:20 -05:00
1 parent 99b8ecab04
commit 239adc583b
3 files changed
+170 -14

No files matched your search

+21
View File
@@ -575,6 +575,27 @@ internal static class Utils
return clip;
}
/// <summary>
/// Generates a normalized directory path by combining folder names from a delimited string.
/// </summary>
/// <param name="path">A string containing folder names separated by the specified separator character. Folder names must not be empty.</param>
/// <param name="separator">The character used to separate folder names in the input string. Defaults to '/'.</param>
/// <returns>A directory path constructed by combining the non-empty folder names from the input string, using the system's
/// directory separator character.</returns>
internal static string GenerateDirectoryPath(string path, char separator = '/')
{
string[] folders = path.Split(separator);
string currentPath = "";
foreach (string folder in folders)
{
if (!string.IsNullOrEmpty(folder))
{
currentPath = Path.Combine(currentPath, folder);
}
}
return currentPath;
}
// Platform utilities
/// <summary>
/// Gets the platform name for a player.
+103 -13
View File
@@ -13,21 +13,37 @@ internal static class AudioOverrideManager
/// </summary>
internal static readonly List<AudioOverrideData> Overrides = [];
internal static readonly AudioOverrideData Music_MainMenuSong = new("Music/MainMenuSong.wav");
internal static readonly AudioOverrideData Music_MainMenuSong = new("Music", "MainMenuSong.wav");
internal static readonly AudioOverrideData Music_LobbySong = new("Music/LobbySong.wav");
internal static readonly AudioOverrideData Music_LobbySong = new("Music", "LobbySong.wav");
internal static readonly AudioOverrideData Sounds_EmergencyMeeting = new("Sounds/Meeting/EmergencyMeeting.wav");
internal static readonly MapAudioOverrideData Sounds_VentEnter = new("Sounds/Gameplay", "VentEnter.wav");
internal static readonly MapAudioOverrideData Sounds_VentExit = new("Sounds/Gameplay", "VentExit.wav");
internal static readonly MapAudioOverrideData Sounds_SabotageAlert = new("Sounds/Gameplay", "SabotageAlert.wav");
internal static readonly AudioOverrideData Sounds_EmergencyMeetingStart = new("Sounds/Meeting", "EmergencyMeetingStart.wav");
internal static readonly AudioOverrideData Sounds_EmergencyMeetingVote = new("Sounds/Meeting", "EmergencyMeetingVote.wav");
internal static readonly AudioOverrideData Sounds_EmergencyMeetingVoteLockin = new("Sounds/Meeting", "EmergencyMeetingLockin.wav");
internal static readonly AudioOverrideData Sounds_EmergencyMeetingEnd = new("Sounds/Meeting", "EmergencyMeetingEnd.wav");
/// <summary>
/// Initializes the AudioOverrideManager by discovering all AudioOverrideData fields,
/// Initializes the AudioOverrideManager by discovering all AudioOverrideData fields and loading their audio clips.
/// </summary>
/// <remarks>
/// This method scans all static fields in AudioOverrideManager that inherit from AudioOverrideData,
/// adds them to the Overrides collection, and loads their associated audio files from disk.
/// </remarks>
internal static void Initialize()
{
// Discover all AudioOverrideInfo fields
var infoFields = typeof(AudioOverrideManager)
.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
.Where(f => f.FieldType == typeof(AudioOverrideData))
.Where(f => typeof(AudioOverrideData).IsAssignableFrom(f.FieldType))
.Select(f => f.GetValue(null) as AudioOverrideData)
.Where(v => v != null);
@@ -48,22 +64,25 @@ internal static class AudioOverrideManager
/// <summary>
/// Represents an audio override file with its path and loaded AudioClip.
/// Provides functionality for loading custom audio files from the file system.
/// </summary>
/// <param name="path">The relative path to the audio file within the audio overrides folder.</param>
internal sealed class AudioOverrideData(string path)
/// <param name="folderPath">The relative folder path to the audio file within the audio overrides directory.</param>
/// <param name="fileName">The name of the audio file, including extension.</param>
internal class AudioOverrideData(string folderPath, string fileName)
{
private readonly string _path = path;
private readonly string _path = Path.Combine(Utils.GenerateDirectoryPath(folderPath), fileName);
private AudioClip? audioClip;
/// <summary>
/// Gets or sets the original audio clip associated with this instance.
/// Gets or sets the original audio clip that this override replaces.
/// </summary>
/// <value>The original game audio clip, or null if not set.</value>
internal AudioClip? Original;
/// <summary>
/// Loads the audio clip from disk. Creates the file and directory structure if they don't exist.
/// </summary>
internal void Load()
internal virtual void Load()
{
if (string.IsNullOrEmpty(_path)) return;
@@ -89,9 +108,9 @@ internal static class AudioOverrideManager
/// <summary>
/// Attempts to retrieve the loaded AudioClip.
/// </summary>
/// <param name="clip">The AudioClip if loaded and available; otherwise, null.</param>
/// <returns>True if the AudioClip is available; otherwise, false.</returns>
internal bool TryGetAudioClip(out AudioClip? clip)
/// <param name="clip">When this method returns, contains the loaded AudioClip if successful; otherwise, null.</param>
/// <returns>True if the AudioClip is available and loaded; otherwise, false.</returns>
internal virtual bool TryGetAudioClip(out AudioClip? clip)
{
if (audioClip != null)
{
@@ -102,5 +121,76 @@ internal static class AudioOverrideManager
clip = null;
return false;
}
/// <summary>
/// Determines whether an audio clip is currently associated with this instance.
/// </summary>
/// <returns><see langword="true"/> if an audio clip is loaded and present; otherwise, <see langword="false"/>.</returns>
internal virtual bool HasAudioClip()
{
return audioClip != null;
}
}
/// <summary>
/// Represents a map specific audio override that loads different audio files for different maps.
/// </summary>
/// <param name="folderPath">The relative folder path to the audio files within the audio overrides directory.</param>
/// <param name="fileName">The base name of the audio file, which will be prefixed with map names.</param>
internal sealed class MapAudioOverrideData(string folderPath, string fileName) : AudioOverrideData(folderPath, fileName)
{
/// <summary>
/// Enumeration of map types for audio override categorization.
/// </summary>
private enum MapTyped
{
Ships,
MiraHQ,
Polus,
Fungle
}
private readonly string _folderPath = folderPath;
private readonly string _fileName = fileName;
private readonly Dictionary<MapTyped, AudioOverrideData> audioOverrideDatas = [];
/// <summary>
/// Loads map specific audio overrides for all supported map types.
/// </summary>
internal override void Load()
{
foreach (var map in Enum.GetValues(typeof(ShipStatus.MapType)))
{
if (map is ShipStatus.MapType mapType)
{
var audioData = new AudioOverrideData(Path.Combine(Utils.GenerateDirectoryPath(_folderPath), Path.GetFileNameWithoutExtension(_fileName)), $"{(MapTyped)mapType}_" + _fileName);
audioOverrideDatas[(MapTyped)mapType] = audioData;
audioData.Load();
}
}
}
/// <summary>
/// Attempts to retrieve the map appropriate AudioClip based on the currently active map.
/// </summary>
/// <param name="clip">When this method returns, contains the map specific AudioClip if successful; otherwise, null.</param>
/// <returns>True if a map-specific AudioClip is available for the current map; otherwise, false.</returns>
internal override bool TryGetAudioClip(out AudioClip? clip)
{
if (ShipStatus.Instance != null)
{
if (audioOverrideDatas.TryGetValue((MapTyped)ShipStatus.Instance.Type, out var audioData))
{
if (audioData.TryGetAudioClip(out var audio))
{
clip = audio;
return true;
}
}
}
clip = null;
return false;
}
}
}
+46 -1
View File
@@ -32,9 +32,54 @@ internal static class AudioOverridePatch
[HarmonyPrefix]
private static void MeetingCalledAnimation_CoShow_Prefix(MeetingCalledAnimation __instance)
{
if (AudioOverrideManager.Sounds_EmergencyMeeting.TryGetAudioClip(out var audio))
if (AudioOverrideManager.Sounds_EmergencyMeetingStart.TryGetAudioClip(out var audio))
{
__instance.Stinger = audio;
}
}
[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Awake))]
[HarmonyPrefix]
private static void MeetingHud_Awake_Prefix(MeetingHud __instance)
{
if (AudioOverrideManager.Sounds_EmergencyMeetingVote.TryGetAudioClip(out var vote))
{
__instance.VoteSound = vote;
}
if (AudioOverrideManager.Sounds_EmergencyMeetingVoteLockin.TryGetAudioClip(out var lockin))
{
__instance.VoteLockinSound = lockin;
}
if (AudioOverrideManager.Sounds_EmergencyMeetingEnd.TryGetAudioClip(out var end))
{
__instance.VoteEndingSound = end;
}
}
[HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.Awake))]
[HarmonyPostfix]
private static void ShipStatus_Awake_Postfix(ShipStatus __instance)
{
if (__instance.VentExitSound == null)
{
__instance.VentExitSound = __instance.VentEnterSound;
}
if (AudioOverrideManager.Sounds_VentEnter.TryGetAudioClip(out var ventEnter))
{
__instance.VentEnterSound = ventEnter;
}
if (AudioOverrideManager.Sounds_VentExit.TryGetAudioClip(out var ventExit))
{
__instance.VentExitSound = ventExit;
}
if (AudioOverrideManager.Sounds_SabotageAlert.TryGetAudioClip(out var sabo))
{
__instance.SabotageSound = sabo;
}
}
}