Merge pull request #862 from RHeavenStudio/cherry-pick-release_1_patches-7a773d02ad34ac98c4568d60c6da8aedbcd236a4

Fix Game Asset Loading Issues
This commit is contained in:
minenice55 2024-04-10 05:07:24 +00:00 committed by GitHub
commit c6c7e05ef9
8 changed files with 243 additions and 229 deletions

View file

@ -51,7 +51,7 @@ namespace HeavenStudio.Common
_renderer.material.mainTextureOffset = new Vector2(NormalizedX, -NormalizedY) * Tile; _renderer.material.mainTextureOffset = new Vector2(NormalizedX, -NormalizedY) * Tile;
if (AutoScroll) { if (AutoScroll) {
float songPos = Conductor.instance.songPositionInBeats/100; float songPos = Conductor.instance.unswungSongPositionInBeats/100;
NormalizedX = songPos*AutoScrollX; NormalizedX = songPos*AutoScrollX;
NormalizedY = songPos*AutoScrollY; NormalizedY = songPos*AutoScrollY;
} }

View file

@ -167,7 +167,9 @@ namespace HeavenStudio
SeekMusicToTime(startPos, offset); SeekMusicToTime(startPos, offset);
songPos = startPos;
songPosBeat = GetBeatFromSongPos(time); songPosBeat = GetBeatFromSongPos(time);
songPositionInBeatsAsDouble = GetSwungBeat(songPosBeat);
gameManager.SetCurrentEventToClosest(beat, true); gameManager.SetCurrentEventToClosest(beat, true);
} }

View file

