I'll start with the errors themselves. The first is : Assertion failed on expression: 'm_UncompressedBlocksOffsets[blockInd] <= from + dstPos && m_UncompressedBlocksOffsets[blockInd] + uncompressedBlockSize >= from + dstPos' UnityEngine.AssetBundle:LoadFromFile(String)
Followed by : Failed to decompress data for the AssetBundle 'D:/Unity/projects/PQv0.10/Assets/AssetBundles/spritesbundle'. UnityEngine.AssetBundle:LoadFromFile(String)
I've always just used the resources folder for my projects but my current project has outgrown what that method can accommodate. So I'm trying to offload assets (in this case 5000 or so sprites)into an assetbundle and load them as needed at runtime. I figured I could just get a reference to the assetbundle and then call assetbundle.LoadAsset(assetname), substituting my old Resources.Load calls. Here's my attempt at making the assetbundle reference that keeps erroring:
AssetBundle sprites;
void loadSprites()
{
sprites = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/spritesbundle"); // " + bundleName);
if (!sprites) {
Debug.Log("failed to load assetbundle");
}
}
For due diligence, here's also the code I used to create that assetbundle. It simple searches my project for png's and packs them into the assetbundle:
public static void SaveSpecificAssets()
{
AssetBundleBuild build = new AssetBundleBuild();
build.assetBundleName = "spritesBundle";
string[] files = AssetDatabase.GetAllAssetPaths();
List<string> validFiles = new List<string>();
foreach (string file in files)
{
if (file.EndsWith(".png")) validFiles.Add(file);
}
build.assetNames = validFiles.ToArray();
BuildPipeline.BuildAssetBundles("Assets/AssetBundles", new AssetBundleBuild[1] { build }, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
}
The assetbundle builds without errors and appears in the directory where it should be. I have no indication that it's faulty other than the errors I get when trying to load it. The manifest it generates contains appropriate items so I think it's working as intended at least.If I'm missing any relevant information, please point it out and I'll try to provide it.
this is the test coroutine I used in place of loadSprites() for testing if it made a difference:
IEnumerator testLoader()
{
WWW www = WWW.LoadFromCacheOrDownload("file:///" + Application.dataPath + "/AssetBundles/spritesbundle", 1);
yield return www;
sprites = www.assetBundle;
}
Try this, for all the PNG's in your project folder, select them all and add them to an AssetBundle via the Editor, Then just build using
BuildPipeline.BuildAssetBundles("Assets/AssetBundles",BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
Then try to load the bundles and see if it shows an error.
Also, look into the Manifest to see if all the files you intended are listed
Related
Specs
Unity editor version: 2018.2.8f1
Firebase Unity SDK version: 5.5.0
Additional SDKs: SimpleFirebaseUnity
Developing on: Mac
Export Platform: Android
Issue
I'm having troubles setting up a system to download pictures from storage. I'm not an expert in databases, but I wanted to give it try, just to learn how it is done.
I found Firebase very useful to store metadata on the real-time database and easy to approach even for an entry level programmer like me.
The problem is that I'm trying to download a .png file from a folder in storage, but I can't manage to find if the file is actually downloaded or if it's just lost in the process. I don't get any errors in the console, but when I open the folder in which the files should be, it's empty.
Code
private SimpleFirebaseUnity.Firebase firebaseDatabase;
private FirebaseQueue firebaseQueue;
private FirebaseStorage firebaseStorage;
private StorageReference m_storage_ref;
// Setup refernece to database and storage
void SetupReferences()
{
// Get a reference to the database service, using SimpleFirebase plugin
firebaseDatabase = SimpleFirebaseUnity.Firebase.CreateNew(FIREBASE_LINK, FIREBASE_SECRET);
// Get a reference to the storage service, using the default Firebase App
firebaseStorage = FirebaseStorage.DefaultInstance;
// Create a storage reference from our storage service
m_storage_ref = firebaseStorage.GetReferenceFromUrl(STORAGE_LINK);
// Create a queue, using SimpleFirebase
firebaseQueue = new FirebaseQueue(true, 3, 1f);
}
// ...
IEnumerator DownloadImage(string address, string fileName)
{
var local_path = Application.persistentDataPath + THUMBNAILS_PATH;
var content_ref = m_storage_ref.Child(THUMBNAILS_PATH + fileName + ".png");
content_ref.GetFileAsync(local_path).ContinueWith(task => {
if (!task.IsFaulted && !task.IsCanceled)
{
Debug.Log("File downloaded.");
}
});
yield return null;
}
There can be many reason for why this is not working for you including:
security rules are not setup properly
paths to files are not correct
you are testing it on wrong platform (Firebase is not working well in the editor)
your device is blocking the connection
etc...
In order to get error messages you need to log them:
IEnumerator DownloadImage(string address, string fileName)
{
var local_path = Application.persistentDataPath + THUMBNAILS_PATH;
var content_ref = m_storage_ref.Child(THUMBNAILS_PATH + fileName + ".png");
content_ref.GetFileAsync(local_path).ContinueWith(task => {
if (!task.IsFaulted && !task.IsCanceled)
{
Debug.Log("File downloaded.");
}
else
{
Debug.Log(task.Exception.ToString());
}
});
yield return null;
}
Keep in mind testing it in the editor may not work.
I need to develop a Shell Context Menu extension that references some other custom assemblies... I don't want to assign a Strong Name Key to those custom assemblies!
The guide I followed to do this uses the SharpShell project and illustrates how to sign (but does not expalins why) the assembly... and this is my problem: if I sign my final .dll then I have many errors during my project's building phase, because some assemblies my project references are not strongly named ("Referenced assembly does not have a strong name").
In general, googling about the C# Shell Extension implementation, all best tutorials I found sign the final assembly... is it mandatory?
Without signing the assembly ServerManager.exe returns this error: "The file 'XYZ.dll' is not a SharpShell Server".
Finally I've solved my troubles... the SharpShell.dll file obtained through NuGet was a different version of the ServerManager.exe ones.
Uninstalling the SharpShell NuGet package and directly referencing the SharpShell.dll you find inside the ServerManager folder was my solution!
Moreover, I was looking between the article comments... please read this question.
You don't need to use old DLL.
Please use this code directly, without using ServerManager.exe.
private static ServerEntry serverEntry = null;
public static ServerEntry SelectedServerEntry
{
get
{
if (serverEntry == null)
serverEntry = ServerManagerApi.LoadServer("xxx.dll");
return serverEntry;
}
}
public static ServerEntry LoadServer(string path)
{
try
{
// Create a server entry for the server.
var serverEntry = new ServerEntry();
// Set the data.
serverEntry.ServerName = Path.GetFileNameWithoutExtension(path);
serverEntry.ServerPath = path;
// Create an assembly catalog for the assembly and a container from it.
var catalog = new AssemblyCatalog(Path.GetFullPath(path));
var container = new CompositionContainer(catalog);
// Get the exported server.
var server = container.GetExport<ISharpShellServer>().Value;
serverEntry.ServerType = server.ServerType;
serverEntry.ClassId = server.GetType().GUID;
serverEntry.Server = server;
return serverEntry;
}
catch (Exception)
{
// It's almost certainly not a COM server.
MessageBox.Show("The file '" + Path.GetFileName(path) + "' is not a SharpShell Server.", "Warning");
return null;
}
}
Install code:
ServerRegistrationManager.InstallServer(SelectedServerEntry.Server, RegistrationType.OS64Bit, true);
Register code:
ServerRegistrationManager.RegisterServer(SelectedServerEntry.Server, RegistrationType.OS64Bit);
I'm storing materials paths in .plist in Unity and rendering them in my objects at runtime. Code looks like this:
public static Dictionary<string, object> uiElements = (Dictionary<string, object>)Plist.readPlist("Assets/EditUI.plist");
foreach (string key in User.purchasedItems.Keys)
{
GameObject tmpObj = (GameObject)Instantiate(Resources.Load(key) ,position ,Quaternion.identity);
tmpObj.transform.localScale = Vector3.one;
tmpObj.SetActive(true);
}
It's working fine in Unity editor, but when I made iOS build (Xcode project), nothing is being loaded. Everything is empty. I couldn't figure out whether the problem is with plist path or loading on runtime. Something related to custom plist is also posted here with no solution:
http://answers.unity3d.com/questions/468667/custom-plist-file-not-added-to-ios-project.html
You'll need to use Unity's iOS Scripting API to add the file to the Xcode project. Create a PostProcessBuild script that does something like this:
[PostProcessBuild]
public static void OnPostProcessBuild(BuildTarget buildTarget, string path)
{
// Go get pbxproj file
string projPath = path + "/Unity-iPhone.xcodeproj/project.pbxproj";
// PBXProject class represents a project build settings file,
// here is how to read that in.
PBXProject proj = new PBXProject ();
proj.ReadFromFile (projPath);
// This is the Xcode target in the generated project
string target = proj.TargetGuidByName ("Unity-iPhone");
// Copy plist from the project folder to the build folder
FileUtil.CopyFileOrDirectory ("Assets/EditUI.plist", path + "/EditUI.plist");
proj.AddFileToBuild (target, proj.AddFile("EditUI.plist", "EditUI.plist"));
// Write PBXProject object back to the file
proj.WriteToFile (projPath);
}
I'm using Unity 5 and C# and I would like to load a movie from anywhere on disk at run-time rather than from the Resources folder.
This is possible to do with regular image textures using the .LoadImage (bytes) method in Texture2D type for example, but there does not appear to be an equivalent for MovieTexture.
The code shows how to do it from the resources folder, but how could i modify it to load from disk?
Thanks
public void loadVideo (GameObject container, string video)
{
// Load MovieTexture from Resources Folder
MovieTexture mat = (MovieTexture)Resources.Load(Path.GetFileNameWithoutExtension(video), typeof(MovieTexture));
MeshRenderer ren = container.GetComponent<MeshRenderer>();
ren.material.mainTexture = mat;
mat.Play();
}
You can. Use the WWW class to to this.
IEnumerator loadAndPlay(){
WWW diskMovieDir = new WWW("file:///C:/yourvideoDir/video.mp4");
//Wait for file finish loading
while(!diskMovieDir.isDone){
yield return null;
}
//Save the loaded movie from WWW to movetexture
MovieTexture movieToPlay = diskMovieDir.movie;
//Hook the movie texture to the current renderer
MeshRenderer ren = container.GetComponent<MeshRenderer>();
ren.material.mainTexture = movieToPlay ;
movieToPlay.play();
}
Now you can call it by starting coroutine.
StartCoroutine(loadAndPlay());
I did not compile this so there might be a compile error but you can easily fix it if there is one. This should also work without problems if it compiles. Note that the url must start with file:///. If that didnt work, try file://
I am having issue with the asset bundle from unity. I have a bundle with multiple assets in it with the same name, but different extension, like bonus.png bonus.prefab.
When I try to instanciate a prefab named bonus, the assetBundle.LoadAssets("bonus") function doesnt return me a gameobject like it usuallly do. This seems to be happening only if i have multiple asset with the same name.
AssetBundleRequest request = assetBundle.LoadAssetAsync(m_ObjectsToPool[i].m_Name, typeof(GameObject));
yield return request;
GameObject prefab = request.asset as GameObject;
if (prefab != null)
{
PoolManager.Instance.AddLoadedPrefabToPool(prefab, m_ObjectsToPool[i].m_Name, null, m_ObjectsToPool[i].m_Amount);
}
But if i call loadallassets(typeof(GameObject)) and then use a for loop, i can find my asset and instanciante it properly. but that is just a dirty way of doing it.
You should be able to load assets of different types with the same name.
What version of Unity are you using?
Your code above looks correct (except for the typo calling it LoadAssetAsync?), and we don't know for sure it is failing to enter the if() statement?
The following worked for me on Unity 4.5.5f1
Added ExportAssetBundles.cs context menu script to my Unity build from Unity Docs
Created something to export
found a JPG dragged it in and named it "marble.jpg"
created a cube, named it "marble" and dragged it into project to create a prefab
created a material, named it "marble", added the jpg and dragged it onto the cube, pressed apply.
Hilighted all 3 and exported asset bundle using "Build Assets From Selection - Track Selection" and saved it to "c:\temp\marble.unity3d"
Added a script to load that asset bundle on start (similiar to yours):
using UnityEngine;
using System.Collections;
public class BundleTest : MonoBehaviour {
void Start () {
StartCoroutine(StartCo());
}
IEnumerator StartCo() {
string url = "file://c:\\temp\\marble.unity3d";
WWW www = new WWW(url);
yield return www;
AssetBundle bundle = www.assetBundle;
AssetBundleRequest request = bundle.LoadAsync ("marble", typeof(GameObject));
yield return request;
Debug.Log ("loaded asset: " + request.asset.ToString());
GameObject prefab = request.asset as GameObject;
GameObject go = (GameObject)Instantiate(prefab);
bundle.Unload(false);
www.Dispose();
}
}
Ran Unity and verified I see the game object correctly.
It used to work when I was on unity 4.6, but I am now using the beta 5.0.17. And no its not a typo, it is really laodassetasync I have, I also tried with loadasset only with the same result. Right now I am using
var allAssets = assetBundle.LoadAllAssets(typeof(GameObject));
for (int i = 0; i < m_ObjectsToPool.Count; i++)
{
bool found = false;
for (int j = 0; j < allAssets.Length; j++)
{
if (allAssets[j].name == m_ObjectsToPool[i].m_Name)
{
PoolManager.Instance.AddLoadedPrefabToPool((GameObject)allAssets[j], m_ObjectsToPool[i].m_Name, null, m_ObjectsToPool[i].m_Amount);
found = true;
break;
}
}
if (!found)
{
Debug.Log(string.Format("{0} object could not be found in assetbundle", m_ObjectsToPool[i].m_Name));
}
}
and it is working, but i dont really like this way of doing it.
Having same issue with Unity 5.1, I've found this solution:
Besides refering asset by base name (no directory, no extension parts of path), you can also use full relative path (including file extension, relative to project root).
Let's say I've got bundle created from directory Assets/Bundle, it contains following files:
Prefabs/Box.prefab
Prefabs/Box2.prefab
Models/Box.fbx
Materials/Box.mat
Textures/Box.png
So the documented way of loading prefab that fails in our cases is
// May return nulll
bundle.LoadAsset<GameObject>("Box")
And this is the not documented way that's working correctly in our case
bundle.LoadAsset<GameObject>("assets/bundle/prefabs/box.prefab")
If you are not sure what is the correct asset name you should use for LoadAsset, you can use following code to list all asset names in bundle
string[] assets = bundle.GetAllAssetNames();
foreach (string asset in assets)
{
Debug.Log(asset);
}