public void CleanupAvatar() { StopLoadingCoroutines(); eyebrowsController?.CleanUp(); eyebrowsController = null; eyesController?.CleanUp(); eyesController = null; mouthController?.CleanUp(); mouthController = null; bodyShapeController?.CleanUp(); bodyShapeController = null; using (var iterator = wearableControllers.GetEnumerator()) { while (iterator.MoveNext()) { iterator.Current.Value.CleanUp(); } } wearableControllers.Clear(); model = null; isLoading = false; OnFailEvent = null; OnSuccessEvent = null; if (lodController != null) { Environment.i.platform.avatarsLODController.RemoveAvatar(lodController); } if (bodySnapshotTexturePromise != null) { AssetPromiseKeeper_Texture.i.Forget(bodySnapshotTexturePromise); } CatalogController.RemoveWearablesInUse(wearablesInUse); wearablesInUse.Clear(); OnVisualCue?.Invoke(VisualCue.CleanedUp); }
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(true); 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); } } if (resolvedBody == null) { isLoading = false; OnFailEvent?.Invoke(true); yield break; } List <Helpers.Promise <WearableItem> > replacementPromises = new List <Helpers.Promise <WearableItem> >(); foreach (var avatarWearablePromise in avatarWearablePromises) { yield return(avatarWearablePromise); if (!string.IsNullOrEmpty(avatarWearablePromise.error)) { Debug.LogError(avatarWearablePromise.error); loadSoftFailed = true; } else { WearableItem wearableItem = avatarWearablePromise.value; wearablesInUse.Add(wearableItem.id); if (wearableItem.GetRepresentation(model.bodyShape) != null) { resolvedWearables.Add(wearableItem); } else { model.wearables.Remove(wearableItem.id); string defaultReplacement = DefaultWearables.GetDefaultWearable(model.bodyShape, wearableItem.data.category); if (!string.IsNullOrEmpty(defaultReplacement)) { model.wearables.Add(defaultReplacement); replacementPromises.Add(CatalogController.RequestWearable(defaultReplacement)); } } } } foreach (var wearablePromise in replacementPromises) { yield return(wearablePromise); if (!string.IsNullOrEmpty(wearablePromise.error)) { Debug.LogError(wearablePromise.error); loadSoftFailed = true; } else { WearableItem wearableItem = wearablePromise.value; wearablesInUse.Add(wearableItem.id); resolvedWearables.Add(wearableItem); } } 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.data.category); if (wearableControllers.ContainsKey(wearable)) { if (wearableControllers[wearable].IsLoadedForBodyShape(bodyShapeController.bodyShapeId)) { UpdateWearableController(wearable); } else { wearableControllers[wearable].CleanUp(); } } else { AddWearableController(wearable); if (wearable.data.category != Categories.EYES && wearable.data.category != Categories.MOUTH && wearable.data.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; } } 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 == null || (eyebrowsController != null && eyebrowsController.isReady)) && (eyesController == null || (eyesController != null && eyesController.isReady)) && (mouthController == null || (mouthController != null && mouthController.isReady)))); if (bodyIsDirty || wearablesIsDirty) { OnVisualCue?.Invoke(VisualCue.Loaded); } bodyShapeController.SetActiveParts(unusedCategories.Contains(Categories.LOWER_BODY), unusedCategories.Contains(Categories.UPPER_BODY), unusedCategories.Contains(Categories.FEET)); bodyShapeController.SetFacialFeaturesVisible(facialFeaturesVisible); bodyShapeController.UpdateVisibility(hiddenList); foreach (WearableController wearableController in wearableControllers.Values) { wearableController.UpdateVisibility(hiddenList); } CleanUpUnusedItems(); isLoading = false; SetWearableBones(); UpdateExpressions(model.expressionTriggerId, model.expressionTriggerTimestamp); if (lastStickerTimestamp != model.stickerTriggerTimestamp && model.stickerTriggerId != null) { lastStickerTimestamp = model.stickerTriggerTimestamp; stickersController?.PlayEmote(model.stickerTriggerId); } if (loadSoftFailed) { OnFailEvent?.Invoke(false); } else { OnSuccessEvent?.Invoke(); } }