Allow games to load assets from AssetBundles (#102)

* Loading improvements: prepwork for loading from assetbundles

* note for sfx

* cleaner code

* correct type

* put loaded assetbundle in the minigame data instead

also lays groundwork for future localization stuff

* add samurai slice gold, coin toss assetbundles

* very messy "already loaded" checks

* make Dj School load from assetbundle
This commit is contained in:
minenice55
2022-06-12 15:32:00 -04:00
committed by GitHub
parent cd70267243
commit 1dda4f9477
387 changed files with 1582 additions and 1463 deletions

View File

@ -31,7 +31,7 @@ namespace HeavenStudio
Coroutine currentGameSwitchIE;
[Header("Properties")]
public int currentEvent, currentTempoEvent;
public int currentEvent, currentTempoEvent, currentPreEvent, currentPreSwitch;
public float startOffset;
public bool playOnStart;
public float startBeat;
@ -57,7 +57,11 @@ namespace HeavenStudio
public void Init()
{
currentPreEvent= 0;
currentPreSwitch = 0;
this.transform.localScale = new Vector3(30000000, 30000000);
SpriteRenderer sp = this.gameObject.AddComponent<SpriteRenderer>();
sp.enabled = false;
sp.color = Color.black;
@ -148,6 +152,49 @@ namespace HeavenStudio
}
}
public void SeekAheadAndPreload(float start, float seekTime = 8f)
{
//seek ahead to preload games that have assetbundles
//check game switches first
var gameSwitchs = Beatmap.entities.FindAll(c => c.datamodel.Split(1) == "switchGame");
if (currentPreSwitch < gameSwitchs.Count && currentPreSwitch >= 0)
{
if (start + seekTime >= gameSwitchs[currentPreSwitch].beat)
{
string gameName = gameSwitchs[currentPreSwitch].datamodel.Split(2);
var inf = GetGameInfo(gameName);
if (inf.usesAssetBundle && !inf.AssetsLoaded)
{
Debug.Log("ASYNC loading assetbundle for game " + gameName);
StartCoroutine(inf.LoadCommonAssetBundleAsync());
StartCoroutine(inf.LoadLocalizedAssetBundleAsync());
}
currentPreSwitch++;
}
}
//then check game entities
List<float> entities = Beatmap.entities.Select(c => c.beat).ToList();
if (currentPreEvent < Beatmap.entities.Count && currentPreEvent >= 0)
{
if (start + seekTime >= entities[currentPreEvent])
{
var entitiesAtSameBeat = Beatmap.entities.FindAll(c => c.beat == Beatmap.entities[currentPreEvent].beat && !EventCaller.FXOnlyGames().Contains(EventCaller.instance.GetMinigame(c.datamodel.Split('/')[0])));
for (int i = 0; i < entitiesAtSameBeat.Count; i++)
{
string gameName = entitiesAtSameBeat[i].datamodel.Split('/')[0];
var inf = GetGameInfo(gameName);
if (inf.usesAssetBundle && !inf.AssetsLoaded)
{
Debug.Log("ASYNC loading assetbundle for game " + gameName);
StartCoroutine(inf.LoadCommonAssetBundleAsync());
StartCoroutine(inf.LoadLocalizedAssetBundleAsync());
}
}
currentPreEvent++;
}
}
}
// LateUpdate works a bit better(?) but causes some bugs (like issues with bop animations).
private void Update()
{
@ -171,6 +218,10 @@ namespace HeavenStudio
}
}
float seekTime = 8f;
//seek ahead to preload games that have assetbundles
SeekAheadAndPreload(Conductor.instance.songPositionInBeats, seekTime);
if (currentEvent < Beatmap.entities.Count && currentEvent >= 0)
{
if (Conductor.instance.songPositionInBeats >= entities[currentEvent] /*&& SongPosLessThanClipLength(Conductor.instance.songPositionInBeats)*/)
@ -281,6 +332,7 @@ namespace HeavenStudio
List<float> entities = Beatmap.entities.Select(c => c.beat).ToList();
currentEvent = entities.IndexOf(Mathp.GetClosestInList(entities, beat));
currentPreEvent = entities.IndexOf(Mathp.GetClosestInList(entities, beat));
var gameSwitchs = Beatmap.entities.FindAll(c => c.datamodel.Split(1) == "switchGame");
@ -289,6 +341,7 @@ namespace HeavenStudio
if (gameSwitchs.Count > 0)
{
int index = gameSwitchs.FindIndex(c => c.beat == Mathp.GetClosestInList(gameSwitchs.Select(c => c.beat).ToList(), beat));
currentPreSwitch = index;
var closestGameSwitch = gameSwitchs[index];
if (closestGameSwitch.beat <= beat)
{
@ -342,6 +395,8 @@ namespace HeavenStudio
}
// Debug.Log("currentTempoEvent is now " + currentTempoEvent);
}
SeekAheadAndPreload(beat);
}
#endregion
@ -434,6 +489,14 @@ namespace HeavenStudio
return !newGameInfo.fxOnly;
}).ToList()[0].datamodel.Split(0);
}
else
{
if (gameInfo.usesAssetBundle)
{
//game is packed in an assetbundle, load from that instead
return gameInfo.GetCommonAssetBundle().LoadAsset<GameObject>(name);
}
}
}
return Resources.Load<GameObject>($"Games/{name}");
}

