Unity 5.3 Assetbundles - c#

I am using the AssetBundleManager API in my unity 5.3 project.
My set-up: I have two scenes. One main scene and another scene that will be loaded as a multi scene into the main scene, which works fine in the editor right now.
Now I wanted to built my main scene to my android device, but when I click on the load level button, nothing happens. I already made a built of my assetbundle which is placed in the AssetBundles folder of my root. This is what I read in the documentations and what should be right?
What am I missing, do I need to put the assetbundle files anywhere else?
I am using this script, which I got from the example of the AssetBundleManager Plugin.
using UnityEngine;
using System.Collections;
using AssetBundles;
using UnityEngine.SceneManagement;
public class LoadScenes : MonoBehaviour
{
public string sceneAssetBundle;
public string sceneName;
public bool load;
public bool destroy;
string curLevel;
// Use this for initialization
IEnumerator Start ()
{
yield return StartCoroutine(Initialize() );
// Load level.
//yield return StartCoroutine(InitializeLevelAsync (sceneName, true) );
}
void Update(){
if (load) {
load = false;
// Load level.
StartCoroutine(InitializeLevelAsync (sceneName, true) );
}
if (destroy) {
destroy = false;
SceneManager.UnloadScene(sceneName);
}
}
public void loadLevel(string level){
curLevel = level;
StartCoroutine (InitializeLevelAsync (level, true));
}
public void unloadLevel(){
SceneManager.UnloadScene(curLevel);
}
// Initialize the downloading url and AssetBundleManifest object.
protected IEnumerator Initialize()
{
// Don't destroy this gameObject as we depend on it to run the loading script.
DontDestroyOnLoad(gameObject);
// With this code, when in-editor or using a development builds: Always use the AssetBundle Server
// (This is very dependent on the production workflow of the project.
// Another approach would be to make this configurable in the standalone player.)
#if DEVELOPMENT_BUILD || UNITY_EDITOR
AssetBundleManager.SetDevelopmentAssetBundleServer ();
#else
// Use the following code if AssetBundles are embedded in the project for example via StreamingAssets folder etc:
AssetBundleManager.SetSourceAssetBundleURL(Application.dataPath + "/");
// Or customize the URL based on your deployment or configuration
//AssetBundleManager.SetSourceAssetBundleURL("http://www.MyWebsite/MyAssetBundles");
#endif
// Initialize AssetBundleManifest which loads the AssetBundleManifest object.
var request = AssetBundleManager.Initialize();
if (request != null)
yield return StartCoroutine(request);
}
protected IEnumerator InitializeLevelAsync (string levelName, bool isAdditive)
{
// This is simply to get the elapsed time for this phase of AssetLoading.
float startTime = Time.realtimeSinceStartup;
// Load level from assetBundle.
AssetBundleLoadOperation request = AssetBundleManager.LoadLevelAsync(sceneAssetBundle, levelName, isAdditive);
if (request == null)
yield break;
yield return StartCoroutine(request);
// Calculate and display the elapsed time.
float elapsedTime = Time.realtimeSinceStartup - startTime;
Debug.Log("Finished loading scene " + levelName + " in " + elapsedTime + " seconds" );
}
}

Instead of using:
AssetBundleManager.SetSourceAssetBundleURL(Application.dataPath + "/");
Try using Application.persistentDataPath, hopefully that'll solve the problem.
Link to the manual.

