#hiya! is there anyone here who has done
1 messages · Page 1 of 1 (latest)
I think one of my first questions is around setup. my game is largely assembled at runtime from CSVs and assets, setting up fixed prefabs was going to take far longer.
as a result everything is in Assets/Resources. does this pose a problem at all for an asset bundle?
Second, I've defined an asset bundle label and I've assigned it to everything I want to be in the asset bundle. I've made the generate-bundles script and done that, the output looks to be about the right size.
That gave me TWO bundles - one is Resources, the other is my asset label.
The manifests indicate that the bundle named Resources references the other asset bundle, so I'm trying to load both.
Does this require some funky IEnumerator or Yield stuff? I've not used them before so I don't really know what I've done. I'll paste some code
using UnityEngine;
using UnityEditor;
using System.IO;
public class CreateAssetBundles
{
[MenuItem("Assets/Build Asset Bundles for Poppy and Buddy")]
static void BuildAllAssetBundlesPoppyAndBuddy()
{
BuildAllAssetBundles("/../PoppyAndBuddyStreaming");
}
[MenuItem("Assets/Build Asset Bundles for Resources")]
static void BuildAllAssetBundlesResources()
{
BuildAllAssetBundles("/../Resources");
}
static private void BuildAllAssetBundles(string Path)
{
string assetBundleDirectoryPath = Application.dataPath + Path;
try
{
BuildPipeline.BuildAssetBundles(assetBundleDirectoryPath, BuildAssetBundleOptions.None, EditorUserBuildSettings.activeBuildTarget);
}
catch (System.Exception e)
{
Debug.LogWarning("Failed to build asset bundles: " + e.Message);
}
finally
{
AssetDatabase.Refresh();
}
}
}```
so that's stopping it from even working in the editor
when I go on to mobile to test (in the hope that it might just work) I get a 403 forbidden error when it tries to download anything.
I can grab the asset bundle from the device's browser or on desktop with no problems. I admin the server it's on and the permissions are all good, so I'm not sure what's up. I've made http 1.1 requests to get the content and it works fine, only Unity is failing. I think I have the relevant stuff switched on in the project settings to allow it
(I'm going to repost the downloader script, that exposed a bit too much)
the script isn't entirely sensical, the object instantiation has moved
also not sure WHY I'm instantiating one object? what happens then? as everything is already instantiated elsehwere, can I just skip that bit, check the download is done and loaded and move on to the next scene?
if you're on android, plain text http is not allowed on certain api levels by default
as a quick test, try enabling insecure http in player settings and see if that gets you by the 403
secondly, if all your assets are in a Resources folder, it seems pointless to put them into an asset bundle. Assets in resources are always included in the build
okey doke. I'll have to enable SSL on my dev server
yeah, I had to drag them out to do the main build. can I get it to load assets by script if they're not in resources?
yeah, that's the whole point of asset bundles. Load the asset (+ any dependencies), then you can instantiate it as needed
did you consider using addressables instead of raw asset bundles? It's a bit overengineered so it might take a bit to wrap your head around, but it's well aligned with what you're doing now
alright, SSL certs all sorted. I'm not getting enough debug output though
(nevermind, that's my own error)
I haven't looked into addressable yet
I don't have a lot of time left on this so it'd need to be a future improvement
is there something I'm missing from this process? Everything is loading successfully, but then is unable to be used later on.
private IEnumerator DownloadBundle(string bundleUrl)
{
Debug.Log("Downloading asset bundle from: " + bundleUrl);
GameObject go = null;
using (UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle(bundleUrl))
{
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.ConnectionError || www.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogWarning("Getting remote asset bundle failed: " + www.error);
}
else
{
Debug.Log("Obtained asset bundle from: " + bundleUrl);
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(www);
foreach (string assetName in bundle.GetAllAssetNames()) {
Debug.Log("Loading asset: " + assetName);
go = bundle.LoadAsset(assetName) as GameObject;
}
bundle.Unload(false);
yield return new WaitForEndOfFrame();
}
www.Dispose();
}
Debug.Log("Loading assets done");
} ```
```CS
Texture2D texture = Resources.Load<Texture2D>(background);
if (texture == null)
{
Debug.LogError("Failed to load texture: " + background);
continue;
}```
During loading after download:
<i>AndroidPlayer "Lenovo_Lenovo TB 7306F@ADB:HA1NSPJ4:0"</i> Loading asset: assets/resources/stories/library/background/library p1 layer0.psd
But later on when I use it:
<i>AndroidPlayer "Lenovo_Lenovo TB 7306F@ADB:HA1NSPJ4:0"</i> Failed to load texture: Stories/Library/Background/Library p1 layer0
what's with the case conversion going on? could that be why? I'm not doing that.
@rigid saffron sorry to tag you, but the thread is quite old now so I don't want you to miss the update
do I perhaps need to load the asset differently if it's in an asset bundle? does the path stay the same?
ooh do spaces cause an issue as well?
your second snippet makes no sense. You want to use Resources, or you want to use asset bundles?
ooh yeah that makes so much sense. that's an easy change, thank you!
I also don't need to do that first pass load at all do I
I'll find out either way, but do you know if it's going to have an issue with the case sensitivity? should I go lower-case everything going forward? I'm surprised it changed them to LC
did you ever consider using addressables instead? a big advantage is you can use AssetReferences (and derivatives) to avoid the brittle strings you're using now
that's something I'm going to implement next. I don't have time to switch it all over now
like if I can release this to the test track today, then out it goes
the first pass load probably does nothing. AssetBundles can contain more than just GameObjects so there's a decent chance that your as cast is failing, and you don't seem to use the go reference anyway
yeah I was just using the load as verification that it was there
this seems like it's going to get a lot simpler now my head is around it a bit more, thank you. addressable next because I want to use multiple DLC packages
I guess I need the AssetBundle object to persist. what's the normal way to get a singleton in Unity? after this step I unload the scene and load a new one, so I assume the gameobjects I make now are destroyed
so for anyone else who stumbles on this, the easiest way to go from Resources.Load<>() to AssetBundle.LoadAsset<>() is to keep your original path, but do a case-insensitive search of the bundle names to check it exists, then use that:
string voiceLineAssetPath = "Stories/" + StoryLoader.StoryName + "/Audio/" + StoryLoader.StoryName + "_" + Language.ToString() + "_" + PageNumber.ToString().PadLeft(2, '0');
string findAsset = Array.Find(Bundle.GetAllAssetNames(), s => s.IndexOf(voiceLineAssetPath, StringComparison.OrdinalIgnoreCase) >= 0);
VoiceLine = (AudioClip)Bundle.LoadAsset<AudioClip>(findAsset);```
then you don't have to alter your path (it becomes lowercase and adds /Assets/Resources/ into the bundle name)
this is useful because the bundles assets do become all lowercase by the looks of it
@rigid saffron thank you so much for the help!
I have one final question: so far the asset bundle and manifest downloaded aren't being saved and it happens again on each load. is there a way to get it to persist the downloaded data on android, desktop, ios, etc?
the overload of UnityWebRequestAssetBundle.GetAssetBundle you're using is probably using the non-cached constructor of DownloadHandlerAssetBundle. Looks like you want to use one that you specify a version for. See https://docs.unity3d.com/ScriptReference/Networking.DownloadHandlerAssetBundle-ctor.html and https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequestAssetBundle.GetAssetBundle.html