View File

@ -38,7 +38,11 @@ namespace HeavenStudio.Games.Loaders
new Param("colorA", Color.white, "Start Color", "The starting color in the fade"),
new Param("colorB", CoinToss.defaultFgColor, "End Color", "The ending color in the fade")
} ),
});
},
new List<string>() {"ntr", "aim"},
"ntrcoin", "en",
new List<string>() {}
);
}
}
}

View File

@ -25,7 +25,11 @@ namespace HeavenStudio.Games.Loaders
{
new Param("type", DJSchool.DJVoice.Standard, "Voice", "The voice line to play"),
}),
});
},
new List<string>() {"ntr", "normal"},
"ntrdj", "en",
new List<string>(){}
);
}
}
}

View File

@ -12,51 +12,55 @@ namespace HeavenStudio.Games.Loaders
{
public static Minigame AddGame(EventCaller eventCaller) {
return new Minigame("fanClub", "Fan Club", "FDFD00", false, false, new List<GameAction>()
{
new GameAction("bop", delegate { var e = eventCaller.currentEntity; FanClub.instance.Bop(e.beat, e.length, e.type); }, 0.5f, true, parameters: new List<Param>()
{
new Param("type", FanClub.IdolBopType.Both, "Bop target", "Who to make bop"),
}),
new GameAction("yeah, yeah, yeah", delegate { var e = eventCaller.currentEntity; FanClub.instance.CallHai(e.beat, e.toggle); }, 8, false, parameters: new List<Param>()
new GameAction("bop", delegate { var e = eventCaller.currentEntity; FanClub.instance.Bop(e.beat, e.length, e.type); }, 0.5f, true, parameters: new List<Param>()
{
new Param("toggle", false, "Disable call", "Disable the idol's call")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.WarnHai(e.beat, e.toggle);}
),
new Param("type", FanClub.IdolBopType.Both, "Bop target", "Who to make bop"),
}),
new GameAction("I suppose", delegate { var e = eventCaller.currentEntity; FanClub.instance.CallKamone(e.beat, e.toggle, 0, e.type); }, 6, false, parameters: new List<Param>()
new GameAction("yeah, yeah, yeah", delegate { var e = eventCaller.currentEntity; FanClub.instance.CallHai(e.beat, e.toggle); }, 8, false, parameters: new List<Param>()
{
new Param("toggle", false, "Disable call", "Disable the idol's call")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.WarnHai(e.beat, e.toggle);}
),
new GameAction("I suppose", delegate { var e = eventCaller.currentEntity; FanClub.instance.CallKamone(e.beat, e.toggle, 0, e.type); }, 6, false, parameters: new List<Param>()
{
new Param("type", FanClub.KamoneResponseType.Through, "Response type", "Type of response to use"),
new Param("toggle", false, "Disable call", "Disable the idol's call")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.WarnKamone(e.beat, e.toggle, 0, e.type);}
),
new GameAction("double clap", delegate { var e = eventCaller.currentEntity; FanClub.instance.CallBigReady(e.beat, e.toggle); }, 4, false, parameters: new List<Param>()
{
new Param("toggle", false, "Disable call", "Disable the call")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.WarnBigReady(e.beat, e.toggle); }
),
new GameAction("play idol animation", delegate { var e = eventCaller.currentEntity; FanClub.instance.PlayAnim(e.beat, e.length, e.type); }, 1, true, parameters: new List<Param>()
{
new Param("type", FanClub.KamoneResponseType.Through, "Response type", "Type of response to use"),
new Param("toggle", false, "Disable call", "Disable the idol's call")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.WarnKamone(e.beat, e.toggle, 0, e.type);}
),
new Param("type", FanClub.IdolAnimations.Bop, "Animation", "Animation to play")
}),
new GameAction("double clap", delegate { var e = eventCaller.currentEntity; FanClub.instance.CallBigReady(e.beat, e.toggle); }, 4, false, parameters: new List<Param>()
new GameAction("play stage animation", delegate { var e = eventCaller.currentEntity; FanClub.instance.PlayAnimStage(e.beat, e.type); }, 1, true, parameters: new List<Param>()
{
new Param("toggle", false, "Disable call", "Disable the call")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.WarnBigReady(e.beat, e.toggle); }
),
new Param("type", FanClub.StageAnimations.Flash, "Animation", "Animation to play")
}),
new GameAction("play idol animation", delegate { var e = eventCaller.currentEntity; FanClub.instance.PlayAnim(e.beat, e.length, e.type); }, 1, true, parameters: new List<Param>()
{
new Param("type", FanClub.IdolAnimations.Bop, "Animation", "Animation to play")
}),
new GameAction("play stage animation", delegate { var e = eventCaller.currentEntity; FanClub.instance.PlayAnimStage(e.beat, e.type); }, 1, true, parameters: new List<Param>()
{
new Param("type", FanClub.StageAnimations.Flash, "Animation", "Animation to play")
}),
new GameAction("set performance type", delegate { var e = eventCaller.currentEntity; FanClub.SetPerformanceType(e.type);}, 0.5f, false, parameters: new List<Param>()
{
new Param("type", FanClub.IdolPerformanceType.Normal, "Performance Type", "Set of animations for the idol to use")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.SetPerformanceType(e.type); }
),
});
new GameAction("set performance type", delegate { var e = eventCaller.currentEntity; FanClub.SetPerformanceType(e.type);}, 0.5f, false, parameters: new List<Param>()
{
new Param("type", FanClub.IdolPerformanceType.Normal, "Performance Type", "Set of animations for the idol to use")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.SetPerformanceType(e.type); }
),
},
new List<string>() {"ntr", "normal"},
"ntridol", "jp",
new List<string>() {"jp"}
);
}
}
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5566a9e256ded1e4f9c7a6a6d177da67
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -21,7 +21,6 @@ namespace HeavenStudio.Games
public float createBeat;
}
public List<PlayerActionEvent> scheduledInputs = new List<PlayerActionEvent>();
/**

View File

@ -91,10 +91,10 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
else
{
startThrowTime = Single.MinValue;
Projectile.transform.localPosition = new Vector3(0, 0);
Projectile.transform.rotation = Quaternion.Euler(0, 0, 0);
if (hasThrown)
{
Projectile.transform.localPosition = new Vector3(0, 0);
Projectile.transform.rotation = Quaternion.Euler(0, 0, 0);
anim.DoUnscaledAnimation("MonkeyBeat");
Projectile.SetActive(false);
hasThrown = false;

View File

@ -114,12 +114,12 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
}
else
{
Projectile.GetComponent<Animator>().Play("NoPose", -1, 0);
startThrowTime = Single.MinValue;
Projectile_Root.transform.localPosition = new Vector3(0, 0);
Projectile.transform.rotation = Quaternion.Euler(0, 0, 0);
if (hasThrown)
{
Projectile.GetComponent<Animator>().Play("NoPose", -1, 0);
Projectile.transform.rotation = Quaternion.Euler(0, 0, 0);
if (throwNg)
{
anim.DoUnscaledAnimation("MakoCatchNg");
@ -129,7 +129,7 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
anim.DoUnscaledAnimation("MakoCatch");
}
//TODO: change when locales are a thing
Jukebox.PlayOneShotGame("pajamaParty/jp/catch" + UnityEngine.Random.Range(0, 2)); //bruh
Jukebox.PlayOneShotGame("pajamaParty/catch" + UnityEngine.Random.Range(0, 2)); //bruh
Projectile.SetActive(false);
hasThrown = false;
@ -197,7 +197,7 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
beat + 0.5f,
delegate {
anim.DoScaledAnimationAsync("MakoPickUp");
Jukebox.PlayOneShotGame("pajamaParty/jp/catch" + UnityEngine.Random.Range(0, 2)); //bruh
Jukebox.PlayOneShotGame("pajamaParty/catch" + UnityEngine.Random.Range(0, 2)); //bruh
Projectile.SetActive(false);
canCharge = true;
canJump = true;
@ -273,7 +273,7 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
public void ChargeJustOrNg(PlayerActionEvent caller, float state) {
StartCharge();
throwNg = (state <= -1f || state >= 1f);
Jukebox.PlayOneShotGame("pajamaParty/jp/throw4");
Jukebox.PlayOneShotGame("pajamaParty/throw4");
}
public void ThrowJustOrNg(PlayerActionEvent caller, float state)
@ -288,7 +288,7 @@ namespace HeavenStudio.Games.Scripts_PajamaParty
}
else
{
Jukebox.PlayOneShotGame("pajamaParty/jp/throw5");
Jukebox.PlayOneShotGame("pajamaParty/throw5");
EndCharge(cond.songPositionInBeats, true, (throwNg || false));
}
caller.CanHit(false);

View File

@ -13,28 +13,32 @@ namespace HeavenStudio.Games.Loaders
{
public static Minigame AddGame(EventCaller eventCaller) {
return new Minigame("pajamaParty", "Pajama Party", "965076", false, false, new List<GameAction>()
{
// both same timing
new GameAction("jump (side to middle)", delegate {PajamaParty.instance.DoThreeJump(eventCaller.currentEntity.beat);}, 4f, false,
inactiveFunction: delegate {PajamaParty.WarnThreeJump(eventCaller.currentEntity.beat);}
),
new GameAction("jump (back to front)", delegate {PajamaParty.instance.DoFiveJump(eventCaller.currentEntity.beat);}, 4f, false,
inactiveFunction: delegate {PajamaParty.WarnFiveJump(eventCaller.currentEntity.beat);}
{
// both same timing
new GameAction("jump (side to middle)", delegate {PajamaParty.instance.DoThreeJump(eventCaller.currentEntity.beat);}, 4f, false,
inactiveFunction: delegate {PajamaParty.WarnThreeJump(eventCaller.currentEntity.beat);}
),
//idem
new GameAction("slumber", delegate {var e = eventCaller.currentEntity; PajamaParty.instance.DoSleepSequence(e.beat, e.toggle);}, 8f, false, parameters: new List<Param>()
{
new Param("toggle", false, "Alt. Animation", "Use an alternate animation for Mako")
},
inactiveFunction: delegate {var e = eventCaller.currentEntity; PajamaParty.WarnSleepSequence(e.beat, e.toggle);}
),
new GameAction("throw", delegate {PajamaParty.instance.DoThrowSequence(eventCaller.currentEntity.beat);}, 8f, false,
inactiveFunction: delegate {PajamaParty.WarnThrowSequence(eventCaller.currentEntity.beat);}
),
//cosmetic
// new GameAction("open / close background", delegate { }, 2f, true),
// do shit with mako's face? (talking?)
});
new GameAction("jump (back to front)", delegate {PajamaParty.instance.DoFiveJump(eventCaller.currentEntity.beat);}, 4f, false,
inactiveFunction: delegate {PajamaParty.WarnFiveJump(eventCaller.currentEntity.beat);}
),
//idem
new GameAction("slumber", delegate {var e = eventCaller.currentEntity; PajamaParty.instance.DoSleepSequence(e.beat, e.toggle);}, 8f, false, parameters: new List<Param>()
{
new Param("toggle", false, "Alt. Animation", "Use an alternate animation for Mako")
},
inactiveFunction: delegate {var e = eventCaller.currentEntity; PajamaParty.WarnSleepSequence(e.beat, e.toggle);}
),
new GameAction("throw", delegate {PajamaParty.instance.DoThrowSequence(eventCaller.currentEntity.beat);}, 8f, false,
inactiveFunction: delegate {PajamaParty.WarnThrowSequence(eventCaller.currentEntity.beat);}
),
//cosmetic
// new GameAction("open / close background", delegate { }, 2f, true),
// do shit with mako's face? (talking?)
},
new List<string>() {"ctr", "normal"},
"ctrpillow", "jp",
new List<string>() {"en", "jp", "ko"}
);
}
}
}
@ -233,8 +237,10 @@ namespace HeavenStudio.Games
new MultiSound.Sound("pajamaParty/throw1", beat),
new MultiSound.Sound("pajamaParty/throw2", beat + 0.5f),
new MultiSound.Sound("pajamaParty/throw3", beat + 1f),
//TODO: change when locales are a thing
//new MultiSound.Sound("pajamaParty/en/throw4a", beat + 1.5f), //will only play if this clip exists (aka just en)
new MultiSound.Sound("pajamaParty/throw4a", beat + 1.5f),
new MultiSound.Sound("pajamaParty/charge", beat + 2f),
}, forcePlay: force);
}

View File

@ -23,7 +23,11 @@ namespace HeavenStudio.Games.Loaders
new Param("valA", new EntityTypes.Integer(0, 30, 1), "Money", "The amount of coins the object spills out when sliced"),
}),
//new GameAction("start bopping", delegate { SamuraiSliceNtr.instance.Bop(eventCaller.currentEntity.beat, eventCaller.currentEntity.length); }, 1),
});
},
new List<string>() {"ntr", "normal"},
"ntrsamurai", "en",
new List<string>() {"en"}
);
}
}
}

View File

@ -1,5 +1,6 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
@ -10,6 +11,7 @@ using HeavenStudio.Games;
using System;
using System.Linq;
using System.Reflection;
using System.IO;
namespace HeavenStudio
{
@ -26,7 +28,24 @@ namespace HeavenStudio
public bool fxOnly;
public List<GameAction> actions = new List<GameAction>();
public Minigame(string name, string displayName, string color, bool threeD, bool fxOnly, List<GameAction> actions)
public List<string> tags;
public string defaultLocale = "en";
public string wantAssetBundle = "";
public List<string> supportedLocales;
public bool usesAssetBundle => (wantAssetBundle != "");
public bool hasLocales => (supportedLocales.Count > 0);
public bool AssetsLoaded => (((hasLocales && localeLoaded && currentLoadedLocale == defaultLocale) || (!hasLocales)) && commonLoaded);
private AssetBundle bundleCommon = null;
private bool commonLoaded = false;
private bool commonPreloaded = false;
private string currentLoadedLocale = "";
private AssetBundle bundleLocalized = null;
private bool localeLoaded = false;
private bool localePreloaded = false;
public Minigame(string name, string displayName, string color, bool threeD, bool fxOnly, List<GameAction> actions, List<string> tags = null, string assetBundle = "", string defaultLocale = "en", List<string> supportedLocales = null)
{
this.name = name;
this.displayName = displayName;
@ -34,6 +53,83 @@ namespace HeavenStudio
this.actions = actions;
this.threeD = threeD;
this.fxOnly = fxOnly;
this.tags = tags ?? new List<string>();
this.wantAssetBundle = assetBundle;
this.defaultLocale = defaultLocale;
this.supportedLocales = supportedLocales ?? new List<string>();
}
public AssetBundle GetLocalizedAssetBundle()
{
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 (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;
}
public IEnumerator LoadCommonAssetBundleAsync()
{
if (commonPreloaded || commonLoaded) yield break;
commonPreloaded = true;
if (!usesAssetBundle) yield break;
if (bundleCommon != null) yield break;
AssetBundleCreateRequest asyncBundleRequest = AssetBundle.LoadFromFileAsync(Path.Combine(Application.streamingAssetsPath, wantAssetBundle + "/common"));
if (bundleCommon != null) yield break;
yield return asyncBundleRequest;
AssetBundle localAssetBundle = asyncBundleRequest.assetBundle;
if (bundleCommon != null) yield break;
yield return localAssetBundle;
if (localAssetBundle == null) yield break;
bundleCommon = localAssetBundle;
commonLoaded = true;
}
public IEnumerator LoadLocalizedAssetBundleAsync()
{
if (localePreloaded) yield break;
localePreloaded = true;
if (!hasLocales) yield break;
if (!usesAssetBundle) yield break;
if (localeLoaded && bundleLocalized != null && currentLoadedLocale == defaultLocale) yield break;
AssetBundleCreateRequest asyncBundleRequest = AssetBundle.LoadFromFileAsync(Path.Combine(Application.streamingAssetsPath, wantAssetBundle + "/locale." + defaultLocale));
if (localeLoaded && bundleLocalized != null && currentLoadedLocale == defaultLocale) yield break;
yield return asyncBundleRequest;
AssetBundle localAssetBundle = asyncBundleRequest.assetBundle;
if (localeLoaded && bundleLocalized != null && currentLoadedLocale == defaultLocale) yield break;
yield return localAssetBundle;
if (localAssetBundle == null) yield break;
bundleLocalized = localAssetBundle;
currentLoadedLocale = defaultLocale;
localeLoaded = true;
}
}

View File

@ -40,7 +40,7 @@ namespace HeavenStudio.Util
FindJukebox().GetComponent<AudioSource>().volume = volume;
}
public static Sound PlayOneShot(string name, float beat = -1, float pitch = 1f, float volume = 1f, bool looping = false)
public static Sound PlayOneShot(string name, float beat = -1, float pitch = 1f, float volume = 1f, bool looping = false, string game = null)
{
GameObject oneShot = new GameObject("oneShot");
@ -49,7 +49,29 @@ namespace HeavenStudio.Util
audioSource.playOnAwake = false;
Sound snd = oneShot.AddComponent<Sound>();
AudioClip clip = Resources.Load<AudioClip>($"Sfx/{name}");
AudioClip clip = null;
if (game != null)
{
string soundName = name.Split('/')[2];
var inf = GameManager.instance.GetGameInfo(game);
//first try the game's common assetbundle
// Debug.Log("Jukebox loading sound " + soundName + " from common");
clip = inf.GetCommonAssetBundle()?.LoadAsset<AudioClip>(soundName);
//then the localized one
if (clip == null)
{
// Debug.Log("Jukebox loading sound " + soundName + " from locale");
clip = inf.GetLocalizedAssetBundle()?.LoadAsset<AudioClip>(soundName);
}
}
//can't load from assetbundle, load from resources
if (clip == null)
{
// Debug.Log("Jukebox loading sound " + name + " from resources");
clip = Resources.Load<AudioClip>($"Sfx/{name}");
}
snd.clip = clip;
snd.beat = beat;
snd.pitch = pitch;
@ -62,7 +84,7 @@ namespace HeavenStudio.Util
return snd;
}
public static Sound PlayOneShotScheduled(string name, double targetTime, float pitch = 1f, float volume = 1f, bool looping = false)
public static Sound PlayOneShotScheduled(string name, double targetTime, float pitch = 1f, float volume = 1f, bool looping = false, string game = null)
{
GameObject oneShot = new GameObject("oneShotScheduled");
@ -70,8 +92,26 @@ namespace HeavenStudio.Util
audioSource.playOnAwake = false;
var snd = oneShot.AddComponent<Sound>();
AudioClip clip = null;
if (game != null)
{
string soundName = name.Split('/')[2];
var inf = GameManager.instance.GetGameInfo(game);
//first try the game's common assetbundle
// Debug.Log("Jukebox loading sound " + soundName + " from common");
clip = inf.GetCommonAssetBundle()?.LoadAsset<AudioClip>(soundName);
//then the localized one
if (clip == null)
{
// Debug.Log("Jukebox loading sound " + soundName + " from locale");
clip = inf.GetLocalizedAssetBundle()?.LoadAsset<AudioClip>(soundName);
}
}
//can't load from assetbundle, load from resources
if (clip == null)
clip = Resources.Load<AudioClip>($"Sfx/{name}");
var clip = Resources.Load<AudioClip>($"Sfx/{name}");
audioSource.clip = clip;
snd.clip = clip;
snd.pitch = pitch;
@ -89,9 +129,11 @@ namespace HeavenStudio.Util
public static Sound PlayOneShotGame(string name, float beat = -1, float pitch = 1f, float volume = 1f, bool looping = false, bool forcePlay = false)
{
if (GameManager.instance.currentGame == name.Split('/')[0] || forcePlay)
string gameName = name.Split('/')[0];
var inf = GameManager.instance.GetGameInfo(gameName);
if (GameManager.instance.currentGame == gameName || forcePlay)
{
return PlayOneShot($"games/{name}", beat, pitch, volume, looping);
return PlayOneShot($"games/{name}", beat, pitch, volume, looping, inf.usesAssetBundle ? gameName : null);
}
return null;
@ -99,14 +141,18 @@ namespace HeavenStudio.Util
public static Sound PlayOneShotScheduledGame(string name, double targetTime, float pitch = 1f, float volume = 1f, bool looping = false, bool forcePlay = false)
{
if (GameManager.instance.currentGame == name.Split('/')[0] || forcePlay)
string gameName = name.Split('/')[0];
var inf = GameManager.instance.GetGameInfo(gameName);
if (GameManager.instance.currentGame == gameName || forcePlay)
{
return PlayOneShotScheduled($"games/{name}", targetTime, pitch, volume, looping);
return PlayOneShotScheduled($"games/{name}", targetTime, pitch, volume, looping, inf.usesAssetBundle ? gameName : null);
}
return null;
}
//TODO: playing sounds from assetbundles
public static void KillLoop(Sound source, float fadeTime)
{
// Safeguard against previously-destroyed sounds.