You will have to set the datapath to your folder where the assetbundle is, i.e myassetbundle.unity3d
For example:-
AssetBundleManager.SetSourceAssetBundleURL(Application.dataPath +
"file:////D:\ptech-user\Documents\assetbundle3\Assets\Assets\AssetBundle
");

Related

check if the image is already downloaded?

Im using unity3d www to download an image from a web server and stored it to my local storage. The only checking that I have is System.IO.File.Exists() to check if its already downloaded. My problem is that it will not re-download when the image from the web server is updated or replace with the same exact filename. I also tried www.responseHeaders but it will only be available once the image is downloaded. I know about assetbundle but I don't want to create assetbundle for just one image.
Edit:
Here is my code, slightly modified. Fist I connect to webserver to fetch all the projects data including the image url as an array of data in json type. Then i will loop through that array which has the url of the image to download.
void ConnectToWeb()
{
StartCoroutine(AppManager.Instance.WebRequest("http://www.google.com",
(AppManager.HttpResponse callback) =>
{
if (callback.ResponseCode == 0 || callback.ResponseCode != 200)
{
throw new ArgumentException(callback.Error);
}
if (callback.Done == true)
{
StartCoroutine(LoadData(callback.JsonResponse));
}
})
);
}
private IEnumerator LoadData(JsonData itemData)
{
for (int i = 0; i < itemData["results"].Count; i++)
{
if (!System.IO.File.Exists(itemData["results"][i]["picture_name"].ToString()))
{
WWW www = new WWW(itemData["results"][i]["picture_url"].ToString());
while (!www.isDone)
{
Debug.Log("downloaded " + (www.progress * 100).ToString() + "%...");
yield return null;
}
File.WriteAllBytes(imagePath, www.bytes);
}
}
}
Use PlayerPrefs
public static void SetBool(string key, bool state)
{
PlayerPrefs.SetInt(key, state ? 1 : 0);
}
public static bool GetBool(string key)
{
int value = PlayerPrefs.GetInt(key);
return value == 1 ? true : false;
}
void DownloadImage() {
var isDownloaded = GetBool("IsImageDownloaded"); // <-- Check this first!
if(!isDownloaded) {
DownloadImageInternal(); // The real function to download an image
SetBool("IsImageDownloaded", true);
}
}
Note that System.IO.File.Exists() may or may not work for Desktop, Android and iOS apps, it is likely your app works fine in Unity Editor, but crashes when deployed to Android or iOS devices.

Unity Asset Bundles

I am creating an editor for a game using Unity game engine and I want to allow a designer to make new spells. What I am trying to achieve is that a designer will download a Unity particle system (or GameObject), save it on the computer and will give the game full path to it. Then the game should load the object and use it as a particle for a new spell.
I need to be able to load a Unity GameObject (particle system) during runtime from a folder. I tried it with Asset Bundles, but I don’t know how to use Asset Bundles when I only want to download the file from the computer (local file system) not from the server. Asset bundles work perfectly in Debug but not when I build and run it (It tries to connect to some server instead).
I use the default script for Asset Bundles:
public class LoadAssets : MonoBehaviour
public const string AssetBundlesOutputPath = "/AssetBundles/";
public string assetBundleName;
public string assetName;
public GameObject loadedObject;
public bool finished;
public MessageWindow messWindow;
// Use this for initialization
//originally was start here might create problems
public IEnumerator Begin ()
{
messWindow.changeMessageAndShow("Asset " + assetName + " is loading.","Loading");
yield return StartCoroutine(Initialize() );
// Load asset.
yield return StartCoroutine(InstantiateGameObjectAsync (assetBundleName, assetName) );
finished=true;
messWindow.Close();
}
public GameObject LoadObject()
{
StartCoroutine(Begin());
//TODO wait for end of couroutine
return loadedObject;
}
// Initialize the downloading url and AssetBundleManifest object.
protected IEnumerator Initialize()
{
// Don't destroy this gameObject as we depend on it to run the loading script.
DontDestroyOnLoad(gameObject);
// With this code, when in-editor or using a development builds: Always use the AssetBundle Server
// (This is very dependent on the production workflow of the project.
// Another approach would be to make this configurable in the standalone player.)
#if DEVELOPMENT_BUILD || UNITY_EDITOR
AssetBundleManager.SetDevelopmentAssetBundleServer ();
#else
// Use the following code if AssetBundles are embedded in the project for example via StreamingAssets folder etc:
// Or customize the URL based on your deployment or configuration
//AssetBundleManager.SetSourceAssetBundleURL("http://www.MyWebsite/MyAssetBundles");
#endif
AssetBundleManager.SetSourceAssetBundleURL(Application.dataPath + "/");
// Initialize AssetBundleManifest which loads the AssetBundleManifest object.
var request = AssetBundleManager.Initialize();
if (request != null)
yield return StartCoroutine(request);
}
protected IEnumerator InstantiateGameObjectAsync (string assetBundleName, string assetName)
{
// This is simply to get the elapsed time for this phase of AssetLoading.
float startTime = Time.realtimeSinceStartup;
// Load asset from assetBundle.
AssetBundleLoadAssetOperation request = AssetBundleManager.LoadAssetAsync(assetBundleName, assetName, typeof(GameObject) );
if (request == null)
yield break;
yield return StartCoroutine(request);
// Get the asset.
GameObject prefab = request.GetAsset<GameObject> ();
if (prefab != null)
{
loadedObject = GameObject.Instantiate(prefab);
DontDestroyOnLoad(loadedObject);
}
// Calculate and display the elapsed time.
float elapsedTime = Time.realtimeSinceStartup - startTime;
Debug.Log(assetName + (prefab == null ? " was not" : " was")+ " loaded successfully in " + elapsedTime + " seconds" );
}
}
Thank you so much.
To load Asset bundle from local system you need Local AssetBundle Server. When Local Asset Server is enabled, AssetBundles must be built and placed in a folder explicitly called AssetBundles in the root of the Project, which is on the same level as the Assets folder.
The built AssetBundles will be available to the Editor and all builds running locally that can reach the Editor on the local network.
Use Assets>AssetBundles>Local AssetBundle Server to enable the Local AssetBundle Server.
Reference to asset bundles and asset bundle manager.

