private IEnumerator LoadAvatar() { yield return(new WaitUntil(() => gameObject.activeSelf)); WearableItem resolvedBody = null; if (!string.IsNullOrEmpty(model.bodyShape) && !CatalogController.wearableCatalog.TryGetValue(model.bodyShape, out resolvedBody)) { Debug.LogError($"Bodyshape {model.bodyShape} not found in catalog"); } List <WearableItem> resolvedWearables = new List <WearableItem>(); if (model.wearables != null) { for (int i = 0; i < model.wearables.Count; i++) { if (!CatalogController.wearableCatalog.TryGetValue(model.wearables[i], out WearableItem item)) { Debug.LogError($"Wearable {model.wearables[i]} not found in catalog"); continue; } resolvedWearables.Add(item); } } if (resolvedBody == null) { isLoading = false; this.OnSuccessEvent?.Invoke(); yield break; } bool bodyIsDirty = false; if (bodyShapeController != null && bodyShapeController.id != model?.bodyShape) { bodyShapeController.CleanUp(); bodyShapeController = null; bodyIsDirty = true; } if (bodyShapeController == null) { HideAll(); bodyShapeController = new BodyShapeController(resolvedBody); eyesController = FacialFeatureController.CreateDefaultFacialFeature(bodyShapeController.bodyShapeId, Categories.EYES, eyeMaterial); eyebrowsController = FacialFeatureController.CreateDefaultFacialFeature(bodyShapeController.bodyShapeId, Categories.EYEBROWS, eyebrowMaterial); mouthController = FacialFeatureController.CreateDefaultFacialFeature(bodyShapeController.bodyShapeId, Categories.MOUTH, mouthMaterial); } else { //If bodyShape is downloading will call OnWearableLoadingSuccess (and therefore SetupDefaultMaterial) once ready if (bodyShapeController.isReady) { bodyShapeController.SetupDefaultMaterial(defaultMaterial, model.skinColor, model.hairColor); } } HashSet <string> unusedCategories = new HashSet <string>(Categories.ALL); int wearableCount = resolvedWearables.Count; for (int index = 0; index < wearableCount; index++) { WearableItem wearable = resolvedWearables[index]; if (wearable == null) { continue; } unusedCategories.Remove(wearable.category); if (wearableControllers.ContainsKey(wearable)) { UpdateWearableController(wearable); } else { AddWearableController(wearable); } } foreach (var category in unusedCategories) { switch (category) { case Categories.EYES: eyesController = FacialFeatureController.CreateDefaultFacialFeature(bodyShapeController.bodyShapeId, Categories.EYES, eyeMaterial); break; case Categories.MOUTH: mouthController = FacialFeatureController.CreateDefaultFacialFeature(bodyShapeController.bodyShapeId, Categories.MOUTH, mouthMaterial); break; case Categories.EYEBROWS: eyebrowsController = FacialFeatureController.CreateDefaultFacialFeature(bodyShapeController.bodyShapeId, Categories.EYEBROWS, eyebrowMaterial); break; } } CleanUpUnusedItems(); HashSet <string> hiddenList = WearableItem.CompoundHidesList(bodyShapeController.bodyShapeId, resolvedWearables); if (!bodyShapeController.isReady) { bodyShapeController.Load(transform, OnWearableLoadingSuccess, OnBodyShapeLoadingFail); } foreach (WearableController wearable in wearableControllers.Values) { if (bodyIsDirty) { wearable.boneRetargetingDirty = true; } wearable.Load(transform, OnWearableLoadingSuccess, x => OnWearableLoadingFail(x)); yield return(null); } yield return(new WaitUntil(() => bodyShapeController.isReady && wearableControllers.Values.All(x => x.isReady))); eyesController.Load(bodyShapeController, model.eyeColor); eyebrowsController.Load(bodyShapeController, model.hairColor); mouthController.Load(bodyShapeController, model.skinColor); yield return(new WaitUntil(() => eyebrowsController.isReady && eyesController.isReady && mouthController.isReady)); bodyShapeController.SetActiveParts(unusedCategories.Contains(Categories.LOWER_BODY), unusedCategories.Contains(Categories.UPPER_BODY), unusedCategories.Contains(Categories.FEET)); bodyShapeController.UpdateVisibility(hiddenList); foreach (WearableController wearableController in wearableControllers.Values) { wearableController.UpdateVisibility(hiddenList); } isLoading = false; SetWearableBones(); UpdateExpressions(model.expressionTriggerId, model.expressionTriggerTimestamp); OnSuccessEvent?.Invoke(); }
private IEnumerator LoadAvatar() { yield return(new WaitUntil(() => gameObject.activeSelf)); bool loadSoftFailed = false; WearableItem resolvedBody = null; Helpers.Promise <WearableItem> avatarBodyPromise = null; if (!string.IsNullOrEmpty(model.bodyShape)) { avatarBodyPromise = CatalogController.RequestWearable(model.bodyShape); } else { OnFailEvent?.Invoke(); yield break; } List <WearableItem> resolvedWearables = new List <WearableItem>(); List <Helpers.Promise <WearableItem> > avatarWearablePromises = new List <Helpers.Promise <WearableItem> >(); if (model.wearables != null) { for (int i = 0; i < model.wearables.Count; i++) { avatarWearablePromises.Add(CatalogController.RequestWearable(model.wearables[i])); } } // In this point, all the requests related to the avatar's wearables have been collected and sent to the CatalogController to be sent to kernel as a unique request. // From here we wait for the response of the requested wearables and process them. if (avatarBodyPromise != null) { yield return(avatarBodyPromise); if (!string.IsNullOrEmpty(avatarBodyPromise.error)) { Debug.LogError(avatarBodyPromise.error); loadSoftFailed = true; } else { resolvedBody = avatarBodyPromise.value; wearablesInUse.Add(avatarBodyPromise.value.id); } } foreach (var avatarWearablePromise in avatarWearablePromises) { yield return(avatarWearablePromise); if (!string.IsNullOrEmpty(avatarWearablePromise.error)) { Debug.LogError(avatarWearablePromise.error); loadSoftFailed = true; } else { resolvedWearables.Add(avatarWearablePromise.value); wearablesInUse.Add(avatarWearablePromise.value.id); } } if (resolvedBody == null) { isLoading = false; this.OnSuccessEvent?.Invoke(); yield break; } bool bodyIsDirty = false; if (bodyShapeController != null && bodyShapeController.id != model?.bodyShape) { bodyShapeController.CleanUp(); bodyShapeController = null; bodyIsDirty = true; } if (bodyShapeController == null) { HideAll(); bodyShapeController = new BodyShapeController(resolvedBody); eyesController = FacialFeatureController.CreateDefaultFacialFeature(bodyShapeController.bodyShapeId, Categories.EYES, eyeMaterial); eyebrowsController = FacialFeatureController.CreateDefaultFacialFeature(bodyShapeController.bodyShapeId, Categories.EYEBROWS, eyebrowMaterial); mouthController = FacialFeatureController.CreateDefaultFacialFeature(bodyShapeController.bodyShapeId, Categories.MOUTH, mouthMaterial); } else { //If bodyShape is downloading will call OnWearableLoadingSuccess (and therefore SetupDefaultMaterial) once ready if (bodyShapeController.isReady) { bodyShapeController.SetupDefaultMaterial(defaultMaterial, model.skinColor, model.hairColor); } } bool wearablesIsDirty = false; HashSet <string> unusedCategories = new HashSet <string>(Categories.ALL); int wearableCount = resolvedWearables.Count; for (int index = 0; index < wearableCount; index++) { WearableItem wearable = resolvedWearables[index]; if (wearable == null) { continue; } unusedCategories.Remove(wearable.category); if (wearableControllers.ContainsKey(wearable)) { if (wearableControllers[wearable].IsLoadedForBodyShape(bodyShapeController.bodyShapeId)) { UpdateWearableController(wearable); } else { wearableControllers[wearable].CleanUp(); } } else { AddWearableController(wearable); if (wearable.category != Categories.EYES && wearable.category != Categories.MOUTH && wearable.category != Categories.EYEBROWS) { wearablesIsDirty = true; } } } foreach (var category in unusedCategories) { switch (category) { case Categories.EYES: eyesController = FacialFeatureController.CreateDefaultFacialFeature(bodyShapeController.bodyShapeId, Categories.EYES, eyeMaterial); break; case Categories.MOUTH: mouthController = FacialFeatureController.CreateDefaultFacialFeature(bodyShapeController.bodyShapeId, Categories.MOUTH, mouthMaterial); break; case Categories.EYEBROWS: eyebrowsController = FacialFeatureController.CreateDefaultFacialFeature(bodyShapeController.bodyShapeId, Categories.EYEBROWS, eyebrowMaterial); break; } } CleanUpUnusedItems(); HashSet <string> hiddenList = WearableItem.CompoundHidesList(bodyShapeController.bodyShapeId, resolvedWearables); if (!bodyShapeController.isReady) { bodyShapeController.Load(bodyShapeController.bodyShapeId, transform, OnWearableLoadingSuccess, OnBodyShapeLoadingFail); } foreach (WearableController wearable in wearableControllers.Values) { if (bodyIsDirty) { wearable.boneRetargetingDirty = true; } wearable.Load(bodyShapeController.bodyShapeId, transform, OnWearableLoadingSuccess, x => OnWearableLoadingFail(x)); yield return(null); } yield return(new WaitUntil(() => bodyShapeController.isReady && wearableControllers.Values.All(x => x.isReady))); eyesController.Load(bodyShapeController, model.eyeColor); eyebrowsController.Load(bodyShapeController, model.hairColor); mouthController.Load(bodyShapeController, model.skinColor); yield return(new WaitUntil(() => eyebrowsController.isReady && eyesController.isReady && mouthController.isReady)); if (useFx && (bodyIsDirty || wearablesIsDirty)) { var particles = Instantiate(fxSpawnPrefab); var particlesFollow = particles.AddComponent <FollowObject>(); particles.transform.position += transform.position; particlesFollow.target = transform; particlesFollow.offset = fxSpawnPrefab.transform.position; } bodyShapeController.SetActiveParts(unusedCategories.Contains(Categories.LOWER_BODY), unusedCategories.Contains(Categories.UPPER_BODY), unusedCategories.Contains(Categories.FEET)); bodyShapeController.UpdateVisibility(hiddenList); foreach (WearableController wearableController in wearableControllers.Values) { wearableController.UpdateVisibility(hiddenList); } isLoading = false; SetWearableBones(); UpdateExpressions(model.expressionTriggerId, model.expressionTriggerTimestamp); if (loadSoftFailed) { OnFailEvent?.Invoke(); } else { OnSuccessEvent?.Invoke(); } }