Search Unity

ContentUpdateSchema Static vs Non-Static

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

  1. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    723
    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).
     
    littledwarf likes this.
  2. unity_bill

    unity_bill

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    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:
    723
    @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

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    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. BradenCarter

    BradenCarter

    Joined:
    Mar 20, 2013
    Posts:
    5
    @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.
     
    aromana, amesa_unity and MNNoxMortem like this.
  6. Rotary-Heart

    Rotary-Heart

    Joined:
    Dec 18, 2012
    Posts:
    813
    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. BradenCarter

    BradenCarter

    Joined:
    Mar 20, 2013
    Posts:
    5
    @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

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    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
     
    jperry_oddgames and MNNoxMortem like this.
  9. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    723
    @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

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    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.
     
  11. MNNoxMortem

    MNNoxMortem

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

    AAK_Lebanon

    Joined:
    May 30, 2015
    Posts:
    77
    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 ...
     
    Egil-Sandfeld likes this.
  13. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    723
    @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

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    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:
    723
    @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

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    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:
    723
    @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

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    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:
    559
    @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

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    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:
    559
    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

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    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.
  23. lejean

    lejean

    Joined:
    Jul 4, 2013
    Posts:
    392
    I've been reading this thread and I still don't fully understand how it works.

    The way I use it now is like this:
    -I made a couple bundles and didn't mark anything static
    -If I change anything at all I just remove the files in serverData folder, do a "update previous build", upload those files and that's that.

    I press play in the editor, the changed bundles get downloaded again and everything is updated.

    The content update way:
    I don't really understand

    -I created a static group
    -put a asset in there
    -I do "check for content update" and the new file is visible in the window
    -i do apply changes and then Update a previous build

    So now a content update bundle is added to server data and the build gets updated as well.

    So I guess my questions are:
    1) The new file is still in in the content update group in the editor though, do I move it back to its original group?
    2) When I move it back the "content update" is flagged again even tho I didn't change anything.
    If I leave it in the content update group and change anything, it doesn't get flagged for content update?

    3) I also don't get the point of static/non-static, anything can change post release even if you think it won't?
    Is static meant for big bundles, like textures, that probably won't change so you don't have to upload them to a server?
    4) But what happens if you add a DLC with lots of new textures? Can they also be marked static and downloaded without creating a new build?
     
    Last edited: Sep 12, 2020
  24. lejean

    lejean

    Joined:
    Jul 4, 2013
    Posts:
    392
  25. davidla_unity

    davidla_unity

    Unity Technologies

    Joined:
    Nov 17, 2016
    Posts:
    763
    @lejean
    Just for context, marking a group as Static is telling the Addressables system "I never want anything in this group to change." The Check for Content Update Restrictions workflow is only for when you've made some critical error and something _does_ need to change in a Static group.

    1) The new file is still in in the content update group in the editor though, do I move it back to its original group?
    No, once you've told Addressables you want something in a Static group to change don't move it back.

    2) When I move it back the "content update" is flagged again even tho I didn't change anything.
    See above.

    If I leave it in the content update group and change anything, it doesn't get flagged for content update?
    It does, but the Content Update groups aren't Static. So if you change something in a "Can Change Post Release" (dynamic) group then it'll automatically get updated.

    3) I also don't get the point of static/non-static, anything can change post release even if you think it won't?
    Is static meant for big bundles, like textures, that probably won't change so you don't have to upload them to a server?
    Static groups create a contract between your player build and your Addressable build. You can break that contract but it isn't recommended.

    4) But what happens if you add a DLC with lots of new textures? Can they also be marked static and downloaded without creating a new build?
    The group can, yes. But if it's DLC and you don't want to do a new player build they'll need to be remote bundles. Remote bundles can be Static (though they typically aren't to my knowledge). What will need to be updated is the content catalog (if you're building remote bundles you should have a remote catalog that you upload to your CDN or whatever). If you post a new AssetBundle up to your CDN but your player build didn't have "build remote catalogs" turned on or you don't upload the new catalog then the system has no way to know about the new DLC texture bundle.
     
    lejean likes this.
  26. lejean

    lejean

    Joined:
    Jul 4, 2013
    Posts:
    392
    Thanks for the answers.

    I tried this but there's an issue and I don't know if it's a bug or if I did something wrong.
    I did a static content update like described in the example here.

    I changed an asset, prepare for update, apply, update previous build.
    But when I reload my scene with the updated files assetB and assetC are missing/pink and only assetA is updated.
     
    Last edited: Sep 16, 2020
  27. dirty-rectangle

    dirty-rectangle

    Joined:
    Apr 23, 2015
    Posts:
    78
    @DavidUnity3d
    You mention that "The Check for Content Update Restrictions workflow is only for when you've made some critical error..."
    This suggests to me that this workflow shouldn't be part of a common process for updating assets on the client.
    Please could you qualify why that is, the documentation here doesn't indicate to me that this workflow is intended for error cases.
    https://docs.unity3d.com/Packages/c...manual/AddressableAssetsDevelopmentCycle.html
    What kind of difficulties could you expect to encounter if you do use this workflow as a more regular means of updating content?
    "Static groups create a contract between your player build and your Addressable build. You can break that contract but it isn't recommended."
    Can you give some details for why this isn't recommended?
     
  28. davidla_unity

    davidla_unity

    Unity Technologies

    Joined:
    Nov 17, 2016
    Posts:
    763
    As for the first post, check what version your on. Try and update to 1.15.1 or newer (if available, 1.16.1 should be out soon) and try again. There were issues with content update that sound very similar to what you're seeing that have been fixed.

    Right, static content shouldn't be a regular part of your content update process. If you use static content as a regular means of updating you'll find you're wasting a lot of space in your AssetBundle cache and your build. When you update a static content group it will break that group into two A (original) and B (Content Update). Now your game has to download B and cache it. However, unchanged content from A will remain in that original bundle since there's no need to download a whole new bundle for the same data. The downside is that that original A bundle still has the data for the old asset of B, it just doesn't get used anymore.
     
  29. felipe-shida-playkids

    felipe-shida-playkids

    Joined:
    Sep 16, 2020
    Posts:
    13
    @davidla_unity

    In our scenario, we are experiencing strange behavior when doing case number one. We are checked out to the exact same git tag of a release build, we have the same content_state.bin generated by our remote build machine. When we run the Check for Content Update Restrictions the list is empty, so our static content should be safe. Every Local loaded asset group is static, so we should be safe to generate an addressable build as an Update to be used in a new client build, right?

    The result we fall into is not expected though, some of our local asset bundles are not generated, debugging the bundle generation we discovered that this asset bundle had changes in its hash and were deleted by the
    ApplyAssetEntryUpdates method on the RevertUnchangedAssetsToPreviousAssetState class, the bundle that was reverted was static and local, and even with the clean Check For Content Update Restriction result, it changed somehow.

    Rerunning the update on our remote machine works fine and it's apparently deterministic. Could it be due to differences in the machine that runs the addressable build? OS, architecture, etc? Can we consider that our workflow is not supported or is it a bug?
     
    Last edited: Jan 28, 2022
  30. davidla_unity

    davidla_unity

    Unity Technologies

    Joined:
    Nov 17, 2016
    Posts:
    763
    @felipe-shida-playkids So, I do know that there are determinism uncertainties across OS/architecture. Different machines should be fine, so long as OS/architecture doesn't differ. I'd have to have someone from the build team go into more detail on that. The basics of what I know is that AssetDatabase.GetDependencyHash can give different results on different OS's for shaders. So that could be what you're running into. I'm inclined to think that is what you're running into since Updates work fine on the remote machine.