Search Unity

1.15.1 AssetReference not allow LoadAssetAsync twice

Discussion in 'Addressables' started by JasonAppxplore, Aug 28, 2020.

  1. JasonAppxplore

    JasonAppxplore

    Joined:
    Jan 14, 2015
    Posts:
    18
    So with this is new change in 1.15.1, how am I supposed to use AssetReference now?

    Let's say there is an AssetReference ref.

    Code (CSharp):
    1. if (ref.OperationHandle.IsValid())
    2.     image.sprite = ref.OperationHandle.Convert<Sprite>().Result;
    3. else
    4.     ref.LoadAssetAsync<Sprite>().Completed += result => image.sprite = result.Result;

    I guess something like this? The problem is when this AssetReference is being used in 2 places/instances at once, when should I release it? Do I have to manually track the ref count now?
     
  2. GreenTVlad

    GreenTVlad

    Joined:
    Oct 2, 2019
    Posts:
    19
    I have additive question to new behaviour.
    Documetation says: "The AsyncOperationHandle currently being used by the AssetReference. For example, if you call AssetReference.LoadAssetAsync, this property will return a handle to that operation."
    If I use 2 different methods for the asset reference in different scripts in the scene. For example, LoadAssetAsync and LoadAsset. Then I'm trying to do it again and get the error. So, how can I determine which operation OperationHandle references on?
     
  3. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,311
    I immediately downgrade back to safe 1.13.1 land after seeing this. So that's 2 versions now totally unusable for me
     
  4. supersolid-jelte

    supersolid-jelte

    Joined:
    Dec 3, 2018
    Posts:
    22
    I don't really understand why this is an error...

    The optimization is fine, but shouldn't it just return the operation instead?


    Code (CSharp):
    1.  
    2.         public virtual AsyncOperationHandle<TObject> LoadAssetAsync<TObject>()
    3.         {
    4.             AsyncOperationHandle<TObject> result = default(AsyncOperationHandle<TObject>);
    5.             if (m_Operation.IsValid())
    6.             {
    7.                 Debug.LogError("Attempting to load AssetReference that has already been loaded. Handle is exposed through getter OperationHandle");
    8.                 return m_Operation.Convert<TObject>();
    9.             }
    10.        
    11.             result = Addressables.LoadAssetAsync<TObject>(RuntimeKey);
    12.             m_Operation = result;
    13.             return result;
    14.         }
    You would still get the error but atleast it wouldn't be breaking code...
     
    Last edited: Aug 29, 2020
    Ben-BearFish and GreenTVlad like this.
  5. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,311
    What I'm most confused about was in previous versions, if I had 1000 objects pointing to the same addressable and they all wanted to load that reference, were 1000 of those references loaded?

    The new implementation tells me that would be true, since why change the implementation and add a warning?

    If it is indeed true, that's really bad, cause that's exactly what I'm doing in my current game. I just assumed Addressables would be smart enough to just return a cached handle to me.
     
    gooby429, Peter77 and Ferazel like this.
  6. Ferazel

    Ferazel

    Joined:
    Apr 18, 2010
    Posts:
    517
    This is how Resources.Load worked from what I understand. First load would hit the disk, second would returned the loaded resource in memory. The downside is that it didn’t do ref counting so you had to count and call unload manually or wait until Resources.UnloadUnusedAssets could clean it up.

    I thought Addressables counted refs for this reason. So Addressables could unload on the asset bundle when all of the asset refs were reduced to 0 in an addressable bundle? I thought Addressables were supposed to make things easier. This change sounds like the worst of both worlds.
     
    Last edited: Aug 31, 2020
  7. xLeo

    xLeo

    Joined:
    Sep 21, 2010
    Posts:
    194
    Just did the same and won't ever bother working around this issue.
    I also agree with what you and @Ferazel said on the following messages.
     
    Sologamer, newtroj and edson-resende like this.
  8. PaulDyatlov

    PaulDyatlov

    Joined:
    Jul 6, 2019
    Posts:
    25
    1.14.2 working fine, seeing this in 1.15.1
     
  9. Ferazel

    Ferazel

    Joined:
    Apr 18, 2010
    Posts:
    517
    Is there nothing to be said from the Addressable team about why this change was made or what the desired flow is supposed to be when working with AssetReferences that are meant to be used multiple times?

    @TreyK-47 could we get some visibility on this change and what best practices should be?

    Another example is, let's say you have a scriptable object that defines an icon that can be loaded multiple times within a display (dynamically) so there are multiple references to the scriptable object that defines what icon should be displayed

    Are we supposed to hack something like this to load? Note that the load requests may happen on the same frame (thus the extra isDone check).

    Code (CSharp):
    1.  
    2.         public AssetReferenceSprite Icon;
    3.         public void LoadIcon(Action<Sprite> loadCallback)
    4.         {
    5.             if (Icon.OperationHandle.IsValid())
    6.             {
    7.                 if (!Icon.OperationHandle.IsDone)
    8.                 {
    9.                     Icon.OperationHandle.Completed += (loadRequest) =>
    10.                     {
    11.                         if (loadRequest.IsValid() && loadRequest.Result != null)
    12.                         {
    13.                             loadCallback((Sprite)loadRequest.Result);
    14.                         }
    15.                     };
    16.                 }
    17.                 else
    18.                 {
    19.                     loadCallback((Sprite)Icon.OperationHandle.Result);
    20.                 }
    21.             }
    22.             else
    23.             {
    24.                 Icon.LoadAssetAsync<Sprite>().Completed += (loadRequest) =>
    25.                 {
    26.                     if (loadRequest.IsValid() && loadRequest.Result != null)
    27.                     {
    28.                         loadCallback(loadRequest.Result);
    29.                     }
    30.                 };
    31.             }
    32.         }
    33.  
    Then on top of that you're not really giving us an option to release the asset easily. You're basically forcing us to refCount these loads such that we can unload the asset when it reaches 0. Which means I need to hold onto a reference to this scriptable object for the entire duration of the loaded display after which I can call Icon.ReleaseAsset() on it because like load I can only call that one time before it throws warnings.

    Do you see how difficult this change is to work with?
     
    Last edited: Sep 12, 2020
  10. chanon81

    chanon81

    Joined:
    Oct 6, 2015
    Posts:
    168
    I don't use AssetReferences, but WHAT?
    Why doesn't it reference count for you?

    If this is what the Addressable team thinks is useful, then I think it would be better for someone to write a new AssetReference that does what everyone expects it should do.
     
    magmagma likes this.
  11. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    easycardgame, firstuser and magmagma like this.
  12. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    It does, I just tested it. See video below where I go over the test. The conclusion is:

    1) When you reference the same asset with different AssetReferences, Unity loads the asset to memory once only (as it should).

    2) Loading the same asset from different AssetReferences uses reference counting. Releasing each AssetReference will remove the loaded asset from memory (as it should).

    3) Calling Load on the same AssetReference causes an error, which is pretty bad from an usage point of view as pointed out in this thread. Makes using the system enormously cumbersome.

     

    Attached Files:

  13. samimylly

    samimylly

    Joined:
    Aug 5, 2019
    Posts:
    1
    Changing the error to a warning would be fine (if it really, really must be there), also adding a callback parameter would be nice.
     
  14. jRocket

    jRocket

    Joined:
    Jul 12, 2012
    Posts:
    700
    I wouldn't mind this change if AssetReference was smart enough to populate the Asset field if it's already loaded into memory from another AssetReference. That would be ideal, and I could just check if .Asset is null before loading. But unless something has changed, it doesn't actually do that.

    So, how am I supposed to get my asset if its already loaded from another AssetReference?
     
    firstuser likes this.
  15. Ferazel

    Ferazel

    Joined:
    Apr 18, 2010
    Posts:
    517
    A separate AssetReference object will load and increment correctly. The problem we're encountering is when you use the same AssetReference object in a scriptable object or used as a reference and you want to access the asset multiple times using the same object. The new implementation assumes that an asset reference should only be loaded once. Which isn't really ideal for some workflows.

    IMO if the asset is loaded multiple times it should act as a reference increment and return immediately from the load call with the already loaded asset. We're using asset references as a safer string analog and that analog defines a location of a particular type of asset.
     
  16. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,311
    I'd just like to know if this change is going to stick moving forward. As I'll need to update all my loading code to accommodate. If not, and Unity plans on fixing this internally in next version I won't bother.

    The lack of communication on this change is concerning
     
    Prodigga and Peter77 like this.
  17. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    @supersolid-jelte Does this at least (patch/fix) the issue for now, or does that present another issue with that implementation? I'm on this thread because we're hitting the same issue.
     
  18. etopian

    etopian

    Joined:
    Dec 11, 2018
    Posts:
    9
    +1
    Need clarity on the intended workflow. Downgrading to older version for now.

    I'd be comfortable with adding checks in my loading code but as far as I can tell there is no OperationHandle getter available on an AssetReference object.
     
  19. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    As far as I can see, changing the code to what @supersolid-jelte suggested has no-visible side effects in our game (does not mean it's safe from side effects though). But all the places where we used AssetReferences seem to be working fine. I'm worried about doing that, and then it breaks reference counters, and we explode memory on the device.
     
  20. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Well seems it's intentional and will stay there :) In our case error happens not because we using duplicated assets, but just because we run a game second time.
    upload_2020-9-17_15-12-47.png

    Like we ran play mode - all loaded properly and works fine. Exit play mode, enter again - this errors. This error really annoying and say nothing helpful. Moreover why it's even happening on second play mode run if we're releasing all our handles.

    Edit: Oh my bad, apologize to Adressabless team, I just missed 2 handles for releasing as they're specific, separate type and was processed a bit differently. Fixed release for them and all works fine. Sorry again :)
     
    Last edited: Sep 17, 2020
    Pleija likes this.
  21. magmagma

    magmagma

    Joined:
    Oct 27, 2017
    Posts:
    41
    Yeah this is ... weird and unexpected...
    At first even with the error it seemed to be working fine but then I realized a few UI buttons were not working now because of this problem, so we reverted to 1.8.5 (the "Verified" one for 2019.4 )
     
  22. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    I'm also interested to hear what the rational behind this change was. The change should probably fix an issue that would occur when calling Load multiple times.

    Too bad the release notes only contain it's been changed but not why. An explanation would help us to understand why.

    What's the reason why the API does not include a Load method that triggers a load when the asset has not been loaded yet and just returns the asset when it's been loaded already?
     
    Pleija, Ferazel, CDF and 1 other person like this.
  23. supersolid-jelte

    supersolid-jelte

    Joined:
    Dec 3, 2018
    Posts:
    22
    @Ben-BearFish This should have no side effect as you are simply returning operation that is being used (the Convert just ensure the correct type).
    I haven't tested this as I decided to wait with updating to 1.15.
    My suggestion for any production code would be to keep using the Verified version, unless 1.15+ actually solves something for you ;)
     
  24. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    @supersolid-jelte I thought 1.15 is verified? How do you check if the package is verified?
     
  25. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,311
    1.16.1 released and still no word from Unity on why this change was made.
    Documentation still not updated.
    No examples or even a mention of checking "IsValid" before loading.

    https://docs.unity3d.com/Packages/c...al/AddressableAssetsAsyncOperationHandle.html
    https://docs.unity3d.com/Packages/com.unity.addressables@1.15/manual/LoadingAddressableAssets.html

    All documentation and examples simply say you just load the reference like so:

    Code (CSharp):
    1. handle = assetReference.LoadAssetAsync();
    2. handle.Completed += OnLoaded;
    But in actual fact, you need to do something like this:

    Code (CSharp):
    1. var op = assetReference.OperationHandle;
    2.  
    3. if (op.IsValid()) {
    4.  
    5.     handle = op.Convert<AssetType>();
    6.  
    7.     if (handle.IsDone) {
    8.  
    9.         OnLoaded(handle);
    10.     }
    11.     else {
    12.  
    13.         handle.Completed += OnLoaded;
    14.     }
    15. }
    16. else {
    17.  
    18.     handle = assetReference.LoadAssetAsync();
    19.     handle.Completed += OnLoaded;
    20. }
    And you need to do this on every load!

    This is so disappointing, please Unity, can you let us know why this change was made and if you plan on keeping it this way? You've gone from 2 lines to load something to 20 lines to load.
     
    Vedran_M and Prodigga like this.
  26. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    In the meantime, an extension helper can make that easier @CDF, but agreed. They need better communication with such a critical package for many.
    Code (CSharp):
    1. public static void LoadAssetAsyncIfValid(this AssetReference assetReference, out AsyncOperationHandle<TObject> handle, Action<AsyncOperationHandle<TObject>> OnLoaded = null)
    2. {
    3.     AsyncOperationHandle op = assetReference.OperationHandle;
    4.  
    5.     if (assetReference.IsValid() && op.IsValid())
    6.     {
    7.         // Increase the usage counter & Convert.
    8.         Addressables.ResourceManager.Acquire(op);
    9.         handle = op.Convert<TObject>();
    10.         if (handle.IsDone)
    11.         {
    12.             OnLoaded(handle);
    13.         }
    14.         else
    15.         {
    16.              // Removed OnLoaded in-case it's already been added.
    17.             handle.Completed -= OnLoaded;
    18.             handle.Completed += OnLoaded;
    19.         }
    20.     }
    21.     else
    22.     {
    23.         handle = assetReference.LoadAssetAsync<TObject>();
    24.  
    25.         // Removed OnLoaded in-case it's already been added.
    26.         handle.Completed -= OnLoaded;
    27.         handle.Completed += OnLoaded;
    28.     }
    29. }
    30.  
    31. // Or without the out parameter
    32. public static AsyncOperationHandle<TObject> LoadAssetAsyncIfValid<TObject>(this AssetReference assetReference, Action<AsyncOperationHandle<TObject>> OnLoaded = null)
    33. {
    34.     AsyncOperationHandle op = assetReference.OperationHandle;
    35.     AsyncOperationHandle<TObject> handle = default(AsyncOperationHandle<TObject>);
    36.  
    37.     if (assetReference.IsValid() && op.IsValid())
    38.     {
    39.         // Increase the usage counter & Convert.
    40.         Addressables.ResourceManager.Acquire(op);
    41.         handle = op.Convert<TObject>();
    42.  
    43.         if (handle.IsDone)
    44.         {
    45.             OnLoaded(handle);
    46.         }
    47.         else
    48.         {
    49.             // Removed OnLoaded in-case it's already been added.
    50.             handle.Completed -= OnLoaded;
    51.             handle.Completed += OnLoaded;
    52.         }
    53.     }
    54.     else
    55.     {
    56.  
    57.         handle = LoadAssetAsync<TObject>();
    58.  
    59.         // Removed OnLoaded in-case it's already been added.
    60.         handle.Completed -= OnLoaded;
    61.         handle.Completed += OnLoaded;
    62.     }
    63.  
    64.     return handle;
    65. }
     
    Last edited: Sep 25, 2020
    Vedran_M, Kazko, andreiagmu and 3 others like this.
  27. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,311
    Yeah, I just don't see why we should have to make Extension methods to a core loading method.
    The fact that 1.15.1 has been out for about 3 weeks now and still no mention of any of these changes in the official documentation is crazy to me.
     
    dogboydog and Ben-BearFish like this.
  28. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    The Unity Way™.
     
  29. magmagma

    magmagma

    Joined:
    Oct 27, 2017
    Posts:
    41
    There's the new official release notes but no further info on this. I hope we can get some explanation soon.
     
  30. MikeHergaarden

    MikeHergaarden

    Joined:
    Mar 9, 2008
    Posts:
    1,027
    I've finally been able to fully understand how Unity wants it to work from 1.15 onward.

    Tips for the rest here:
    1. Don't forget to use the Addressables event viewer to understand how many assetreferences are open

    2. In order to use one AssetReference multiple times; use
    Addressables.ResourceManager.Acquire(assetRef.OperationHandle);to increase the counter (this method is quite hidden) Looks like this is missing in above examples(!)

    3. Make your own wrapper around Unitys addressables for proper load/unloading code.

    4. In your wrapper: Don't forget to check the AssetReference status when reusing an assetref. If it's NONE then the asset had not yet loaded: subscribe to the .Completed instead here.

    Code (CSharp):
    1.   public static void LoadAssetAsync<T>(AssetReference assetRef, Action<AddressablesM2HGAMEResult<T>> callback)
    2.     {
    3.         if (assetRef.IsValid() && assetRef.OperationHandle.IsValid())
    4.         {
    5.             Addressables.ResourceManager.Acquire(assetRef.OperationHandle); //Increase the usage counter(!)
    6.             if (assetRef.OperationHandle.Status == AsyncOperationStatus.None)
    7.             {
    8.                 assetRef.OperationHandle.Completed += handle => callback(new AddressablesM2HGAMEResult<T>(assetRef, assetRef.OperationHandle));
    9.             }
    10.             else
    11.             {              
    12.                 callback(new AddressablesM2HGAMEResult<T>(assetRef, assetRef.OperationHandle));
    13.             }
    14.         }
    15.         else
    16.         {
    17.             var op = assetRef.LoadAssetAsync<T>();
    18.             op.Completed += handle => callback(new AddressablesM2HGAMEResult<T>(assetRef, op));
    19.         }
    20.     }
     
    Last edited: Sep 24, 2020
  31. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Sigh, this is so confusing. Isn't the point of the internal reference counting that we just call LoadAssetAsync some number of times and make sure we mirror that with the same number of ReleaseAsset's, and Unity takes care of the rest? Why do we need an additional layer on top of it? What the heck?

     
  32. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    In our game we spawn a character consisting of multiple parts based on some descriptor. We have a character factory class with a Spawn and Unspawn method.

    In spawn: We first load all the assets required for the character using LoadAssetsAsync then instantiate the necessary prefabs etc.

    In unspawn: We delete the gameobject and call ReleaseAsset on each asset that was loaded to construct the character. This is tracked internally. Spawn returns a handle to the character (+ the instantiated gameobject) and Unspawn accepts the handle so it knows which assets it needs to unload.

    This works fine:
    Code (CSharp):
    1. var character1 = await CharacterFactory.Spawn(characterSetup);
    2.  
    3. //...gameplay...some time later:
    4.  
    5. CharacterFactory.Unspawn(character1);
    6.  
    7. var character2 = await CharacterFactory.Spawn(characterSetup);
    8.  
    9. //...gameplay...some time later:
    10.  
    11. CharacterFactory.Unspawn(character2 );
    But if we have 2 characters active at once now, we get this dumb error?

    Code (CSharp):
    1. var character1 = await CharacterFactory.Spawn(characterSetup);
    2. var character2 = await CharacterFactory.Spawn(characterSetup); //ERROR no can do
    3.  
    4. //...gameplay...some time later:
    5.  
    6. CharacterFactory.Unspawn(character1);
    7. CharacterFactory.Unspawn(character2);
    What is the point of this? Why do I need my own layer here? The API is already convoluted as heck. Why put this responsibility back on us when the API was capable of handling it?

    Why
     
    Last edited: Sep 27, 2020
  33. Shaunyowns

    Shaunyowns

    Joined:
    Nov 4, 2019
    Posts:
    328
    Hey there,

    Leaving a general reply here just to let you all know that I've sent this post over to the team for you!
     
  34. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    If some resource is acquired, shouldn't it be eventually released? I don't see any release in your sample code.

    PS. I really hope the changes introduces in 1.15 will be reviewed / reverted and there will be no need for such manual resource management.
     
  35. Ferazel

    Ferazel

    Joined:
    Apr 18, 2010
    Posts:
    517
    I'm not letting this go to the 2nd page without some explanation. If the addressable team is responding to posts on the front page can they please understand their user's pain here and give some guidance?
     
    DrunkenMastah and firstuser like this.
  36. SurprisedPikachu

    SurprisedPikachu

    Joined:
    Mar 12, 2020
    Posts:
    84
    Why doesn't it return the already valid operation handle instead of a default/invalid operation handle?
    This recent change forces us to do a check before every call to addressables. Please revert this change. This is such a big pain.
    @unity_bill @DavidUnity3d
     
    skwsk8, peilivision, xLeo and 2 others like this.
  37. EdwinLyons

    EdwinLyons

    Joined:
    Oct 4, 2012
    Posts:
    84
    My theory is that you should create a new AssetReference for each usage, so I fixed this using this (fairly simple) pattern:

    Code (CSharp):
    1. _loadedAssetReference = new AssetReference(existingAssetReference.AssetGUID); // clone the existing asset reference
    2. var handle = _loadedAssetReference.LoadAssetAsync<Whatever>();
    3. var loadedAsset = await handle.Task;
    4. ...
    5. // When you're done
    6. Addressables.Release(_loadedAssetReference);
    Cloning the reference is more tricky if you're dealing with sub assets (e.g. sprites), but the same principle applies I think.

    It feels like Addressables gets the concept of an AssetReference a bit confused. Is it a reference to an asset in a bundle, a reference to a loaded asset or both? It seems to be both, but that doesn't feel right to me.

    Conceptually it seems to make sense to treat the asset references that you have serialised (e.g. in a ScriptableObject or MonoBehaviour) as immutable - i.e. never call LoadAssetAsync on it, then create copies of that each time you load from it.
     
  38. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    224
    This is not GC-friendly.
     
  39. EdwinLyons

    EdwinLyons

    Joined:
    Oct 4, 2012
    Posts:
    84
    This is true - but for us isn't a major concern in the project we're working on as we generally load assets behind a loading screen and the AssetReference lasts the length of the lifetime of the object (generally until the next loading screen).
     
  40. unity_bill

    unity_bill

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    I apologize for the unclear release notes. There are a few parts of the docs that reference this, but understandably they are hard to find. Let me summarize...

    AssetReference.LoadAssetAsync() is a helper we've provided that you in no way need to use when loading an AssetReference. Addressables.LoadAssetAsync(AssetReference) will work just as well. If you do the latter, the async operation handle is returned to you and you are in charge of it. You can call that as many times as you want, and get as many handles as you want. Each will be ref-counted.

    If you choose to use the AssetReference.LoadAssetAsync() helper, the asset reference itself will hold on to the handle. This enabled the helper method AssetReference.ReleaseAsset(). Prior to 1.15.1, if you called load twice, the first handle would simply get stomped. If you happened to keep up with it, great, but if not, it was lost forever.

    So, in short, AssetReference.LoadAssetAsync() is a convenience helper that really only works in the most simple case. If you are doing anything beyond the simple, and are keeping up with the handles yourself, just use Addr.Load... If I were starting addressables over I likely wouldn't have the helpers at all, requiring the Addressables.Load..(AssetRef) be used instead.

    I hope this clarifies things.
     
  41. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Right. I feel like a big refactoring is in order and this helper functionality should really be moved into an examples package. It is completely impractical to use in any real project, right? Yet it gets centre stage attention.

    So this:
    Code (CSharp):
    1.         var prefabAsset = await prefabReference.LoadAssetAsync().Task;
    2.         //..later...:
    3.         prefabReference.ReleaseAsset();
    Becomes this:
    Code (CSharp):
    1.         var loadOp = Addressables.LoadAssetAsync<GameObject>(prefabReference);
    2.         var prefabAsset = await loadOp.Task;
    3.         //...later...:
    4.         Addressables.Release(loadOp);
    This works.

    Though annoyingly, C# can't infer the type from the variable, so I need to manually specify that prefabReference is a Gameobject, despite the fact that prefabReference is of type AssetReferenceGameObject.

    So now all of the stub classes I've created AssetReferenceXXXX are only useful for the 'rich inspector' they provide, I guess? They serve no purpose in code. I have to manually specify the type on every Addressables.LoadAssetAsync call. (ie, if later I change the prefabReference type, load line of code wont throw a compiler error. <GameObject> will still be valid, even though prefabReference's type might've changed..) This feels like the "wrong" way to do it, and I guarantee most users will go for the other approach where they will eventually shoot themselves in the foot.

    On a side note, could you please put some time aside every week to go through and answer some questions here? You were very active last year and prior, but lately you are rarely around to answer any questions and we need to kick up a big stink to get you to reply and help us out. You seem like the brains behind it all. We are all trying to adopt the Addressables system you worked so hard on, but we are doing so blind. We are having to spend hours testing things to figure out how it works.

    It is a big black box that none of us truly understand, made worse by the fact that every new release steers the ship in a completely different direction. We never truly know what is going to happen next and it does not give us much confidence in the product.
     
    Last edited: Oct 6, 2020
  42. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,311
    Looks like I got some refactoring to do :(
     
  43. DrunkenMastah

    DrunkenMastah

    Joined:
    Sep 26, 2017
    Posts:
    51
    @unity_bill Can you please provide the example project like `Unity Tanks` or any working project that has the addressables system implemented?

    My project is way too large for such a change to be made. I need to figure out what and how to make this work without breaking my game.
    I could certainly create my own test project but I would be doing it with "MY" understanding of how "addressables" are supposed to work.
    I would rather use the official test project you are using to test this out and compare the differences as the subtle differences in the implementation are what are causing the problems in my project.

    Also, if we can use your test project, it would help in reproducing the errors and report them properly to the Unity Support team.

    Please let us know if this is doable / feasible?
     
    Prodigga likes this.
  44. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,311
    This should be pinned to top of the Addressable forums in all caps and bold!
     
    andreiagmu, Vedran_M and Weiky like this.
  45. magmagma

    magmagma

    Joined:
    Oct 27, 2017
    Posts:
    41
    Wow that does explain a lot of things... Mind = blown...
    I wish I'd understood this earlier, but I think refactoring all the code up to know is at least doable in a reasonable amount of time.
    Thanks for the explanation.
     
    Wilhelm_LAS likes this.
  46. SurprisedPikachu

    SurprisedPikachu

    Joined:
    Mar 12, 2020
    Posts:
    84
    But why AssetReference holds an instance to the load operation? Why not making those helper methods into direct calls to Addressables?
    So instead of
    Code (CSharp):
    1. public virtual AsyncOperationHandle<TObject> LoadAssetAsync<TObject>()
    2.         {
    3.             AsyncOperationHandle<TObject> result = default(AsyncOperationHandle<TObject>);
    4.             if (m_Operation.IsValid())
    5.             {
    6.                 Debug.LogError("Attempting to load AssetReference that has already been loaded. Handle is exposed through getter OperationHandle");
    7.                 return m_Operation.Convert<TObject>();
    8.             }
    9.      
    10.             result = Addressables.LoadAssetAsync<TObject>(RuntimeKey);
    11.             m_Operation = result;
    12.             return result;
    13.         }
    we have:
    Code (CSharp):
    1. public virtual AsyncOperationHandle<TObject> LoadAssetAsync<TObject>()
    2.         {
    3.             return Addressables.LoadAssetAsync<TObject>(RuntimeKey);
    4.         }
    The truly become what they are supposed to be. Some helpers. Nothing else.


    Another question is that why AssetReference doesn't return the valid operation if it already has one instead of creating a default operation handle and returning it?
     
  47. Ferazel

    Ferazel

    Joined:
    Apr 18, 2010
    Posts:
    517
    I appreciate the clarification from Unity_Bill, but I agree this should be the fix. Either make the helper object manage all of its references or none of them. Don't make an API that only works in one particular use case which isn't explained in the API docs or the error. To me, an AssetReference is an inspector friendly built-in way to point to an addressable asset. It is not meant to represent a single load proxy of that asset.
     
    halagame, Vedran_M, dogboydog and 8 others like this.
  48. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
  49. magmagma

    magmagma

    Joined:
    Oct 27, 2017
    Posts:
    41
    Well I managed to rewrite all of our loading and unloading sections. It was a bit of a pain to have to manually store references to all the handles, which honestly felt a bit like defeating the point... but now it works at least.
     
    Prodigga and CDF like this.
  50. Arthur-LVGameDev

    Arthur-LVGameDev

    Joined:
    Mar 14, 2016
    Posts:
    228
    This is utterly absurd. I can live with the change. I cannot live with the lack of documentation & communication, and the continued lack of communication, not to mention the complete disregard for timeliness.

    This is such CORE stuff that Unity just flat out FLUNKS the smell test on, and it's not a new thing, users/devs have been telling you this (myself included!) for over a year now WRT Addressables. As if we needed to add any further insult to injury, the silence amounts to what feels like a sharply deafening acknowledgement of the continued failures here. Bleh, it's disturbing, frustrating, and truly this package alone has & continues to have a tangible negative impact on my team.

    Please get on the ball; at the minimum you must COMMUNICATE with your paying users. If the underlying issue here is resources, or management/leadership, or whatever it may be -- hell, make an anon account and start speaking up. The longer this S*** goes on, the worse off we all are, big/small alike, Unity's stock price eventually included. =|