Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Loading assets with the same name from different packages

Discussion in 'Addressables' started by Loden_Heathen, May 13, 2021.

  1. Loden_Heathen

    Loden_Heathen

    Joined:
    Sep 1, 2012
    Posts:
    480
    We have a case we are looking at the Addressable system to solve for.
    In short we want player's to be able to bring in new content they made with the Unity engine.

    I know this sort of use case gets asked a lot but haven't found the answer to this question.

    How do we load an asset from a specific "mod" where we cannot assure the name of the asset is unique but can assue the name of the mod is.

    So here is the use case

    As a modder I need to be able to make new content for the app that can be loaded at run time and not conflict with other assets/mobs

    As a developer I have created the tools to insure that the resulting packages get a unique name based on a GUID system however the indavidual assets could have the same name. One key part is the "package payload" object we have created, this is a common scriptable object that we look for in the package and load up to know what content is in the package and how its meant to be used in the app. We intend to insistt that this object always has the same name e.g. "Package Payload" for example so

    Code (CSharp):
    1. var result = Addressables.LoadAssetAsync<PackagePayloadReference>("Package Payload");
    That would load the object we desire however if the user has loaded multiple mods they all have that same name so I assume the first one loaded is what would get pulled and that is not correct.
    Or is it that the same name would be a conflict and cause issues beyond that.

    More importantly; how do we insure we are loading the desired Package Payload, i.e. the one from the indicated package.

    We thought about apenind the package id to the address

    Code (CSharp):
    1. var result = Addressables.LoadAssetAsync<PackagePayloadReference>("[packageId]/Package Payload");
    or if it was possible in some way load the asset from the resource locator in question

    Code (CSharp):
    1. IResourceLocator modLocator = //load this package;
    2. var result = modLocator.LoadAssetAsync<PackagePayloadReference>("Package Payload");
    TL;DR

    How can I load an asset from a specific addressable package/resource locator where many loaded packages will have an asset by that same name.
     
  2. zhuxianzhi

    zhuxianzhi

    Joined:
    Mar 30, 2015
    Posts:
    122
    You can use Labels.
     
  3. Loden_Heathen

    Loden_Heathen

    Joined:
    Sep 1, 2012
    Posts:
    480
    Thank you for the responce in examples googled I did see examples of people callign LoadAsset passing in a label and an asset ID but I didn't find such in Unity documentation or when exploring the asset in IDE e.g. no such method.

    I did however find a LoadAsset taking the type of the asset to load and the IResourceLocator which might do it but only because in our case there is only 1 of the type we are looking for. This seems like its either a gap in the Addressable system or in its documentaiton it should be trivial to load a specific asset by that assets name from a specific locator.

    Follows is the Load method we have added to our Manifest object ... here is a little background on our system in hopes of some feedback.

    1) We have our content creators author 2 addressable groups
    The first is a "Manifest" it contains meta information if you like about what the other package contains e.g. it has icons, names, etc but not the content its self e.g. not the models, textures, mateirals and so forth. The idea is its a small bit of info you load to explore what is in the package before you comit to loading the main package up.

    The second is a "Payload" it contains the actual content

    2) We house these packages at a given address hence the need for them to have a globally unique name which we satisfy by naming the package via GUID. Our system handles teh meta information for the manigest e.g. its human name and image. The object which loads off the manifest also tracks the status of the Payload e.g. is the payload loaded, loading, etc. and if not it has the means to load it in that it can assume its name and its content.

    Follows is sample code for that loading process and this is the area we are least sure about at the moment ... haven't had a chance to properly test it yet.

    Summarized example of the code to shorten it I am aware this isn't handling errors or calling the callback
    Code (CSharp):
    1. public IEnumerator Load(Action callback = null)
    2.         {
    3.             yield return null;
    4.  
    5.             if (Payload == null)
    6.             {
    7.                 AsyncOperationHandle<IResourceLocator> packageHandle;
    8.                 AsyncOperationHandle<PackagePayloadReference> payloadHandle;
    9.  
    10.                 packageHandle = Addressables.LoadContentCatalogAsync(SystemSettings.AssetServerPath + "/" + id.ToString() + "_package.json", true);
    11.                 yield return packageHandle;
    12.  
    13.                 if (packageHandle.Status == AsyncOperationStatus.Succeeded)
    14.                 {
    15.                     payloadHandle = Addressables.LoadAssetAsync<PackagePayloadReference>(packageHandle.Result);
    16.                     yield return packageHandle;
    17.  
    18.                     if(payloadHandle.Status == AsyncOperationStatus.Succeeded)
    19.                     {
    20.                         Payload = payloadHandle.Result;
    21.                     }
    22.                 }
    23.             }
    24.         }
     
    Last edited: May 20, 2021
  4. Loden_Heathen

    Loden_Heathen

    Joined:
    Sep 1, 2012
    Posts:
    480
    For Unity if you read over this.

    While this project isn't Steam based we usually do work on Steam based games and would expect to use the Addressable system with Valve's Workshop aka UGC.

    The same sort of issue would present its self in that a seemingly logicle thing to do would be to let your gamers use the Untiy engine as a modding tool to author addressable packages.

    You cant assure that your gamers are giving objects within the addressables a unique name you will however not have to deal with metadata info issue as that is what Workshop does that for you in that it gives you an easily browsable way to locate mods and express to the user what the mod contains. So you will end up knowing where a package is located and needing to load some object you can assume is within it and can then read to determin how to handle the rest of the content. To reword that you will have a situation where you know the IResourceLocator and the name and type of 1 asset in that package which you will want to load not as a replacement for existing content but in addition to.
     
  5. zhuxianzhi

    zhuxianzhi

    Joined:
    Mar 30, 2015
    Posts:
    122

    Code (CSharp):
    1.             Addressables.LoadAssetsAsync<GameObject>(new string[2] {"key", "DLC1"},null,Addressables.MergeMode.UseFirst);
    2.          
    3.          
    4.             Addressables.LoadAssetsAsync<GameObject>(new string[2] {"key", "DLC2"},null,Addressables.MergeMode.UseFirst);

    In addition, your Load function is feasible, but you need to ensure the uniqueness of the key, or at least ensure that the same key has different Labels;

    In other words, if the key and Labels are the same, the loading is uncertain.
     
  6. Loden_Heathen

    Loden_Heathen

    Joined:
    Sep 1, 2012
    Posts:
    480
    Thank you for the responce

    Looks like it will work out then ... follows is what we are doing editor side which should insure unique keys and the proper structure for our 2 part packages.

    1) We create editor tools that help insure the proper folder structure such as

    - [Folder named for the package ID]
    -- Manifest (scriptable object)
    -- Payload (scriptable object)
    -- Manifest Content (folder)
    --- all content for the manifest goes here
    -- Payload Content (folder)
    --- all content for the payload goes here

    2) We mark the objects within the folder (named for the package ID) as being addressable

    3) We create 2 groups named for the package e.g. <ID>_Manifest and <ID>_Payload
    All content is added to the appropreate group

    4) We name the key for manifest and payload SOs accordingly
    <ID>/Manifest and <ID>/Payload

    ....

    What we expect this is doing for us

    1) The addressable build should result in 2 asset bundles per platform named as
    [PlatformFolder] / <ID>_Manifest
    [PlatformFolder] / <ID>_Payload

    This means that once its deployed to our content distribution tool that it has a unique name ... all be it a human unfriendly name but we dont care as we have another system that will relate the <ID> to the huaman friendly bit of metadata e.g. name, description, etc. for display

    2) The manifest can assume its Payload's address based on its own address

    3) The system can assume the "key" of the Mainfest and Payload objects respectivly based on the ID whcih we already know as we used that to load the packages in the first place.

    If we get it working I will see if we can do a write up on what we did and why to help others out with it.