Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using DCL.WebRequests;
using Global.Dynamic;
using SceneRunner.Scene;
using UnityEngine;
using System.Threading;

namespace ECS.SceneLifeCycle.Systems
{
Expand Down Expand Up @@ -43,7 +43,7 @@ public LoadHybridSceneSystemLogic(IWebRequestController webRequestController, UR
protected override string GetAssetBundleSceneId(string _) =>
hybridSceneHashedContent!.remoteSceneID;

protected override async UniTask<ISceneContent> GetSceneHashedContentAsync(SceneEntityDefinition definition, URLDomain contentBaseUrl, ReportData reportCategory)
protected override async UniTask<ISceneContent> GetSceneHashedContentAsync(SceneEntityDefinition definition, URLDomain contentBaseUrl, ReportData reportCategory, CancellationToken ct)
{
hybridSceneHashedContent = new HybridSceneHashedContent(webRequestController, definition, contentBaseUrl, assetBundleURL);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,49 @@
using Cysharp.Threading.Tasks;
using DCL.Diagnostics;
using DCL.Ipfs;
using DCL.Utilities.Extensions;
using DCL.WebRequests;
using SceneRunner.Scene;
using System.Threading;

namespace ECS.SceneLifeCycle.Systems
{
public class LoadSceneSystemLogic : LoadSceneSystemLogicBase
{
private static readonly string[] CDN_FILE_NAMES = { "index.js", "scene.json", "main.crdt" };

public LoadSceneSystemLogic(IWebRequestController webRequestController, URLDomain assetBundleURL)
: base(webRequestController, assetBundleURL) { }

protected override string GetAssetBundleSceneId(string ipfsPathEntityId) =>
ipfsPathEntityId;

protected override async UniTask<ISceneContent> GetSceneHashedContentAsync(SceneEntityDefinition definition, URLDomain contentBaseUrl, ReportData reportCategory) =>
new SceneHashedContent(definition.content!, contentBaseUrl);
protected override async UniTask<ISceneContent> GetSceneHashedContentAsync(SceneEntityDefinition definition, URLDomain contentBaseUrl, ReportData reportCategory, CancellationToken ct)
{
var hashedContent = new SceneHashedContent(definition.content!, contentBaseUrl);

string? abVersion = definition.assetBundleManifestVersion?.GetAssetBundleManifestVersion();

if (string.IsNullOrEmpty(abVersion) || string.IsNullOrEmpty(definition.metadata?.main))
return hashedContent;

var cdnBasePath = $"{abVersion}/{definition.id}/";

// Check all three CDN files in parallel with HEAD requests
var headTasks = new UniTask<bool>[CDN_FILE_NAMES.Length];

for (var i = 0; i < CDN_FILE_NAMES.Length; i++)
{
URLAddress cdnUrl = assetBundleURL.Append(URLPath.FromString($"{cdnBasePath}{CDN_FILE_NAMES[i]}"));
headTasks[i] = webRequestController.IsHeadReachableAsync(reportCategory, cdnUrl, ct).SuppressAnyExceptionWithFallback(false);
}

bool[] results = await UniTask.WhenAll(headTasks);

if (results[0] && results[1] && results[2])
return new SceneHashedContentWithCDN(hashedContent, definition.metadata.main, assetBundleURL, cdnBasePath);

return hashedContent;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ public async UniTask<ISceneFacade> FlowAsync(World world, ISceneFactory sceneFac

ReportHub.LogProductionInfo( $"Loading scene '{definition?.GetLogSceneName()}' began");

var hashedContent = await GetSceneHashedContentAsync(definition, ipfsPath.BaseUrl, reportCategory);
ISceneContent? hashedContent = await GetSceneHashedContentAsync(definition, ipfsPath.BaseUrl, reportCategory, ct);
UniTask<UniTaskVoid> loadSceneMetadata = OverrideSceneMetadataAsync(hashedContent, intention, reportCategory, ipfsPath.EntityId, ct);
var loadMainCrdt = LoadMainCrdtAsync(hashedContent, reportCategory, ct);
UniTask<ReadOnlyMemory<byte>> loadMainCrdt = LoadMainCrdtAsync(hashedContent, reportCategory, ct);
var ISSContainedAssetsPromise = LoadISSAsync(world, definition, ct);

(_, var mainCrdt, var ISSAssets) = await UniTask.WhenAll(loadSceneMetadata, loadMainCrdt, ISSContainedAssetsPromise);
Expand Down Expand Up @@ -94,14 +94,15 @@ private async UniTask<IInitialSceneState> LoadISSAsync(World world, SceneEntityD

protected abstract string GetAssetBundleSceneId(string ipfsPathEntityId);

protected abstract UniTask<ISceneContent> GetSceneHashedContentAsync(SceneEntityDefinition definition, URLDomain contentBaseUrl, ReportData reportCategory);
protected abstract UniTask<ISceneContent> GetSceneHashedContentAsync(SceneEntityDefinition definition, URLDomain contentBaseUrl, ReportData reportCategory, CancellationToken ct);

protected async UniTask<ReadOnlyMemory<byte>> LoadMainCrdtAsync(ISceneContent sceneContent, ReportData reportCategory, CancellationToken ct)
{
const string NAME = "main.crdt";

// if scene does not contain main.crdt, do nothing
if (!sceneContent.TryGetContentUrl(NAME, out var url))
// CDN-first resolution is handled by SceneHashedContentWithCDN when available.
// TryGetContentUrl will return the CDN URL if HEAD-validated, otherwise the catalyst URL.
if (!sceneContent.TryGetContentUrl(NAME, out URLAddress url))
return ReadOnlyMemory<byte>.Empty;

return await webRequestController.GetAsync(new CommonArguments(url), ct, reportCategory).GetDataCopyAsync();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using CommunicationData.URLHelpers;
using System;

namespace SceneRunner.Scene
{
/// <summary>
/// Wraps <see cref="SceneHashedContent" /> and redirects <c>index.js</c>, <c>scene.json</c>,
/// and <c>main.crdt</c> to the asset bundle CDN instead of the catalyst.
/// Only used when all three files have been validated via HEAD requests.
/// </summary>
public class SceneHashedContentWithCDN : ISceneContent
{
private const string SCENE_JSON = "scene.json";
private const string MAIN_CRDT = "main.crdt";

private readonly SceneHashedContent innerContent;
private readonly string mainScriptFileName;
private readonly URLDomain cdnBaseUrl;
private readonly string cdnBasePath;

public URLDomain ContentBaseUrl => innerContent.ContentBaseUrl;

public SceneHashedContentWithCDN(
SceneHashedContent innerContent,
string mainScriptFileName,
URLDomain cdnBaseUrl,
string cdnBasePath)
{
this.innerContent = innerContent;
this.mainScriptFileName = mainScriptFileName;
this.cdnBaseUrl = cdnBaseUrl;
this.cdnBasePath = cdnBasePath;
}

public bool TryGetContentUrl(string contentPath, out URLAddress result)
{
if (string.Equals(contentPath, mainScriptFileName, StringComparison.OrdinalIgnoreCase))
{
result = cdnBaseUrl.Append(URLPath.FromString($"{cdnBasePath}index.js"));
return true;
}

if (string.Equals(contentPath, SCENE_JSON, StringComparison.OrdinalIgnoreCase))
{
result = cdnBaseUrl.Append(URLPath.FromString($"{cdnBasePath}{SCENE_JSON}"));
return true;
}

if (string.Equals(contentPath, MAIN_CRDT, StringComparison.OrdinalIgnoreCase))
{
result = cdnBaseUrl.Append(URLPath.FromString($"{cdnBasePath}{MAIN_CRDT}"));
return true;
}

return innerContent.TryGetContentUrl(contentPath, out result);
}

public bool TryGetHash(string name, out string hash) =>
innerContent.TryGetHash(name, out hash);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading