Search Unity

ContentUpdateSchema Static vs Non-Static

Discussion in 'Addressables' started by MNNoxMortem, Dec 17, 2018.

  1. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    323
    What does this flag exactly do?

    I mean it is explained here as https://docs.unity3d.com/Packages/c...DevelopmentCycle.html#content-update-workflow

    Code (CSharp):
    1. The recommended approach to content updates is to structure your game data into two groups: static content that you expect never to update and dynamic content that you expect to update. In this content structure, static content ships with the Player (or download soon after install) and resides in a single or a few large bundles. Dynamic content resides online and should be in smaller bundles to minimize the amount of data needed for each update. One of the goals of the Addressables system is to make this structure easy to work with and modify without having to change scripts. Sometimes you find yourself in a situation that requires changes to the "never update" content but you do not want to publish a full player build
    I understand this as: I can do with static bundles exactly the same as I can do with non-static ones and there is nothing I can't do with non-static ones. For every group I am able to set where I want the bundle to be build to and loaded from.

    The only difference seems to be what is written to the *.bin file, which is required for Content Updates.

    It would be really nice if we get a bit more information on how to properly set those groups up and a bit more detail about the Content Update would be nice. I'm currently trying to follow the linked explanation, but there are some weird thing which looks more like missing features/bugs than actual intended workflow:
    • A change to a group, marked as static build to "LocalBuild" and loaded from "LocalLoad" will result in the asset moved to a new group ContentUpdate group with settings "non-static" and "RemoteBuild" and "RemoteLoad" as locations.
    • The AssetBundles are platform dependent but it looks like I have to manually set the current platform, change the Addressable Profile to my platform dependent setting profile and delete whatever other bundles were build to Streaming Assets from other platforms to not have them copied all together.
    Also one question I have: When am I actually required to publish a full player build? I mean there are some obvious scenarios, but where approximatively is the breaking point? I have so many questions about the robustness of the system and seem to find little information about that (although I assume the answer is "it is as with Asset Bundles" - but I never used them before and there is not much information about them either as obviously the minority of users really seem to have adopted them).
     
  2. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    381
    I will note that we need to update our docs. In the interim, please watch the last Unite talk and let me know if you still have questions:

     
  3. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    323
    @unity_bill Have I missed it? Watched it and there is no deeper explanation of the static flag?

    Unless you are referring to the slide on 23:42. Is this the ONLY thing static does? When would I use "non-static" then? I want to be able to update all bundles via prepare for content-update / build for content update but 23:42 sounds like prepare will "only" detect changes in "static" marked content.

    [29:42] What especially confuses me is that the "local Demo Data" must be "static" but the "content update" has not ticked "static". Am I not able to update the "content update" later again? How would it detect subsequent changes down the road (updates of updates of updates).
     
    Last edited: Dec 19, 2018
  4. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    381
    let's have this example:
    groupA_static
    - assetA
    - assetB
    - assetC
    groupB_nonStatic
    - assetX
    - assetY
    - assetZ

    now you change assetA and assetX. Prepare will do this:
    groupA_static
    - assetB
    - assetC
    groupB_nonStatic
    - assetX
    - assetY
    - assetZ
    content_update_group
    - assetA

    so static tells the prepare step "is this a group that can or cannot be updated post-launch". Note that groupA_static did technically change, but it changed only via removal. So after the build, you can discard the new groupA_static since the pre-existing one has all the same content (and then some)

    hope that helps
     
  5. CC9

    CC9

    Joined:
    Mar 20, 2013
    Posts:
    3
    @unity_bill Just for clarification:

    Setting Static content to true signals it as a group that CAN be updated post-launch, while setting to false flags it as a group that CAN NOT be updated post launch? The fact that the static group changed (removal of A) in your ABC,XYZ seems counter-intuitive and thus the confusion.

    Thanks.
     
    MNNoxMortem likes this.
  6. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    442
    I think that you understood it wrong, quoting bill here:
    @unity_bill correct me if I'm wrong, but what I understood is that if you set it to static it will mean that it cannot be updated post-launch, hence the static. After the build the content was updated on the old (original) groupA_static instead of a new update, which is why you can discard the new groupA_static.
     
  7. CC9

    CC9

    Joined:
    Mar 20, 2013
    Posts:
    3
    @Rotary-Heart Yeah, I felt like I might be since it uses the word static but I wasn't sure. I've been trying to assess which way to do it but I have a fairly large project so generating bundles is a timely process.
     
  8. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    381
    ok, I wasn't totally clear. Static does mean unchangeable, even though it "changed" in my example. Here's what I mean. I have the two bundles as stated, and then, also as already stated, I change A and X to end up with:
    groupA_static
    - assetB
    - assetC
    groupB_nonStatic
    - assetX
    - assetY
    - assetZ
    content_update_group
    - assetA

    so far this is all copied from above. The thing I didn't clarify originally, is that this group layout is what Addressables will setup in your project. This gives you the ability to build bundles, then put groupB_nonStatic and content_update_group up on your CDN. Then on the users device, they'll end up with:
    groupA_static <--old, already existed
    - assetA <-- no longer referenced by the content catalog.
    - assetB
    - assetC
    groupB_nonStatic <--newly downloaded
    - assetX <-- updated thanks to new download
    - assetY
    - assetZ
    content_update_group <-- newly downloaded
    - assetA <-- what is referenced by new content catalog

    so yes, locally we change the group layout, so that when we build, we'll get the proper remote bundles.

    That help?

    -Bill
     
    MNNoxMortem likes this.
  9. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    323
    @unity_bill Thank you that helps a lot. I guess my main question is why would I ever want to mark something not as static.
    • groupB_nonStatic is completly rebuild although assetY and assetZ did not even change. It is also uploaded in full size again and downloaded in full size
    • The adressable asset system hides the fact that assetA is in content_update_group anyway. groupA_static would be on the server already anyway and the hash has changed because of the change to assetX
    Maybe I still have a mental roadblock but nonStatic looks worse in any scenario to me.
     
  10. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    381
    to show the pros/cons of static, let's look at toggling static ON for groupB. What you end up with on the server is:

    groupB_static <-- original, unchanged bundle
    - assetX <-- dead asset with no one referencing it.
    - assetY
    - assetZ
    content_update_group
    - assetX

    So imagine assetX was a huge texture. If the user has already downloaded groupB, they will have to keep that in their cache (potentially re-downloading if cache is cleared) because Y and Z are still referenced. And they have to download the new content_update_group. If they have not downloaded groupB yet, then they now have to download both bundles, which causes them to download X twice. Once as the dead copy in groupB, once as the new one.

    So what's better? having a dead X to download/cache, or having to re-download Y/Z even though they haven't changed? depends on your situation.
     
    MNNoxMortem likes this.
  11. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    323
    Thank you so much, now I finally got it.
     
  12. AAK_Lebanon

    AAK_Lebanon

    Joined:
    May 30, 2015
    Posts:
    43
    I hope that the new release will clarify things better and the workflow will be more intuitive because for now, I think it is very hard to imagine what is happening here! anyone can summarize this thread ?? because the "truth" now lies between replies ...
     
  13. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    323
    @AAK_Lebanon Let me try to point out how it seems to work and how it is meant to work at the moment.
    • Static A: (X1,Y,Z)
      • Change Asset X1 to X2
      • Prepare for Content Update moves X to a new ContentUpdateBundle U1: (X2)
      • Old Client Downloads & Caches A: (X1,Y,Z)
      • New Client Downloads & Caches A: (X1,Y,Z) AND U1: (X2) because Y,Z are still referenced from A
      • Better if X is much SMALLER than Y,Z as Y,Z are likely already cached and only small U1 is required to be downloaded
    • NonStatic B: (E1,F,G)
      • Change Asset E1 to E2
      • [Wrong: See unity_bills answer below] Prepare for Content Update creates a new Group ContentUpdateBundle U2: (E2,F,G)
      • Old Client Downloads & Caches ONLY B: (E1,F,G)
      • New Client Downloads & Caches ONLY U2: (E2,F,G) because a new bundle is created
      • Better if E is much LARGER than F,G because we do not need to download & cache B anymore
    • In both cases the Content Update Workflow is meant to update the catalog to point to the very latest version of an asset (as long as you use at least 1 Remote bundle, otherwise no new remote catalog can be found) without requring a new build (X2 instead of X1 and E2 instead of E1) - but this does not work for us and others at the moment (depending on how you changed the asset or a dependency).
     
    Last edited: Jan 31, 2019
    AAK_Lebanon likes this.
  14. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    381
    That is all correct, except for the second step under NonStatic B. In the case of a non-static group, prepare will do nothing. Simply rebuilding will create what you call U2, though it will have the same original name, with a new hash. So you get:
    • Old Client Downloads & Caches ONLY B1: (E1,F,G)
    • New Client Downloads & Caches ONLY B2: (E2,F,G) because a new bundle is created
     
    MNNoxMortem likes this.
  15. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    323
    @unity_bill Really sorry to ask like the 20(00)-iest time already but pondering about your last post really confused me. Maybe because the difference between "building player content" and "building a build/exe" and my own failure to mix client and build in the post above. Also the difference between "how it is meant to work" and "how it currently works" adds another layer of confusion for me.

    I thought the whole purpose of the content update workflow was that the Old Client v1 would be able to download the new B2 bundle by looking at the catalog file in the remote location and the content update workflow would spit out a new catalog file, which would be read by the Old Client v1 and that would point to the new bundle without the client knowing that the underlying addressable assets changed.

    As you said at Unite L.A. 29:30: "I haven't touched my deployed build". And then you just rerun the space game and the new asset change is detected.

    That was what I meant with the last point that without building a new exe regardless of static or non-static always the latest asset should be downloaded (E2 instead fo E1 and X2 instead of X1).

    If new non-static groups after assets changes in them are only created during a full "build player content" they are even less updateable than static groups. This would mean non-static groups can not be updated with the content update workflow. This is very confusing.

    So far I thought

    • Build Player Content (sic! not: Update) means new hashes and creates a new catalog and means any application (e.g. .exe) before that point will not be able to read the new content.
    • Old Client v1 can not read New Build Player Content
    • Old Client v1 can only read content from Old Build Player Content + Updates to old.bin
    • New Client v2 can read Old Build Player Content + Updates to old.bin. (latest available)
    • New Client v2 can read New Build Player Content + Updates to new.bin (latest available, v2.exe newer than content)
    Update: Tried to visualize this in a timeline based way
    upload_2019-1-31_12-7-8.png
    upload_2019-1-31_12-7-25.png
    upload_2019-1-31_12-7-47.png
     
    Last edited: Jan 31, 2019
  16. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    381
    I'm sorry, I think I had misunderstood what you had meant (due to not reading carefully enough I suppose). Whey I copy pasted "old/new client downloads", I was interpreting that as "the old data that the client had downloaded" and "the new data the client will download".

    I did not realize you were referring to actually building a new client. Though after re-reading your post, that makes sense.

    I like your drawing. To be clear, the two potential places where you have built v2 are different scenarios. You may have meant that in the drawing, but just to clarify, I'll outline this:

    1. Each time you run Build Player Content, you get a new catalog version.
    2. when you build the player, it takes the last catalog and locks into that file name. Which means one of these is true and one false, depending on your scenario:

    If you only have run "build player content" once in this entire flow, then yes,

    Let's say you run "Build Player Content" and get "catalog_2019.01....json". Now you build a player (Client1), and do some content updates (creating "catalog_2019.01....json"v2. The player is locked to that catalog ("catalog_2019.01....json"), and the updates overwrite that catalog (creating a v2, v3, etc, but the file name is still "catalog_2019.01....json"). So a user with this Client1, has the original catalog on their device (because the client shipped with it), and if they've connected to the server, they'll have the newest version, and will use it.

    Now you build a new player (Client2) and have one of two scenarios....
    1. If you have not rerun "Build Player Content", this new player will be locked in to the same version of the catalog. It will ship with "catalog_2019.01....json"v3, and as you do updates (say, "catalog_2019.01....json"v4) both players will look at that up catalog.
    2. if you have rerun "Build Player Content", then the new player will look at the newly created catalog (say "catalog_2019.02....json"v1), and only that catalog (based on file name, overwrites are possible).


    Hope that clarifies. As a note, I'm taking a lot of this explanation and integrating it into the official docs to hopefully smooth things out for future users.
     
    MNNoxMortem likes this.
  17. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    323
    @unity_bill As always: Thank you for bearing with me and taking your time for all those explanations! The addressables and all this have led to some very interesting last 3 weeks :D

    Your explanations are very helpful and important for us at the moment, therefore a big thanks!
     
    unity_bill likes this.
  18. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    381
    One other note on what we anticipate being a best practice (but don't know for sure):

    1. Build Player Content, build player, ship game.
    2. change content.
    3. Branch Version Control
    4. on shipped branch, do prepare for content update, build for content update, and release new bundles for shipped player
    5. on a mainline branch, start over at #1 for what we had been calling "Client2"

    The reasoning is that "prepare for content update" will move things you had presumably wanted to be local, to now be remote.
     
    MNNoxMortem likes this.
  19. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    382
    @unity_bill this would have some problems in my current workflow. we have something like this:
    - we have a live, constantly updated client (iOS/Android)
    - client updates include new features and bugfixes. new features may cause new content "class"
    - we also want to update existing content, and/or add new content to an existing "class"
    - player will not always be on the last client version, but we want to push new content
    - new/changed content for old client should be synchronized to all newer client versions, without us needing to branch and rebuild for each released version still out there (e,g, assume there are players on version range 1.2.3 to 1.2.15, that would be a lot of rebuilds)

    example:
    - game client v1 has main gameplay, with addressable levels or stages
    - game client v2 adds IAP, with addressable store items
    - (other versions add more features)

    so my expected workflow with addressable, if supported, would be:
    1) Build Player Content / generate catalog only once in history
    2) client v1 loads levels by label "Level" (a bunch of them included in first release, more planned)
    3) release client v1
    4) want to create new levels, e.g. new content with the label "Level" <-- this would be a content update?
    5) client v2 loads items with label "Purchase"
    6) release client v2
    7) more new levels, we want to build them once and have them available to both versions
    8) modify IAP items, e.g. by changing color/positioning <-- still content update?
    9) only when we upgrade Unity (or make some huge incompatible changes ourselves), we want to generate a new catalog, rebuild all, then either force old clients to update (this will cost a significant percentage of active users) or ignore content updates for old client. or support the build twice for a limited time

    is this supported? are there some gotchas that explain why the "best practice" would be to branch each version?
    (provided that we are ensuring that all content under label e.g. "Level" is compatible with v1 client, either manually or via a custom rule)
     
  20. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    381
    I don't see anything in that list that wouldn't be supported. The reason for the best practice is specifically for the scenario where you have changes to Static=true groups.

    To be clear, if nothing in a static group changed, you have no need to run Prepare, and running Prepare will do nothing.


    If things in static groups have changed, then prepare rearranges your groups. Presumably, it does so in ways that no longer match how you had intended for your shipped game. Hence the branch.
     
    MNNoxMortem likes this.
  21. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    382
    so:
    if we have no static content, we do "build player content" for the first release, and "build for content update" afterwards (without "prepare...") and it will work like I said.
    if we do have static content, does it means that "prepare" will make the old version unable to find the content update group? even if we already have some remote content?
    more specifically, what kind of group rearranging would make the old executable not compatible?
     
  22. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    381
    say you have "tank" in a local (in StreamingAssets) group. Being local it should be marked Static. Now you change "tank".

    Your already released build of the game has "tank" as a local asset along with some remote bundles we'll call "bundle set 1". Prepare will move "tank" into a new remote group to be put up on a server. The update build will create "bundle set 2", which has this new tank. For everyone with this existing (already released) player, when the player tries to show "tank" it'll forget about the old local one, and download a new remote one.

    Now, lets say it's a ways into the future, and you want to release a new player. Presumably, you want "tank" to be local again. Since you wanted it so originally, I'm guessing you may want it that way now. With this player, you build "bundle set 3"


    so "make the old executable not compatible"? Not exactly sure what you're asking, but to be clear, the original player build will work with "bundle set 1" and "bundle set 2". The new player build will work with "bundle set 3". If you put all the sets in the same folder on a server, then perhaps there's be some bundles that were unchanged across all the builds. In this case, they'd have the same file name (with hash appended) and there would just be one copy on the server that all players point to. But fundamentally, each player points to a specific set of bundles.
     
    M_R likes this.