| | 1 | | using System; |
| | 2 | | using System.Collections.Generic; |
| | 3 | | using DCL.Components; |
| | 4 | | using DCL.Configuration; |
| | 5 | | using DCL.Controllers; |
| | 6 | | using DCL.ECS7.InternalComponents; |
| | 7 | | using DCL.ECSRuntime; |
| | 8 | | using DCL.Helpers; |
| | 9 | | using DCL.Models; |
| | 10 | | using UnityEngine; |
| | 11 | | using Object = UnityEngine.Object; |
| | 12 | |
|
| | 13 | | namespace DCL.ECSComponents |
| | 14 | | { |
| | 15 | | public class GltfContainerHandler : IECSComponentHandler<PBGltfContainer> |
| | 16 | | { |
| | 17 | | const string POINTER_COLLIDER_NAME = "OnPointerEventCollider"; |
| | 18 | |
|
| | 19 | | internal RendereableAssetLoadHelper gltfLoader; |
| | 20 | | internal GameObject gameObject; |
| | 21 | | private IList<Collider> physicColliders; |
| | 22 | | private IList<Collider> pointerColliders; |
| | 23 | | private IList<Renderer> renderers; |
| | 24 | | private string prevLoadedGltf = null; |
| | 25 | |
|
| | 26 | | private readonly IInternalECSComponent<InternalColliders> pointerColliderComponent; |
| | 27 | | private readonly IInternalECSComponent<InternalColliders> physicColliderComponent; |
| | 28 | | private readonly IInternalECSComponent<InternalRenderers> renderersComponent; |
| | 29 | | private readonly DataStore_ECS7 dataStoreEcs7; |
| | 30 | |
|
| 6 | 31 | | public GltfContainerHandler(IInternalECSComponent<InternalColliders> pointerColliderComponent, |
| | 32 | | IInternalECSComponent<InternalColliders> physicColliderComponent, |
| | 33 | | IInternalECSComponent<InternalRenderers> renderersComponent, |
| | 34 | | DataStore_ECS7 dataStoreEcs7) |
| | 35 | | { |
| 6 | 36 | | this.pointerColliderComponent = pointerColliderComponent; |
| 6 | 37 | | this.physicColliderComponent = physicColliderComponent; |
| 6 | 38 | | this.renderersComponent = renderersComponent; |
| 6 | 39 | | this.dataStoreEcs7 = dataStoreEcs7; |
| 6 | 40 | | } |
| | 41 | |
|
| | 42 | | public void OnComponentCreated(IParcelScene scene, IDCLEntity entity) |
| | 43 | | { |
| 6 | 44 | | gameObject = new GameObject("GLTF mesh"); |
| | 45 | |
|
| 6 | 46 | | Transform transform = gameObject.transform; |
| 6 | 47 | | transform.SetParent(entity.gameObject.transform); |
| 6 | 48 | | transform.ResetLocalTRS(); |
| | 49 | |
|
| 6 | 50 | | gltfLoader = new RendereableAssetLoadHelper(scene.contentProvider, scene.sceneData.baseUrlBundles); |
| 6 | 51 | | gltfLoader.settings.forceGPUOnlyMesh = true; |
| 6 | 52 | | gltfLoader.settings.parent = transform; |
| 6 | 53 | | gltfLoader.settings.visibleFlags = AssetPromiseSettings_Rendering.VisibleFlags.VISIBLE_WITH_TRANSITION; |
| 6 | 54 | | } |
| | 55 | |
|
| | 56 | | public void OnComponentRemoved(IParcelScene scene, IDCLEntity entity) |
| | 57 | | { |
| 8 | 58 | | CleanUp(scene, entity); |
| 8 | 59 | | Object.Destroy(gameObject); |
| 8 | 60 | | } |
| | 61 | |
|
| | 62 | | public void OnComponentModelUpdated(IParcelScene scene, IDCLEntity entity, PBGltfContainer model) |
| | 63 | | { |
| 12 | 64 | | if (string.IsNullOrEmpty(model.Src) || prevLoadedGltf == model.Src) |
| 0 | 65 | | return; |
| | 66 | |
|
| 12 | 67 | | prevLoadedGltf = model.Src; |
| | 68 | |
|
| 12 | 69 | | CleanUp(scene, entity); |
| | 70 | |
|
| 23 | 71 | | gltfLoader.OnSuccessEvent += rendereable => OnLoadSuccess(scene, entity, rendereable); |
| 12 | 72 | | gltfLoader.OnFailEvent += exception => OnLoadFail(scene, exception); |
| | 73 | |
|
| 12 | 74 | | dataStoreEcs7.AddPendingResource(scene.sceneData.id, prevLoadedGltf); |
| 12 | 75 | | gltfLoader.Load(model.Src); |
| 12 | 76 | | } |
| | 77 | |
|
| | 78 | | private void OnLoadSuccess(IParcelScene scene, IDCLEntity entity, Rendereable rendereable) |
| | 79 | | { |
| | 80 | | // create physic colliders |
| 11 | 81 | | MeshFilter[] meshFilters = gameObject.GetComponentsInChildren<MeshFilter>(); |
| 11 | 82 | | physicColliders = SetUpPhysicColliders(meshFilters); |
| | 83 | |
|
| | 84 | | // create pointer colliders and renderers |
| 11 | 85 | | (pointerColliders, renderers) = SetUpPointerCollidersAndRenderers(rendereable.renderers); |
| | 86 | |
|
| | 87 | | // set colliders and renderers |
| 74 | 88 | | for (int i = 0; i < pointerColliders.Count; i++) |
| | 89 | | { |
| 26 | 90 | | pointerColliderComponent.AddCollider(scene, entity, pointerColliders[i]); |
| | 91 | | } |
| 34 | 92 | | for (int i = 0; i < physicColliders.Count; i++) |
| | 93 | | { |
| 6 | 94 | | physicColliderComponent.AddCollider(scene, entity, physicColliders[i]); |
| | 95 | | } |
| 74 | 96 | | for (int i = 0; i < renderers.Count; i++) |
| | 97 | | { |
| 26 | 98 | | renderersComponent.AddRenderer(scene, entity, renderers[i]); |
| | 99 | | } |
| | 100 | | // TODO: modify Animator component to remove `AddShapeReady` usage |
| 11 | 101 | | dataStoreEcs7.AddShapeReady(entity.entityId, gameObject); |
| 11 | 102 | | dataStoreEcs7.RemovePendingResource(scene.sceneData.id, prevLoadedGltf); |
| 11 | 103 | | } |
| | 104 | |
|
| | 105 | | private void OnLoadFail(IParcelScene scene, Exception exception) |
| | 106 | | { |
| 0 | 107 | | MaterialTransitionController[] transitionController = |
| | 108 | | gameObject.GetComponentsInChildren<MaterialTransitionController>(true); |
| | 109 | |
|
| 0 | 110 | | for (int i = 0; i < transitionController.Length; i++) |
| | 111 | | { |
| 0 | 112 | | MaterialTransitionController material = transitionController[i]; |
| 0 | 113 | | Object.Destroy(material); |
| | 114 | | } |
| 0 | 115 | | dataStoreEcs7.RemovePendingResource(scene.sceneData.id, prevLoadedGltf); |
| 0 | 116 | | } |
| | 117 | |
|
| | 118 | | private void CleanUp(IParcelScene scene, IDCLEntity entity) |
| | 119 | | { |
| 20 | 120 | | int count = pointerColliders?.Count ?? 0; |
| 92 | 121 | | for (int i = 0; i < count; i++) |
| | 122 | | { |
| 26 | 123 | | pointerColliderComponent.RemoveCollider(scene, entity, pointerColliders[i]); |
| | 124 | | } |
| 20 | 125 | | count = physicColliders?.Count ?? 0; |
| 52 | 126 | | for (int i = 0; i < count; i++) |
| | 127 | | { |
| 6 | 128 | | physicColliderComponent.RemoveCollider(scene, entity, physicColliders[i]); |
| | 129 | | } |
| 20 | 130 | | count = renderers?.Count ?? 0; |
| 92 | 131 | | for (int i = 0; i < count; i++) |
| | 132 | | { |
| 26 | 133 | | renderersComponent.RemoveRenderer(scene, entity, renderers[i]); |
| | 134 | | } |
| | 135 | |
|
| 20 | 136 | | physicColliders = null; |
| 20 | 137 | | pointerColliders = null; |
| 20 | 138 | | renderers = null; |
| | 139 | |
|
| 20 | 140 | | if (!string.IsNullOrEmpty(prevLoadedGltf)) |
| | 141 | | { |
| 20 | 142 | | dataStoreEcs7.RemovePendingResource(scene.sceneData.id, prevLoadedGltf); |
| | 143 | | } |
| | 144 | | // TODO: modify Animator component to remove `RemoveShapeReady` usage |
| 20 | 145 | | dataStoreEcs7.RemoveShapeReady(entity.entityId); |
| | 146 | |
|
| 20 | 147 | | gltfLoader.ClearEvents(); |
| 20 | 148 | | gltfLoader.Unload(); |
| 20 | 149 | | } |
| | 150 | |
|
| | 151 | | private static List<Collider> SetUpPhysicColliders(MeshFilter[] meshFilters) |
| | 152 | | { |
| 11 | 153 | | List<Collider> physicColliders = new List<Collider>(meshFilters.Length); |
| | 154 | |
|
| 86 | 155 | | for (int i = 0; i < meshFilters.Length; i++) |
| | 156 | | { |
| 32 | 157 | | if (meshFilters[i].gameObject.layer == PhysicsLayers.characterOnlyLayer) |
| | 158 | | { |
| 1 | 159 | | physicColliders.Add(meshFilters[i].gameObject.GetComponent<Collider>()); |
| 1 | 160 | | continue; |
| | 161 | | } |
| | 162 | |
|
| 31 | 163 | | if (!meshFilters[i].transform.parent.name.ToLower().Contains("_collider")) |
| | 164 | | continue; |
| | 165 | |
|
| 5 | 166 | | MeshCollider collider = meshFilters[i].gameObject.AddComponent<MeshCollider>(); |
| 5 | 167 | | collider.sharedMesh = meshFilters[i].sharedMesh; |
| 5 | 168 | | meshFilters[i].gameObject.layer = PhysicsLayers.characterOnlyLayer; |
| 5 | 169 | | physicColliders.Add(collider); |
| | 170 | |
|
| 5 | 171 | | Object.Destroy(meshFilters[i].GetComponent<Renderer>()); |
| | 172 | | } |
| | 173 | |
|
| 11 | 174 | | return physicColliders; |
| | 175 | | } |
| | 176 | |
|
| | 177 | | private static (List<Collider>, List<Renderer>) SetUpPointerCollidersAndRenderers(HashSet<Renderer> renderers) |
| | 178 | | { |
| 11 | 179 | | List<Collider> pointerColliders = new List<Collider>(renderers.Count); |
| 11 | 180 | | List<Renderer> rendererList = new List<Renderer>(renderers.Count); |
| | 181 | |
|
| | 182 | | // (sadly we are stuck with a hashset here) |
| 74 | 183 | | foreach (var renderer in renderers) |
| | 184 | | { |
| 26 | 185 | | rendererList.Add(renderer); |
| 26 | 186 | | Transform rendererT = renderer.transform; |
| 26 | 187 | | bool alreadyHasCollider = false; |
| 52 | 188 | | for (int i = 0; i < rendererT.childCount; i++) |
| | 189 | | { |
| 5 | 190 | | Transform child = rendererT.GetChild(i); |
| 5 | 191 | | if (child.gameObject.layer != PhysicsLayers.onPointerEventLayer) |
| | 192 | | continue; |
| | 193 | |
|
| 5 | 194 | | alreadyHasCollider = true; |
| 5 | 195 | | pointerColliders.Add(child.GetComponent<Collider>()); |
| 5 | 196 | | break; |
| | 197 | | } |
| | 198 | |
|
| 26 | 199 | | if (alreadyHasCollider) |
| | 200 | | continue; |
| | 201 | |
|
| 21 | 202 | | GameObject colliderGo = new GameObject(POINTER_COLLIDER_NAME); |
| 21 | 203 | | colliderGo.layer = PhysicsLayers.onPointerEventLayer; |
| 21 | 204 | | MeshCollider collider = colliderGo.AddComponent<MeshCollider>(); |
| 21 | 205 | | collider.sharedMesh = renderer.GetComponent<MeshFilter>().sharedMesh; |
| 21 | 206 | | colliderGo.transform.SetParent(renderer.transform); |
| 21 | 207 | | colliderGo.transform.ResetLocalTRS(); |
| 21 | 208 | | pointerColliders.Add(collider); |
| | 209 | | } |
| | 210 | |
|
| 11 | 211 | | return (pointerColliders, rendererList); |
| | 212 | | } |
| | 213 | | } |
| | 214 | | } |