1

I'm using UnityWebRequestAssetBundle.GetAssetBundle(url, bundleData.version, bundleData.crc); system and I can successfully download and use bundleAssets online. But when I want to download multiple bundle assets and save them to use offline for later I have a problem. I have 2 files for example, 'A' and 'B'. Case 1: When I download A and go offline I can load A anytime even I close the app. But when I want to download B and come back to A can't load A again because it deletes cache for some reason and tries to download it again.

Case 2: When I download A and B together and go offline, if I load B it loads. But if I try A it can't load and needs internet connection. After that when I try to load B again I loose package so it needs internet connection again.

So basicly I want to download multiple asset bundles and I want to use them whenever I want. How can I solve this problem? Thanks.

Code example:

using UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle(url, bundleData.version, bundleData.crc);
        yield return uwr.SendWebRequest();

            bundle = DownloadHandlerAssetBundle.GetContent(uwr);
            Debug.Log(bundle);

        if (bundle==null)
        {
                Debug.Log("COULDN'T CONNECT TO URL");
                callback(null);
        }
        else
        {
            Debug.Log("FOUND AT SEARCH!");
            // Get downloaded asset bundle
            bundle = DownloadHandlerAssetBundle.GetContent(uwr);
            Sprite sprite = isDiff ? bundle.LoadAsset<Sprite>(levelText + "Diff") : bundle.LoadAsset<Sprite>(levelText);

            callback(sprite);
        }
  • I think you are just overwriting it with the next bundle. Can you show how are you are saving it in storage? and how you are retrieving it? – Saad Anees Jul 05 '21 at 08:40
  • @SaadAnees actually I don't save to storage. People say when you download it once and when you ask again to download it should get it from storage. Is there a way to save bundles to exact location and get bundles from that path? I found some solutions for that but all of them before 2018 and some of them are not working. – Volkan Ege Dindar Jul 05 '21 at 09:12
  • Please show the code where you are downloading it. I cant say anything at this moment. – Saad Anees Jul 05 '21 at 09:54
  • @SaadAnees Added to topic. – Volkan Ege Dindar Jul 05 '21 at 10:23
  • What is the name of bundles A and B? And did you try `GetAssetBundle(string uri, CachedAssetBundle cachedAssetBundle, uint crc);` – Saad Anees Jul 05 '21 at 11:09
  • do you actually have crc for each asset bundle? if not just put 0. The presence of version will imply using the cache system. Next time having the same uri and version you will always obtain it from the cache. – kolodi Jul 06 '21 at 07:29
  • I have version and crc numbers. But it didn't work anyway. I found a solution by myself. I wrote a new answer you can see below. – Volkan Ege Dindar Jul 06 '21 at 07:30

1 Answers1

0

I solved my issue by saving images to persistentFolder. I write image to disk first by Texture2D.EncodeToJPG();

private void writeImageOnDisk(Sprite sprite, string fileName)
{
    Texture2D texture = DeCompress(sprite.texture);
    byte[] textureBytes = texture.EncodeToJPG();

    File.WriteAllBytes(Application.persistentDataPath + "/" + fileName+".jpg", textureBytes);
    Debug.Log("File Written On Disk!");
}

To EncodeToJPG image must be Read/Write enabled before having AssetBundles and you should decompress them first, I found solution from this topic.

private Texture2D DeCompress(Texture2D source)
{
    RenderTexture renderTex = RenderTexture.GetTemporary(
                source.width,
                source.height,
                0,
                RenderTextureFormat.Default,
                RenderTextureReadWrite.Linear);

    Graphics.Blit(source, renderTex);
    RenderTexture previous = RenderTexture.active;
    RenderTexture.active = renderTex;
    Texture2D readableText = new Texture2D(source.width, source.height);
    readableText.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0);
    readableText.Apply();
    RenderTexture.active = previous;
    RenderTexture.ReleaseTemporary(renderTex);
    return readableText;
}

And finally you can load image with this code:

private Sprite loadImageFromDisk(string fileName)
{
    string dataPath = Application.persistentDataPath + "/" + fileName + ".jpg";
    if (!File.Exists(dataPath))
    {
        Debug.LogError("File Does Not Exist!");
        return null;
    }

    byte[] textureBytes = File.ReadAllBytes(dataPath);
    Texture2D loadedTexture = new Texture2D(2048,2048,TextureFormat.ARGB32, false);
    loadedTexture.LoadImage(textureBytes);
    Sprite spr = Sprite.Create(loadedTexture, new Rect(0f, 0f, loadedTexture.width, loadedTexture.height), new Vector2(.5f,.5f), 2048); // 2048 is pixel per unit if you have a custom pixelPerUnit value you should set it here. Or you will see only some part of pixels of image.
    spr.name = fileName;
    return spr;
}

I hope this will work for you guys. This is how I store my images after downloading assetbundles and how I call them in game.

  • If your asset bundle contains images, why would you not store them as images on the server instead of asset bundles? – kolodi Jul 06 '21 at 07:30
  • Also Sprite.Create is quite heavy operation. I woukld suggest you to use directly textures. If you have canvas UI you can make use of RawImage component. – kolodi Jul 06 '21 at 07:31
  • I'm using this for only 2 images in a level load. So it's not that heavy for me. I don't use them in UI, I use them as sprites. – Volkan Ege Dindar Jul 06 '21 at 07:33
  • Asset bundles have their own level info in each image. This is an image puzzle game. – Volkan Ege Dindar Jul 06 '21 at 07:34
  • 1
    You can make a simple JSON file (put it on your server) with a list of levels where each level has its all info + a URL to the image file on your server. Asset bundle are much more harder to update then. – kolodi Jul 06 '21 at 07:42
  • But I want to use Asset Bundles for version control, if there's a newer version it should update. Do you have any suggestion to download images and json with version control? – Volkan Ege Dindar Jul 06 '21 at 07:45
  • Add a version field for level image in your JSON. After you download an image, add `v1` (or `v2`, `v3`, depending on your version) to the end of the filename, so next time you can find last index of `v` in filename string to extract the cached version and decide to download new version or not. – kolodi Jul 06 '21 at 07:49
  • I changed everyting and I'm downloading images as bytes and writing them all to storage. When I need them I create sprites by using them. It solved cpu cost problems very much. I'm also keeping levels as json file and do same method so I don't try to keep images and jsons in an assetbundle, I use them separately. – Volkan Ege Dindar Aug 03 '21 at 16:09