I have a mobile project which displays various AR experiences to the user via a mobile application. This application is made in Unity.
Alongside this Unity project we have a second project that stores asset bundles exclusively. Each AR experience is a prefab marked with a unique asset bundle name. These bundles are stored online and downloaded into the main mobile application when relevant. We're having issues with having these bundles correctly update, when changing things on the prefab such as scale or rotation they aren't reflected in the rebuilt asset bundle.
Here's a look at the process we're using for rebuilding assets, It's only a simple script.
[MenuItem("Spiff/Build AssetBundles")]
static void BuildAllAssetBundles()
{
// BuildPlatformBundles(BuildTarget.iOS);
BuildPlatformBundles(BuildTarget.Android);
}
static void BuildPlatformBundles(BuildTarget platform)
{
// We convert the passed platform enum to a string.
string platformFolder = platform.ToString();
string assetBundleDirectory = "Assets/AssetBundles/" + platformFolder;
// Build our bundles out to the relevent platform specific folder.
if (!AssetDatabase.IsValidFolder(assetBundleDirectory))
{
AssetDatabase.CreateFolder("Assets/AssetBundles/", platformFolder);
}
BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, platform);
}
Currently we use 'BuildAssetBundleOptions.None' We've also tried the ForceRebuild flag but this has no effect. Am I correct in assuming that Unity has some sort of internal cache it keeps for assets bundles? If so can we clear this somehow so I can ensure 100% that the bundle I am building is going to be the most up to date based on the prefab tagged with it?
Loaded Assetbundles are indeed cached, and will remain so until AssetBundle.Unload() has been called to free up all memory accociated with the asset.
After the asset has been unloaded a newer version of the assetbundle can be downnloaded and instantiated with the new values (Assuming the file downloaded has all the updated information), else it will load the data from cache if available.
On a side note: It seems like you're still using the old assetbundle pipeline. Unity has a plugin tool that makes the assetbundle workflow considerably easier called the assetbundle browser found here. It comes with a way easier UI for building bundles and inspecting bundles, open source and a very customisable pipeline. It may be worth checking out.
Like remy_rm mentioned, do give the Unity Asset Bundle Browser tool a try. It gives more control over what assets are in the bundle.
Your problem can be solved if you ensure two things:
1- When you make changes to a prefab and create a new bundle, is it indeed created with the said changes? (again using the tool would make checking this easier)
2- The bundles you are downloading in the main application are the new ones and not the old cached ones. In Unity Webgl for instance, you need to clear the browser cache to be 100% sure that the application downloads the new asset bundles and doesn't use the old ones in browser cache.
Related
I am limited to the size of web applications I can build by the "Build\application.data" file.
I.e if its over a certain size I cannot upload it certain hosts, github, etc.
Ideally I would like to split the application into multiple data files under a certain size, while the application is still executable.
How would this be possible? Is this something I can do from Unity build configuration?
Can I do it after the build is done?
Can I split the file into chunks by archiving it with zero compression, and somehow still execute it from the browser? There is a file called Build.Loader.js, is it something that can be edited for this purpose?
This is for the purposes of using the application after it has been uploaded, not sharing it, I do not want to compress it into separate archives, or use gitlfs, I've tested this and the application does not work from the browser with github and gitlfs.
Thanks
Unity has 2 technologies for split data file:
Asset bundle
An AssetBundle is an archive file that contains platform-specific
non-code Assets (such as Models, Textures, Prefabs, Audio clips, and
even entire Scenes) that Unity can load at run time
Addressbles
The Addressable Asset System allows the developer to ask for an asset
via its address. Once an asset (e.g. a prefab) is marked
"addressable", it generates an address which can be called from
anywhere. Wherever the asset resides (local or remote), the system
will locate it and its dependencies, then return it.
Both technologies create separate files that you can host on a server and download as needed. Addressable is a newer technology that Unity team recommends.
Probably the total size of the bundle will grow, but user will be able to download only the necessary assets and the amount of data for the user may decrease
If you do not use Unity solutions, you can divide data file into parts. But on the client side (javascript) you will need to download all the parts, connect them and pass to Unity loader. You probably won't be able to use the browser's built-in gzip or brotli (not sure). It seems to be quite difficult.
In my project, I have a bunch of items stored as assetBundles. In my server, I stored a list of item including their id and version. So ideally, using UnityWebRequest.GetAssetBundle(uri, versionId)I just get the item lists every time I open the app, if first opened, it will download every item; if secondly open, it will only download the one I have updated the version number on the server. Everything is very easy.
But now, I want to store those assetBundles at local first so that people don't need to download with cellular data.Is there an easy way to manage those assetBundles?
You can place the AssetBundles in the StreamingAssets folder. This is what the folder should look like:
Assets/StreamingAssets/
When you build the project, Unity will include the AssetBundles in the build. Of-course, you can use the Resources API but the StreamingAssets folder seems to be more appropriate here.
Once you place the AssetBundles there, you can use Application.streamingAssetsPath and AssetBundle.LoadFromFile to load the AssetBundle.
You can also use the WWW API with Application.streamingAssetsPath to load the AssetBundle.
You 'dont' keep a local text file. you have the version number inside the local bundle. You have a text file on the server. then get the text file, compare that with the version in the bundle and update if necessary.
In the server, you can have an assetbundle with only a textasset to secure that too.
you can build the asset bundles and have them in the streamingAssets folder or anywhere and use AssetBundle.LoadFromFile()
I'm starting learn unity not long ago. Now, I have issues. When I build a game, I don't want build all assets in project. I want download some assets when Client after install game (Ex : first load Splashscreen). I tried to search and found WWW.LoadFromCacheOrDownload. I don't sure it correct!.
Can you give me solutions or keyword?
Thank you very much.
You are on correct road. But i think you need to google a bit deeply the keyword and you would have reached the "Asset Bundles".
Asset Bundle Defination
Scripting Asset bundles
Asset Bundle management
Asset Bundle detail description
I did asset bundle usage quite some time ago so i might miss something while explaining this.
First you need to build the resources which you will be required.(Each platform has different builds so you need to keep that also in mind)
You will need a script to download and cache the asset bundle from the net.
WWW.LoadFromCacheOrDownload
After caching comes the part of loading and unloading asset bundle from cache/resources. Also for every update we pushed we allowed application to check for any asset bundles were available so that it could fetch and use it.
I think there are some more helper scripts for the asset bundles and tutorials to go with on the net as I had used a script to generate asset bundles
to modify it.
Here is unity asset store Example and scripts for asset bundles
So basically it will be a long solution to implement but it is worth every time you spend.
Hope this helps.
Edit : Here is script I had used to create asset bundles. Unifycommunity Asset bundle builder Link
I'm currently trying to set up my project to allow users to download mini games post release. Todo this I am trying to use asset bundles to facilitate this, one containing the new games scene and one containing the assets and DLLs for the scripts required. The problem I am having is that when I load the scene or a prefab from the bundle all the attached scripts are still there but a warning says "the associated script can not be loaded. please fix any compile errors and assign a valid script". Is there something obvious that I am missing or do asset bundles not work this way and I'm going to have to rebuild my scene on load?
You can't have the scripts in the asset bundles assigned as references from GameObjects like you normally would. You can only access scripts from asset bundles by loading them with reflection. Then you can programmatically attach them to GameObjects, etc. from there (for example, load the assembly, find your Type, then use AddComponent() on a GameObject with your new loaded type).
See http://docs.unity3d.com/Manual/scriptsinassetbundles.html.
But even if you were to overcome these hurdles, it won't work on Windows Phone and it's against the terms of service of Apple's store, so ...
Before going to ask the question, I will explain what kind of requirements I need.
In my game, there are a lot of textures needed in order to play it. Because of this and the limitation of ipa size (iOS), I think using assetbundle is a must. Because the existing code implementation, I create the assetbundle, 1 asset bundle for 1 image. For example: I have 100 images, then I will create 100 assetbundle(with the mainasset will be the texture), with the same name.
I want my game can be played offline AFTER at first time the user has downloaded all the needed assetbundles. So if the user play for the first time or download the updated version of my game, the game will be forced into special scene where it will download all needed assetbundle, after that, the user can play the game without internet connection.
I thought there are 2 ways regarding of how to download these assetbundle:
The normal way: I put all 100 assetbundles in my server, and put 1 xml file, which consist all assetbundles information and its version. At the special scene, the game will download the xml file, and from that it will download 100 assetbundles via WWW.LoadFromCacheOrDownload. The purpose is just to store the needed assetbundles to the cache of game. After successfully downloaded all of them, user can play offline and if the game need the assetbundle to be loaded, then I just callagain the WWW.LoadFromCacheOrDownload, since it is still in the cache, it can be played offline. Of course, I assume the cache is still there as long as I dont clear the cache explicitly.
The hard way: I will zip all 100 assetbundle to 1 zip file. The game will download the xml file, and the zip file. I will decompress the zip, and put all 100 assetbundle in the mobile storage (iOS and Android). So after that, in case the game need to load the asset, I just call the WWW.LoadFromCacheOrDownload with the url is using file:/// scheme that point to the path of mobile storage.
Summary:
The Normal Way:
Minus: I assume the cache is still there, but if there is something wrong in the cache, the user can't play the game.
Plus: simple implementation, because the assumption that cache will be fine.
The Hard Way:
Minus: well, i don't know it is minus point or not, but this one, I have to implement the unarchived zip file and store them in storage. More implementation needed at server side and the application side. And since I am newbie, I don't know the best practice in this area.
Plus: more robust
So which one is better ? or any better recommendation?
We have essentially implemented a mix of your normal and hard way for our application. As yours, it's rather texture heavy, so most groups of texture assets are packed into their own asset bundles. (In our application texture have a logical grouping, so we don't pack them individually). We however don't download them directly to the cache. We download these to the sdcard and from there load them (or get them from cache) as we need them. (i.e. LoadFromCacheOrDownload).
It depends a bit on your situation, but I would generally advise against packing them into a single zip file. Primarily with regards to updates. It has happened in our case that an asset needed some updates, or that we wanted to add assets later on. By having an XML file or database containing versioning data, updating the data on the device is trivial. And if only one bundle changes, you only need to download that single bundle. And 2MB vs 450MB in our case is quite the difference.