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. Dismiss Notice

Question How to actually use ENABLE_CONTENT_DELIVERY in build ?

Discussion in 'Entity Component System' started by Sylafrs, Sep 25, 2023.

  1. Sylafrs

    Sylafrs

    Joined:
    Jun 25, 2013
    Posts:
    53
    Hello,

    With Unity 2022.3.6f1, I'm trying to load a scene and its subscenes using ENABLE_CONTENT_DELIVERY.
    I used ContentDeliveryGlobalState.Initialize on the first scene, which returns that it's loading the assets from StreamingAssets but then: no subscene can load, remaining in an infinite Loading status.

    I tried using the sample "EntitySamples/Streaming/RuntimeContentManagement".
    - Without the define symbol, in build, everything works fine
    - With the define symbol, the issue happens. Even we add the first scene that's supposed to load everything.

    I tried loading the first scene by many means :
    - Using the SceneManagement API
    - Using a WeakObjectSceneReference, a SystemBase and static data from the loader
    - Using EntitySceneReference

    it just doesn't work; at all.
    except the SceneManagement API that does load the scene but without its subscene; subscene I don't manage to load with any API.

    Have you managed to load an entity-baked scene (subscene) with ENABLE_CONTENT_DELIVERY ?

    Thanks :)


    The code to load with a SystemBase, and static data
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using Unity.Entities.Content;
    4. using UnityEngine;
    5. using UnityEngine.SceneManagement;
    6.  
    7. public class InitializeEntitiesContent : MonoBehaviour
    8. {
    9.     public static bool CanLoadFirstScene;
    10.     public static FirstSceneRefComponent FirstSceneData;
    11.  
    12.     //public string remoteUrlRoot;
    13.     public string initialContentSet;
    14.     public FirstSceneRefComponent compData;
    15.  
    16.     void Start()
    17.     {
    18.         FirstSceneData = compData;
    19.  
    20.         string remoteUrlRoot = System.IO.Path.Combine(Application.streamingAssetsPath, "ContentBuild-RemoteContent");
    21.         Debug.Log("Loading " + remoteUrlRoot.Replace('\\', '/'));
    22.      
    23.  
    24. #if ENABLE_CONTENT_DELIVERY && !UNITY_EDITOR
    25.         ContentDeliveryGlobalState.Initialize(remoteUrlRoot.Replace('\\', '/'), Application.persistentDataPath + "/content-cache", initialContentSet, s =>
    26.         {
    27.             Debug.Log("STATE => " + s);
    28.             if (s >= ContentDeliveryGlobalState.ContentUpdateState.ContentReady)
    29.                 LoadMainScene();
    30.         });
    31. #else
    32.         LoadMainScene();
    33. #endif
    34.     }
    35.  
    36.     void LoadMainScene()
    37.     {
    38.         //content is ready here...
    39.         Debug.Log("Loading main scene");
    40.  
    41. #if ENABLE_CONTENT_DELIVERY && !UNITY_EDITOR
    42.         CanLoadFirstScene = true;
    43. #else
    44.         SceneManager.LoadScene(1);
    45. #endif
    46.     }
    47. }
    48.  
    49. public struct FirstSceneRefComponent: IComponentData
    50. {
    51.     public WeakObjectSceneReference sceneRef;
    52.     public bool startedLoad;
    53. }
    54.  
    55. [WorldSystemFilter(WorldSystemFilterFlags.Default | WorldSystemFilterFlags.Editor)]
    56. [UpdateInGroup(typeof(PresentationSystemGroup))]
    57. public partial class LoadFirstSceneSystem : SystemBase
    58. {
    59.     protected override void OnUpdate()
    60.     {
    61.         if (InitializeEntitiesContent.CanLoadFirstScene)
    62.         {
    63.             var sceneData = InitializeEntitiesContent.FirstSceneData;
    64.             //SystemAPI.GetSingleton<FirstSceneRefComponent>();
    65.  
    66.             if (!sceneData.startedLoad)
    67.             {
    68.                 sceneData.sceneRef.LoadAsync(new Unity.Loading.ContentSceneParameters()
    69.                 {
    70.                      loadSceneMode = UnityEngine.SceneManagement.LoadSceneMode.Single,
    71.                      autoIntegrate = true
    72.                 });
    73.                 sceneData.startedLoad = true;
    74.             }
    75.             else
    76.             {
    77.  
    78.             }
    79.  
    80.         }
    81.     }
    82. }
    83.  
     
    Last edited: Sep 25, 2023
    koonm and yokobe0012 like this.
  2. Sylafrs

    Sylafrs

    Joined:
    Jun 25, 2013
    Posts:
    53
    Note: I fixed their Publish method (removing the '/' before Library).
    I place the "RemoteContent" directly inside StreamingAssets

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using Unity.Entities.Build;
    5. using Unity.Entities.Content;
    6. using Unity.Scenes.Editor;
    7. using UnityEditor;
    8. using UnityEngine;
    9.  
    10. public static class ContentUpdateMenuItem
    11. {
    12.  
    13. #if !USING_PLATFORMS_PACKAGE
    14.     [MenuItem("Assets/Publish/Content Update (fixed)")]
    15.     static void Execute()
    16.     {
    17.         {
    18.             //var buildFolder = EditorUtility.OpenFolderPanel("Select Build To Publish", Path.GetDirectoryName(Application.dataPath), "Builds");
    19.             string buildFolder = Path.Combine(Application.streamingAssetsPath, "ContentBuild");
    20.             if (!string.IsNullOrEmpty(buildFolder))
    21.             {
    22.                 var buildTarget = EditorUserBuildSettings.activeBuildTarget;
    23.  
    24.                 if (!Directory.Exists(Path.Combine(Path.GetDirectoryName(Application.dataPath), $"Library/ContentUpdateBuildDir")))
    25.                     Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(Application.dataPath), $"Library/ContentUpdateBuildDir"));
    26.                 if (!Directory.Exists(Path.Combine(Path.GetDirectoryName(Application.dataPath), $"Library/ContentUpdateBuildDir/{PlayerSettings.productName}")))
    27.                     Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(Application.dataPath), $"Library/ContentUpdateBuildDir/{PlayerSettings.productName}"));
    28.  
    29.                 var tmpBuildFolder = Path.Combine(Path.GetDirectoryName(Application.dataPath), $"Library/ContentUpdateBuildDir/{PlayerSettings.productName}");
    30.  
    31.                 var instance = DotsGlobalSettings.Instance;
    32.                 var playerGuid = instance.GetPlayerType() == DotsGlobalSettings.PlayerType.Client ? instance.GetClientGUID() : instance.GetServerGUID();
    33.                 if (!playerGuid.IsValid)
    34.                     throw new Exception("Invalid Player GUID");
    35.  
    36.                 var subSceneGuids = new HashSet<Unity.Entities.Hash128>();
    37.                 for (int i = 0; i < EditorBuildSettings.scenes.Length; i++)
    38.                 {
    39.                     var ssGuids = EditorEntityScenes.GetSubScenes(EditorBuildSettings.scenes[i].guid);
    40.                     foreach (var ss in ssGuids)
    41.                     {
    42.                         if (!subSceneGuids.Contains(ss))
    43.                         {
    44.                             Debug.Log("GUID -> " + ss);
    45.                             subSceneGuids.Add(ss);
    46.                         }
    47.                     }
    48.  
    49.                     // if(EditorBuildSettings.scenes[i].path.Contains("SubScenes"))
    50.                     // {
    51.                     //     if (!subSceneGuids.Contains(EditorBuildSettings.scenes[i].guid))
    52.                     //     {
    53.                     //         Debug.Log("GUID -> " + EditorBuildSettings.scenes[i].guid);
    54.                     //         subSceneGuids.Add(EditorBuildSettings.scenes[i].guid);
    55.                     //     }
    56.                     // }
    57.                 }
    58.  
    59.                 RemoteContentCatalogBuildUtility.BuildContent(subSceneGuids, playerGuid, buildTarget, tmpBuildFolder);
    60.  
    61.                 var publishFolder = Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds", $"{buildFolder}-RemoteContent");
    62.                 RemoteContentCatalogBuildUtility.PublishContent(tmpBuildFolder, publishFolder, f => new string[] { "all" });
    63.  
    64.  
    65.                 //RemoteContentCatalogBuildUtility.BuildContent
    66.                 //ContentArchivesBuildUtility.BuildContentArchives
    67.             }
    68.         }
    69.     }
    70. #endif
    71. }
     
    yokobe0012 likes this.
  3. wang88yan

    wang88yan

    Joined:
    Mar 10, 2021
    Posts:
    4
    I had the same problem
     
    yokobe0012 likes this.
  4. DukeLabs

    DukeLabs

    Joined:
    Aug 7, 2017
    Posts:
    3
    I had the same problem x2)
     
    yokobe0012 likes this.
  5. DukeLabs

    DukeLabs

    Joined:
    Aug 7, 2017
    Posts:
    3
    Finally, I was able to get this to work
    You need add this line of code before you call ContentDeliveryGlobalState.Initialize

    Code (CSharp):
    1. RuntimeContentSystem.LoadContentCatalog(remoteUrlRoot, Application.persistentDataPath + "/content-cache",
    2.                 initialContentSet);

    Because, they add line to changelog https://docs.unity3d.com/Packages/c...angelog/CHANGELOG.html#100-pre44---2023-02-13, but forgot to update documentation
    • RuntimeContentSystem.LoadContentCatalog allows for starting the content delivery and update process when ENABLE_CONTENT_DELIVERY is defined. The automatic update is no longer triggered when the applications starts.
    Don't know if it's the best/correct solution, but it works fine for Mac build
     
  6. yokobe0012

    yokobe0012

    Joined:
    Nov 2, 2021
    Posts:
    9
    I had the same problem x3)
     
  7. wang88yan

    wang88yan

    Joined:
    Mar 10, 2021
    Posts:
    4
    I use ContentDeliveryGlobalState loading the subscene success.
    Thanks to DukeLabs and Sylafrs for some help.
    This code works fine on a PC:
    Code (CSharp):
    1.              RuntimeContentSystem.LoadContentCatalog(remoteUrlRoot, Application.persistentDataPath + "/content-cache", initialContentSet);
    2.  
    3.              ContentDeliveryGlobalState.Initialize(remoteUrlRoot, Application.persistentDataPath + "/content-cache", initialContentSet, s =>
    4.              {
    5.                  if (s >= ContentDeliveryGlobalState.ContentUpdateState.ContentReady)
    6.                  {
    7.                      loaded_content = true;
    8.                  }
    9.              });
    By the way, if the loading message is "NoContentAvailable" you need to check for inappropriate names on your path.
    My previous load path had a section "1.0" in "TestECS1.0-RemoteContent" that failed to load data from disk.

    I hope my return will help everyone!
     
    yokobe0012 likes this.
  8. yokobe0012

    yokobe0012

    Joined:
    Nov 2, 2021
    Posts:
    9
    How did you use content management to load the sub-scene after building? I used the same method as you, but after running, no elements in the sub-scene were loaded.
    Code (CSharp):
    1.  public string remoteUrlRoot;
    2.     public string initialContentSet;
    3.     private EntityManager _entityManager;
    4.     private EntityQuery _query;
    5.     private bool isInit;
    6.  
    7.     private void Start()
    8.     {
    9.         _entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
    10.  
    11.         _query = _entityManager.CreateEntityQuery(typeof(InitSceneData));
    12.  
    13. #if ENABLE_CONTENT_DELIVERY
    14.         RuntimeContentSystem.LoadContentCatalog(remoteUrlRoot, Application.persistentDataPath + "/content-cache",
    15.             initialContentSet);
    16.  
    17.         ContentDeliveryGlobalState.Initialize(remoteUrlRoot, Application.persistentDataPath + "/content-cache",
    18.             initialContentSet, s =>
    19.             {
    20.                 Debug.Log($"{s}");
    21.                 if (s >= ContentDeliveryGlobalState.ContentUpdateState.ContentReady)
    22.                 {
    23.                     Debug.Log($"ContentReady");
    24.                     isInit = true;
    25.                 }
    26.             });
    27. #endif
    28.     }
    29.  
    30.     private void LoadMainScene()
    31.     {
    32.         var sceneData = _query.ToComponentDataArray<InitSceneData>(Allocator.Temp)[0];
    33.  
    34.         sceneData.scene.LoadAsync(new Unity.Loading.ContentSceneParameters()
    35.         {
    36.             loadSceneMode = UnityEngine.SceneManagement.LoadSceneMode.Additive
    37.         });
    38.  
    39.         isInit = false;
    40.     }
    41.  
    42.     private void Update()
    43.     {
    44.         if (!isInit) return;
    45.         if (_query.IsEmpty) return;
    46.  
    47.         LoadMainScene();
    48.     }
     
  9. DukeLabs

    DukeLabs

    Joined:
    Aug 7, 2017
    Posts:
    3
    Maybe your _query isEmpty and it returns in Update, so Scene will never be loaded, because I don't see where you put something into it
     
  10. yokobe0012

    yokobe0012

    Joined:
    Nov 2, 2021
    Posts:
    9
    Actually,I bake the entity that referenced the scene as follows:
    Code (CSharp):
    1. public class WeakRefSceneAuthoring : MonoBehaviour
    2. {
    3.     public WeakObjectSceneReference scene;
    4.  
    5.     public WeakObjectReference<GameObject> go;
    6.  
    7.     class BulletDataBaker : Baker<WeakRefSceneAuthoring>
    8.     {
    9.         public override void Bake(WeakRefSceneAuthoring authoring)
    10.         {
    11.             var entity = GetEntity(TransformUsageFlags.Dynamic);
    12.             AddComponent(entity, new InitSceneData
    13.             {
    14.                 scene = authoring.scene,
    15.                 go = authoring.go,
    16.                 startedLoad = false
    17.             });
    18.         }
    19.     }
    20. }
    21.  
    22. public struct InitSceneData : IComponentData
    23. {
    24.     public WeakObjectSceneReference scene;
    25.     public WeakObjectReference<GameObject> go;
    26.  
    27.     public bool startedLoad;
    28. }
    I can use WeakObjectReference<GameObject> normally, but I cannot load the scene or sub-scene properly using WeakObjectSceneReference.
    upload_2023-10-6_22-42-43.png
     
  11. wang88yan

    wang88yan

    Joined:
    Mar 10, 2021
    Posts:
    4
    I tested was the loading of the sub-scene after packing the content.
    This is my project source code, I hope to help you.
     

    Attached Files:

    koonm and yokobe0012 like this.
  12. koonm

    koonm

    Joined:
    Jan 5, 2016
    Posts:
    12
    when i upgrade my Unity to 2022.3.8, it't work well!
    not in editor, but work in pc.
     
    yokobe0012 likes this.
  13. wang88yan

    wang88yan

    Joined:
    Mar 10, 2021
    Posts:
    4
    “Load Content” takes effect only after it is packaged and will not work under editor