Search Unity

Make the same build load different version of bundles

Discussion in 'Addressables' started by better_walk_away, Oct 2, 2019.

  1. better_walk_away

    better_walk_away

    Joined:
    Jul 12, 2016
    Posts:
    291
    How can I make client to load different version of bundles? Let me give you a detailed example.

    I have a dog image in the scene, I include this image as an Addressable asset, I put it in a group called "image", and I labelled it "image". I have a HTTP Server that stores the catalogs and bundles of the Addressable assets, and here is the folder hierarchy of my HTTP Server (I set the Bundle Naming to "No Hash"):
    Android
    --0.1
    ----catalog_2019.10.02.02.39.08.json
    ----catalog_2019.10.02.02.39.08.hash
    ----image_all.bundle
    --0.2
    ----catalog_2019.10.02.02.41.13.json
    ----catalog_2019.10.02.02.41.13.hash
    ----image_all.bundle

    iOS
    --0.1
    ----catalog_2019.10.02.02.39.08.json
    ----catalog_2019.10.02.02.39.08.hash
    ----image_all.bundle
    --0.2
    ----catalog_2019.10.02.02.41.13.json
    ----catalog_2019.10.02.02.41.13.hash
    ----image_all.bundle

    ServerConfig.json

    There are three things in the root of my HTTP Server, "Android" and "iOS" are two folders for the two mobile platforms, below them are the folders for each version that has been built, in this case, they are "0.1" and "0.2". ServerConfig.json is the setting file of my HTTP Server, the client must download this file before download any bundle.

    Here is my AddressableAssetSettings:
    upload_2019-10-2_11-32-45.png
    Everytime client starts the game, the "Downloader" class will download the ServerConfig.json file from server, then use JsonUtility to parse the text of this file into "ServerConfig". Here is the definition of the ServerConfig.
    Code (CSharp):
    1.  
    2. [Serializable]
    3. public struct ServerConfig
    4. {
    5.     public List<VersionCodeToBundleCode> Dictionary;
    6. }
    7. [Serializable]
    8. public struct VersionCodeToBundleCode
    9. {
    10.     public string key;
    11.     public string value;
    12. }
    The Downloader class has a public static string variable named "TargetVersion". When ServerConfig is read successfully, Downloader will pass "Application.version" into ServerConfig.Dictionary to try to find a VersionCodeToBundleCode with key that is equal to "Application.version", then assign its value to the public static string variable "TargetVersion". This way, I should be able to control what version of bundle each version of build should download. For example, build version 0.1 downloads bundle version 0.1 by default, I could let build version 0.1 download bundle version 0.2 instead by modifying the setting of ServerConfig.json.

    All these steps are done before Addressables is initialized or loads anything.

    Let's say I target Android platform this time. First, I set the version code to 0.1, the sprite of the image is a dog, I build the Addressable assets, it generates a folder named "0.1" under "Android" which contains remote catalog and bundle file on my HTTP Server. In the meantime, there is a local catalog file generated under C:\Users\h3902340\Documents\MyProject\Library\com.unity.addressables\StreamingAssetsCopy\aa\Android
    Then I set the version code to 0.2, I change the sprite of the image to a cat, I build the Addressable assets again, it generates a folder named "0.2" under "Android", and it contains a catalog file and a bundle file as well, but because I have changed the sprite of the image, Addressable generate a new hash code for the image's bundle, and the hash code of the local catalog file is also updated. Local catalog file now contains the hash code of the version 0.2, not 0.1.
    Finally, I change the version code back to 0.1. When Unity output the apk, this local catalog is also included in the apk. When client runs the game, Unity first load the local catalog file that is in the apk, then try to find the bundle with the same hash code on my HTTP Server. Because the hash codes of the two versions of the bundles are different, if I let this build download the bundle version 0.1. It will try to find the bundle with the hash code that belongs to 0.2 in the folder 0.1, so it simply throws an error saying that it couldn't find the bundle.

    How can I make one version of build to download different versions of bundle while still maintaining all versions of bundles so that I could make it download any version of bundle at any time?

    Please help me...
     
    Last edited: Oct 2, 2019
  2. unity_bill

    unity_bill

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    when you build the player, it remembers the name of the remote catalog it needs to load. So it knows to look for, say: IP/Android/{Downloader.Version}/catalog_2019.10.02.02.41.13.json & catalog_2019.10.02.02.41.13.hash.

    Based on your example, you are dynamically replacing Downloader.Version, but if that points to a folder without catalog_2019.10.02.02.41.13.json things won't work. I think all you need to fix this is to "Player Version Override" in the top level settings (it's in your screenshot). If you set that to, say, "hello", you'd get IP/Android/{Downloader.Version}/catalog_hello.json & .hash.

    So no matter which folder you were looking in, the correct catalog would be there.

    Unless i'm misunderstanding the situation.
     
  3. better_walk_away

    better_walk_away

    Joined:
    Jul 12, 2016
    Posts:
    291
    Yes, this is the exact solution for me!
     
    unity_bill likes this.
  4. better_walk_away

    better_walk_away

    Joined:
    Jul 12, 2016
    Posts:
    291
    @unity_bill
    Hello, I now bumped into another problem. Although by setting the file name of the remote catalog to be the same, we can force the game to load the newest catalog. However, this method has one downside, if we use some kinds of CDN services, CDN help us cache the bundles to the server that is closest to the user, so the user could download the bundles more quickly. But CDN checks only the file name, not its content, it would think that the catalog we have updated doesn't need to be downloaded because the client already has this file. How do we address this issue?

    Bundles don't have this issue because they have hash code in the end of their file names, when the assets change, the hash code also gets changed. So the file name is different every time we update the bundle, namely, the url is also different.
     
    Last edited: Jul 8, 2020
  5. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    586
    See my thread about loading content catalogs using cache in an unexpected manner (I expect the built-in initialization catalog does the same thing): https://forum.unity.com/threads/clear-cached-content-catalogs.910448/

    So @unity_bill 's advice won't even work for this purpose (unless you manually change the override every time). You will have to have a different generated catalog name for each version, until the Addressables team makes the cache more versatile. You can include the catalog name in your ServerConfig.json, and instead of relying on
    Addressables.InitializeAsync
    , use
    Addressables.LoadContentCatalogAsync
    .

    P.S. if you're updating a build (overwriting an existing catalog, not building a whole new version), you will have to invalidate your CDN cache. Addressables can't do anything about that.
     
    Last edited: Jul 7, 2020
  6. cngznrgz

    cngznrgz

    Joined:
    Apr 6, 2018
    Posts:
    1
    I solved this problem by adding a random parameter to the url

    Code (CSharp):
    1.    static string AddRandomParameters(IResourceLocation location)
    2.     {
    3.         string u;
    4.         if (location.InternalId.StartsWith("http") && location.InternalId.Contains("/catalog_"))
    5.         {
    6.             u = $"{location.InternalId}?r={Use.RndmStr()}";
    7.         }
    8.         else u = location.InternalId;
    9.         return u;
    10.     }
    11.  
    12.  private void Awake()
    13.     {
    14.         Addressables.InternalIdTransformFunc = AddRandomParameters;
    15.     }
    16.  
    17.  
    18.  
     
    outgoingnxt likes this.