| | 1 | | using Cysharp.Threading.Tasks; |
| | 2 | | using DCL; |
| | 3 | | using DCL.Components; |
| | 4 | | using DCL.Helpers; |
| | 5 | | using MainScripts.DCL.Controllers.AssetManager.AssetBundles.SceneAB; |
| | 6 | | using System; |
| | 7 | | using System.Threading; |
| | 8 | | using UnityEngine; |
| | 9 | |
|
| | 10 | | namespace AvatarSystem |
| | 11 | | { |
| | 12 | | public class WearableRetriever : IWearableRetriever |
| | 13 | | { |
| | 14 | | private const string FEATURE_NEW_ASSET_BUNDLES = "ab-new-cdn"; |
| 12 | 15 | | public Rendereable rendereable { get; private set; } |
| | 16 | |
|
| | 17 | | private RendereableAssetLoadHelper loaderAssetHelper; |
| | 18 | |
|
| | 19 | | public async UniTask<Rendereable> Retrieve(GameObject container, WearableItem wearable, string bodyShapeId, Canc |
| | 20 | | { |
| 2 | 21 | | ct.ThrowIfCancellationRequested(); |
| | 22 | |
|
| 2 | 23 | | WearableItem.Representation representation = wearable.GetRepresentation(bodyShapeId); |
| 2 | 24 | | if (representation == null) |
| | 25 | | { |
| 0 | 26 | | Debug.Log($"No representation for body shape {bodyShapeId} of wearable {wearable.id}"); |
| 0 | 27 | | return null; |
| | 28 | | } |
| | 29 | |
|
| 2 | 30 | | var contentProvider = wearable.GetContentProvider(bodyShapeId); |
| 2 | 31 | | string baseUrl = wearable.baseUrlBundles; |
| 2 | 32 | | string mainFile = representation.mainFile; |
| | 33 | |
|
| | 34 | | try |
| | 35 | | { |
| 2 | 36 | | loaderAssetHelper?.Unload(); |
| | 37 | |
|
| | 38 | | // Before loading the asset, we check if asset bundles exist, then we fill the content provider with it |
| 2 | 39 | | if (IsNewAssetBundleFlagEnabled()) |
| | 40 | | { |
| 0 | 41 | | if (string.IsNullOrEmpty(wearable.entityId)) |
| | 42 | | { |
| | 43 | | //Debug.LogWarning(mainFile + " has no entity ID, ignore this message if you are on a testnet"); |
| | 44 | | } |
| | 45 | | else |
| | 46 | | { |
| 0 | 47 | | var sceneAb = await FetchSceneAssetBundles(wearable.entityId, contentProvider.assetBundlesBaseUr |
| | 48 | |
|
| 0 | 49 | | if (sceneAb != null && sceneAb.IsSceneConverted()) |
| | 50 | | { |
| 0 | 51 | | contentProvider.assetBundles = sceneAb.GetConvertedFiles(); |
| 0 | 52 | | contentProvider.assetBundlesBaseUrl = sceneAb.GetBaseUrl(); |
| 0 | 53 | | contentProvider.assetBundlesVersion = sceneAb.GetVersion(); |
| | 54 | | } |
| | 55 | | #if UNITY_EDITOR |
| | 56 | | else |
| | 57 | | { |
| 0 | 58 | | Debug.Log($"<color=red>Wearable AB FAILED -> {mainFile} {wearable.entityId} use this ID to r |
| | 59 | | } |
| | 60 | | #endif |
| | 61 | |
|
| 0 | 62 | | contentProvider.assetBundlesFetched = true; |
| | 63 | | } |
| | 64 | |
|
| | 65 | | // even if it we not fetch the asset bundle because the wearable has no ID, we set this to true to a |
| 0 | 66 | | contentProvider.assetBundlesFetched = true; |
| | 67 | | } |
| | 68 | |
|
| 2 | 69 | | loaderAssetHelper = new RendereableAssetLoadHelper(contentProvider, baseUrl); |
| | 70 | |
|
| 2 | 71 | | loaderAssetHelper.settings.forceNewInstance = false; |
| | 72 | | // TODO Review this hardcoded offset and try to solve it by offseting the Avatar container |
| 2 | 73 | | loaderAssetHelper.settings.initialLocalPosition = Vector3.up * AvatarSystemUtils.AVATAR_Y_OFFSET; |
| 2 | 74 | | loaderAssetHelper.settings.visibleFlags = AssetPromiseSettings_Rendering.VisibleFlags.INVISIBLE; |
| 2 | 75 | | loaderAssetHelper.settings.parent = container.transform; |
| 2 | 76 | | loaderAssetHelper.settings.layer = container.layer; |
| | 77 | |
|
| 2 | 78 | | bool done = false; |
| 2 | 79 | | Exception exception = null; |
| | 80 | |
|
| | 81 | | void OnSuccessWrapper(Rendereable rendereable) |
| | 82 | | { |
| 2 | 83 | | loaderAssetHelper?.ClearEvents(); |
| 2 | 84 | | done = true; |
| 2 | 85 | | this.rendereable = rendereable; |
| 2 | 86 | | } |
| | 87 | |
|
| | 88 | | void OnFailEventWrapper(Exception e) |
| | 89 | | { |
| 0 | 90 | | exception = e; |
| 0 | 91 | | loaderAssetHelper?.ClearEvents(); |
| 0 | 92 | | done = true; |
| 0 | 93 | | rendereable = null; |
| 0 | 94 | | } |
| | 95 | |
|
| 2 | 96 | | loaderAssetHelper.OnSuccessEvent += OnSuccessWrapper; |
| 2 | 97 | | loaderAssetHelper.OnFailEvent += OnFailEventWrapper; |
| 2 | 98 | | loaderAssetHelper.Load(mainFile, AvatarSystemUtils.UseAssetBundles() ? RendereableAssetLoadHelper.Loadin |
| | 99 | |
|
| | 100 | | // AttachExternalCancellation is needed because a cancelled WaitUntil UniTask requires a frame |
| 6 | 101 | | await UniTaskUtils.WaitForBoolean(ref done, cancellationToken: ct).AttachExternalCancellation(ct); |
| | 102 | |
|
| 2 | 103 | | if (exception != null) |
| 0 | 104 | | throw exception; |
| | 105 | |
|
| 2 | 106 | | if (rendereable == null) |
| 0 | 107 | | throw new Exception($"Couldnt retrieve Wearable assets at: {mainFile}"); |
| | 108 | |
|
| 2 | 109 | | return rendereable; |
| | 110 | | } |
| 0 | 111 | | catch (OperationCanceledException e) |
| | 112 | | { |
| 0 | 113 | | Dispose(); |
| 0 | 114 | | throw; |
| | 115 | | } |
| 2 | 116 | | } |
| | 117 | |
|
| | 118 | | private bool IsNewAssetBundleFlagEnabled() => |
| 2 | 119 | | DataStore.i.featureFlags.flags.Get().IsFeatureEnabled(FEATURE_NEW_ASSET_BUNDLES); |
| | 120 | |
|
| | 121 | | private async UniTask<Asset_SceneAB> FetchSceneAssetBundles(string sceneId, string dataBaseUrlBundles) |
| | 122 | | { |
| 0 | 123 | | AssetPromise_SceneAB promiseSceneAb = new AssetPromise_SceneAB(dataBaseUrlBundles, sceneId); |
| 0 | 124 | | AssetPromiseKeeper_SceneAB.i.Keep(promiseSceneAb); |
| 0 | 125 | | await promiseSceneAb.ToUniTask(); |
| 0 | 126 | | return promiseSceneAb.asset; |
| 0 | 127 | | } |
| | 128 | |
|
| 2 | 129 | | public void Dispose() { loaderAssetHelper?.Unload(); } |
| | 130 | | } |
| | 131 | | } |