Lazy-load Addressables music (#7303)

* Lazy-load addressable music

* Clean Addressables output before rebuild
This commit is contained in:
2026-06-16 18:20:44 -07:00
committed by GitHub
parent 3a9d2f7eec
commit ba6a776688
2 changed files with 74 additions and 51 deletions
@@ -39,6 +39,15 @@ public static class BuildScript {
LogAddressableGroupPackingModes();
LogAddressableLabelFanout();
var settings = AddressableAssetSettingsDefaultObject.Settings;
var resolvedBuildPath = "";
if (settings != null) {
var profileId = settings.activeProfileId;
var buildPath = settings.profileSettings.GetValueByName(profileId, "Remote.BuildPath");
resolvedBuildPath = ResolveAddressablesProfilePath(settings, profileId, buildPath);
CleanAddressablesOutput(resolvedBuildPath);
}
AddressablesPlayerBuildResult result = null;
LogTimed("Build Addressables content", () => {
BuildAddressables(generateLayoutReport, out result);
@@ -52,13 +61,9 @@ public static class BuildScript {
Debug.Log($"Addressables build completed. Duration: {result.Duration}s");
// Log the output location for remote bundles
var settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings != null) {
var profileId = settings.activeProfileId;
var buildPath = settings.profileSettings.GetValueByName(profileId, "Remote.BuildPath");
var resolvedPath = ResolveAddressablesProfilePath(settings, profileId, buildPath);
Debug.Log($"Addressables bundles built to: {resolvedPath}");
LogAddressablesOutput(resolvedPath);
if (!string.IsNullOrEmpty(resolvedBuildPath)) {
Debug.Log($"Addressables bundles built to: {resolvedBuildPath}");
LogAddressablesOutput(resolvedBuildPath);
LogAddressablesBuildReports();
Debug.Log("Upload these bundles to your CDN at the configured Remote.LoadPath");
}
@@ -394,6 +399,29 @@ public static class BuildScript {
}
}
private static void CleanAddressablesOutput(string path) {
if (string.IsNullOrEmpty(path)) {
Debug.LogWarning("Addressables output path is empty; skipping output cleanup.");
return;
}
var fullPath = Path.GetFullPath(path);
var projectRoot = Path.GetFullPath(Path.Combine(Application.dataPath, ".."));
if (!fullPath.StartsWith(
projectRoot + Path.DirectorySeparatorChar,
StringComparison.Ordinal) ||
fullPath.IndexOf("ServerData", StringComparison.Ordinal) < 0) {
Debug.LogWarning($"Refusing to clean unexpected Addressables output path: {fullPath}");
return;
}
if (!Directory.Exists(fullPath)) { return; }
Directory.Delete(fullPath, true);
Directory.CreateDirectory(fullPath);
Debug.Log($"Deleted stale Addressables output at {fullPath}");
}
private static void LogAddressableGroupPackingModes() {
var settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null) {
@@ -9,18 +9,24 @@ public class SoundManager : MonoBehaviour {
public AudioSource musicSource;
private class MusicTypeInfo {
public readonly string label;
public int currentIndex = 0;
public float currentTime = 0f;
public List<AudioClip> clips = new List<AudioClip>();
public bool loadStarted = false;
public bool loadFinished = false;
public bool loadFailed = false;
public MusicTypeInfo(string label) { this.label = label; }
}
private readonly MusicTypeInfo _springMusic = new MusicTypeInfo();
private readonly MusicTypeInfo _summerMusic = new MusicTypeInfo();
private readonly MusicTypeInfo _autumnMusic = new MusicTypeInfo();
private readonly MusicTypeInfo _winterMusic = new MusicTypeInfo();
private readonly MusicTypeInfo _travelingMusic = new MusicTypeInfo();
private readonly MusicTypeInfo _battleMusic = new MusicTypeInfo();
private readonly MusicTypeInfo _victoryMusic = new MusicTypeInfo();
private readonly MusicTypeInfo _springMusic = new MusicTypeInfo("music-spring");
private readonly MusicTypeInfo _summerMusic = new MusicTypeInfo("music-summer");
private readonly MusicTypeInfo _autumnMusic = new MusicTypeInfo("music-autumn");
private readonly MusicTypeInfo _winterMusic = new MusicTypeInfo("music-winter");
private readonly MusicTypeInfo _travelingMusic = new MusicTypeInfo("music-travel");
private readonly MusicTypeInfo _battleMusic = new MusicTypeInfo("music-battle");
private readonly MusicTypeInfo _victoryMusic = new MusicTypeInfo("music-victory");
private Dictionary<ActionType, AudioClip> _clipForType;
private Dictionary<MusicType, MusicTypeInfo> _musicInfoForType;
@@ -54,8 +60,9 @@ public class SoundManager : MonoBehaviour {
// Gauntlet throw impact sound
private AudioClip _duelChallenge;
private bool _musicLoaded = false;
public bool MusicLoaded => _musicLoaded;
public bool MusicLoaded =>
_musicInfoForType != null &&
_musicInfoForType.Values.Where(info => info != null).Any(info => info.loadFinished);
private bool _musicLoadFailed = false;
/// <summary>
@@ -64,39 +71,23 @@ public class SoundManager : MonoBehaviour {
/// </summary>
public bool MusicLoadFailed => _musicLoadFailed;
private IEnumerator LoadMusicAsync(string label, MusicTypeInfo targetInfo) {
private IEnumerator LoadMusicAsync(MusicType type, MusicTypeInfo targetInfo) {
targetInfo.loadStarted = true;
targetInfo.loadFailed = false;
yield return AddressableLoader.LoadWithRetry<AudioClip>(
label,
clips => { targetInfo.clips = clips.ToList(); },
() => { _musicLoadFailed = true; });
}
targetInfo.label,
clips => {
targetInfo.clips = clips.ToList();
targetInfo.loadFinished = true;
},
() => {
targetInfo.loadStarted = false;
targetInfo.loadFailed = true;
_musicLoadFailed = true;
});
private IEnumerator LoadAllMusic() {
// Priority 1: Summer (most likely starting season)
yield return StartCoroutine(LoadMusicAsync("music-summer", _summerMusic));
TryStartMusicIfNotPlaying();
// Priority 2: Autumn (next season)
yield return StartCoroutine(LoadMusicAsync("music-autumn", _autumnMusic));
TryStartMusicIfNotPlaying();
// Load remaining music in parallel
var springHandle = StartCoroutine(LoadMusicAsync("music-spring", _springMusic));
var winterHandle = StartCoroutine(LoadMusicAsync("music-winter", _winterMusic));
var travelHandle = StartCoroutine(LoadMusicAsync("music-travel", _travelingMusic));
var battleHandle = StartCoroutine(LoadMusicAsync("music-battle", _battleMusic));
var victoryHandle = StartCoroutine(LoadMusicAsync("music-victory", _victoryMusic));
yield return springHandle;
yield return winterHandle;
yield return travelHandle;
yield return battleHandle;
yield return victoryHandle;
_musicLoaded = true;
// Start playing if a music type was already requested before loading finished
TryStartMusicIfNotPlaying();
if (CurrentMusicType == type) { TryStartMusicIfNotPlaying(); }
}
/// <summary>
@@ -111,6 +102,12 @@ public class SoundManager : MonoBehaviour {
if (info != null && info.clips.Count > 0) { PlayMusic(); }
}
private void EnsureMusicLoaded(MusicType type) {
var info = _musicInfoForType[type];
if (info == null || info.loadStarted || info.loadFinished) { return; }
StartCoroutine(LoadMusicAsync(type, info));
}
private IEnumerator LoadSoundEffects() {
yield return AddressableLoader.LoadWithRetry<AudioClip>("sfx-combat", results => {
var clips = new Dictionary<string, AudioClip>();
@@ -253,10 +250,7 @@ public class SoundManager : MonoBehaviour {
};
}
public void Start() {
StartCoroutine(LoadAllMusic());
StartCoroutine(LoadSoundEffects());
}
public void Start() { StartCoroutine(LoadSoundEffects()); }
public AudioClip SoundForType(ActionType actionType) {
if (_clipForType != null && _clipForType.ContainsKey(actionType)) {
@@ -361,6 +355,7 @@ public class SoundManager : MonoBehaviour {
var previousInfo = _musicInfoForType[_musicType];
if (previousInfo != null) { previousInfo.currentTime = musicSource.time; }
_musicType = value;
EnsureMusicLoaded(_musicType);
PlayMusic();
}
}