From 2897ab607563a62a9577ac71cf23a29816449ea7 Mon Sep 17 00:00:00 2001 From: minenice55 Date: Wed, 7 Feb 2024 00:01:39 -0500 Subject: [PATCH] basic audio preloading could this operation be timesliced even more? --- Assets/Scripts/Conductor.cs | 4 +- Assets/Scripts/GameManager.cs | 37 +++--- Assets/Scripts/Minigames.cs | 19 ++- Assets/Scripts/Util/SoundByte.cs | 161 ++++++++++++++++++++++--- ProjectSettings/GraphicsSettings.asset | 8 +- ProjectSettings/ProjectSettings.asset | 8 +- ProjectSettings/QualitySettings.asset | 6 +- 7 files changed, 183 insertions(+), 60 deletions(-) diff --git a/Assets/Scripts/Conductor.cs b/Assets/Scripts/Conductor.cs index ece56c33d..e1f96b8f3 100644 --- a/Assets/Scripts/Conductor.cs +++ b/Assets/Scripts/Conductor.cs @@ -179,7 +179,6 @@ namespace HeavenStudio { AudioConfiguration config = AudioSettings.GetConfiguration(); dspSizeSeconds = config.dspBufferSize / (double)config.sampleRate; - Debug.Log($"dsp size: {dspSizeSeconds}"); dspMargin = 2 * dspSizeSeconds; SetMinigameVolume(1f); @@ -210,7 +209,6 @@ namespace HeavenStudio } musicSource.PlayScheduled(musicScheduledTime); musicSource.pitch = timelinePitch; - Debug.Log($"playback scheduled for dsptime {dspStart}"); } songPosBeat = beat; @@ -234,7 +232,7 @@ namespace HeavenStudio if (deferTimeKeeping && dsp >= dspStart - dspSizeSeconds) { deferTimeKeeping = false; - Debug.Log($"dsptime: {dsp}, deferred timekeeping for {DateTime.Now - startTime} seconds (delta dsp {dsp - dspStart})"); + // Debug.Log($"dsptime: {dsp}, deferred timekeeping for {DateTime.Now - startTime} seconds (delta dsp {dsp - dspStart})"); startTime += TimeSpan.FromSeconds(dsp - dspStart); absTimeAdjust = 0; dspStart = dsp; diff --git a/Assets/Scripts/GameManager.cs b/Assets/Scripts/GameManager.cs index 007c43850..b362c60fe 100644 --- a/Assets/Scripts/GameManager.cs +++ b/Assets/Scripts/GameManager.cs @@ -159,6 +159,7 @@ namespace HeavenStudio GoForAPerfect.instance.Disable(); ///// + SoundByte.BasicCheck(); SoundObjects = new ObjectPool(CreatePooledSound, OnTakePooledSound, OnReturnPooledSound, OnDestroyPooledSound, true, SoundPoolSizeMin, SoundPoolSizeMax); @@ -303,22 +304,10 @@ namespace HeavenStudio { Stop(0); } - SetCurrentEventToClosest(0); - - if (Beatmap.Entities.Count >= 1) - { - string game = Beatmap.Entities[0].datamodel.Split(0); - SetCurrentGame(game); - StartCoroutine(WaitAndSetGame(game)); - } - else - { - SetGame("noGame"); - } + SetCurrentEventToClosest(0, true); if (editor) { - Debug.Log(Beatmap.data.riqOrigin); if (Beatmap.data.riqOrigin != "HeavenStudio") { string origin = Beatmap.data.riqOrigin?.DisplayName() ?? "Unknown Origin"; @@ -709,10 +698,7 @@ namespace HeavenStudio { yield return new WaitForSeconds(delay); } - } - if (!paused) - { Conductor.instance.PlaySetup(beat); Minigame miniGame = null; if (minigameObj != null && minigameObj.TryGetComponent(out miniGame)) @@ -813,6 +799,10 @@ namespace HeavenStudio private IEnumerator WaitReadyAndPlayCo(double beat, float delay = 1f, bool discord = true) { + SoundByte.UnloadAudioClips(); + SoundByte.PreloadAudioClipAsync("skillStar"); + SoundByte.PreloadAudioClipAsync("perfectMiss"); + WaitUntil yieldOverlays = new WaitUntil(() => OverlaysManager.OverlaysReady); WaitUntil yieldBeatmap = new WaitUntil(() => Beatmap != null && BeatmapEntities() > 0); WaitUntil yieldAudio = new WaitUntil(() => AudioLoadDone || (ChartLoadError && !GlobalGameManager.IsShowingDialog)); @@ -856,7 +846,7 @@ namespace HeavenStudio { Debug.Log("Killing all sounds"); SoundObjects.Clear(); - Util.SoundByte.KillOneShots(); + SoundByte.KillOneShots(); } #endregion @@ -945,7 +935,7 @@ namespace HeavenStudio return 0; } - public void SetCurrentEventToClosest(double beat) + public void SetCurrentEventToClosest(double beat, bool canPreload = false) { SortEventsList(); onBeatChanged?.Invoke(beat); @@ -991,7 +981,15 @@ namespace HeavenStudio if (!GetGameInfo(newGame).fxOnly) { - SetGame(newGame); + if (canPreload) + { + StartCoroutine(WaitAndSetGame(newGame)); + } + else + { + SetGame(newGame); + } + SetCurrentGame(newGame); } List allEnds = EventCaller.GetAllInGameManagerList("gameManager", new string[] { "end" }); @@ -1129,6 +1127,7 @@ namespace HeavenStudio public void DestroyGame() { cachedGamePrefabs.Clear(); + SoundByte.UnloadAudioClips(); SetGame("noGame"); } diff --git a/Assets/Scripts/Minigames.cs b/Assets/Scripts/Minigames.cs index 969e36c51..621ec8250 100644 --- a/Assets/Scripts/Minigames.cs +++ b/Assets/Scripts/Minigames.cs @@ -382,8 +382,6 @@ namespace HeavenStudio private bool localeLoaded = false; private bool localePreloaded = false; private GameObject loadedPrefab = null; - private Dictionary commonAudioClips; - private Dictionary localeAudioClips; private SoundSequence.SequenceKeyValue[] soundSequences = null; @@ -392,8 +390,6 @@ namespace HeavenStudio get => soundSequences; set => soundSequences = value; } - public Dictionary CommonAudioClips => commonAudioClips; - public Dictionary LocaleAudioClips => localeAudioClips; public Minigame(string name, string displayName, string color, bool hidden, bool fxOnly, List actions, List tags = null, string assetBundle = "", string defaultLocale = "en", List supportedLocales = null, bool inferred = false) { @@ -475,11 +471,15 @@ namespace HeavenStudio return bundleCommon; } - public async UniTask LoadAssetsAsync() + bool alreadyLoading = false; + public async UniTaskVoid LoadAssetsAsync() { - if (AssetsLoaded || !usesAssetBundle) return; + if (alreadyLoading || AssetsLoaded || !usesAssetBundle) return; + alreadyLoading = true; await UniTask.WhenAll(LoadCommonAssetBundleAsync(), LoadLocalizedAssetBundleAsync()); await UniTask.WhenAll(LoadGamePrefabAsync(), LoadCommonAudioClips(), LoadLocalizedAudioClips()); + SoundByte.PreloadGameAudioClips(this); + alreadyLoading = false; } public async UniTask LoadCommonAssetBundleAsync() @@ -558,8 +558,6 @@ namespace HeavenStudio if (!commonLoaded) return; if (bundleCommon == null) return; - commonAudioClips = new(); - var assets = bundleCommon.LoadAllAssetsAsync(); await assets; } @@ -569,8 +567,6 @@ namespace HeavenStudio if (!localeLoaded) return; if (bundleLocalized == null) return; - localeAudioClips = new(); - var assets = bundleLocalized.LoadAllAssetsAsync(); await assets; } @@ -578,8 +574,6 @@ namespace HeavenStudio public async UniTask UnloadAllAssets() { if (!usesAssetBundle) return; - commonAudioClips.Clear(); - localeAudioClips.Clear(); if (loadedPrefab != null) { loadedPrefab = null; @@ -598,6 +592,7 @@ namespace HeavenStudio localeLoaded = false; localePreloaded = false; } + SoundByte.UnloadAudioClips(name); } } diff --git a/Assets/Scripts/Util/SoundByte.cs b/Assets/Scripts/Util/SoundByte.cs index 8e6ea4525..21516caf8 100644 --- a/Assets/Scripts/Util/SoundByte.cs +++ b/Assets/Scripts/Util/SoundByte.cs @@ -1,6 +1,8 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; +using Cysharp.Threading.Tasks; using UnityEngine; namespace HeavenStudio.Util @@ -11,6 +13,8 @@ namespace HeavenStudio.Util static AudioSource oneShotAudioSource; static int soundIdx = 0; + static Dictionary audioClips = new Dictionary(); + public enum AudioType { OGG, @@ -32,12 +36,6 @@ namespace HeavenStudio.Util /// public static void BasicCheck() { - if (FindJukebox() == null) - { - GameObject Jukebox = new GameObject("Jukebox"); - Jukebox.AddComponent(); - Jukebox.tag = "Jukebox"; - } if (oneShotAudioSourceObject == null) { oneShotAudioSourceObject = new GameObject("OneShot Audio Source"); @@ -46,14 +44,6 @@ namespace HeavenStudio.Util } } - public static GameObject FindJukebox() - { - if (GameObject.FindGameObjectWithTag("Jukebox") != null) - return GameObject.FindGameObjectWithTag("Jukebox"); - else - return null; - } - /// /// Stops all currently playing sounds. /// @@ -87,13 +77,142 @@ namespace HeavenStudio.Util } } + public static void PreloadGameAudioClips(Minigames.Minigame inf) + { + if (inf.usesAssetBundle) + { + var cmnAb = inf.GetCommonAssetBundle(); + if (cmnAb != null) + { + cmnAb.LoadAllAssetsAsync().completed += (op) => + { + foreach (var clip in (op as AssetBundleRequest).allAssets.Cast()) + { + OnResourceLoaded(clip, clip.name); + } + }; + } + var locAb = inf.GetLocalizedAssetBundle(); + if (locAb != null) + { + locAb.LoadAllAssetsAsync().completed += (op) => + { + foreach (var clip in (op as AssetBundleRequest).allAssets.Cast()) + { + OnResourceLoaded(clip, clip.name); + } + }; + } + } + else + { + string path = $"Sfx/games/{inf.name}"; + var clips = Resources.LoadAll(path); + foreach (var clip in clips) + { + OnResourceLoaded(clip, clip.name); + } + } + } + + public static void PreloadGameAudioClips(string game) + { + var inf = GameManager.instance.GetGameInfo(game); + PreloadGameAudioClips(inf); + } + + public static void PreloadAudioClipAsync(string name, string game) + { + if (audioClips.ContainsKey(name)) return; + var inf = GameManager.instance.GetGameInfo(game); + if (inf.usesAssetBundle) + { + var cmnAb = inf.GetCommonAssetBundle(); + if (cmnAb != null && cmnAb.Contains(name)) + { + var request = cmnAb.LoadAssetAsync(name); + request.completed += (op) => + { + OnResourceLoaded((op as ResourceRequest).asset as AudioClip, name); + }; + } + else + { + var locAb = inf.GetLocalizedAssetBundle(); + if (locAb != null && locAb.Contains(name)) + { + var request = locAb.LoadAssetAsync(name); + request.completed += (op) => + { + OnResourceLoaded((op as ResourceRequest).asset as AudioClip, name); + }; + } + } + } + else + { + PreloadAudioClipAsync($"{game}/{name}"); + } + } + + public static void PreloadAudioClipAsync(string name) + { + if (audioClips.ContainsKey(name)) return; + string path = $"Sfx/{name}"; + ResourceRequest request = Resources.LoadAsync(path); + request.completed += (op) => + { + OnResourceLoaded((op as ResourceRequest).asset as AudioClip, name); + }; + } + + static void OnResourceLoaded(AudioClip clip, string name) + { + if (audioClips.ContainsKey(name)) + { + audioClips[name] = clip; + } + else + { + audioClips.Add(name, clip); + } + } + + public static void UnloadAudioClips(params string[] names) + { + foreach (string s in names) + { + if (audioClips.ContainsKey(s)) audioClips.Remove(s); + } + Resources.UnloadUnusedAssets(); + } + + public static void UnloadAudioClips() + { + audioClips.Clear(); + Resources.UnloadUnusedAssets(); + } + + public static void UnloadAudioClips(string game) + { + foreach (string s in audioClips.Where(x => x.Key.Split('/')[0] == game).Select(x => x.Key).ToList()) + { + audioClips.Remove(s); + } + Resources.UnloadUnusedAssets(); + } + /// /// Gets the length of an audio clip /// public static double GetClipLength(string name, float pitch = 1f, string game = null) { AudioClip clip = null; - if (game != null) + if (audioClips.ContainsKey(name)) + { + clip = audioClips[name]; + } + else if (game != null) { string soundName = name.Split('/')[2]; var inf = GameManager.instance.GetGameInfo(game); @@ -147,7 +266,11 @@ namespace HeavenStudio.Util public static Sound PlayOneShot(string name, double beat = -1, float pitch = 1f, float volume = 1f, bool looping = false, string game = null, double offset = 0f) { AudioClip clip = null; - if (game != null) + if (audioClips.ContainsKey(name)) + { + clip = audioClips[name]; + } + else if (game != null) { string soundName = name.Split('/')[2]; var inf = GameManager.instance.GetGameInfo(game); @@ -205,7 +328,11 @@ namespace HeavenStudio.Util Sound snd = GetAvailableScheduledSound(); AudioClip clip = null; - if (game != null) + if (audioClips.ContainsKey(name)) + { + clip = audioClips[name]; + } + else if (game != null) { string soundName = name.Split('/')[2]; var inf = GameManager.instance.GetGameInfo(game); diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset index daf49ea41..7a77c4bc5 100644 --- a/ProjectSettings/GraphicsSettings.asset +++ b/ProjectSettings/GraphicsSettings.asset @@ -3,7 +3,7 @@ --- !u!30 &1 GraphicsSettings: m_ObjectHideFlags: 0 - serializedVersion: 13 + serializedVersion: 14 m_Deferred: m_Mode: 1 m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} @@ -28,7 +28,7 @@ GraphicsSettings: m_LensFlare: m_Mode: 1 m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} - m_VideoShadersIncludeMode: 2 + m_VideoShadersIncludeMode: 1 m_AlwaysIncludedShaders: - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} @@ -40,6 +40,7 @@ GraphicsSettings: - {fileID: 4800000, guid: 534727a34958a6b409102bf07fadffab, type: 3} - {fileID: 4800000, guid: 95d6144eab187a34b929151454e2969d, type: 3} m_PreloadedShaders: [] + m_PreloadShadersBatchTimeLimit: -1 m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} m_CustomRenderPipeline: {fileID: 0} m_TransparencySortMode: 0 @@ -81,3 +82,6 @@ GraphicsSettings: m_LightsUseColorTemperature: 0 m_DefaultRenderingLayerMask: 1 m_LogWhenShaderIsCompiled: 1 + m_SRPDefaultSettings: {} + m_CameraRelativeLightCulling: 0 + m_CameraRelativeShadowCulling: 0 diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 4f2257a34..beaddb302 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -49,7 +49,7 @@ PlayerSettings: m_StereoRenderingPath: 0 m_ActiveColorSpace: 0 m_MTRendering: 1 - mipStripping: 0 + mipStripping: 1 numberOfMipsStripped: 0 m_StackTraceTypes: 010000000100000001000000010000000100000001000000 iosShowActivityIndicatorOnLoading: -1 @@ -134,7 +134,7 @@ PlayerSettings: 16:10: 1 16:9: 1 Others: 1 - bundleVersion: 1.0.1 + bundleVersion: 1.0.2 preloadedAssets: - {fileID: 102900000, guid: 5348c08b82446e0478cee8bda6c02cfc, type: 3} metroInputSource: 0 @@ -158,11 +158,11 @@ PlayerSettings: applicationIdentifier: Standalone: com.RHeavenStudio.Heaven-Studio buildNumber: - Standalone: 1018 + Standalone: 100002 iPhone: 0 tvOS: 0 overrideDefaultApplicationIdentifier: 0 - AndroidBundleVersionCode: 1018 + AndroidBundleVersionCode: 100002 AndroidMinSdkVersion: 22 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset index 77f40348e..aab60c300 100644 --- a/ProjectSettings/QualitySettings.asset +++ b/ProjectSettings/QualitySettings.asset @@ -4,7 +4,7 @@ QualitySettings: m_ObjectHideFlags: 0 serializedVersion: 5 - m_CurrentQuality: 5 + m_CurrentQuality: 3 m_QualitySettings: - serializedVersion: 2 name: Very Low @@ -201,7 +201,7 @@ QualitySettings: skinWeights: 255 textureQuality: 0 anisotropicTextures: 2 - antiAliasing: 0 + antiAliasing: 4 softParticles: 1 softVegetation: 1 realtimeReflectionProbes: 1 @@ -229,7 +229,7 @@ QualitySettings: PS4: 5 Server: 0 Stadia: 5 - Standalone: 5 + Standalone: 3 WebGL: 3 Windows Store Apps: 5 XboxOne: 5