mirror of
https://github.com/TheJordanDev/PEAK-JordanMod.git
synced 2026-10-17 08:05:25 +02:00
0.1.9 | Centralized Audio loading & BingBong voices
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -15,14 +16,26 @@ class AudioSyncService
|
||||
{
|
||||
public static string API_BASE_URL => ConfigHandler.BugleSoundAPIURL.Value;
|
||||
|
||||
private static AudioSyncService? Instance { get; set; }
|
||||
public static AudioSyncService GetInstance()
|
||||
public async static Task<bool> DownloadAPIAudio(APIAudioFormat apiAudio, string SoundsDirectory, Song? existingSong = null)
|
||||
{
|
||||
Instance ??= new AudioSyncService();
|
||||
return Instance;
|
||||
bool success = true;
|
||||
try
|
||||
{
|
||||
if (existingSong != null && apiAudio.Filename != existingSong.Name)
|
||||
{
|
||||
File.Delete(Path.Combine(SoundsDirectory, $"{existingSong.Name}.{existingSong.Extension}"));
|
||||
}
|
||||
await apiAudio.DownloadToFolder(SoundsDirectory);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"Failed to download API audio: {ex.Message}");
|
||||
success = false;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
public List<APIAudioFormat> GetAudioClips()
|
||||
public static List<APIAudioFormat> GetAudioClips()
|
||||
{
|
||||
List<APIAudioFormat> audioClips = [];
|
||||
|
||||
@@ -48,6 +61,19 @@ class AudioSyncService
|
||||
return audioClips;
|
||||
}
|
||||
|
||||
public static void ClearAudioClips()
|
||||
{
|
||||
foreach (Song song in Song.Sounds.Values.ToList())
|
||||
{
|
||||
song.Dispose();
|
||||
}
|
||||
Song.Sounds.Clear();
|
||||
Song.SoundsByHash.Clear();
|
||||
Song.Songs.Clear();
|
||||
Song.BB_VoiceLines.Clear();
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
public class APIAudioFormat
|
||||
{
|
||||
[JsonProperty("_id")]
|
||||
@@ -105,6 +131,164 @@ class AudioSyncService
|
||||
|
||||
}
|
||||
|
||||
class AudioSyncWorker
|
||||
{
|
||||
|
||||
private static AudioSyncWorker? Instance { get; set; }
|
||||
public static AudioSyncWorker GetInstance()
|
||||
{
|
||||
Instance ??= new AudioSyncWorker();
|
||||
return Instance;
|
||||
}
|
||||
|
||||
public static readonly string SoundsDirectory = Path.Combine(BepInEx.Paths.BepInExRootPath, "bugleSounds");
|
||||
public static readonly Dictionary<string, AudioType> AudioTypes = new()
|
||||
{
|
||||
{ "wav", AudioType.WAV },
|
||||
{ "mp3", AudioType.MPEG },
|
||||
{ "ogg", AudioType.OGGVORBIS },
|
||||
{ "aiff", AudioType.AIFF },
|
||||
};
|
||||
|
||||
public static bool IsLoading = false;
|
||||
public static bool IsSyncing = false;
|
||||
|
||||
public static int CurrentSongIndex = 0;
|
||||
public static string CurrentSongName = "None";
|
||||
|
||||
public static Action? OnAudioLoadComplete;
|
||||
|
||||
public static void GetAudioClips()
|
||||
{
|
||||
if (IsLoading || IsSyncing) return;
|
||||
if (!Directory.Exists(SoundsDirectory)) return;
|
||||
IsLoading = true;
|
||||
Plugin.Instance.StartCoroutine(LoadAllAudioClipsCoroutine(SoundsDirectory));
|
||||
}
|
||||
|
||||
public static void TrySyncAndLoadAudioClips()
|
||||
{
|
||||
if (IsLoading || IsSyncing) return;
|
||||
Task.Run(() =>
|
||||
{
|
||||
SyncAndLoadAudioClipsCoroutine().GetAwaiter().GetResult();
|
||||
});
|
||||
}
|
||||
|
||||
private static IEnumerator LoadAllAudioClipsCoroutine(string directoryPath, string[]? forceReload = null)
|
||||
{
|
||||
List<(string filePath, string ext, string name)> filesToLoad = new();
|
||||
|
||||
foreach (var ext in AudioTypes.Keys)
|
||||
{
|
||||
var files = Directory.GetFiles(directoryPath, $"*.{ext}");
|
||||
foreach (var file in files)
|
||||
{
|
||||
string name = Path.GetFileNameWithoutExtension(file);
|
||||
bool shouldForceReload = forceReload != null && forceReload.Contains($"{name}.{ext}");
|
||||
if (!Song.Sounds.ContainsKey(name) || shouldForceReload)
|
||||
{
|
||||
filesToLoad.Add((file, ext, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int BATCH_SIZE = 2;
|
||||
int loadedCount = 0;
|
||||
|
||||
for (int i = 0; i < filesToLoad.Count; i += BATCH_SIZE)
|
||||
{
|
||||
List<Coroutine> loadCoroutines = [];
|
||||
|
||||
for (int j = i; j < i + Math.Min(BATCH_SIZE, filesToLoad.Count - i) && j < filesToLoad.Count; j++)
|
||||
{
|
||||
var (filePath, ext, name) = filesToLoad[j];
|
||||
bool forceReloadClip = forceReload != null && forceReload.Contains($"{name}.{ext}");
|
||||
Coroutine loadCoroutine = Plugin.Instance.StartCoroutine(LoadAudioClipCoroutine(filePath, ext, name, forceReloadClip));
|
||||
loadCoroutines.Add(loadCoroutine);
|
||||
}
|
||||
|
||||
foreach (var coroutine in loadCoroutines) yield return coroutine;
|
||||
loadedCount += loadCoroutines.Count;
|
||||
BetterBugleUI.Instance?.ShowActionbar($"Loading audio clips... {loadedCount}/{filesToLoad.Count}");
|
||||
}
|
||||
OnAudioLoadComplete?.Invoke();
|
||||
IsLoading = false;
|
||||
}
|
||||
|
||||
private static IEnumerator LoadAudioClipCoroutine(string filePath, string ext, string name, bool forceReload = false)
|
||||
{
|
||||
using UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip($"file://{filePath}", AudioTypes[ext]);
|
||||
yield return www.SendWebRequest();
|
||||
|
||||
if (www.result != UnityWebRequest.Result.Success) yield break;
|
||||
|
||||
bool songExists = Song.Sounds.ContainsKey(name);
|
||||
|
||||
if (songExists && !forceReload) yield break;
|
||||
|
||||
if (songExists && forceReload)
|
||||
{
|
||||
Song? previousSong = Song.Sounds.TryGetValue(name, out var existingSong) ? existingSong : null;
|
||||
previousSong?.Dispose();
|
||||
}
|
||||
|
||||
AudioClip audioClip = DownloadHandlerAudioClip.GetContent(www);
|
||||
if (audioClip == null) yield break;
|
||||
|
||||
Song song = new(name, ext, filePath, audioClip);
|
||||
song.Register();
|
||||
}
|
||||
|
||||
private static async Task SyncAndLoadAudioClipsCoroutine()
|
||||
{
|
||||
if (IsLoading || IsSyncing) return;
|
||||
IsSyncing = true;
|
||||
Dictionary<AudioSyncService.APIAudioFormat, Song?> toDownload = new();
|
||||
|
||||
string[] existingSongNames = [.. Song.Sounds.Keys];
|
||||
AudioSyncService.APIAudioFormat[] existingAPIFormats = [.. AudioSyncService.GetAudioClips()];
|
||||
string[] apiExistingNames = [.. existingAPIFormats.Select(apiAudio => apiAudio.Filename)];
|
||||
|
||||
var songsToRemove = existingSongNames.Except(apiExistingNames).ToArray();
|
||||
foreach (var songName in songsToRemove)
|
||||
{
|
||||
if (Song.Sounds.TryGetValue(songName, out var songToDispose))
|
||||
{
|
||||
songToDispose.Dispose();
|
||||
songToDispose.DeleteFile();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (AudioSyncService.APIAudioFormat apiAudio in existingAPIFormats)
|
||||
{
|
||||
Song? existingSong = Song.SoundsByHash.GetValueOrDefault(apiAudio.Hash);
|
||||
if (existingSong == null || existingSong.Hash != apiAudio.Hash)
|
||||
{
|
||||
toDownload.Add(apiAudio, existingSong);
|
||||
}
|
||||
}
|
||||
|
||||
BetterBugleUI.Instance?.ShowActionbar($"Syncing audio bank... {toDownload.Count} changed/new files found.");
|
||||
|
||||
string[] filesToOverload = [];
|
||||
|
||||
foreach (AudioSyncService.APIAudioFormat apiAudio in toDownload.Keys)
|
||||
{
|
||||
bool success = await AudioSyncService.DownloadAPIAudio(apiAudio, SoundsDirectory, toDownload[apiAudio]);
|
||||
if (success)
|
||||
{
|
||||
Debug.Log($"Successfully downloaded audio: {apiAudio.Filename}.{apiAudio.Extension}, adding to forceload");
|
||||
filesToOverload = [.. filesToOverload, $"{apiAudio.Filename}.{apiAudio.Extension}"];
|
||||
}
|
||||
}
|
||||
IsSyncing = false;
|
||||
IsLoading = true;
|
||||
Plugin.Instance.StartCoroutine(LoadAllAudioClipsCoroutine(SoundsDirectory, filesToOverload));
|
||||
}
|
||||
}
|
||||
|
||||
public class Song : IDisposable
|
||||
{
|
||||
public static readonly Dictionary<string, Song> Sounds = new();
|
||||
@@ -180,7 +364,7 @@ public class Song : IDisposable
|
||||
public void DeleteFile()
|
||||
{
|
||||
if (AudioClip == null) return;
|
||||
var filePath = Path.Combine(BetterBugleModule.SoundsDirectory, $"{Name}.{Extension}");
|
||||
var filePath = Path.Combine(AudioSyncWorker.SoundsDirectory, $"{Name}.{Extension}");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
|
||||
Reference in New Issue
Block a user