Extract Shader, Material and Texture2D from an AssetBundle

In the following Unity Package, I attempt to load an Asset Bundle that contains a fairly complex particle system.

The asset bundle is loaded via www.

                m_www =
                    new WWW(m_assetBundleURL);

assetBundle.LoadAll() loads all the Objects[ ] from the asset bundle.

I then iterate through each Object and attempts to save the asset to file with AssetDatabase.CreateAsset(obj, assetPath).

I get a bunch of errors like:

Couldn't create asset file because the Texture2D 'Fire 1' is already an asset at ''!
Couldn't create asset file because the MonoScript 'FractalTexture' is already an asset at ''!

Is there another way to do this?

To try this 3k package, simple import to an empty project. And then using the Unity Editor to access the menu item: “Assets/Save Asset Bundle As Assets”.

(next post)

141075–5154–$editor_saveassetbundleasassets_633.unitypackage (2.44 KB)

Here’s an idea. I’ll try to add the object with another path.

                //Debug.Log(string.Format("**Creating Asset Type: {0} Path: {1}", copyObj.GetType(), assetPath));
                //AssetDatabase.CreateAsset(copyObj, assetPath);

                Debug.Log(string.Format("**Add Asset Type: {0} Path: {1}", copyObj.GetType(), assetPath));
                AssetDatabase.AddObjectToAsset(obj, assetPath);

Oopps!!!

You may not change the path if an object is already peristent in another one

Isn’t the concept of Unity persistence mean that the asset is on disk. With an asset bundle, the Object is not actually on disk.

Yey! I got the material to save out of the asset bundle to a file by creating a simple Material and copying the serialized data into the simple Material.

(next post)

I can now extract materials and textures from asset bundles. MonoScripts may be protected because the text is showing as blank.

141105–5157–$saveassetbundleasassets_203.cs (5.11 KB)

I found a substantial issue.

Unloading the asset bundle is getting stuck in an infinite loop.

m_assetBundle.Unload(true);

It repeats this log over and over until I kill unity.

o == NULL
UnityEngine.AssetBundle:Unload(Boolean)
UnityEngine.AssetBundle:Unload(Boolean)
SaveAssetBundleAsAssets:Update() (at Assets\Editor\SaveAssetBundleAsAssets.cs:255)
System.Reflection.MonoMethod:InternalInvoke(Object, Object[])
System.Reflection.MonoMethod:InternalInvoke(Object, Object[])
System.Reflection.MonoMethod:Invoke(Object, BindingFlags, Binder, Object[], CultureInfo)
System.Reflection.MethodBase:Invoke(Object, Object[])
UnityEditor.HostView:Invoke(String) (at C:\builds\unity-trunk\unity\Editor\Mono\GUI\DockArea.cs:156)
UnityEditor.HostView:SendUpdate() (at C:\builds\unity-trunk\unity\Editor\Mono\GUI\DockArea.cs:184)
UnityEditor.EditorApplication:Internal_CallUpdateFunctions() (at C:\builds\unity-trunk\unity\Editor\Mono\Generated\InternalUtility.cs:198)

[c:\builds\unity-trunk\unity\runtime\baseclasses\BaseObject.h line 210] 
(Filename: Assets/Editor/SaveAssetBundleAsAssets.cs Line: 255)

141351–5166–$editor_saveassetbundleasassets3_181.unitypackage (3.43 KB)

As a workaround for now I’ll have to do this:

m_assetBundle.Unload(false);

That means that after importing the assets, I can’t verify that the reference hierarchy is intact without restarting Unity.

141364–5167–$editor_saveassetbundleasassets4_498.unitypackage (3.71 KB)

I added logic to fix references to custom shaders and textures.

There are going to be some types that I can’t extract because Unity crashes:

MonoScript - cs or js files, the text and bytes fields are blank
ParticleEmitter - Any attempt to copy the particle emitters cause memory corruption and unity crashes
Shaders - Shaders lack a constructor and cannot be copied directly. Instead I can extract shaders from any material that uses the shader.
Prefabs - Prefabs don't appear to be in the asset bundle

141442–5169–$editor_saveassetbundleasassets5_401.unitypackage (4.25 KB)

I added some logic to fix texture references for all the common properties in the built in shaders.

        string[] commonTextureNames =            
        {
            "_AlphaTex",
            "_BumpMap",
            "_BackTex",
            "_BumpMap",
            "_Control",
            "_DecalTex",
            "_Detail",
            "_DownTex",
            "_FrontTex",
            "_LeftTex",
            "_LightMap",
            "_MainTex",
            "_RightTex",
            "_Splat0",
            "_Splat1",
            "_Splat2",
            "_Splat3",
            "_UpTex"
        };

141466–5170–$editor_saveassetbundleasassets7_111.unitypackage (4.36 KB)

Here is a screencast of the package which shows how it works:

http://screencast.com/t/TnLmTWQz

I added logic that exports the main asset from the asset bundle as a prefab. Unfortunately, if you restart Unity, most of the hierarchy is lost.

And the attached scripts aren’t saved properly.

141683–5181–$editor_saveassetbundleasassets11_427.unitypackage (4.48 KB)

The classes contained within an asset bundle don’t appear to exist.

There are MonoScript objects, but the text, bytes, and GetClass type are empty/null.

When I load the asset bundle I get warnings that the classes don’t exist that are attached to the objects.

See the attached package and check the console log for more details.

141722–5182–$editor_saveassetbundleasassets12_986.unitypackage (4.61 KB)

1 Like

I thought maybe if I exported a script as the main asset, the text in the MonoScript might be filled in.

@MenuItem("Assets/Build AssetBundle From Script")
static function ExportResourceScript () {
	// Bring up save panel
	var path = EditorUtility.SaveFilePanel ("Save Resource", "", "New Resource", "unity3d");
	if (path.Length != 0)
	{
		BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/UpdateGUITextScript.cs"), null, path);
	}
}

Uploaded the asset bundle:
http://tagenigma.com/qa/Unity3d/AssetBundleTester/UpdateGUITextPrefab3.unity3d

In the script above I was trying to explicitly get a full copy of a script into the asset bundle. Unfortunately, as I found in another thread http://forum.unity3d.com/viewtopic.php?p=145095#145095, asset bundles only include script references. Still I had the source script in my project and the MonoScript.text property was still empty.

142597–5203–$editor_saveassetbundleasassets13_805.unitypackage (4.64 KB)

Anyway you can extract mesh data as well?

Amazing, great code!

Not support for SubstanceArchive, ProceduralMaterial and ProceduralTexture. Is there any solution?

Thank you. great code!