APPNAME was compiled with optimization - stepping may behave oddly; variables may not be available

This project is develop in Unity3d and build it to iOS.
This is my .cs file.
IEnumerator DownloadModel(string modelUrl)
{
isDownloading = true;
// Wait for the Caching system to be ready
while (!Caching.ready)
yield return null;
// Load the AssetBundle file from Cache if it exists with the same version or download and store it in the cache
WWW www = WWW.LoadFromCacheOrDownload (modelUrl, 1);
Debug.Log ("modelURL : " + modelUrl);
while (!www.isDone) {
progressText.text = "Progress : " + (www.progress * 100).ToString ("N0") + "%";
Debug.Log("Download Progress : " + (www.progress * 100).ToString ("N0") + "%");
yield return null;
}
yield return www;
isDownloading = false;
if (www.error != null) {
throw new UnityException ("WWW download had an error:" + www.error);
}
AssetBundle bundle = www.assetBundle;
downloadedObjectContainer = bundle.LoadAllAssets ();
// tempObj = Instantiate(downloadedObjectContainer[0]) as GameObject;
//
// tempObj.transform.SetParent(this.transform);
isDownloading = false;
// Unload the AssetBundles compressed contents to conserve memory
bundle.Unload (false);
// memory is freed from the web stream (www.Dispose() gets called implicitly)
Debug.LogWarning ("START CALLING OUT OBJECT");
if (downloadedObjectContainer[0] != null) {
Debug.Log("Downloadable content count : " + downloadedObjectContainer.Length );
currentDownloadedModel = Instantiate(downloadedObjectContainer[0]) as GameObject;
Debug.Log("OBJECT INSTANTIATE.");
currentDownloadedModel.transform.SetParent(this.transform);
//set the ARContent and ImageTarget
sic.setARContentAndMarker(currentDownloadedModel, ImageTarget);
Debug.Log("CONTENT MARKER SET.");
currentDownloadedModel.SetActive(true);
}
Debug.LogWarning ("COROUTINE FINISHED");
}
and my "currentDownloadedModel" is declared at the top as GameObject.
public class cloudTrackableEventHandler : MonoBehaviour{
GameObject currentDownloadedModel;
When i build my App to Android, there is no problem at all. But once i build it in iOS, this error occurs
START CALLING OUT OBJECT
(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 64)
Downloadable content count : 1
(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 64)
MarcV2 was compiled with optimization - stepping may behave oddly; variables may not be available.
By the Debug.Log(), I found out that the problem occurs when I want to assign the currentDownloadedModel with the model i instantiate. Can anyone help me on this ? Thanks in advance.
Note : the "Script call optimization" at the unity player settings is set to "slow and safe"
For anyone who also face this problem, try uncheck the "Strip Engine Code" at File > Build Settings > Player Settings (iOS).
http://docs.unity3d.com/Manual/iphone-playerSizeOptimization.html

Unity C# Add Song on runtime then play that song

I am trying to allow the user to Import a song using a file browser Add on from the unity store. Currently I am trying to just play the song in the menu, just to see if I have loaded it correctly but it seems I cannot get past this stage. The WWW function makes no sense to me and I will need someone to explain it very simply. In my eyes this should open the file browser, the user then selects that file, then the selected file should be loaded into the audio clip. then the debug play button should play that audio clip, but from pausing the game I can see that the file browser finds the file and has the correct string but the audio is never assigned to the clip correctly. I am using .wav and .ogg files so no problem with formats.
public FileBrowser fb = new FileBrowser();
public bool toggleBrowser = true;
public string userAudio;
public AudioSource aSource;
public AudioListener aListener;
public AudioClip aClip;
void Start()
{
if (aSource == null)
{
aSource = gameObject.AddComponent<AudioSource>();
aListener = gameObject.AddComponent<AudioListener>();
}
}
void OnGUI()
{
// File browser, cancel returns to menu and select chooses music file to load
if (fb.draw())
{
if (fb.outputFile == null)
{
Application.LoadLevel("_WaveRider_Menu");
}
else
{
Debug.Log("Ouput File = \"" + fb.outputFile.ToString() + "\"");
// Taking the selected file and assigning it a string
userAudio = fb.outputFile.ToString();
}
}
}
public void playTrack()
{
//assigns the clip to the audio source and plays it
aSource.clip = aClip;
aSource.Play();
}
IEnumerator LoadFilePC(string filePath)
{
filePath = userAudio;
print("loading " + filePath);
//Loading the string file from the File browser
WWW www = new WWW("file:///" + filePath);
//create audio clip from the www
aClip = www.GetAudioClip(false);
while (!aClip.isReadyToPlay)
{
yield return www;
}
}
}
There are a few things that may be causing you some trouble.
I'm not sure how exactly the file browser add-on works, but in the code you posted the PlayTrack() function is never called, and the LoadFilePC coroutine is never started. Even if you're loading the file correctly, it's never being assigned to the AudioSource or playing.
Try adding "playTrack();" at the end of your coroutine, and starting it using the MonoBehaviour.StartCoroutine() function after the file is selected.