@ -181,15 +181,13 @@ namespace HeavenStudio
if (!preLoaded) if (!preLoaded)
{ {
if (Beatmap.Entities.Count >= 1) if (Beatmap.Entities.Count == 0)
{ {
string game = Beatmap.Entities[0].datamodel.Split(0); SetGame("noGame");
SetCurrentGame(game);
StartCoroutine(WaitAndSetGame(game));
} }
else else
{ {
SetGame("noGame"); SetCurrentEventToClosest(0, true);
} }
} }
@ -380,7 +378,7 @@ namespace HeavenStudio
inf = GetGameInfo(gameName); inf = GetGameInfo(gameName);
if (inf != null && !(inf.inferred || inf.fxOnly)) if (inf != null && !(inf.inferred || inf.fxOnly))
{ {
if (inf.usesAssetBundle && !(inf.AssetsLoaded || inf.AlreadyLoading)) if (inf.UsesAssetBundle && !(inf.AssetsLoaded || inf.AlreadyLoading))
{ {
gamesToPreload.Add(inf); gamesToPreload.Add(inf);
Debug.Log($"ASYNC loading assetbundles for game {gameName}"); Debug.Log($"ASYNC loading assetbundles for game {gameName}");
@ -409,7 +407,7 @@ namespace HeavenStudio
inf = GetGameInfo(gameName); inf = GetGameInfo(gameName);
if (inf != null && !(inf.inferred || inf.fxOnly)) if (inf != null && !(inf.inferred || inf.fxOnly))
{ {
if (inf.usesAssetBundle && !inf.AssetsLoaded) if (inf.UsesAssetBundle && !inf.AssetsLoaded)
{ {
gamesToPreload.Add(inf); gamesToPreload.Add(inf);
Debug.Log($"ASYNC loading assetbundles for game {gameName}"); Debug.Log($"ASYNC loading assetbundles for game {gameName}");
@ -445,13 +443,6 @@ namespace HeavenStudio
foreach (RiqEntity entity in entitiesInRange) foreach (RiqEntity entity in entitiesInRange)
{ {
string gameName = entity.datamodel.Split('/')[0];
var inf = GetGameInfo(gameName);
if (inf != null && inf.usesAssetBundle && inf.AssetsLoaded && !inf.SequencesPreloaded)
{
// Debug.Log($"Preparing game {gameName}");
PreloadGameSequences(gameName);
}
eventCaller.CallPreEvent(entity); eventCaller.CallPreEvent(entity);
currentPreSequence++; currentPreSequence++;
} }
@ -579,7 +570,7 @@ namespace HeavenStudio
foreach (RiqEntity entity in entitiesInRange) foreach (RiqEntity entity in entitiesInRange)
{ {
// if game isn't loaded, preload game so whatever event that would be called will still run outside if needed // if game isn't loaded, run inactive event
if (entity.datamodel.Split('/')[0] != currentGame) if (entity.datamodel.Split('/')[0] != currentGame)
{ {
eventCaller.CallEvent(entity, false); eventCaller.CallEvent(entity, false);
@ -628,13 +619,17 @@ namespace HeavenStudio
{ {
if (string.IsNullOrEmpty(name)) return; if (string.IsNullOrEmpty(name)) return;
Sound sound; Sound sound;
if (game == "common") { if (game == "common")
{
sound = SoundByte.PlayOneShot(name, beat, pitch, volume, looping, null, (offset / 1000f)); sound = SoundByte.PlayOneShot(name, beat, pitch, volume, looping, null, (offset / 1000f));
} else { }
else
{
SoundByte.PreloadGameAudioClips(game); SoundByte.PreloadGameAudioClips(game);
sound = SoundByte.PlayOneShotGame(game + "/" + name, beat, pitch, volume, looping, true, (offset / 1000f)); sound = SoundByte.PlayOneShotGame(game + "/" + name, beat, pitch, volume, looping, true, (offset / 1000f));
} }
if (looping) { if (looping)
{
BeatAction.New(null, new() { BeatAction.New(null, new() {
new(beat + length, () => sound.KillLoop(0)), new(beat + length, () => sound.KillLoop(0)),
}); });
@ -644,7 +639,8 @@ namespace HeavenStudio
public void PlayAnimationArbitrary(string animator, string animation, float scale) public void PlayAnimationArbitrary(string animator, string animation, float scale)
{ {
Transform animTrans = minigameObj.transform.Find(animator); Transform animTrans = minigameObj.transform.Find(animator);
if (animTrans != null && animTrans.TryGetComponent(out Animator anim)) { if (animTrans != null && animTrans.TryGetComponent(out Animator anim))
{
anim.DoScaledAnimationAsync(animation, scale); anim.DoScaledAnimationAsync(animation, scale);
} }
} }
@ -1020,17 +1016,12 @@ namespace HeavenStudio
if (canPreload) if (canPreload)
{ {
Minigames.Minigame inf = GetGameInfo(newGame); Minigames.Minigame inf = GetGameInfo(newGame);
if (inf != null && inf.usesAssetBundle && !inf.AssetsLoaded) if (inf != null && inf.UsesAssetBundle && !inf.AssetsLoaded)
{ {
preload.Add(inf); preload.Add(inf);
} }
StartCoroutine(WaitAndSetGame(newGame));
} }
else StartCoroutine(WaitAndSetGame(newGame));
{
SetGame(newGame);
}
SetCurrentGame(newGame);
} }
List<RiqEntity> allEnds = EventCaller.GetAllInGameManagerList("gameManager", new string[] { "end" }); List<RiqEntity> allEnds = EventCaller.GetAllInGameManagerList("gameManager", new string[] { "end" });
@ -1099,6 +1090,13 @@ namespace HeavenStudio
#endregion #endregion
/// <summary>
/// While playing a chart, switches the currently active game
/// Should only be called by chart entities
/// </summary>
/// <param name="game">name of the game to switch to</param>
/// <param name="beat">beat of the chart entity calling the switch</param>
/// <param name="flash">hide the screen during the switch</param>
public void SwitchGame(string game, double beat, bool flash) public void SwitchGame(string game, double beat, bool flash)
{ {
if (game != currentGame) if (game != currentGame)
@ -1142,11 +1140,16 @@ namespace HeavenStudio
SetAmbientGlowToCurrentMinigameColor(); SetAmbientGlowToCurrentMinigameColor();
} }
/// <summary>
/// Immediately sets the current minigame to the specified game
/// </summary>
/// <param name="game"></param>
/// <param name="useMinigameColor"></param>
private void SetGame(string game, bool useMinigameColor = true) private void SetGame(string game, bool useMinigameColor = true)
{ {
ResetCamera(); // resetting camera before setting new minigame so minigames can set camera values in their awake call - Rasmus ResetCamera(); // resetting camera before setting new minigame so minigames can set camera values in their awake call - Rasmus
GameObject prefab = GetGame(game); GameObject prefab = GetGamePrefab(game);
if (prefab == null) return; if (prefab == null) return;
Destroy(minigameObj); Destroy(minigameObj);
@ -1166,13 +1169,13 @@ namespace HeavenStudio
SetCurrentGame(game, useMinigameColor); SetCurrentGame(game, useMinigameColor);
} }
public void DestroyGame()
{
SoundByte.UnloadAudioClips();
SetGame("noGame");
}
string currentGameRequest = null; string currentGameRequest = null;
/// <summary>
/// Waits for a given game to preload, then sets it as the current game
/// </summary>
/// <param name="game"></param>
/// <param name="useMinigameColor"></param>
/// <returns></returns>
private IEnumerator WaitAndSetGame(string game, bool useMinigameColor = true) private IEnumerator WaitAndSetGame(string game, bool useMinigameColor = true)
{ {
if (game == currentGameRequest) if (game == currentGameRequest)
@ -1181,7 +1184,7 @@ namespace HeavenStudio
} }
currentGameRequest = game; currentGameRequest = game;
var inf = GetGameInfo(game); var inf = GetGameInfo(game);
if (inf != null && inf.usesAssetBundle) if (inf != null && inf.UsesAssetBundle)
{ {
if (!(inf.AssetsLoaded || inf.AlreadyLoading)) if (!(inf.AssetsLoaded || inf.AlreadyLoading))
{ {
@ -1199,16 +1202,18 @@ namespace HeavenStudio
} }
} }
public void PreloadGameSequences(string game) public void DestroyGame()
{ {
var gameInfo = GetGameInfo(game); SoundByte.UnloadAudioClips();
//load the games' sound sequences SetGame("noGame");
// TODO: sound sequences sould be stored in a ScriptableObject
if (gameInfo != null && gameInfo.LoadedSoundSequences == null)
gameInfo.LoadedSoundSequences = GetGame(game).GetComponent<Minigame>().SoundSequences;
} }
public GameObject GetGame(string name) /// <summary>
/// Get the game prefab for a given game name
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public GameObject GetGamePrefab(string name)
{ {
if (name is null or "" or "noGame") if (name is null or "" or "noGame")
{ {
@ -1242,29 +1247,21 @@ namespace HeavenStudio
} }
GameObject prefab; GameObject prefab;
if (gameInfo.usesAssetBundle) if (gameInfo.UsesAssetBundle)
{ {
//game is packed in an assetbundle, load from that instead //game is packed in an assetbundle, load from that instead
if (gameInfo.AssetsLoaded && gameInfo.LoadedPrefab != null) return gameInfo.LoadedPrefab; if (gameInfo.AssetsLoaded && gameInfo.LoadedPrefab != null) return gameInfo.LoadedPrefab;
// couldn't load cached prefab, try loading from assetbundle // couldn't load cached prefab, try loading from resources (usually indev games with mispacked assetbundles)
try Debug.LogWarning($"Failed to load prefab for game {name} from assetbundle, trying Resources...");
prefab = Resources.Load<GameObject>($"Games/{name}");
if (prefab != null)
{ {
Debug.LogWarning($"Game prefab wasn't cached, loading from assetbundle for game {name}"); return prefab;
return gameInfo.LoadGamePrefab();
} }
catch (Exception e) else
{ {
Debug.LogWarning($"Failed to load assetbundle for game {name}, using sync loading: {e.Message}"); Debug.LogWarning($"Game {name} not found, using noGame");
prefab = Resources.Load<GameObject>($"Games/{name}"); return Resources.Load<GameObject>($"Games/noGame");
if (prefab != null)
{
return prefab;
}
else
{
Debug.LogWarning($"Game {name} not found, using noGame");
return Resources.Load<GameObject>($"Games/noGame");
}
} }
} }
// games with no assetbundle (usually indev games) // games with no assetbundle (usually indev games)
@ -1293,10 +1290,13 @@ namespace HeavenStudio
public bool TryGetMinigame<T>(out T mg) where T : Minigame public bool TryGetMinigame<T>(out T mg) where T : Minigame
{ {
if (minigame is T tempMinigame) { if (minigame is T tempMinigame)
{
mg = tempMinigame; mg = tempMinigame;
return true; return true;
} else { }
else
{
mg = null; mg = null;
return false; return false;
} }

View file

@ -220,7 +220,7 @@ namespace HeavenStudio.Editor.Commands
for (var i = 0; i < original.Count; i++) for (var i = 0; i < original.Count; i++)
{ {
var entity = original[i].DeepCopy(); var entity = original[i].DeepCopy();
entity.beat = Conductor.instance.songPositionInBeatsAsDouble + (entity.beat - firstEntityBeat); entity.beat = Timeline.instance.PlaybackBeat + (entity.beat - firstEntityBeat);
entityIds.Add(Guid.NewGuid()); entityIds.Add(Guid.NewGuid());
pasteEntityData.Add(entity); pasteEntityData.Add(entity);

View file

@ -48,7 +48,7 @@ namespace HeavenStudio.Editor.Track
private Vector2 relativeMousePos; private Vector2 relativeMousePos;
public Vector2 RelativeMousePos => relativeMousePos; public Vector2 RelativeMousePos => relativeMousePos;
public float PlaybackBeat = 0.0f; public double PlaybackBeat = 0d;
public static float SnapInterval() { return instance.snapInterval; } public static float SnapInterval() { return instance.snapInterval; }
@ -420,19 +420,19 @@ namespace HeavenStudio.Editor.Track
} }
else else
{ {
SongBeat.text = $"Beat {string.Format("{0:0.000}", cond.songPositionInBeats)}"; SongBeat.text = $"Beat {string.Format("{0:0.000}", cond.songPositionInBeatsAsDouble)}";
SongPos.text = FormatTime(cond.songPositionAsDouble); SongPos.text = FormatTime(cond.songPositionAsDouble);
} }
// Metronome animation // Metronome animation
{ {
var rectTransform = MetronomeBTN.transform.GetChild(1).GetComponent<RectTransform>(); RectTransform rectTransform = MetronomeBTN.transform.GetChild(1).GetComponent<RectTransform>();
var rot = 0.0f; float rot = 0f;
if (Conductor.instance.metronome) if (cond.metronome)
{ {
var startBeat = Mathf.FloorToInt(Conductor.instance.songPositionInBeats - 0.5f); int startBeat = (int)Math.Floor(cond.songPositionInBeats - 0.5);
var nm = Conductor.instance.GetLoopPositionFromBeat(0.5f, 1f, ignoreSwing: false); float nm = cond.GetLoopPositionFromBeat(0.5f, 1f, ignoreSwing: false);
var loop = (startBeat % 2 == 0) ? Mathf.SmoothStep(-1.1f, 1f, nm) : Mathf.SmoothStep(1f, -1f, nm); float loop = (startBeat % 2 == 0) ? Mathf.SmoothStep(-1.1f, 1f, nm) : Mathf.SmoothStep(1f, -1f, nm);
rot = loop * 45f; rot = loop * 45f;
} }
@ -631,12 +631,12 @@ namespace HeavenStudio.Editor.Track
} }
} }
public void Play(bool fromStart, float time) public void Play(bool fromStart, double time)
{ {
GameManager.instance.SafePlay(time, 0, false); GameManager.instance.SafePlay(time, 0, false);
if (!Conductor.instance.isPaused) if (!Conductor.instance.isPaused)
{ {
TimelineSongPosLineRef.transform.localPosition = new Vector3(time * PixelsPerBeat, TimelineSongPosLineRef.transform.localPosition.y); TimelineSongPosLineRef.transform.localPosition = new Vector3((float)time * PixelsPerBeat, TimelineSongPosLineRef.transform.localPosition.y);
} }
SetTimeButtonColors(false, true, true); SetTimeButtonColors(false, true, true);
@ -649,7 +649,7 @@ namespace HeavenStudio.Editor.Track
SetTimeButtonColors(true, false, true); SetTimeButtonColors(true, false, true);
} }
public void Stop(float time) public void Stop(double time)
{ {
if (TimelineSongPosLineRef != null) if (TimelineSongPosLineRef != null)
TimelineSongPosLineRef.gameObject.SetActive(false); TimelineSongPosLineRef.gameObject.SetActive(false);
@ -840,7 +840,8 @@ namespace HeavenStudio.Editor.Track
{ {
for (int i = 0; i < ep.Count; i++) for (int i = 0; i < ep.Count; i++)
{ {
object returnVal = ep[i].parameter switch { object returnVal = ep[i].parameter switch
{
EntityTypes.Integer intVal => intVal.val, EntityTypes.Integer intVal => intVal.val,
EntityTypes.Note noteVal => noteVal.val, EntityTypes.Note noteVal => noteVal.val,
EntityTypes.Float floatVal => floatVal.val, EntityTypes.Float floatVal => floatVal.val,
@ -850,7 +851,8 @@ namespace HeavenStudio.Editor.Track
_ => ep[i].parameter, _ => ep[i].parameter,
}; };
if (returnVal.GetType().IsEnum) { if (returnVal.GetType().IsEnum)
{
returnVal = (int)ep[i].parameter; returnVal = (int)ep[i].parameter;
} }
@ -907,8 +909,10 @@ namespace HeavenStudio.Editor.Track
{ {
var newEntity = entity.DeepCopy(); var newEntity = entity.DeepCopy();
// there's gotta be a better way to do this. i just don't know how... -AJ // there's gotta be a better way to do this. i just don't know how... -AJ
foreach ((var key, var value) in new Dictionary<string, dynamic>(newEntity.dynamicData)) { foreach ((var key, var value) in new Dictionary<string, dynamic>(newEntity.dynamicData))
if (value is EntityTypes.DropdownObj dd) { {
if (value is EntityTypes.DropdownObj dd)
{
newEntity[key] = new EntityTypes.DropdownObj(dd.value, dd.Values); newEntity[key] = new EntityTypes.DropdownObj(dd.value, dd.Values);
} }
} }

View file

@ -384,26 +384,26 @@ namespace HeavenStudio
public List<string> supportedLocales; public List<string> supportedLocales;
public bool inferred; public bool inferred;
public bool usesAssetBundle => wantAssetBundle is not null or ""; public bool UsesAssetBundle => (wantAssetBundle is not null or "") && (!badBundle);
public bool hasLocales => supportedLocales.Count > 0; public bool HasLocales => supportedLocales.Count > 0;
public bool AssetsLoaded => ((hasLocales && localeLoaded && currentLoadedLocale == defaultLocale) || (!hasLocales)) && commonLoaded && (!loadingPrefab) && loadComplete; public bool AssetsLoaded => (!badBundle) && ((HasLocales && audioLoaded && currentLoadedLocale == defaultLocale) || (!HasLocales)) && resourcesLoaded && loadComplete;
public bool AlreadyLoading => alreadyLoading; public bool AlreadyLoading => alreadyLoading;
public bool LoadingPrefab => loadingPrefab;
public bool SequencesPreloaded => soundSequences != null; public bool SequencesPreloaded => soundSequences != null;
public string LoadableName => inferred ? "noGame" : name; public string LoadableName => inferred ? "noGame" : name;
public GameObject LoadedPrefab => loadedPrefab; public GameObject LoadedPrefab => loadedPrefab;
private AssetBundle bundleCommon = null;
private bool commonLoaded = false;
private bool commonPreloaded = false;
private string currentLoadedLocale = ""; private string currentLoadedLocale = "";
private AssetBundle bundleLocalized = null; private AssetBundle bundleResources = null;
private bool localeLoaded = false; private bool resourcesLoaded = false;
private bool localePreloaded = false; private bool resourcesPreloaded = false;
private AssetBundle bundleAudio = null;
private bool audioLoaded = false;
private bool audioPreloaded = false;
private GameObject loadedPrefab = null; private GameObject loadedPrefab = null;
private bool badBundle = false;
// eventually implement secondary assetbundles for localization instead of one "common" and one "locale"
bool loadingPrefab = false;
bool loadComplete = false; bool loadComplete = false;
private SoundSequence.SequenceKeyValue[] soundSequences = null; private SoundSequence.SequenceKeyValue[] soundSequences = null;
@ -452,114 +452,132 @@ namespace HeavenStudio
this.splitColorR = splitColorR; this.splitColorR = splitColorR;
} }
public AssetBundle GetLocalizedAssetBundle()
{
if (bundleLocalized != null && !localeLoaded)
{
bundleLocalized.Unload(true);
bundleLocalized = null;
localeLoaded = false;
localePreloaded = false;
}
if (!hasLocales) return null;
if (!usesAssetBundle) return null;
if (bundleLocalized == null || currentLoadedLocale != defaultLocale) //TEMPORARY: use the game's default locale until we add localization support
{
if (localeLoaded) return bundleLocalized;
// TODO: try/catch for missing assetbundles
currentLoadedLocale = defaultLocale;
bundleLocalized = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, wantAssetBundle + "/locale." + defaultLocale));
localeLoaded = true;
}
return bundleLocalized;
}
public AssetBundle GetCommonAssetBundle()
{
if (bundleCommon != null && !commonLoaded)
{
bundleCommon.Unload(true);
bundleCommon = null;
commonLoaded = false;
commonPreloaded = false;
}
if (commonLoaded) return bundleCommon;
if (!usesAssetBundle) return null;
if (bundleCommon == null)
{
// TODO: try/catch for missing assetbundles
bundleCommon = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, wantAssetBundle + "/common"));
commonLoaded = true;
}
return bundleCommon;
}
bool alreadyLoading = false; bool alreadyLoading = false;
public async UniTaskVoid LoadAssetsAsync() public async UniTaskVoid LoadAssetsAsync()
{ {
if (alreadyLoading || AssetsLoaded || !usesAssetBundle) return; if (alreadyLoading || AssetsLoaded || !UsesAssetBundle) return;
loadComplete = false; loadComplete = false;
alreadyLoading = true; alreadyLoading = true;
loadingPrefab = true; await UniTask.WhenAll(LoadResourcesAssetBundleAsync(), LoadAudioAssetBundleAsync());
await UniTask.WhenAll(LoadCommonAssetBundleAsync(), LoadLocalizedAssetBundleAsync()); if (badBundle)
await UniTask.WhenAll(LoadGamePrefabAsync(), LoadCommonAudioClips(), LoadLocalizedAudioClips()); {
Debug.LogWarning($"Bad bundle for {name}");
alreadyLoading = false;
loadComplete = true;
return;
}
await UniTask.WhenAll(LoadGamePrefabAsync(), PrepareResources(), PrepareAudio());
SoundByte.PreloadGameAudioClips(this); SoundByte.PreloadGameAudioClips(this);
alreadyLoading = false; alreadyLoading = false;
loadComplete = true; loadComplete = true;
} }
public async UniTask LoadCommonAssetBundleAsync() public AssetBundle GetAudioAssetBundle()
{ {
if (bundleCommon != null && !commonLoaded) if (bundleAudio != null && !audioLoaded)
{ {
await bundleCommon.UnloadAsync(true); bundleAudio.Unload(true);
bundleCommon = null; bundleAudio = null;
commonLoaded = false; audioLoaded = false;
commonPreloaded = false; audioPreloaded = false;
} }
if (!HasLocales) return null;
if (commonPreloaded || commonLoaded) return; if (!UsesAssetBundle) return null;
commonPreloaded = true; if (bundleAudio == null || currentLoadedLocale != defaultLocale) //TEMPORARY: use the game's default locale until we add localization support
if (!usesAssetBundle) return; {
if (bundleCommon != null) return; if (audioLoaded) return bundleAudio;
// TODO: try/catch for missing assetbundles
AssetBundle bundle = await AssetBundle.LoadFromFileAsync(Path.Combine(Application.streamingAssetsPath, wantAssetBundle + "/common")).ToUniTask(timing: PlayerLoopTiming.PreLateUpdate); currentLoadedLocale = defaultLocale;
bundleAudio = AssetBundle.LoadFromFile(Path.GetFullPath(Path.Combine(Application.streamingAssetsPath, wantAssetBundle, "locale." + defaultLocale)));
bundleCommon = bundle; audioLoaded = true;
commonLoaded = true; }
return bundleAudio;
} }
public async UniTask LoadLocalizedAssetBundleAsync() public AssetBundle GetResourcesAssetBundle()
{ {
if (bundleLocalized != null && !localeLoaded) if (badBundle) return null;
string path = Path.GetFullPath(Path.Combine(Application.streamingAssetsPath, wantAssetBundle, "common"));
if (bundleResources != null && !resourcesLoaded)
{ {
await bundleLocalized.UnloadAsync(true); bundleResources.Unload(true);
bundleLocalized = null; bundleResources = null;
localeLoaded = false; resourcesLoaded = false;
localePreloaded = false; resourcesPreloaded = false;
}
if (!File.Exists(path))
{
badBundle = true;
return null;
}
if (resourcesLoaded) return bundleResources;
if (!UsesAssetBundle) return null;
if (bundleResources == null)
{
bundleResources = AssetBundle.LoadFromFile(path);
resourcesLoaded = true;
}
return bundleResources;
}
public async UniTask LoadResourcesAssetBundleAsync()
{
if (badBundle) return;
string path = Path.GetFullPath(Path.Combine(Application.streamingAssetsPath, wantAssetBundle, "common"));
if (bundleResources != null && !resourcesLoaded)
{
await bundleResources.UnloadAsync(true);
bundleResources = null;
resourcesLoaded = false;
resourcesPreloaded = false;
}
// ignore all AB checks if path doesn't exist
if (!File.Exists(path))
{
badBundle = true;
return;
}
if (resourcesPreloaded || resourcesLoaded) return;
resourcesPreloaded = true;
if (!UsesAssetBundle) return;
if (bundleResources != null) return;
AssetBundle bundle = await AssetBundle.LoadFromFileAsync(path).ToUniTask(timing: PlayerLoopTiming.PreLateUpdate);
bundleResources = bundle;
resourcesLoaded = true;
}
public async UniTask LoadAudioAssetBundleAsync()
{
if (bundleAudio != null && !audioLoaded)
{
await bundleAudio.UnloadAsync(true);
bundleAudio = null;
audioLoaded = false;
audioPreloaded = false;
} }
if (!hasLocales) return; if (!HasLocales) return;
if (localePreloaded) return; if (audioPreloaded) return;
localePreloaded = true; audioPreloaded = true;
if (!usesAssetBundle) return; if (!UsesAssetBundle) return;
if (localeLoaded && bundleLocalized != null && currentLoadedLocale == defaultLocale) return; if (audioLoaded && bundleAudio != null && currentLoadedLocale == defaultLocale) return;
AssetBundle bundle = await AssetBundle.LoadFromFileAsync(Path.Combine(Application.streamingAssetsPath, wantAssetBundle + "/locale." + defaultLocale)).ToUniTask(timing: PlayerLoopTiming.PreLateUpdate); AssetBundle bundle = await AssetBundle.LoadFromFileAsync(Path.GetFullPath(Path.Combine(Application.streamingAssetsPath, wantAssetBundle, "locale." + defaultLocale))).ToUniTask(timing: PlayerLoopTiming.PreLateUpdate);
if (localeLoaded && bundleLocalized != null && currentLoadedLocale == defaultLocale) return; if (audioLoaded && bundleAudio != null && currentLoadedLocale == defaultLocale) return;
bundleLocalized = bundle; bundleAudio = bundle;
currentLoadedLocale = defaultLocale; currentLoadedLocale = defaultLocale;
localeLoaded = true; audioLoaded = true;
} }
public async UniTask LoadGamePrefabAsync() public async UniTask LoadGamePrefabAsync()
{ {
if (!usesAssetBundle) return; if (!UsesAssetBundle) return;
if (!commonLoaded) return; if (!resourcesLoaded) return;
if (bundleCommon == null) return; if (bundleResources == null) return;
if (badBundle) return;
AssetBundleRequest request = bundleCommon.LoadAssetAsync<GameObject>(name); AssetBundleRequest request = bundleResources.LoadAssetAsync<GameObject>(name);
request.completed += (op) => OnPrefabLoaded(op as AssetBundleRequest); request.completed += (op) => OnPrefabLoaded(op as AssetBundleRequest);
await request; await request;
loadedPrefab = request.asset as GameObject; loadedPrefab = request.asset as GameObject;
@ -576,59 +594,49 @@ namespace HeavenStudio
soundSequences = minigame.SoundSequences; soundSequences = minigame.SoundSequences;
} }
loadedPrefab = prefab; loadedPrefab = prefab;
loadingPrefab = false;
} }
public GameObject LoadGamePrefab() public async UniTask PrepareResources()
{ {
if (!usesAssetBundle) return null; if (!resourcesLoaded) return;
if (bundleResources == null) return;
loadedPrefab = GetCommonAssetBundle().LoadAsset<GameObject>(name); var assets = bundleResources.LoadAllAssetsAsync();
return loadedPrefab;
}
public async UniTask LoadCommonAudioClips()
{
if (!commonLoaded) return;
if (bundleCommon == null) return;
var assets = bundleCommon.LoadAllAssetsAsync();
await assets; await assets;
} }
public async UniTask LoadLocalizedAudioClips() public async UniTask PrepareAudio()
{ {
if (!localeLoaded) return; if (!audioLoaded) return;
if (bundleLocalized == null) return; if (bundleAudio == null) return;
var assets = bundleLocalized.LoadAllAssetsAsync(); var assets = bundleAudio.LoadAllAssetsAsync();
await assets; await assets;
} }
public async UniTask UnloadAllAssets() public async UniTask UnloadAllAssets()
{ {
if (!usesAssetBundle) return; if (!UsesAssetBundle) return;
if (loadedPrefab != null) if (loadedPrefab != null)
{ {
loadedPrefab = null; loadedPrefab = null;
} }
if (bundleCommon != null) if (bundleResources != null)
{ {
await bundleCommon.UnloadAsync(true); await bundleResources.UnloadAsync(true);
bundleCommon = null; bundleResources = null;
commonLoaded = false; resourcesLoaded = false;
commonPreloaded = false; resourcesPreloaded = false;
} }
if (bundleLocalized != null) if (bundleAudio != null)
{ {
await bundleLocalized.UnloadAsync(true); await bundleAudio.UnloadAsync(true);
bundleLocalized = null; bundleAudio = null;
localeLoaded = false; audioLoaded = false;
localePreloaded = false; audioPreloaded = false;
} }
SoundByte.UnloadAudioClips(name); SoundByte.UnloadAudioClips(name);
loadComplete = false; loadComplete = false;
loadingPrefab = false;
} }
} }
@ -1243,8 +1251,8 @@ namespace HeavenStudio
string gameName = ((EntityTypes.DropdownObj)e["game"]).CurrentValue; string gameName = ((EntityTypes.DropdownObj)e["game"]).CurrentValue;
List<string> clips; List<string> clips;
if (eventCaller.minigames.TryGetValue(gameName, out Minigame game) && game != null) { if (eventCaller.minigames.TryGetValue(gameName, out Minigame game) && game != null) {
IEnumerable<AudioClip> audioClips = game.GetCommonAssetBundle().LoadAllAssets<AudioClip>(); IEnumerable<AudioClip> audioClips = game.GetResourcesAssetBundle().LoadAllAssets<AudioClip>();
var localAssBun = game.GetLocalizedAssetBundle(); var localAssBun = game.GetAudioAssetBundle();
if (localAssBun != null) { if (localAssBun != null) {
audioClips = audioClips.Concat(localAssBun.LoadAllAssets<AudioClip>()); audioClips = audioClips.Concat(localAssBun.LoadAllAssets<AudioClip>());
} }

View file

@ -20,7 +20,7 @@ namespace HeavenStudio.Common
[SerializeField] private Animator starAnim; [SerializeField] private Animator starAnim;
[SerializeField] private ParticleSystem starParticle; [SerializeField] private ParticleSystem starParticle;
public double StarTargetTime { get { return starStart + starLength; } } public double StarTargetTime { get { return cond.GetUnSwungBeat(starStart + starLength); } }
public bool IsEligible { get; private set; } public bool IsEligible { get; private set; }
public bool IsCollected { get { return state == StarState.Collected; } } public bool IsCollected { get { return state == StarState.Collected; } }
@ -41,14 +41,14 @@ namespace HeavenStudio.Common
{ {
if (cond.songPositionInBeatsAsDouble > starStart && state == StarState.In) if (cond.songPositionInBeatsAsDouble > starStart && state == StarState.In)
{ {
double offset = cond.SecsToBeats(Minigame.AceEarlyTime()-1, cond.GetBpmAtBeat(StarTargetTime)); double offset = cond.SecsToBeats(Minigame.AceEarlyTime() - 1, cond.GetBpmAtBeat(StarTargetTime));
if (cond.songPositionInBeatsAsDouble <= starStart + starLength + offset) if (cond.unswungSongPositionInBeatsAsDouble <= StarTargetTime + offset)
starAnim.DoScaledAnimation("StarIn", starStart, starLength + (float)offset); starAnim.DoScaledAnimation("StarIn", starStart, starLength + (float)offset);
else else
starAnim.Play("StarIn", -1, 1f); starAnim.Play("StarIn", -1, 1f);
offset = cond.SecsToBeats(Minigame.AceLateTime()-1, cond.GetBpmAtBeat(StarTargetTime)); offset = cond.SecsToBeats(Minigame.AceLateTime() - 1, cond.GetBpmAtBeat(StarTargetTime));
if (cond.songPositionInBeatsAsDouble > starStart + starLength + offset) if (cond.unswungSongPositionInBeatsAsDouble > StarTargetTime + offset)
KillStar(); KillStar();
} }
} }
@ -94,8 +94,8 @@ namespace HeavenStudio.Common
public bool DoStarJust() public bool DoStarJust()
{ {
if (state == StarState.In && if (state == StarState.In &&
cond.songPositionInBeatsAsDouble >= StarTargetTime + cond.SecsToBeats(Minigame.AceEarlyTime()-1, cond.GetBpmAtBeat(StarTargetTime)) && cond.unswungSongPositionInBeatsAsDouble >= StarTargetTime + cond.SecsToBeats(Minigame.AceEarlyTime() - 1, cond.GetBpmAtBeat(StarTargetTime)) &&
cond.songPositionInBeatsAsDouble <= StarTargetTime + cond.SecsToBeats(Minigame.AceLateTime()-1, cond.GetBpmAtBeat(StarTargetTime)) cond.unswungSongPositionInBeatsAsDouble <= StarTargetTime + cond.SecsToBeats(Minigame.AceLateTime() - 1, cond.GetBpmAtBeat(StarTargetTime))
) )
{ {
state = StarState.Collected; state = StarState.Collected;
@ -111,7 +111,7 @@ namespace HeavenStudio.Common
public void KillStar() public void KillStar()
{ {
if (state == StarState.In && cond.songPositionInBeatsAsDouble >= starStart + starLength*0.5f || !cond.isPlaying) if (state == StarState.In && cond.songPositionInBeatsAsDouble >= starStart + (starLength * 0.5f) || !cond.isPlaying)
{ {
IsEligible = false; IsEligible = false;
state = StarState.Out; state = StarState.Out;

View file

@ -81,9 +81,9 @@ namespace HeavenStudio.Util
public static void PreloadGameAudioClips(Minigames.Minigame inf) public static void PreloadGameAudioClips(Minigames.Minigame inf)
{ {
if (inf.usesAssetBundle) if (inf.UsesAssetBundle)
{ {
var cmnAb = inf.GetCommonAssetBundle(); var cmnAb = inf.GetResourcesAssetBundle();
if (cmnAb != null) if (cmnAb != null)
{ {
cmnAb.LoadAllAssetsAsync<AudioClip>().completed += (op) => cmnAb.LoadAllAssetsAsync<AudioClip>().completed += (op) =>
@ -94,7 +94,7 @@ namespace HeavenStudio.Util
} }
}; };
} }
var locAb = inf.GetLocalizedAssetBundle(); var locAb = inf.GetAudioAssetBundle();
if (locAb != null) if (locAb != null)
{ {
locAb.LoadAllAssetsAsync<AudioClip>().completed += (op) => locAb.LoadAllAssetsAsync<AudioClip>().completed += (op) =>
@ -131,9 +131,9 @@ namespace HeavenStudio.Util
name = $"games/{name}"; name = $"games/{name}";
} }
if (audioClips.ContainsKey(name)) return; if (audioClips.ContainsKey(name)) return;
if (inf.usesAssetBundle) if (inf.UsesAssetBundle)
{ {
var cmnAb = inf.GetCommonAssetBundle(); var cmnAb = inf.GetResourcesAssetBundle();
if (cmnAb != null && cmnAb.Contains(name)) if (cmnAb != null && cmnAb.Contains(name))
{ {
var request = cmnAb.LoadAssetAsync<AudioClip>(name); var request = cmnAb.LoadAssetAsync<AudioClip>(name);
@ -144,7 +144,7 @@ namespace HeavenStudio.Util
} }
else else
{ {
var locAb = inf.GetLocalizedAssetBundle(); var locAb = inf.GetAudioAssetBundle();
if (locAb != null && locAb.Contains(name)) if (locAb != null && locAb.Contains(name))
{ {
var request = locAb.LoadAssetAsync<AudioClip>(name); var request = locAb.LoadAssetAsync<AudioClip>(name);
@ -232,12 +232,12 @@ namespace HeavenStudio.Util
var inf = GameManager.instance.GetGameInfo(game); var inf = GameManager.instance.GetGameInfo(game);
//first try the game's common assetbundle //first try the game's common assetbundle
// Debug.Log("Jukebox loading sound " + soundName + " from common"); // Debug.Log("Jukebox loading sound " + soundName + " from common");
clip = inf.GetCommonAssetBundle()?.LoadAsset<AudioClip>(soundName); clip = inf.GetResourcesAssetBundle()?.LoadAsset<AudioClip>(soundName);
//then the localized one //then the localized one
if (clip == null) if (clip == null)
{ {
// Debug.Log("Jukebox loading sound " + soundName + " from locale"); // Debug.Log("Jukebox loading sound " + soundName + " from locale");
clip = inf.GetLocalizedAssetBundle()?.LoadAsset<AudioClip>(soundName); clip = inf.GetAudioAssetBundle()?.LoadAsset<AudioClip>(soundName);
} }
} }
} }
@ -274,7 +274,7 @@ namespace HeavenStudio.Util
var inf = GameManager.instance.GetGameInfo(gameName); var inf = GameManager.instance.GetGameInfo(gameName);
if (inf != null) if (inf != null)
{ {
return GetClipLength($"games/{name}", pitch, inf.usesAssetBundle ? gameName : null); return GetClipLength($"games/{name}", pitch, inf.UsesAssetBundle ? gameName : null);
} }
return double.NaN; return double.NaN;
@ -301,12 +301,12 @@ namespace HeavenStudio.Util
var inf = GameManager.instance.GetGameInfo(game); var inf = GameManager.instance.GetGameInfo(game);
//first try the game's common assetbundle //first try the game's common assetbundle
// Debug.Log("Jukebox loading sound " + soundName + " from common"); // Debug.Log("Jukebox loading sound " + soundName + " from common");
clip = inf.GetCommonAssetBundle()?.LoadAsset<AudioClip>(soundName); clip = inf.GetResourcesAssetBundle()?.LoadAsset<AudioClip>(soundName);
//then the localized one //then the localized one
if (clip == null) if (clip == null)
{ {
// Debug.Log("Jukebox loading sound " + soundName + " from locale"); // Debug.Log("Jukebox loading sound " + soundName + " from locale");
clip = inf.GetLocalizedAssetBundle()?.LoadAsset<AudioClip>(soundName); clip = inf.GetAudioAssetBundle()?.LoadAsset<AudioClip>(soundName);
} }
} }
} }
@ -374,12 +374,12 @@ namespace HeavenStudio.Util
var inf = GameManager.instance.GetGameInfo(game); var inf = GameManager.instance.GetGameInfo(game);
//first try the game's common assetbundle //first try the game's common assetbundle
// Debug.Log("Jukebox loading sound " + soundName + " from common"); // Debug.Log("Jukebox loading sound " + soundName + " from common");
clip = inf.GetCommonAssetBundle()?.LoadAsset<AudioClip>(soundName); clip = inf.GetResourcesAssetBundle()?.LoadAsset<AudioClip>(soundName);
//then the localized one //then the localized one
if (clip == null) if (clip == null)
{ {
// Debug.Log("Jukebox loading sound " + soundName + " from locale"); // Debug.Log("Jukebox loading sound " + soundName + " from locale");
clip = inf.GetLocalizedAssetBundle()?.LoadAsset<AudioClip>(soundName); clip = inf.GetAudioAssetBundle()?.LoadAsset<AudioClip>(soundName);
} }
} }
} }
@ -424,7 +424,7 @@ namespace HeavenStudio.Util
var inf = GameManager.instance.GetGameInfo(gameName); var inf = GameManager.instance.GetGameInfo(gameName);
if (GameManager.instance.currentGame == gameName || forcePlay) if (GameManager.instance.currentGame == gameName || forcePlay)
{ {
return PlayOneShot($"games/{name}", beat, pitch, volume, looping, inf.usesAssetBundle ? gameName : null, offset, ignoreConductorPause); return PlayOneShot($"games/{name}", beat, pitch, volume, looping, inf.UsesAssetBundle ? gameName : null, offset, ignoreConductorPause);
} }
return null; return null;
@ -440,7 +440,7 @@ namespace HeavenStudio.Util
var inf = GameManager.instance.GetGameInfo(gameName); var inf = GameManager.instance.GetGameInfo(gameName);
if (GameManager.instance.currentGame == gameName || forcePlay) if (GameManager.instance.currentGame == gameName || forcePlay)
{ {
return PlayOneShotScheduled($"games/{name}", targetTime, pitch, volume, looping, inf.usesAssetBundle ? gameName : null, ignoreConductorPause); return PlayOneShotScheduled($"games/{name}", targetTime, pitch, volume, looping, inf.UsesAssetBundle ? gameName : null, ignoreConductorPause);
} }
return null; return null;