mirror of
https://github.com/D1GQ/BetterAmongUs.git
synced 2026-10-20 01:46:19 +00:00
Add ability for audio overrides
This commit is contained in:
1 parent
476441ec71
commit
99b8ecab04
5 files changed
+227
No files matched your search
@@ -9,6 +9,7 @@ using BetterAmongUs.Data.Config;
|
||||
using BetterAmongUs.Data.Json;
|
||||
using BetterAmongUs.Enums;
|
||||
using BetterAmongUs.Helpers;
|
||||
using BetterAmongUs.Managers;
|
||||
using BetterAmongUs.Modules;
|
||||
using BetterAmongUs.Modules.OptionItems;
|
||||
using BetterAmongUs.Modules.Support;
|
||||
@@ -153,6 +154,7 @@ internal class BAUPlugin : BasePlugin
|
||||
GithubAPI.Connect();
|
||||
BAUConfigs.LoadConfigs();
|
||||
BetterDataManager.Initialize();
|
||||
AudioOverrideManager.Initialize();
|
||||
Translator.Initialize();
|
||||
Harmony.PatchAll();
|
||||
GameSettingsPatch.SetupSettings(true);
|
||||
|
||||
@@ -25,6 +25,11 @@ internal static class BetterDataManager
|
||||
/// </summary>
|
||||
internal static readonly string starLightDataFolderPath = Environment.GetEnvironmentVariable("STAR_DATA_PATH") ?? string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Directory for audio overrides files.
|
||||
/// </summary>
|
||||
internal static readonly string audioOverridesFolderPath = Path.Combine(fileFolderPath, $"AudioOverrides");
|
||||
|
||||
/// <summary>
|
||||
/// Directory for save information files.
|
||||
/// </summary>
|
||||
|
||||
@@ -501,6 +501,80 @@ internal static class Utils
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads a WAV audio clip from a file on disk.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The full path to the WAV file.</param>
|
||||
/// <returns>An AudioClip containing the loaded WAV data, or null if loading fails.</returns>
|
||||
internal static AudioClip? LoadWavFromDisk(string filePath)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
Logger_.Error($"File not found: {filePath}");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Path.GetExtension(filePath).ToLower() != ".wav")
|
||||
{
|
||||
Logger_.Error("Only .wav files are supported.");
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
byte[] wavBytes = File.ReadAllBytes(filePath);
|
||||
if (wavBytes.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var audio = ToAudioClip(wavBytes);
|
||||
return audio;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger_.Error($"Failed to load WAV: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts raw WAV byte data into an AudioClip.
|
||||
/// </summary>
|
||||
/// <param name="wavBytes">The raw WAV file bytes.</param>
|
||||
/// <returns>An AudioClip containing the converted WAV data.</returns>
|
||||
internal static AudioClip ToAudioClip(byte[] wavBytes)
|
||||
{
|
||||
int sampleRate = BitConverter.ToInt32(wavBytes, 24);
|
||||
int channels = BitConverter.ToInt16(wavBytes, 22);
|
||||
int samples = BitConverter.ToInt32(wavBytes, 40) / 2;
|
||||
|
||||
int offset = 36;
|
||||
while (offset < wavBytes.Length - 8)
|
||||
{
|
||||
if (wavBytes[offset] == 'd' && wavBytes[offset + 1] == 'a' &&
|
||||
wavBytes[offset + 2] == 't' && wavBytes[offset + 3] == 'a')
|
||||
{
|
||||
offset += 4;
|
||||
offset += 4;
|
||||
break;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
float[] floatData = new float[samples];
|
||||
for (int i = 0; i < samples; i++)
|
||||
{
|
||||
short sample = BitConverter.ToInt16(wavBytes, offset + i * 2);
|
||||
floatData[i] = sample / 32768f;
|
||||
}
|
||||
|
||||
AudioClip clip = AudioClip.Create("LoadedWav", samples / channels, channels, sampleRate, false);
|
||||
clip.SetData(floatData, 0);
|
||||
clip.hideFlags = HideFlags.HideAndDontSave;
|
||||
|
||||
return clip;
|
||||
}
|
||||
|
||||
// Platform utilities
|
||||
/// <summary>
|
||||
/// Gets the platform name for a player.
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
using BetterAmongUs.Data;
|
||||
using BetterAmongUs.Helpers;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Manages audio override files and their corresponding AudioClip data.
|
||||
/// </summary>
|
||||
internal static class AudioOverrideManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection of all discovered audio override data instances.
|
||||
/// </summary>
|
||||
internal static readonly List<AudioOverrideData> Overrides = [];
|
||||
|
||||
internal static readonly AudioOverrideData Music_MainMenuSong = new("Music/MainMenuSong.wav");
|
||||
|
||||
internal static readonly AudioOverrideData Music_LobbySong = new("Music/LobbySong.wav");
|
||||
|
||||
internal static readonly AudioOverrideData Sounds_EmergencyMeeting = new("Sounds/Meeting/EmergencyMeeting.wav");
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the AudioOverrideManager by discovering all AudioOverrideData fields,
|
||||
/// </summary>
|
||||
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))
|
||||
.Select(f => f.GetValue(null) as AudioOverrideData)
|
||||
.Where(v => v != null);
|
||||
|
||||
Overrides.Clear();
|
||||
foreach (var overrideData in infoFields)
|
||||
{
|
||||
if (overrideData != null)
|
||||
{
|
||||
Overrides.Add(overrideData);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var overrideInfo in Overrides)
|
||||
{
|
||||
overrideInfo.Load();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an audio override file with its path and loaded AudioClip.
|
||||
/// </summary>
|
||||
/// <param name="path">The relative path to the audio file within the audio overrides folder.</param>
|
||||
internal sealed class AudioOverrideData(string path)
|
||||
{
|
||||
private readonly string _path = path;
|
||||
private AudioClip? audioClip;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the original audio clip associated with this instance.
|
||||
/// </summary>
|
||||
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()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_path)) return;
|
||||
|
||||
var fullPath = Path.Combine(BetterDataManager.Folders.audioOverridesFolderPath, _path);
|
||||
if (!Directory.Exists(fullPath))
|
||||
{
|
||||
string? directoryPath = Path.GetDirectoryName(fullPath);
|
||||
if (directoryPath == null) return;
|
||||
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
}
|
||||
if (!File.Exists(fullPath))
|
||||
{
|
||||
File.Create(fullPath).Close();
|
||||
}
|
||||
audioClip = Utils.LoadWavFromDisk(fullPath);
|
||||
if (audioClip != null)
|
||||
{
|
||||
audioClip.name = "Override_" + Path.GetFileNameWithoutExtension(_path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
if (audioClip != null)
|
||||
{
|
||||
clip = audioClip;
|
||||
return true;
|
||||
}
|
||||
|
||||
clip = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using HarmonyLib;
|
||||
|
||||
namespace BetterAmongUs.Patches.Client;
|
||||
|
||||
[HarmonyPatch]
|
||||
internal static class AudioOverridePatch
|
||||
{
|
||||
[HarmonyPatch(typeof(SoundStarter), nameof(SoundStarter.Awake))]
|
||||
[HarmonyPrefix]
|
||||
private static void SoundStarter_Awake_Prefix(SoundStarter __instance)
|
||||
{
|
||||
if (__instance.gameObject.name == "MainMenuBgMusic")
|
||||
{
|
||||
if (AudioOverrideManager.Music_MainMenuSong.TryGetAudioClip(out var audio))
|
||||
{
|
||||
__instance.SoundToPlay = audio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(LobbyBehaviour), nameof(LobbyBehaviour.Start))]
|
||||
[HarmonyPrefix]
|
||||
private static void LobbyBehaviour_Start_Prefix(LobbyBehaviour __instance)
|
||||
{
|
||||
if (AudioOverrideManager.Music_LobbySong.TryGetAudioClip(out var audio))
|
||||
{
|
||||
__instance.MapTheme = audio;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(MeetingCalledAnimation), nameof(MeetingCalledAnimation.CoShow))]
|
||||
[HarmonyPrefix]
|
||||
private static void MeetingCalledAnimation_CoShow_Prefix(MeetingCalledAnimation __instance)
|
||||
{
|
||||
if (AudioOverrideManager.Sounds_EmergencyMeeting.TryGetAudioClip(out var audio))
|
||||
{
|
||||
__instance.Stinger = audio;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user