mirror of
https://github.com/TheJordanDev/PEAK-JordanMod.git
synced 2026-10-16 23:56:44 +02:00
0.1.9 | Centralized Audio loading & BingBong voices
This commit is contained in:
@@ -41,4 +41,9 @@
|
|||||||
|
|
||||||
# v0.1.8 | Changed dependencies
|
# v0.1.8 | Changed dependencies
|
||||||
|
|
||||||
- Added ModConfig and PeakPresence (my mod), Updated BepInEx
|
- Added ModConfig and PeakPresence (my mod), Updated BepInEx
|
||||||
|
|
||||||
|
# v0.1.9 | AudioSyncWorker & Dynamic BingBong voices
|
||||||
|
|
||||||
|
- Centralized Audio loading in Worker class
|
||||||
|
- Now load BingBong voicelines dynamically after Sound reloads.
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<!-- This is the display name of your mod. Example: BepInEx Template -->
|
<!-- This is the display name of your mod. Example: BepInEx Template -->
|
||||||
<AssemblyTitle>JordanMod</AssemblyTitle>
|
<AssemblyTitle>JordanMod</AssemblyTitle>
|
||||||
<!-- This is the version number of your mod. -->
|
<!-- This is the version number of your mod. -->
|
||||||
<Version>0.1.8</Version>
|
<Version>0.1.9</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -24,19 +24,6 @@ class BetterBugleModule : Module
|
|||||||
public override string ModuleName => "BetterBugle";
|
public override string ModuleName => "BetterBugle";
|
||||||
public static readonly string bugleItemName = "Bugle";
|
public static readonly string bugleItemName = "Bugle";
|
||||||
|
|
||||||
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 { get; private set; } = false;
|
|
||||||
public static bool IsSyncing { get; private set; } = false;
|
|
||||||
public static int CurrentSongIndex { get; set; } = 0;
|
|
||||||
public static string CurrentSongName { get; set; } = "None";
|
|
||||||
public static bool HadConfirmation { get; set; } = false;
|
public static bool HadConfirmation { get; set; } = false;
|
||||||
|
|
||||||
public static bool IsPlaying = false;
|
public static bool IsPlaying = false;
|
||||||
@@ -51,9 +38,10 @@ class BetterBugleModule : Module
|
|||||||
{
|
{
|
||||||
if (Instance != null) return;
|
if (Instance != null) return;
|
||||||
Instance = this;
|
Instance = this;
|
||||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
|
||||||
ManageLocalizedText();
|
ManageLocalizedText();
|
||||||
GetAudioClips();
|
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||||
|
AudioSyncWorker.OnAudioLoadComplete += OnAllAudioClipsLoaded;
|
||||||
|
AudioSyncWorker.GetAudioClips();
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,13 +49,13 @@ class BetterBugleModule : Module
|
|||||||
{
|
{
|
||||||
if (Input.GetKeyDown(ConfigHandler.SyncAudioRepository.Value))
|
if (Input.GetKeyDown(ConfigHandler.SyncAudioRepository.Value))
|
||||||
{
|
{
|
||||||
Instance?.TrySyncAndLoadAudioClips();
|
AudioSyncWorker.TrySyncAndLoadAudioClips();
|
||||||
}
|
}
|
||||||
if (Input.GetKeyDown(ConfigHandler.FavoriteSongToggleKey.Value))
|
if (Input.GetKeyDown(ConfigHandler.FavoriteSongToggleKey.Value))
|
||||||
{
|
{
|
||||||
if (Character.localCharacter == null) return;
|
if (Character.localCharacter == null) return;
|
||||||
if (Song.Songs.Count == 0) return;
|
if (Song.Songs.Count == 0) return;
|
||||||
if (!Song.Songs.ContainsKey(CurrentSongName)) return;
|
if (!Song.Songs.ContainsKey(AudioSyncWorker.CurrentSongName)) return;
|
||||||
Character character = Character.localCharacter;
|
Character character = Character.localCharacter;
|
||||||
|
|
||||||
Optionable<byte> selectedSlot = character.refs.items.currentSelectedSlot;
|
Optionable<byte> selectedSlot = character.refs.items.currentSelectedSlot;
|
||||||
@@ -82,7 +70,7 @@ class BetterBugleModule : Module
|
|||||||
List<string> supportedItemNames = ["Bugle", "Bugle_Magic", "Megaphone"];
|
List<string> supportedItemNames = ["Bugle", "Bugle_Magic", "Megaphone"];
|
||||||
if (!supportedItemNames.Contains(item.UIData.itemName)) return;
|
if (!supportedItemNames.Contains(item.UIData.itemName)) return;
|
||||||
|
|
||||||
Song? currentSong = Song.Songs.GetValueOrDefault(CurrentSongName);
|
Song? currentSong = Song.Songs.GetValueOrDefault(AudioSyncWorker.CurrentSongName);
|
||||||
if (currentSong == null) return;
|
if (currentSong == null) return;
|
||||||
|
|
||||||
if (Song.FavoriteSongs.Contains(currentSong.Name))
|
if (Song.FavoriteSongs.Contains(currentSong.Name))
|
||||||
@@ -113,7 +101,7 @@ class BetterBugleModule : Module
|
|||||||
|
|
||||||
public override void Destroy()
|
public override void Destroy()
|
||||||
{
|
{
|
||||||
ClearAudioClips();
|
AudioSyncService.ClearAudioClips();
|
||||||
base.Destroy();
|
base.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,105 +117,6 @@ class BetterBugleModule : Module
|
|||||||
LocalizedText.mainTable.Add("CHANGE_SONG", scrollActionLocalizations);
|
LocalizedText.mainTable.Add("CHANGE_SONG", scrollActionLocalizations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetAudioClips()
|
|
||||||
{
|
|
||||||
if (IsLoading || IsSyncing) return;
|
|
||||||
if (!Directory.Exists(SoundsDirectory)) return;
|
|
||||||
IsLoading = true;
|
|
||||||
Plugin.Instance.StartCoroutine(LoadAllAudioClipsCoroutine(SoundsDirectory));
|
|
||||||
}
|
|
||||||
private void ClearAudioClips()
|
|
||||||
{
|
|
||||||
foreach (Song song in Song.Songs.Values.ToList())
|
|
||||||
{
|
|
||||||
song.Dispose();
|
|
||||||
}
|
|
||||||
Song.Sounds.Clear();
|
|
||||||
Song.SoundsByHash.Clear();
|
|
||||||
Song.Songs.Clear();
|
|
||||||
Song.BB_VoiceLines.Clear();
|
|
||||||
GC.Collect();
|
|
||||||
}
|
|
||||||
private 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.Songs.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 = new();
|
|
||||||
|
|
||||||
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}");
|
|
||||||
}
|
|
||||||
OnAllAudioClipsLoaded();
|
|
||||||
}
|
|
||||||
private IEnumerator LoadAudioClipCoroutine(string filePath, string ext, string name, bool forceReload = false)
|
|
||||||
{
|
|
||||||
|
|
||||||
Debug.Log($"Loading audio clip: {name}.{ext} from {filePath}" + (forceReload ? " (forced reload)" : ""));
|
|
||||||
|
|
||||||
using UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip($"file://{filePath}", AudioTypes[ext]);
|
|
||||||
yield return www.SendWebRequest();
|
|
||||||
|
|
||||||
if (www.result != UnityWebRequest.Result.Success)
|
|
||||||
{
|
|
||||||
Debug.LogError($"Failed to load audio clip from {filePath}: {www.error}");
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool songExists = Song.Songs.ContainsKey(name);
|
|
||||||
|
|
||||||
Debug.Log($"Audio clip '{name}' exists: {songExists}. Force reload: {forceReload}");
|
|
||||||
|
|
||||||
if (songExists && !forceReload)
|
|
||||||
{
|
|
||||||
Debug.LogWarning($"Audio clip with name '{name}' already exists. Skipping duplicate.");
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (songExists && forceReload)
|
|
||||||
{
|
|
||||||
Song? previousSong = Song.Songs.TryGetValue(name, out var existingSong) ? existingSong : null;
|
|
||||||
previousSong?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioClip audioClip = DownloadHandlerAudioClip.GetContent(www);
|
|
||||||
if (audioClip == null)
|
|
||||||
{
|
|
||||||
Debug.LogError($"Failed to load audio clip from {filePath}: {www.error}");
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Song song = new(name, ext, filePath, audioClip);
|
|
||||||
song.Register();
|
|
||||||
Debug.Log($"Loaded audio clip: {name} from {filePath}");
|
|
||||||
}
|
|
||||||
private void OnAllAudioClipsLoaded()
|
private void OnAllAudioClipsLoaded()
|
||||||
{
|
{
|
||||||
if (Song.Songs.Count == 0) Debug.LogWarning("No songs loaded. Please ensure audio files are in the Sounds directory.");
|
if (Song.Songs.Count == 0) Debug.LogWarning("No songs loaded. Please ensure audio files are in the Sounds directory.");
|
||||||
@@ -239,86 +128,10 @@ class BetterBugleModule : Module
|
|||||||
if (Song.Songs.ContainsKey(songKeyName) && !Song.FavoriteSongs.Contains(songKeyName))
|
if (Song.Songs.ContainsKey(songKeyName) && !Song.FavoriteSongs.Contains(songKeyName))
|
||||||
Song.FavoriteSongs.Add(songKeyName);
|
Song.FavoriteSongs.Add(songKeyName);
|
||||||
|
|
||||||
if (!Song.Songs.ContainsKey(CurrentSongName))
|
if (!Song.Songs.ContainsKey(AudioSyncWorker.CurrentSongName))
|
||||||
CurrentSongName = Song.GetSongNames_Alphabetically()[CurrentSongIndex];
|
AudioSyncWorker.CurrentSongName = Song.GetSongNames_Alphabetically()[AudioSyncWorker.CurrentSongIndex];
|
||||||
|
|
||||||
IsLoading = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TrySyncAndLoadAudioClips()
|
|
||||||
{
|
|
||||||
if (IsLoading || IsSyncing) return;
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
SyncAndLoadAudioClipsCoroutine().GetAwaiter().GetResult();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
private async Task SyncAndLoadAudioClipsCoroutine()
|
|
||||||
{
|
|
||||||
if (IsLoading || IsSyncing) return;
|
|
||||||
IsSyncing = true;
|
|
||||||
AudioSyncService audioSyncService = AudioSyncService.GetInstance();
|
|
||||||
Dictionary<AudioSyncService.APIAudioFormat, Song?> toDownload = new();
|
|
||||||
|
|
||||||
string[] existingSongNames = Song.Songs.Keys.ToArray();
|
|
||||||
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.Songs.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 DownloadAPIAudio(apiAudio, 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));
|
|
||||||
}
|
|
||||||
private async Task<bool> DownloadAPIAudio(AudioSyncService.APIAudioFormat apiAudio, Song? existingSong = null)
|
|
||||||
{
|
|
||||||
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 class BetterBugleSFX : MonoBehaviourPun
|
public class BetterBugleSFX : MonoBehaviourPun
|
||||||
@@ -347,7 +160,7 @@ public class BetterBugleSFX : MonoBehaviourPun
|
|||||||
audioSource.volume = 0f;
|
audioSource.volume = 0f;
|
||||||
audioSource.loop = true;
|
audioSource.loop = true;
|
||||||
if (IsLocal()) BetterBugleModule.CurrentAudioSource = audioSource;
|
if (IsLocal()) BetterBugleModule.CurrentAudioSource = audioSource;
|
||||||
song = Song.Songs.GetValueOrDefault(BetterBugleModule.CurrentSongName);
|
song = Song.Songs.GetValueOrDefault(AudioSyncWorker.CurrentSongName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsLocal()
|
private bool IsLocal()
|
||||||
@@ -393,7 +206,7 @@ public class BetterBugleSFX : MonoBehaviourPun
|
|||||||
|
|
||||||
if (flag != hold)
|
if (flag != hold)
|
||||||
{
|
{
|
||||||
if (flag) photonView.RPC("RPC_StartBetterToot", RpcTarget.All, BetterBugleModule.CurrentSongName);
|
if (flag) photonView.RPC("RPC_StartBetterToot", RpcTarget.All, AudioSyncWorker.CurrentSongName);
|
||||||
else photonView.RPC("RPC_StopBetterToot", RpcTarget.All);
|
else photonView.RPC("RPC_StopBetterToot", RpcTarget.All);
|
||||||
hold = flag;
|
hold = flag;
|
||||||
}
|
}
|
||||||
@@ -526,7 +339,7 @@ public class BetterBugleUI : MonoBehaviour
|
|||||||
{
|
{
|
||||||
if (customStyle == null) return;
|
if (customStyle == null) return;
|
||||||
if (BetterBugleModule.CurrentAudioSource == null || !BetterBugleModule.IsPlaying) return;
|
if (BetterBugleModule.CurrentAudioSource == null || !BetterBugleModule.IsPlaying) return;
|
||||||
Song? currentAudio = Song.Songs.FirstOrDefault(s => s.Value.Name == BetterBugleModule.CurrentSongName).Value;
|
Song? currentAudio = Song.Songs.FirstOrDefault(s => s.Value.Name == AudioSyncWorker.CurrentSongName).Value;
|
||||||
if (currentAudio == null || BetterBugleModule.CurrentAudioSource.clip == null) return;
|
if (currentAudio == null || BetterBugleModule.CurrentAudioSource.clip == null) return;
|
||||||
|
|
||||||
float MAX_WIDTH = Screen.width - (offsetX * 2);
|
float MAX_WIDTH = Screen.width - (offsetX * 2);
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using JordanMod.Utils;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.InputSystem;
|
||||||
|
|
||||||
namespace JordanMod.Modules.ReplaceBingBong;
|
namespace JordanMod.Modules.ReplaceBingBong;
|
||||||
|
|
||||||
@@ -6,6 +11,9 @@ namespace JordanMod.Modules.ReplaceBingBong;
|
|||||||
class ReplaceBingBongModule : Module
|
class ReplaceBingBongModule : Module
|
||||||
{
|
{
|
||||||
public override string ModuleName => "Replace BingBong Module";
|
public override string ModuleName => "Replace BingBong Module";
|
||||||
|
|
||||||
|
public static bool HasReplacedSounds = false;
|
||||||
|
public static BingBongResponseData[] OriginalResponsesData = [];
|
||||||
|
|
||||||
public override Type[] GetPatches()
|
public override Type[] GetPatches()
|
||||||
{
|
{
|
||||||
@@ -16,5 +24,124 @@ class ReplaceBingBongModule : Module
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
LocalizedText.mainTable.Add("idk_funny", ["Test subtitle!"]);
|
LocalizedText.mainTable.Add("idk_funny", ["Test subtitle!"]);
|
||||||
|
AudioSyncWorker.OnAudioLoadComplete += OnAudioLoadComplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
if (Input.GetKeyDown(KeyCode.P))
|
||||||
|
{
|
||||||
|
Helper.FindItemByName("BingBong_Prop Variant", out Item? item);
|
||||||
|
if (item == null) return;
|
||||||
|
Debug.Log($"Found item: {item.name} in scene {item.gameObject.scene.name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnAudioLoadComplete()
|
||||||
|
{
|
||||||
|
if (!HasReplacedSounds) return;
|
||||||
|
Action_AskBingBong[] allBingBongActions = UnityEngine.Object.FindObjectsByType<Action_AskBingBong>(FindObjectsSortMode.None);
|
||||||
|
foreach (Action_AskBingBong askBingBong in allBingBongActions) {
|
||||||
|
ReplaceBingBongResponses(askBingBong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ReplaceBingBongResponses(Action_AskBingBong askBingBong)
|
||||||
|
{
|
||||||
|
Action_AskBingBong.BingBongResponse[] currentResponses = new Action_AskBingBong.BingBongResponse[OriginalResponsesData.Length];
|
||||||
|
for (int index = 0; index < OriginalResponsesData.Length; index++)
|
||||||
|
{
|
||||||
|
currentResponses[index] = OriginalResponsesData[index].ToBingBongResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
askBingBong.responses = [];
|
||||||
|
|
||||||
|
Dictionary<string, SFX_Instance> sfxDict = new();
|
||||||
|
for (int i = 0; i < currentResponses.Length; i++)
|
||||||
|
{
|
||||||
|
Action_AskBingBong.BingBongResponse response = currentResponses[i];
|
||||||
|
if (response.sfx != null && response.sfx.clips != null && response.sfx.clips.Length > 0)
|
||||||
|
{
|
||||||
|
foreach (AudioClip clip in response.sfx.clips)
|
||||||
|
{
|
||||||
|
sfxDict[response.sfx.name] = response.sfx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Song> voices = [.. Song.BB_VoiceLines.Values];
|
||||||
|
|
||||||
|
foreach (Song voice in voices)
|
||||||
|
{
|
||||||
|
AudioClip clip = voice.AudioClip;
|
||||||
|
|
||||||
|
bool isNew = !sfxDict.ContainsKey(voice.Name);
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
SFX_Instance sFX_Instance = new()
|
||||||
|
{
|
||||||
|
clips = [clip]
|
||||||
|
};
|
||||||
|
Action_AskBingBong.BingBongResponse newResponse = new()
|
||||||
|
{
|
||||||
|
sfx = sFX_Instance,
|
||||||
|
subtitleID = "idk_funny",
|
||||||
|
mouthCurve = null,
|
||||||
|
mouthCurveTime = 1f
|
||||||
|
};
|
||||||
|
currentResponses = [.. currentResponses, newResponse];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sfxDict[voice.Name].clips = [clip];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
askBingBong.responses = new Action_AskBingBong.BingBongResponse[currentResponses.Length];
|
||||||
|
for (int i = 0; i < currentResponses.Length; i++)
|
||||||
|
{
|
||||||
|
askBingBong.responses[i] = currentResponses[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BingBongResponseData
|
||||||
|
{
|
||||||
|
public AudioClip[] Clips { get; set; } = [];
|
||||||
|
public string SfxName { get; set; } = "";
|
||||||
|
public string SubtitleID { get; set; } = "";
|
||||||
|
public AnimationCurve? MouthCurve { get; set; } = null;
|
||||||
|
public float MouthCurveTime { get; set; } = 0f;
|
||||||
|
|
||||||
|
public Action_AskBingBong.BingBongResponse ToBingBongResponse()
|
||||||
|
{
|
||||||
|
return new Action_AskBingBong.BingBongResponse
|
||||||
|
{
|
||||||
|
sfx = new SFX_Instance
|
||||||
|
{
|
||||||
|
name = SfxName,
|
||||||
|
clips = (AudioClip[])Clips.Clone()
|
||||||
|
},
|
||||||
|
subtitleID = SubtitleID,
|
||||||
|
mouthCurve = MouthCurve,
|
||||||
|
mouthCurveTime = MouthCurveTime
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BingBongResponseData FromBingBongResponse(Action_AskBingBong.BingBongResponse response)
|
||||||
|
{
|
||||||
|
return new BingBongResponseData
|
||||||
|
{
|
||||||
|
Clips = (AudioClip[])response.sfx.clips.Clone(),
|
||||||
|
SfxName = response.sfx.name,
|
||||||
|
SubtitleID = response.subtitleID,
|
||||||
|
MouthCurve = response.mouthCurve,
|
||||||
|
MouthCurveTime = response.mouthCurveTime
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ public class BetterBuglePatch
|
|||||||
// BetterBugleUI.Instance?.ShowActionbar("No songs available.");
|
// BetterBugleUI.Instance?.ShowActionbar("No songs available.");
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
if (BetterBugleModule.IsLoading) return;
|
if (AudioSyncWorker.IsLoading) return;
|
||||||
if (!BetterBugleModule.HadConfirmation)
|
if (!BetterBugleModule.HadConfirmation)
|
||||||
{
|
{
|
||||||
BetterBugleUI.Instance?.ShowActionbar("Are you sure you want to refresh songs ? Right-click again to reload.");
|
BetterBugleUI.Instance?.ShowActionbar("Are you sure you want to refresh songs ? Right-click again to reload.");
|
||||||
@@ -57,7 +57,7 @@ public class BetterBuglePatch
|
|||||||
{
|
{
|
||||||
BetterBugleModule.HadConfirmation = false; // Reset confirmation state
|
BetterBugleModule.HadConfirmation = false; // Reset confirmation state
|
||||||
BetterBugleUI.Instance?.ShowActionbar("Refreshing songs...");
|
BetterBugleUI.Instance?.ShowActionbar("Refreshing songs...");
|
||||||
BetterBugleModule.Instance?.GetAudioClips();
|
AudioSyncService.GetAudioClips();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ public class BetterBuglePatch
|
|||||||
|
|
||||||
private static void OnScroll(float scrollDelta)
|
private static void OnScroll(float scrollDelta)
|
||||||
{
|
{
|
||||||
if (BetterBugleModule.IsLoading) return;
|
if (AudioSyncWorker.IsLoading) return;
|
||||||
bool isNext = scrollDelta > 0;
|
bool isNext = scrollDelta > 0;
|
||||||
if (Song.Songs.Count == 0)
|
if (Song.Songs.Count == 0)
|
||||||
{
|
{
|
||||||
@@ -80,15 +80,15 @@ public class BetterBuglePatch
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNext && BetterBugleModule.CurrentSongIndex < Song.Songs.Count - 1) BetterBugleModule.CurrentSongIndex++;
|
if (isNext && AudioSyncWorker.CurrentSongIndex < Song.Songs.Count - 1) AudioSyncWorker.CurrentSongIndex++;
|
||||||
else if (isNext && BetterBugleModule.CurrentSongIndex == Song.Songs.Count - 1) BetterBugleModule.CurrentSongIndex = 0;
|
else if (isNext && AudioSyncWorker.CurrentSongIndex == Song.Songs.Count - 1) AudioSyncWorker.CurrentSongIndex = 0;
|
||||||
else if (!isNext && BetterBugleModule.CurrentSongIndex > 0) BetterBugleModule.CurrentSongIndex--;
|
else if (!isNext && AudioSyncWorker.CurrentSongIndex > 0) AudioSyncWorker.CurrentSongIndex--;
|
||||||
else BetterBugleModule.CurrentSongIndex = Song.Songs.Count - 1;
|
else AudioSyncWorker.CurrentSongIndex = Song.Songs.Count - 1;
|
||||||
BetterBugleModule.CurrentSongName = Song.GetSongNames_Alphabetically()[BetterBugleModule.CurrentSongIndex];
|
AudioSyncWorker.CurrentSongName = Song.GetSongNames_Alphabetically()[AudioSyncWorker.CurrentSongIndex];
|
||||||
|
|
||||||
Song currentSong = Song.Songs[BetterBugleModule.CurrentSongName];
|
Song currentSong = Song.Songs[AudioSyncWorker.CurrentSongName];
|
||||||
|
|
||||||
bool isFavorite = Song.FavoriteSongs.Contains(BetterBugleModule.CurrentSongName);
|
bool isFavorite = Song.FavoriteSongs.Contains(AudioSyncWorker.CurrentSongName);
|
||||||
BetterBugleUI.Instance?.ShowActionbar($" {(isFavorite ? "★" : " ")} {currentSong.RealIndex} | {currentSong.Name.Replace("_", " ")}");
|
BetterBugleUI.Instance?.ShowActionbar($" {(isFavorite ? "★" : " ")} {currentSong.RealIndex} | {currentSong.Name.Replace("_", " ")}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,10 +104,10 @@ public class BetterBuglePatch
|
|||||||
if (currentItem.itemState != ItemState.Held) return;
|
if (currentItem.itemState != ItemState.Held) return;
|
||||||
if (currentItem.TryGetComponent<BugleSFX>(out var bugleSFX))
|
if (currentItem.TryGetComponent<BugleSFX>(out var bugleSFX))
|
||||||
{
|
{
|
||||||
Song? song = Song.Songs.GetValueOrDefault(BetterBugleModule.CurrentSongName);
|
Song? song = Song.Songs.GetValueOrDefault(AudioSyncWorker.CurrentSongName);
|
||||||
if (song == null) return;
|
if (song == null) return;
|
||||||
|
|
||||||
bool isFavorite = Song.FavoriteSongs.Contains(BetterBugleModule.CurrentSongName);
|
bool isFavorite = Song.FavoriteSongs.Contains(AudioSyncWorker.CurrentSongName);
|
||||||
BetterBugleUI.Instance?.ShowActionbar($"{(isFavorite ? "★" : " ")} {song.RealIndex} | {song.Name}");
|
BetterBugleUI.Instance?.ShowActionbar($"{(isFavorite ? "★" : " ")} {song.RealIndex} | {song.Name}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using JordanMod.Utils;
|
using JordanMod.Utils;
|
||||||
@@ -8,6 +9,14 @@ namespace JordanMod.Modules.ReplaceBingBong;
|
|||||||
public class ReplaceBingBongPatch
|
public class ReplaceBingBongPatch
|
||||||
{
|
{
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Item), "Start")]
|
||||||
|
[HarmonyPrefix]
|
||||||
|
static void OnItemStart(Item __instance)
|
||||||
|
{
|
||||||
|
if (__instance.name != "BingBong_Prop Variant") return;
|
||||||
|
Debug.Log($"Item {__instance.name} Start in scene {__instance.gameObject.scene.name} ({__instance.gameObject.scene.buildIndex})");
|
||||||
|
}
|
||||||
|
|
||||||
[HarmonyPatch(typeof(ItemActionBase), "OnEnable")]
|
[HarmonyPatch(typeof(ItemActionBase), "OnEnable")]
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
static bool PreActionAskBingBongConstructorFix(ItemActionBase __instance)
|
static bool PreActionAskBingBongConstructorFix(ItemActionBase __instance)
|
||||||
@@ -16,54 +25,18 @@ public class ReplaceBingBongPatch
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
Action_AskBingBong.BingBongResponse[] currentResponses = [..askBingBong.responses];
|
Action_AskBingBong.BingBongResponse[] currentResponses = [..askBingBong.responses];
|
||||||
// Each response has a .sfx which has a Object.name, store a ref to the sfx with key being sfx name
|
|
||||||
Dictionary<string, SFX_Instance> sfxDict = new();
|
if (!ReplaceBingBongModule.HasReplacedSounds)
|
||||||
for (int i = 0; i < currentResponses.Length; i++)
|
|
||||||
{
|
{
|
||||||
Action_AskBingBong.BingBongResponse response = currentResponses[i];
|
ReplaceBingBongModule.OriginalResponsesData = new BingBongResponseData[currentResponses.Length];
|
||||||
if (response.sfx != null && response.sfx.clips != null && response.sfx.clips.Length > 0)
|
for (int index = 0; index < currentResponses.Length; index++)
|
||||||
{
|
{
|
||||||
foreach (AudioClip clip in response.sfx.clips)
|
ReplaceBingBongModule.OriginalResponsesData[index] = BingBongResponseData.FromBingBongResponse(currentResponses[index]);
|
||||||
{
|
|
||||||
sfxDict[response.sfx.name] = response.sfx;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
ReplaceBingBongModule.HasReplacedSounds = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Song> voices = [.. Song.BB_VoiceLines.Values];
|
ReplaceBingBongModule.ReplaceBingBongResponses(askBingBong);
|
||||||
|
|
||||||
foreach (Song voice in voices)
|
|
||||||
{
|
|
||||||
AudioClip clip = voice.AudioClip;
|
|
||||||
|
|
||||||
bool isNew = !sfxDict.ContainsKey(voice.Name);
|
|
||||||
if (isNew)
|
|
||||||
{
|
|
||||||
SFX_Instance sFX_Instance = new()
|
|
||||||
{
|
|
||||||
clips = [clip]
|
|
||||||
};
|
|
||||||
Action_AskBingBong.BingBongResponse newResponse = new()
|
|
||||||
{
|
|
||||||
sfx = sFX_Instance,
|
|
||||||
subtitleID = "idk_funny",
|
|
||||||
mouthCurve = null,
|
|
||||||
mouthCurveTime = 1f
|
|
||||||
};
|
|
||||||
currentResponses = [.. currentResponses, newResponse];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sfxDict[voice.Name].clips = [clip];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
askBingBong.responses = new Action_AskBingBong.BingBongResponse[currentResponses.Length];
|
|
||||||
for (int i = 0; i < currentResponses.Length; i++)
|
|
||||||
{
|
|
||||||
askBingBong.responses[i] = currentResponses[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -15,14 +16,26 @@ class AudioSyncService
|
|||||||
{
|
{
|
||||||
public static string API_BASE_URL => ConfigHandler.BugleSoundAPIURL.Value;
|
public static string API_BASE_URL => ConfigHandler.BugleSoundAPIURL.Value;
|
||||||
|
|
||||||
private static AudioSyncService? Instance { get; set; }
|
public async static Task<bool> DownloadAPIAudio(APIAudioFormat apiAudio, string SoundsDirectory, Song? existingSong = null)
|
||||||
public static AudioSyncService GetInstance()
|
|
||||||
{
|
{
|
||||||
Instance ??= new AudioSyncService();
|
bool success = true;
|
||||||
return Instance;
|
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 = [];
|
List<APIAudioFormat> audioClips = [];
|
||||||
|
|
||||||
@@ -48,6 +61,19 @@ class AudioSyncService
|
|||||||
return audioClips;
|
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
|
public class APIAudioFormat
|
||||||
{
|
{
|
||||||
[JsonProperty("_id")]
|
[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 class Song : IDisposable
|
||||||
{
|
{
|
||||||
public static readonly Dictionary<string, Song> Sounds = new();
|
public static readonly Dictionary<string, Song> Sounds = new();
|
||||||
@@ -180,7 +364,7 @@ public class Song : IDisposable
|
|||||||
public void DeleteFile()
|
public void DeleteFile()
|
||||||
{
|
{
|
||||||
if (AudioClip == null) return;
|
if (AudioClip == null) return;
|
||||||
var filePath = Path.Combine(BetterBugleModule.SoundsDirectory, $"{Name}.{Extension}");
|
var filePath = Path.Combine(AudioSyncWorker.SoundsDirectory, $"{Name}.{Extension}");
|
||||||
if (File.Exists(filePath))
|
if (File.Exists(filePath))
|
||||||
{
|
{
|
||||||
File.Delete(filePath);
|
File.Delete(filePath);
|
||||||
|
|||||||
Reference in New Issue
Block a user