Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Bug Inconsistent return type between build and editor

Discussion in 'Addressables' started by KronosAmon, Jul 31, 2022.

  1. KronosAmon

    KronosAmon

    Joined:
    Jan 19, 2018
    Posts:
    3
    When using LoadAssetAsync<Object>, the returned object's type is different in Unity and the build.

    Code (CSharp):
    1.        
    2. public Image image;
    3. public AssetReferenceSprite sprite;
    4.  
    5. public void Setup()
    6. {
    7.     var operationHandler = Addressables.LoadAssetAsync<Object>(sprite);
    8.     operationHandler.WaitForCompletion();
    9.  
    10.     object load = operationHandler.Result;
    11.     Debug.LogError(load.GetType());
    12.     image.sprite = (Sprite)load;
    13. }
    14.  
    Editor debug result:
    UnityEngine.Sprite

    Build debug result:
    UnityEngine.Texture2D
    InvalidCastException: Specified cast is not valid.

    I am building a generic system so I have to use the Object as a return type.
    Otherwise, I know that replacing it with Sprite would solve the problem.
    Code (CSharp):
    1. Addressables.LoadAssetAsync<Sprite>(sprite)
    I attached the addressable file I used in this test:
     

    Attached Files:

  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,016
    Kinda amusing considering Sprite doesn't inherit from Texture2D. Though considering sprites are special textures in a way, I can see why this might happen.

    Is this code just a reproduction example or roughly the code you're using? because, bugs aside, Why does it need to be generic? If you're loading an sprite through an AssetReferenceSprite then the return is only ever going to be a sprite.

    If you mean a generic system in the context of your own extension methods, then you should use generics and constraint it to
    where T : UnityEngine.Object
    .
     
  3. KronosAmon

    KronosAmon

    Joined:
    Jan 19, 2018
    Posts:
    3
    As you guessed, It is just a reproduction example.

    I have a generic class that deals with some addressable related stuff for me which looks like this:
    Code (CSharp):
    1. public class AddressablesDatabase <Asset> where Asset : AssetReference
    I use it for any kind of AssetReference including some custom-made ones, so AssetReferenceSprite is just an example.

    I was using it as:
    Code (CSharp):
    1. AssetReferenceSprite sprite;
    2. AddressablesDatabase<AssetReferenceSprite> spriteDatabase = new();
    3. Sprite test = (Sprite)spriteDatabase.LoadObject(sprite); //Returns Object
    Because of the inconsistent return type I mentioned in my initial question, I had to change the return type from (Sprite) to (Texture2D) for it to work.
    But it made me worry that it might not be the only inconsistency between the editor and the build.

    So I added type as a generic variable to the class:
    Code (CSharp):
    1. public class AddressablesDatabase <Asset, Type> where Asset : AssetReference
    And I return to that type instead of returning to an object:
    Code (CSharp):
    1. AssetReferenceSprite sprite;
    2. AddressablesDatabase<AssetReferenceSprite, Sprite> spriteDatabase = new();
    3. Sprite test = spriteDatabase.LoadObject(sprite); //Returns Sprite
    I am not that happy with this solution but at least it ensures that there is no conflict.
     
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,016
    In my use of addressables I've always specified the asset return type and it's always worked perfectly for me. I've not tried to use UnityEngine.Object as a general purpose return type, admittedly.

    For example this is my general purpose addressables loading helper method: https://forum.unity.com/threads/adv...treaming-best-practises.1202158/#post-7694488

    If you are constraining the type of asset in the database, when you'll want to make sure the generic parameter is constrained to UnityEngine.Object as well.

    I assume you want to keep this database 'generic' so it can store multiple types of assets? You can probably still do that, and instead just make your LoadObject method into
    LoadObject<T>(reference) where T : UnityEngine.Object
    and use that type in your addressables loading.