Cannot load cached AssetBundle. A file of the same name is already loaded from another AssetBundle

I am trying to load a scene but I am getting the error from title and I simply don't know why because I call Unload(false) on AssetBundle. Can someone help me? Thanks.
void Start() {
...
StartCoroutine (DownloadAndCache());
...
}
IEnumerator DownloadAndCache (){
// Wait for the Caching system to be ready
while (!Caching.ready)
yield return null;
// Load the AssetBundle file from Cache if it exists with the same version or download and store it in the cache
using(WWW www = WWW.LoadFromCacheOrDownload (BundleURL, version)){
yield return www;
if (www.error != null)
throw new Exception("WWW download had an error:" + www.error);
AssetBundle bundle = www.assetBundle;
bundle.LoadAll();
AsyncOperation async = Application.LoadLevelAsync("main");
Debug.Log (async.progress);
yield return async;
bundle.Unload(false);
}
}
if you do not want to use Unload() function clear the cache after asset bundle is used:-
Caching.CleanCache();
And every things will work fine but you have to download the asset bundle every time as you clearing out the cache after bundle use.
Or you can do this way
First of all call DoNotDestroyOnLoad() (for keeping the reference through out) function in Start() function and make a static variable to store a reference of the asset bundle when you use WWW.LoadFromCacheOrDownload to download the asset,assign the reference to the static variable and unload the asset after its use. if you don not unload the asset bundle and use WWW.LoadFromCacheOrDownload again the same error will be thrown as you have stated.
Suppose if you loaded a scene using asset bundle then before quitting the scene unload the asset bundle reference stored in that static variable. That is why static variable is used so that we can access it from any script and unload it whenever we want also be careful about version.
class LoadScene:MonoBehaviour{
***public static AssetBundle refrenceOfAsset;***
private AssetBundle assetBundle;
void Start(){
***DoNotDestroyOnLoad(gameObject);*** }
protected IEnumerator LoadTheScene()
{
if (!Caching.IsVersionCached(url, version)){
WWW www = WWW.LoadFromCacheOrDownload(url, version);
yeild return www; assetBundle = www.assetBundle;
***refrenceOfAsset = assetBundle;***
www.Dispose();
// Do what ever you want to do with the asset bundle but do not for get to unload it
refrenceOfAsset.Unload(true);
}
}
else{
Debug.Log("Asset Already Cached...");
if(refrenceOfAsset!=null)
refrenceOfAsset.Unload(true);
}
}
or
or you can visit unity http://docs.unity3d.com/Manual/keepingtrackofloadedassetbundles.html

Categories

Resources