#The simplest possible remote content delivery example?

1 messages · Page 1 of 1 (latest)

cosmic ginkgo
#

I'm at the end of my rope with this after lots of googling. I can't find a single hard example of the following, which I assumed should be a pretty basic feature of the Content Management system:

  • I want to build a single subscene into a content archive.
  • I want to read this content archive from disk at runtime.
  • I want to load the scene that is contained by it.

This is something that would be fairly straightforward in the Addressables workflow. I would sincerely appreciate any help with this. I don't know if I'm just missing something, but I haven't found a single helpful resource online, including Unity's official examples and (pretty subpar) documentation.

livid copper
cosmic ginkgo
# livid copper https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/content-manageme...

Hey Tertle! Much respect for your work and presence in the ECS community.

So here's what I'm using to try and build a single subscene. I have the target subscene as the only scene in my build settings.

[MenuItem("Aminal/Planets/Build Current Planet")]
        private static void Build()
        {
            var buildTarget = EditorUserBuildSettings.activeBuildTarget;
            var instance = DotsGlobalSettings.Instance;
            var dataPath = Path.GetDirectoryName(Application.dataPath);

            if (dataPath == null)
            {
                Debug.LogError("Data path is null");
                return;
            }

            var tmpBuildFolder = Path.Combine(dataPath, $"/Library/content-staging/{buildTarget}/CelestialBodies");
            var playerGuid = instance.GetPlayerType() == DotsGlobalSettings.PlayerType.Client
                ? instance.GetClientGUID()
                : instance.GetServerGUID();

            if (!playerGuid.IsValid)
            {
                Debug.LogError("Player GUID is invalid");
                return;
            }
            
            var subsceneGuids = new HashSet<Hash128>();

            for (int i = 0; i < EditorBuildSettings.scenes.Length; i++)
            {
                var scene = EditorBuildSettings.scenes[i];
                var ssGuids = EditorEntityScenes.GetSubScenes(EditorBuildSettings.scenes[i].guid);
                
                foreach (var ssGuid in ssGuids)
                {
                    subsceneGuids.Add(ssGuid);
                    Debug.Log($"Building planet terrain for subscene {ssGuid}");

                }
            }

            RemoteContentCatalogBuildUtility.BuildContent(subsceneGuids, playerGuid, buildTarget, tmpBuildFolder);

            var publishFolder = Path.Combine(dataPath,
                "content", $"Erba-Content");

            if (!Directory.Exists(publishFolder))
            {
                Directory.CreateDirectory(publishFolder);
            }

            RemoteContentCatalogBuildUtility.PublishContent(tmpBuildFolder, publishFolder,
                f => new string[]
                {
                    "all"
                });
        }```
#

Seems so far, so good?

#

It's loading it at runtime that I'm running into issues with. Here's how I'm trying to do that:

private async void Start()
        {
            var url = $"file://D:/dev/aminal/content/Erba-Content/";
            Debug.Log($"Content URL: {url}");
            var cachePath = Path.Combine(Application.persistentDataPath, "Erba-Content");
            RuntimeContentSystem.LoadContentCatalog(url, cachePath, "all");
            while (ContentDeliveryGlobalState.CurrentContentUpdateState<=ContentDeliveryGlobalState.ContentUpdateState.ContentReady){
                await Task.Yield();
                Debug.Log($"Waiting for content to load {ContentDeliveryGlobalState.CurrentContentUpdateState}");
            }
            
            Debug.Log("Content loaded");

            await Load();
            
            Debug.Log("Scene loaded");
        
            Initialize();
        }
        
        public async Task Load()
        {
            var guid = new Hash128("f781dd42d4028a64ab9ed0cb4cb3cd14");

            var sceneEntity = SceneSystem.LoadSceneAsync(World.DefaultGameObjectInjectionWorld.Unmanaged, guid, new SceneSystem.LoadParameters(){
                AutoLoad = true
            });

            SceneSystem.SceneStreamingState sceneStreamingState = SceneSystem.SceneStreamingState.Unloaded;
            while (sceneStreamingState == SceneSystem.SceneStreamingState.Loading || sceneStreamingState == SceneSystem.SceneStreamingState.Unloaded){
                await Task.Yield();
                sceneStreamingState = SceneSystem.GetSceneStreamingState(World.DefaultGameObjectInjectionWorld.Unmanaged, sceneEntity);
            }
        }```
#

I just pulled the hash directly from the subscene asset. My problem is that the "Content loaded" debug log never gets hit. It loops on "Waiting for content to load" with an update state of "None."

#

Erba-Content is a folder that contains the catalogs.bin file that I produced.

#

I'm not sure if I'm using the wrong URL syntax, wrong location or what. 😭

livid copper
#

what's this state ContentDeliveryGlobalState.CurrentContentUpdateState

cosmic ginkgo
#

It's the state they use to check for completion in the official docs. They're using ContentDeliveryGlobalState.Initialize but RuntimeContentSystem.LoadContentCatalog ultimately calls that method as well. I tried using the method in the docs with the same result.

#

Replacing my code with the same thing:

#

Same result. Never hits content loaded. Never even hits "Content state: {state}".

livid copper
#

i would try just load your data from the streaming assets folder to start with

#

but you probably just need to hook up a debugger and figure out what line is failing

cosmic ginkgo
#

Good idea re: debugger! For the case of StreamingAssets, would that essentially just look like providing a file URL like: var url = $"file://{Application.streamingAssetsPath}/content/Erba-Content"? I feel like I'm failing to understand how to construct the proper URL.

livid copper
#

just to rule out the silly

#

you have defined ENABLE_CONTENT_DELIVERY correct?

livid copper
#

but actually if you're using streaming assets don't do any of this

#

just leave the url null

#

and put it in the root of streaming assets

#
            if (string.IsNullOrEmpty(remoteUrlRoot))
            {
                contentUpdateState = ContentUpdateState.UsingContentFromStreamingAssets;
                PathRemapFunc = p => $"{Application.streamingAssetsPath}/{p}";
            }```
#

just to see if you can get it to work

#

(it defaults to streaming assets)