diff --git a/Explorer/Assets/AddressableAssetsData/AssetGroups/Settings.asset b/Explorer/Assets/AddressableAssetsData/AssetGroups/Settings.asset index 4723dc1408..cb817038c9 100644 --- a/Explorer/Assets/AddressableAssetsData/AssetGroups/Settings.asset +++ b/Explorer/Assets/AddressableAssetsData/AssetGroups/Settings.asset @@ -22,6 +22,11 @@ MonoBehaviour: m_ReadOnly: 0 m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: 12f48d0297bd3f746b92a97878478086 + m_Address: VideoPrioritizationSettings + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 - m_GUID: 134b7bf082a11ae499e9e62958051ca7 m_Address: AnalyticsConfiguration m_ReadOnly: 0 diff --git a/Explorer/Assets/DCL/Audio/Prefabs/MediaPlayer.prefab b/Explorer/Assets/DCL/Audio/Prefabs/MediaPlayer.prefab index fe2d12e763..d4828e9d10 100644 --- a/Explorer/Assets/DCL/Audio/Prefabs/MediaPlayer.prefab +++ b/Explorer/Assets/DCL/Audio/Prefabs/MediaPlayer.prefab @@ -250,7 +250,7 @@ AudioSource: MinDistance: 40 MaxDistance: 60 Pan2D: 0 - rolloffMode: 1 + rolloffMode: 2 BypassEffects: 0 BypassListenerEffects: 0 BypassReverbZones: 0 @@ -258,23 +258,23 @@ AudioSource: serializedVersion: 2 m_Curve: - serializedVersion: 3 - time: 0 + time: 0.16666667 value: 1 - inSlope: 0 - outSlope: 0 - tangentMode: 0 - weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 + inSlope: -1.6265876 + outSlope: 0.01024792 + tangentMode: 1 + weightedMode: 3 + inWeight: 0 + outWeight: 0.29192546 - serializedVersion: 3 time: 1 value: 0 - inSlope: 0 - outSlope: 0 + inSlope: 0.013024294 + outSlope: 0.013024294 tangentMode: 0 weightedMode: 0 - inWeight: 0.33333334 - outWeight: 0.33333334 + inWeight: 0.28074533 + outWeight: 0 m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 @@ -283,7 +283,7 @@ AudioSource: m_Curve: - serializedVersion: 3 time: 0 - value: 0 + value: 1 inSlope: 0 outSlope: 0 tangentMode: 0 diff --git a/Explorer/Assets/DCL/AvatarRendering/AvatarShape/Systems/AvatarLoaderSystem.cs b/Explorer/Assets/DCL/AvatarRendering/AvatarShape/Systems/AvatarLoaderSystem.cs index eae9f7723e..8c6827388b 100644 --- a/Explorer/Assets/DCL/AvatarRendering/AvatarShape/Systems/AvatarLoaderSystem.cs +++ b/Explorer/Assets/DCL/AvatarRendering/AvatarShape/Systems/AvatarLoaderSystem.cs @@ -89,8 +89,9 @@ private void UpdateAvatarFromSDKComponent(ref PBAvatarShape pbAvatarShape, ref A avatarShapeComponent.WearablePromise.ForgetLoading(World); WearablePromise newPromise = CreateWearablePromise(pbAvatarShape, partition); + avatarShapeComponent.ID = pbAvatarShape.Id; + avatarShapeComponent.Name = pbAvatarShape.Name; avatarShapeComponent.WearablePromise = newPromise; - avatarShapeComponent.BodyShape = pbAvatarShape; avatarShapeComponent.HairColor = pbAvatarShape.GetHairColor().ToUnityColor(); avatarShapeComponent.SkinColor = pbAvatarShape.GetSkinColor().ToUnityColor(); diff --git a/Explorer/Assets/DCL/Character/CharacterMotion/Components/PlayerTeleportIntent.cs b/Explorer/Assets/DCL/Character/CharacterMotion/Components/PlayerTeleportIntent.cs index 7148a4e9ab..390ed3e34c 100644 --- a/Explorer/Assets/DCL/Character/CharacterMotion/Components/PlayerTeleportIntent.cs +++ b/Explorer/Assets/DCL/Character/CharacterMotion/Components/PlayerTeleportIntent.cs @@ -25,17 +25,20 @@ public JustTeleported(int expireFrame) public readonly CancellationToken CancellationToken; /// - /// Strictly it's the same report added to "SceneReadinessReportQueue" + /// Strictly it's the same report added to "SceneReadinessReportQueue"
+ /// Teleport operation will wait for this report to be resolved before finishing the teleport operation
+ /// Otherwise the teleport operation will be executed immediately ///
- public readonly AsyncLoadProcessReport? LoadReport; + public readonly AsyncLoadProcessReport? AssetsResolution; + public readonly float CreationTime; - public PlayerTeleportIntent(Vector3 position, Vector2Int parcel, CancellationToken cancellationToken, AsyncLoadProcessReport? loadReport = null) + public PlayerTeleportIntent(Vector3 position, Vector2Int parcel, CancellationToken cancellationToken, AsyncLoadProcessReport? assetsResolution = null) { Position = position; Parcel = parcel; CancellationToken = cancellationToken; - LoadReport = loadReport; + AssetsResolution = assetsResolution; CreationTime = Time.realtimeSinceStartup; } diff --git a/Explorer/Assets/DCL/Character/CharacterMotion/Systems/RotateCharacterSystem.cs b/Explorer/Assets/DCL/Character/CharacterMotion/Systems/RotateCharacterSystem.cs index 1db0f2384f..14d3ac4ed1 100644 --- a/Explorer/Assets/DCL/Character/CharacterMotion/Systems/RotateCharacterSystem.cs +++ b/Explorer/Assets/DCL/Character/CharacterMotion/Systems/RotateCharacterSystem.cs @@ -8,6 +8,7 @@ using DCL.CharacterMotion.Platforms; using DCL.CharacterMotion.Settings; using DCL.Diagnostics; +using DCL.ECSComponents; using ECS.Abstract; using ECS.Unity.Transforms.Components; using UnityEngine; @@ -32,7 +33,7 @@ protected override void Update(float t) } [Query] - [None(typeof(PlayerLookAtIntent))] + [None(typeof(PlayerLookAtIntent), typeof(PBAvatarShape))] private void LerpRotation( [Data] float dt, ref ICharacterControllerSettings settings, @@ -55,6 +56,7 @@ private void LerpRotation( } [Query] + [None(typeof(PBAvatarShape))] private void ForceLookAt(in Entity entity, ref CharacterRigidTransform rigidTransform, ref CharacterTransform transform, in PlayerLookAtIntent lookAtIntent) { // Rotate player to look at camera target diff --git a/Explorer/Assets/DCL/Character/CharacterMotion/Systems/TeleportCharacterSystem.cs b/Explorer/Assets/DCL/Character/CharacterMotion/Systems/TeleportCharacterSystem.cs index 03f30b5b27..5d70b4df2f 100644 --- a/Explorer/Assets/DCL/Character/CharacterMotion/Systems/TeleportCharacterSystem.cs +++ b/Explorer/Assets/DCL/Character/CharacterMotion/Systems/TeleportCharacterSystem.cs @@ -40,9 +40,12 @@ protected override void Update(float t) [Query] private void TeleportPlayer(Entity entity, CharacterController controller, ref CharacterPlatformComponent platformComponent, in PlayerTeleportIntent teleportIntent) { - AsyncLoadProcessReport? loadReport = teleportIntent.LoadReport; + AsyncLoadProcessReport? loadReport = teleportIntent.AssetsResolution; - if (loadReport != null) + if (loadReport == null) + // If there are no assets to wait for, teleport immediately + ResolveAsSuccess(entity, in teleportIntent, controller, ref platformComponent); + else { AsyncLoadProcessReport.Status status = loadReport.GetStatus(); @@ -58,22 +61,22 @@ private void TeleportPlayer(Entity entity, CharacterController controller, ref C ResolveAsFailure(entity, in teleportIntent, status.Exception!); return; } - } - // pending cases left + // pending cases left - if (teleportIntent.TimedOut) - { - var exception = new TimeoutException("Teleport timed out"); - loadReport?.SetException(exception); - ResolveAsFailure(entity, in teleportIntent, exception); - return; - } + if (teleportIntent.TimedOut) + { + var exception = new TimeoutException("Teleport timed out"); + loadReport?.SetException(exception); + ResolveAsFailure(entity, in teleportIntent, exception); + return; + } - if (teleportIntent.CancellationToken.IsCancellationRequested) - { - loadReport?.SetCancelled(); - ResolveAsCancelled(entity, in teleportIntent); + if (teleportIntent.CancellationToken.IsCancellationRequested) + { + loadReport?.SetCancelled(); + ResolveAsCancelled(entity, in teleportIntent); + } } } @@ -91,7 +94,7 @@ private void FinalizeQueuedLoadReport(in PlayerTeleportIntent intent, Action(e), Is.False); + Assert.That(characterController.transform.position, Is.EqualTo(new Vector3(100, 100, 100))); + } + [Test] public async Task RestoreCameraDataOnFailureAsync([Values(UniTaskStatus.Faulted, UniTaskStatus.Canceled)] UniTaskStatus status) { diff --git a/Explorer/Assets/DCL/Editor/DCL.Editor.asmdef b/Explorer/Assets/DCL/Editor/DCL.Editor.asmdef index c2770eb0e0..9e93c3e1a4 100644 --- a/Explorer/Assets/DCL/Editor/DCL.Editor.asmdef +++ b/Explorer/Assets/DCL/Editor/DCL.Editor.asmdef @@ -20,7 +20,8 @@ "GUID:166b65e6dfc848bb9fb075f53c293a38", "GUID:fa7b3fdbb04d67549916da7bd2af58ab", "GUID:d28a7e4beeca475418c15757abf1b6f1", - "GUID:286980af24684da6acc1caa413039811" + "GUID:286980af24684da6acc1caa413039811", + "GUID:fc37ca6521833154cab08ec51af097d9" ], "includePlatforms": [ "Editor" diff --git a/Explorer/Assets/DCL/MapRenderer/MapLayers/PlayerMarker/PlayerMarkerController.cs b/Explorer/Assets/DCL/MapRenderer/MapLayers/PlayerMarker/PlayerMarkerController.cs index 0f506947b1..ef11c748c3 100644 --- a/Explorer/Assets/DCL/MapRenderer/MapLayers/PlayerMarker/PlayerMarkerController.cs +++ b/Explorer/Assets/DCL/MapRenderer/MapLayers/PlayerMarker/PlayerMarkerController.cs @@ -4,6 +4,7 @@ using Arch.SystemGroups.DefaultSystemGroups; using Cysharp.Threading.Tasks; using DCL.Character.Components; +using DCL.ECSComponents; using DCL.MapRenderer.CoordsUtils; using DCL.MapRenderer.Culling; using MVC; @@ -54,8 +55,9 @@ public void CreateSystems(ref ArchSystemsWorldBuilder builder) system.Activate(); } - [All(typeof(PlayerComponent))] [Query] + [All(typeof(PlayerComponent))] + [None(typeof(PBAvatarShape))] private void SetPlayerTransform(in CharacterTransform transformComponent) { SetPosition(transformComponent.Transform.position); diff --git a/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/UsersMarkersHotAreaController.cs b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/UsersMarkersHotAreaController.cs index 4d2d6d08e3..879a7b9c66 100644 --- a/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/UsersMarkersHotAreaController.cs +++ b/Explorer/Assets/DCL/MapRenderer/MapLayers/UsersMarker/UsersMarkersHotAreaController.cs @@ -7,6 +7,7 @@ using DCL.AvatarRendering.AvatarShape.Components; using DCL.Character.Components; using DCL.CharacterPreview.Components; +using DCL.ECSComponents; using DCL.MapRenderer.CoordsUtils; using DCL.MapRenderer.Culling; using DCL.MapRenderer.MapLayers.UsersMarker; @@ -59,7 +60,7 @@ public void CreateSystems(ref ArchSystemsWorldBuilder builder) } [Query] - [None(typeof(PlayerComponent), typeof(CharacterPreviewComponent), typeof(DeleteEntityIntention))] + [None(typeof(PlayerComponent), typeof(CharacterPreviewComponent), typeof(PBAvatarShape), typeof(DeleteEntityIntention))] private void SetPlayerMarker(in CharacterTransform transformComponent, in AvatarShapeComponent avatarShape) { if (!isEnabled) diff --git a/Explorer/Assets/DCL/Minimap/Minimap.asmdef b/Explorer/Assets/DCL/Minimap/Minimap.asmdef index 635aa781de..9262fdb9db 100644 --- a/Explorer/Assets/DCL/Minimap/Minimap.asmdef +++ b/Explorer/Assets/DCL/Minimap/Minimap.asmdef @@ -25,7 +25,8 @@ "GUID:766b242fb43af451aaa331f39872177d", "GUID:d832748739a186646b8656bdbd447ad0", "GUID:286980af24684da6acc1caa413039811", - "GUID:1300820cd310d4584b09afde765bdd16" + "GUID:1300820cd310d4584b09afde765bdd16", + "GUID:3c7b57a14671040bd8c549056adc04f5" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Explorer/Assets/DCL/Minimap/MinimapController.cs b/Explorer/Assets/DCL/Minimap/MinimapController.cs index 4a5476955f..fc22c706c9 100644 --- a/Explorer/Assets/DCL/Minimap/MinimapController.cs +++ b/Explorer/Assets/DCL/Minimap/MinimapController.cs @@ -7,6 +7,7 @@ using DCL.Chat.Commands; using DCL.Chat.MessageBus; using DCL.Diagnostics; +using DCL.ECSComponents; using DCL.ExplorePanel; using DCL.MapRenderer; using DCL.MapRenderer.CommonBehavior; @@ -155,8 +156,9 @@ private void HidePinInMinimapEdge() } - [All(typeof(PlayerComponent))] [Query] + [All(typeof(PlayerComponent))] + [None(typeof(PBAvatarShape))] private void QueryPlayerPosition(in CharacterTransform transformComponent) { Vector3 position = transformComponent.Position; diff --git a/Explorer/Assets/DCL/Multiplayer/Movement/Systems/RemotePlayersMovementSystem.cs b/Explorer/Assets/DCL/Multiplayer/Movement/Systems/RemotePlayersMovementSystem.cs index 3f1356fafe..32a33a1ce0 100644 --- a/Explorer/Assets/DCL/Multiplayer/Movement/Systems/RemotePlayersMovementSystem.cs +++ b/Explorer/Assets/DCL/Multiplayer/Movement/Systems/RemotePlayersMovementSystem.cs @@ -8,6 +8,7 @@ using DCL.CharacterMotion.Settings; using DCL.CharacterMotion.Utils; using DCL.Diagnostics; +using DCL.ECSComponents; using DCL.Multiplayer.Movement.Settings; using ECS.Abstract; using ECS.LifeCycle.Components; @@ -47,7 +48,7 @@ private void HandleFirstMessage(ref CharacterTransform transComp, in NetworkMove } [Query] - [None(typeof(PlayerComponent), typeof(DeleteEntityIntention))] + [None(typeof(PlayerComponent), typeof(PBAvatarShape), typeof(DeleteEntityIntention))] private void UpdateRemotePlayersMovement([Data] float deltaTime, ref CharacterTransform transComp, ref RemotePlayerMovementComponent remotePlayerMovement, ref InterpolationComponent intComp, ref ExtrapolationComponent extComp) { diff --git a/Explorer/Assets/DCL/Multiplayer/SDK/Systems/GlobalWorld/PlayerCRDTEntitiesHandlerSystem.cs b/Explorer/Assets/DCL/Multiplayer/SDK/Systems/GlobalWorld/PlayerCRDTEntitiesHandlerSystem.cs index ced9534ce7..d8d01df495 100644 --- a/Explorer/Assets/DCL/Multiplayer/SDK/Systems/GlobalWorld/PlayerCRDTEntitiesHandlerSystem.cs +++ b/Explorer/Assets/DCL/Multiplayer/SDK/Systems/GlobalWorld/PlayerCRDTEntitiesHandlerSystem.cs @@ -6,6 +6,7 @@ using CrdtEcsBridge.Components; using DCL.Character.Components; using DCL.Diagnostics; +using DCL.ECSComponents; using DCL.Multiplayer.Profiles.Systems; using DCL.Multiplayer.SDK.Components; using DCL.Profiles; @@ -46,7 +47,7 @@ protected override void Update(float t) [Query] [All(typeof(Profile))] - [None(typeof(PlayerCRDTEntity), typeof(DeleteEntityIntention))] + [None(typeof(PlayerCRDTEntity), typeof(PBAvatarShape), typeof(DeleteEntityIntention))] private void AddPlayerCRDTEntity(Entity entity, in CharacterTransform characterTransform) { // Reserve entity straight-away, numeration will be preserved across all scenes @@ -63,7 +64,7 @@ private void AddPlayerCRDTEntity(Entity entity, in CharacterTransform characterT } [Query] - [None(typeof(DeleteEntityIntention))] + [None(typeof(DeleteEntityIntention), typeof(PBAvatarShape))] private void ModifyPlayerScene(in CharacterTransform characterTransform, ref PlayerCRDTEntity playerCRDTEntity) { ResolvePlayerCRDTScene(characterTransform, ref playerCRDTEntity, playerCRDTEntity.CRDTEntity); diff --git a/Explorer/Assets/DCL/Multiplayer/SDK/Systems/GlobalWorld/PlayerTransformPropagationSystem.cs b/Explorer/Assets/DCL/Multiplayer/SDK/Systems/GlobalWorld/PlayerTransformPropagationSystem.cs index 65a868d959..98749d7e9a 100644 --- a/Explorer/Assets/DCL/Multiplayer/SDK/Systems/GlobalWorld/PlayerTransformPropagationSystem.cs +++ b/Explorer/Assets/DCL/Multiplayer/SDK/Systems/GlobalWorld/PlayerTransformPropagationSystem.cs @@ -9,11 +9,7 @@ using DCL.Multiplayer.SDK.Components; using DCL.Optimization.Pools; using ECS.Abstract; -using ECS.Groups; using ECS.LifeCycle.Components; -using Utility; -using Quaternion = UnityEngine.Quaternion; -using Vector3 = UnityEngine.Vector3; namespace DCL.Multiplayer.SDK.Systems.GlobalWorld { diff --git a/Explorer/Assets/DCL/NameTags/NametagView.cs b/Explorer/Assets/DCL/NameTags/NametagView.cs index 20084b8635..f5ba2026b2 100644 --- a/Explorer/Assets/DCL/NameTags/NametagView.cs +++ b/Explorer/Assets/DCL/NameTags/NametagView.cs @@ -87,7 +87,7 @@ public void InjectConfiguration(ChatBubbleConfigurationSO chatBubbleConfiguratio messageContentAnchoredPosition = new (0, chatBubbleConfiguration.bubbleMarginOffsetHeight / 3); } - public void SetUsername(string username, string walletId, bool hasClaimedName) + public void SetUsername(string username, string walletId, bool hasClaimedName, bool useVerifiedIcon) { ResetElement(); @@ -95,7 +95,7 @@ public void SetUsername(string username, string walletId, bool hasClaimedName) cts = new CancellationTokenSource(); isClaimedName = hasClaimedName; - VerifiedIcon.gameObject.SetActive(hasClaimedName); + VerifiedIcon.gameObject.SetActive(hasClaimedName && useVerifiedIcon); Username.text = hasClaimedName ? username : $"{username}#{walletId}"; Username.rectTransform.sizeDelta = new Vector2(Username.preferredWidth, DEFAULT_HEIGHT); MessageContent.color = startingTextColor; @@ -103,11 +103,11 @@ public void SetUsername(string username, string walletId, bool hasClaimedName) float nametagMarginOffsetHeight = chatBubbleConfiguration?.nametagMarginOffsetHeight ?? DEFAULT_MARGIN_OFFSET_HEIGHT; float nametagMarginOffsetWidth = chatBubbleConfiguration?.nametagMarginOffsetWidth ?? DEFAULT_MARGIN_OFFSET_WIDTH; - if (hasClaimedName) + if (hasClaimedName && useVerifiedIcon) { + usernamePos.x = Username.rectTransform.anchoredPosition.x; verifiedIconInitialPosition = new Vector2(Username.rectTransform.anchoredPosition.x + (Username.preferredWidth / 2) + (VerifiedIcon.sizeDelta.x / 2) - (nametagMarginOffsetHeight / 2), 0); VerifiedIcon.anchoredPosition = verifiedIconInitialPosition; - usernamePos.x = Username.rectTransform.anchoredPosition.x; usernamePos.x -= VerifiedIcon.sizeDelta.x / 2; Username.rectTransform.anchoredPosition = usernamePos; Background.size = new Vector2(Username.preferredWidth + nametagMarginOffsetWidth + VerifiedIcon.sizeDelta.x, Username.preferredHeight + nametagMarginOffsetHeight); diff --git a/Explorer/Assets/DCL/NameTags/Systems/NametagPlacementSystem.cs b/Explorer/Assets/DCL/NameTags/Systems/NametagPlacementSystem.cs index b1dca33325..731a615c3e 100644 --- a/Explorer/Assets/DCL/NameTags/Systems/NametagPlacementSystem.cs +++ b/Explorer/Assets/DCL/NameTags/Systems/NametagPlacementSystem.cs @@ -14,6 +14,7 @@ using ECS.Prioritization.Components; using System.Runtime.CompilerServices; using DCL.AvatarRendering.AvatarShape.UnityInterface; +using DCL.ECSComponents; using UnityEngine; using UnityEngine.Pool; @@ -29,6 +30,7 @@ namespace DCL.Nametags public partial class NametagPlacementSystem : BaseUnityLoopSystem { private const float NAMETAG_SCALE_MULTIPLIER = 0.15f; + private const string NAMETAG_DEFAULT_WALLET_ID = "0000"; private readonly IObjectPool nametagViewPool; private readonly ChatEntryConfigurationSO chatEntryConfiguration; @@ -67,26 +69,33 @@ protected override void Update(float t) CameraComponent camera = playerCamera.GetCameraComponent(World); UpdateTagQuery(World, camera); - AddTagQuery(World, camera); + AddTagForPlayerAvatarsQuery(World, camera); + AddTagForNonPlayerAvatarsQuery(World, camera); ProcessChatBubbleComponentsQuery(World); UpdateOwnTagQuery(World, camera); RemoveUnusedChatBubbleComponentsQuery(World); } [Query] - [None(typeof(NametagView), typeof(DeleteEntityIntention))] - private void AddTag([Data] in CameraComponent camera, Entity e, in AvatarShapeComponent avatarShape, in CharacterTransform characterTransform, in PartitionComponent partitionComponent, in Profile profile) + [None(typeof(NametagView), typeof(PBAvatarShape), typeof(DeleteEntityIntention))] + private void AddTagForPlayerAvatars([Data] in CameraComponent camera, Entity e, in AvatarShapeComponent avatarShape, in CharacterTransform characterTransform, in PartitionComponent partitionComponent, in Profile profile) { if (partitionComponent.IsBehind || IsOutOfRenderRange(camera, characterTransform) || (camera.Mode == CameraMode.FirstPerson && World.Has(e))) return; - NametagView nametagView = nametagViewPool.Get(); - nametagView.Id = avatarShape.ID; - nametagView.Username.color = chatEntryConfiguration.GetNameColor(avatarShape.Name); - nametagView.InjectConfiguration(chatBubbleConfigurationSo); - nametagView.SetUsername(avatarShape.Name, avatarShape.ID.Substring(avatarShape.ID.Length - 4), profile.HasClaimedName); - nametagView.gameObject.name = avatarShape.ID; - UpdateTagTransparencyAndScale(nametagView, camera.Camera, characterTransform.Position); + NametagView nametagView = CreateNameTagView(in avatarShape, profile.HasClaimedName, true); + UpdateTagPosition(nametagView, camera.Camera, characterTransform.Position); + + World.Add(e, nametagView); + } + + [Query] + [None(typeof(NametagView), typeof(Profile), typeof(DeleteEntityIntention))] + [All(typeof(PBAvatarShape))] + private void AddTagForNonPlayerAvatars([Data] in CameraComponent camera, Entity e, in AvatarShapeComponent avatarShape, in CharacterTransform characterTransform, in PartitionComponent partitionComponent) + { + if (partitionComponent.IsBehind || IsOutOfRenderRange(camera, characterTransform) || string.IsNullOrEmpty(avatarShape.Name)) return; + NametagView nametagView = CreateNameTagView(in avatarShape, true, false); UpdateTagPosition(nametagView, camera.Camera, characterTransform.Position); World.Add(e, nametagView); @@ -104,6 +113,7 @@ private void EnableTag(in NametagView nametagView) } [Query] + [None(typeof(PBAvatarShape))] private void UpdateOwnTag([Data] in CameraComponent camera, in AvatarShapeComponent avatarShape, in CharacterTransform characterTransform, in Profile profile, in NametagView nametagView) { if (nametagView.Id == avatarShape.ID) @@ -111,7 +121,7 @@ private void UpdateOwnTag([Data] in CameraComponent camera, in AvatarShapeCompon nametagView.Id = avatarShape.ID; nametagView.Username.color = chatEntryConfiguration.GetNameColor(avatarShape.Name); - nametagView.SetUsername(avatarShape.Name, avatarShape.ID.Substring(avatarShape.ID.Length - 4), profile.HasClaimedName); + nametagView.SetUsername(avatarShape.Name, avatarShape.ID.Substring(avatarShape.ID.Length - 4), profile.HasClaimedName, true); nametagView.gameObject.name = avatarShape.ID; UpdateTagTransparencyAndScale(nametagView, camera.Camera, characterTransform.Position); @@ -128,7 +138,6 @@ private void ProcessChatBubbleComponents(Entity e, in ChatBubbleComponent chatBu World.Remove(e); } - [Query] [All(typeof(ChatBubbleComponent))] //This query is used to remove the ChatBubbleComponent from the entity if the chat bubble has not been displayed @@ -177,5 +186,20 @@ private void UpdateTagTransparencyAndScale(NametagView view, Camera camera, Vect private bool IsOutOfRenderRange(CameraComponent camera, CharacterTransform characterTransform) => Vector3.Distance(camera.Camera.transform.position, characterTransform.Position) > chatBubbleConfigurationSo.maxDistance; + + private NametagView CreateNameTagView(in AvatarShapeComponent avatarShape, bool hasClaimedName, bool useVerifiedIcon) + { + NametagView nametagView = nametagViewPool.Get(); + nametagView.gameObject.name = avatarShape.ID; + nametagView.Id = avatarShape.ID; + nametagView.Username.color = chatEntryConfiguration.GetNameColor(avatarShape.Name); + nametagView.InjectConfiguration(chatBubbleConfigurationSo); + + int walletIdLastDigitsIndex = avatarShape.ID.Length - 4; + string walletId = walletIdLastDigitsIndex >= 0 ? avatarShape.ID.Substring(walletIdLastDigitsIndex) : NAMETAG_DEFAULT_WALLET_ID; + nametagView.SetUsername(avatarShape.Name, walletId, hasClaimedName, useVerifiedIcon); + + return nametagView; + } } } diff --git a/Explorer/Assets/DCL/PluginSystem/DCL.Plugins.asmdef b/Explorer/Assets/DCL/PluginSystem/DCL.Plugins.asmdef index 9d090859e1..806213764b 100644 --- a/Explorer/Assets/DCL/PluginSystem/DCL.Plugins.asmdef +++ b/Explorer/Assets/DCL/PluginSystem/DCL.Plugins.asmdef @@ -135,6 +135,7 @@ "GUID:ecd9230b77a12534cbb829d1b5fcd665", "GUID:887770ff22b647ac864047b3c1af9a8b", "GUID:f0968673e9444d64b49cde6a40d7df7a", + "GUID:fc37ca6521833154cab08ec51af097d9", "DCL.Clipboard", "CameraReelGallery", "ExplorePanelComponents" diff --git a/Explorer/Assets/DCL/PluginSystem/Global/ExplorePanelPlugin.cs b/Explorer/Assets/DCL/PluginSystem/Global/ExplorePanelPlugin.cs index 4b205fe06b..7ff2b3016f 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/ExplorePanelPlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/ExplorePanelPlugin.cs @@ -45,6 +45,8 @@ using DCL.InWorldCamera.CameraReelStorageService; using DCL.Multiplayer.Connections.DecentralandUrls; using DCL.Optimization.PerformanceBudgeting; +using DCL.PluginSystem.World; +using DCL.SDKComponents.MediaStream.Settings; using DCL.Settings.Settings; using UnityEngine; using UnityEngine.AddressableAssets; @@ -238,12 +240,12 @@ public async UniTask InitializeAsync(ExplorePanelSettings settings, Cancellation ProvidedAsset settingsMenuConfiguration = await assetsProvisioner.ProvideMainAssetAsync(settings.SettingsMenuConfiguration, ct); ProvidedAsset generalAudioMixer = await assetsProvisioner.ProvideMainAssetAsync(settings.GeneralAudioMixer, ct); ProvidedAsset realmPartitionSettings = await assetsProvisioner.ProvideMainAssetAsync(settings.RealmPartitionSettings, ct); + ProvidedAsset videoPrioritizationSettings = await assetsProvisioner.ProvideMainAssetAsync(settings.VideoPrioritizationSettings, ct); ProvidedAsset landscapeData = await assetsProvisioner.ProvideMainAssetAsync(settings.LandscapeData, ct); ProvidedAsset qualitySettingsAsset = await assetsProvisioner.ProvideMainAssetAsync(settings.QualitySettingsAsset, ct); ProvidedAsset controlsSettingsAsset = await assetsProvisioner.ProvideMainAssetAsync(settings.ControlsSettingsAsset, ct); - settingsController = new SettingsController(explorePanelView.GetComponentInChildren(), settingsMenuConfiguration.Value, generalAudioMixer.Value, realmPartitionSettings.Value, landscapeData.Value, qualitySettingsAsset.Value, controlsSettingsAsset.Value, systemMemoryCap, worldVolumeMacBus); - + settingsController = new SettingsController(explorePanelView.GetComponentInChildren(), settingsMenuConfiguration.Value, generalAudioMixer.Value, realmPartitionSettings.Value, videoPrioritizationSettings.Value, landscapeData.Value, qualitySettingsAsset.Value, controlsSettingsAsset.Value, systemMemoryCap, worldVolumeMacBus); navmapController = new NavmapController(navmapView: explorePanelView.GetComponentInChildren(), mapRendererContainer.MapRenderer, placesAPIService, webRequestController, webBrowser, dclInput, realmNavigator, realmData, mapPathEventBus, world, playerEntity, inputBlock, chatMessagesBus); @@ -292,6 +294,9 @@ public class ExplorePanelSettings : IDCLPluginSettings [field: SerializeField] public StaticSettings.RealmPartitionSettingsRef RealmPartitionSettings { get; private set; } + [field: SerializeField] + public StaticSettings.VideoPrioritizationSettingsRef VideoPrioritizationSettings { get; private set; } + [field: SerializeField] public LandscapeSettings.LandscapeDataRef LandscapeData { get; private set; } diff --git a/Explorer/Assets/DCL/PluginSystem/Global/Global Plugins Settings.asset b/Explorer/Assets/DCL/PluginSystem/Global/Global Plugins Settings.asset index c2e4fb2cf8..396d218c2c 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/Global Plugins Settings.asset +++ b/Explorer/Assets/DCL/PluginSystem/Global/Global Plugins Settings.asset @@ -220,6 +220,11 @@ MonoBehaviour: m_SubObjectName: m_SubObjectType: m_EditorAssetChanged: 0 + k__BackingField: + m_AssetGUID: 12f48d0297bd3f746b92a97878478086 + m_SubObjectName: + m_SubObjectType: + m_EditorAssetChanged: 0 k__BackingField: m_AssetGUID: 32f2b877400526d4cbf648ba5c5064b4 m_SubObjectName: @@ -263,6 +268,11 @@ MonoBehaviour: m_SubObjectName: m_SubObjectType: m_EditorAssetChanged: 0 + k__BackingField: + m_AssetGUID: 12f48d0297bd3f746b92a97878478086 + m_SubObjectName: + m_SubObjectType: + m_EditorAssetChanged: 0 k__BackingField: m_AssetGUID: 0703f7736b8c9b244953ae7c6ff9a037 m_SubObjectName: diff --git a/Explorer/Assets/DCL/PluginSystem/Global/StaticSettings.cs b/Explorer/Assets/DCL/PluginSystem/Global/StaticSettings.cs index 42794bab1e..6c90ea72a5 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/StaticSettings.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/StaticSettings.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using DCL.Roads.Settings; using DCL.AvatarRendering; +using DCL.PluginSystem.World; +using DCL.SDKComponents.MediaStream.Settings; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.Profiling; @@ -60,6 +62,12 @@ public class RealmPartitionSettingsRef : AssetReferenceT + { + public VideoPrioritizationSettingsRef(string guid) : base(guid) { } + } + [Serializable] public class LODSettingsRef : AssetReferenceT { diff --git a/Explorer/Assets/DCL/PluginSystem/World/MediaPlayerPlugin.cs b/Explorer/Assets/DCL/PluginSystem/World/MediaPlayerPlugin.cs index 1150948bbd..bba4260bd3 100644 --- a/Explorer/Assets/DCL/PluginSystem/World/MediaPlayerPlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/World/MediaPlayerPlugin.cs @@ -1,10 +1,13 @@ using Arch.SystemGroups; using Cysharp.Threading.Tasks; using DCL.AssetsProvision; +using DCL.CharacterCamera; using DCL.Optimization.PerformanceBudgeting; using DCL.Optimization.Pools; +using DCL.PluginSystem.Global; using DCL.PluginSystem.World.Dependencies; using DCL.ResourcesUnloading; +using DCL.SDKComponents.MediaStream.Settings; using DCL.SDKComponents.MediaStream.Wrapper; using DCL.Settings; using DCL.WebRequests; @@ -29,6 +32,7 @@ public class MediaPlayerPlugin : IDCLWorldPlugin builder, public async UniTask InitializeAsync(MediaPlayerPluginSettings settings, CancellationToken ct) { + VideoPrioritizationSettings videoPrioritizationSettings = (await assetsProvisioner.ProvideMainAssetAsync(settings.VideoPrioritizationSettings, ct: ct)).Value; mediaPlayerPrefab = (await assetsProvisioner.ProvideMainAssetAsync(settings.MediaPlayerPrefab, ct: ct)).Value.GetComponent(); - mediaPlayerPluginWrapper = new MediaPlayerPluginWrapper(sharedDependencies.ComponentPoolsRegistry, webRequestController, cacheCleaner, videoTexturePool, frameTimeBudget, mediaPlayerPrefab, worldVolumeMacBus); + mediaPlayerPluginWrapper = new MediaPlayerPluginWrapper(sharedDependencies.ComponentPoolsRegistry, webRequestController, cacheCleaner, videoTexturePool, frameTimeBudget, mediaPlayerPrefab, worldVolumeMacBus, exposedCameraData, videoPrioritizationSettings); } @@ -67,6 +74,8 @@ public class MediaPlayerPluginSettings : IDCLPluginSettings { [field: SerializeField] public AssetReferenceGameObject MediaPlayerPrefab; + + public StaticSettings.VideoPrioritizationSettingsRef VideoPrioritizationSettings; } } } diff --git a/Explorer/Assets/DCL/PluginSystem/World/World Plugins Container.asset b/Explorer/Assets/DCL/PluginSystem/World/World Plugins Container.asset index f062e2e290..c349b20c95 100644 --- a/Explorer/Assets/DCL/PluginSystem/World/World Plugins Container.asset +++ b/Explorer/Assets/DCL/PluginSystem/World/World Plugins Container.asset @@ -183,6 +183,11 @@ MonoBehaviour: m_SubObjectName: m_SubObjectType: m_EditorAssetChanged: 0 + VideoPrioritizationSettings: + m_AssetGUID: 12f48d0297bd3f746b92a97878478086 + m_SubObjectName: + m_SubObjectType: + m_EditorAssetChanged: 0 - rid: 6784895267130048515 type: {class: MaterialsPlugin/Settings, ns: DCL.PluginSystem.World, asm: DCL.Plugins} data: diff --git a/Explorer/Assets/DCL/Quality/Container/QualityContainer.cs b/Explorer/Assets/DCL/Quality/Container/QualityContainer.cs index 46bcf6aff2..4a6a677ecf 100644 --- a/Explorer/Assets/DCL/Quality/Container/QualityContainer.cs +++ b/Explorer/Assets/DCL/Quality/Container/QualityContainer.cs @@ -34,6 +34,7 @@ public static async UniTask CreateAsync(IPluginSettingsContain Settings settings = pluginSettingsContainer.GetSettings(); var realmPartitionSettings = await assetsProvisioner.ProvideMainAssetAsync(settings.RealmPartitionSettings, CancellationToken.None); + var videoPrioritizationSettings = await assetsProvisioner.ProvideMainAssetAsync(settings.VideoPrioritizationSettings, CancellationToken.None); var lodSettingsAsset = await assetsProvisioner.ProvideMainAssetAsync(settings.LODSettingAsset, CancellationToken.None); var landscapeData = await assetsProvisioner.ProvideMainAssetAsync(settings.LandscapeData, CancellationToken.None); @@ -42,6 +43,7 @@ public static async UniTask CreateAsync(IPluginSettingsContain rendererFeaturesCache, settings.QualitySettings, realmPartitionSettings.Value, + videoPrioritizationSettings.Value, lodSettingsAsset.Value, landscapeData.Value); @@ -108,6 +110,9 @@ public class Settings : IDCLPluginSettings [field: SerializeField] public StaticSettings.RealmPartitionSettingsRef RealmPartitionSettings { get; private set; } + [field: SerializeField] + public StaticSettings.VideoPrioritizationSettingsRef VideoPrioritizationSettings { get; private set; } + [field: SerializeField] public StaticSettings.LODSettingsRef LODSettingAsset { get; set; } diff --git a/Explorer/Assets/DCL/Quality/DCL.Quality.asmdef b/Explorer/Assets/DCL/Quality/DCL.Quality.asmdef index 084eef6404..f18cd2276d 100644 --- a/Explorer/Assets/DCL/Quality/DCL.Quality.asmdef +++ b/Explorer/Assets/DCL/Quality/DCL.Quality.asmdef @@ -10,7 +10,8 @@ "GUID:275e22790c04e9b47a5085d7b0c4432a", "GUID:4794e238ed0f65142a4aea5848b513e5", "GUID:a29f69b42fb1815409464ac7b05381d0", - "GUID:21c2e77c042a2d34d8cfbf58f8217053" + "GUID:21c2e77c042a2d34d8cfbf58f8217053", + "GUID:fc37ca6521833154cab08ec51af097d9" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Explorer/Assets/DCL/Quality/Quality Settings.asset b/Explorer/Assets/DCL/Quality/Quality Settings.asset index 40d7abed20..57a52f0c90 100644 --- a/Explorer/Assets/DCL/Quality/Quality Settings.asset +++ b/Explorer/Assets/DCL/Quality/Quality Settings.asset @@ -322,6 +322,7 @@ MonoBehaviour: detailDensity: 30 grassDistance: 75 chunkCullDistance: 1000 + maxSimultaneousVideos: 1 - volumeProfile: {fileID: -4880458653563171804} fogSettings: m_Fog: 1 @@ -334,6 +335,7 @@ MonoBehaviour: detailDensity: 70 grassDistance: 150 chunkCullDistance: 3000 + maxSimultaneousVideos: 5 - volumeProfile: {fileID: 8971067228855834029} fogSettings: m_Fog: 1 @@ -346,6 +348,7 @@ MonoBehaviour: detailDensity: 100 grassDistance: 300 chunkCullDistance: 7000 + maxSimultaneousVideos: 10 allRendererFeatures: - {fileID: -2846649767180898789, guid: 0c7b9d3b12885d541a70add26520ccdb, type: 2} - {fileID: 8138120187327749282, guid: 0c7b9d3b12885d541a70add26520ccdb, type: 2} diff --git a/Explorer/Assets/DCL/Quality/Runtime/EnvironmentSettingsRuntime.cs b/Explorer/Assets/DCL/Quality/Runtime/EnvironmentSettingsRuntime.cs index d94400b127..d9aea1a77b 100644 --- a/Explorer/Assets/DCL/Quality/Runtime/EnvironmentSettingsRuntime.cs +++ b/Explorer/Assets/DCL/Quality/Runtime/EnvironmentSettingsRuntime.cs @@ -1,6 +1,7 @@ using DCL.DebugUtilities; using DCL.Landscape.Settings; using DCL.LOD; +using DCL.SDKComponents.MediaStream.Settings; using ECS.Prioritization; using System; using System.Collections.Generic; @@ -11,6 +12,7 @@ namespace DCL.Quality.Runtime { public class EnvironmentSettingsRuntime : IQualitySettingRuntime { + private PersistentSetting maxSimultaneousVideos; private PersistentSetting sceneLoadRadius; private PersistentSetting lod1Threshold; private PersistentSetting terrainLODBias; @@ -19,6 +21,7 @@ public class EnvironmentSettingsRuntime : IQualitySettingRuntime private PersistentSetting chunkCullDistance; private readonly RealmPartitionSettingsAsset? realmPartitionSettings; + private readonly VideoPrioritizationSettings? videoPrioritizationSettings; private readonly ILODSettingsAsset? lodSettingsAsset; private readonly LandscapeData? landscapeData; @@ -26,12 +29,16 @@ public class EnvironmentSettingsRuntime : IQualitySettingRuntime public EnvironmentSettingsRuntime( RealmPartitionSettingsAsset? realmPartitionSettings, + VideoPrioritizationSettings? videoPrioritizationSettings, ILODSettingsAsset? lodSettingsAsset, LandscapeData? landscapeData) { if (realmPartitionSettings != null) this.realmPartitionSettings = realmPartitionSettings; + if(videoPrioritizationSettings != null) + this.videoPrioritizationSettings = videoPrioritizationSettings; + if (lodSettingsAsset != null) this.lodSettingsAsset = lodSettingsAsset; @@ -62,6 +69,9 @@ public void ApplyPreset(QualitySettingsAsset.QualityCustomLevel preset) SetChunkCullDistance(preset.environmentSettings.chunkCullDistance); this.chunkCullDistance.Value = preset.environmentSettings.chunkCullDistance; + + SetMaxSimultaneousVideos(preset.environmentSettings.maxSimultaneousVideos); + this.maxSimultaneousVideos.Value = preset.environmentSettings.maxSimultaneousVideos; } public void RestoreState(QualitySettingsAsset.QualityCustomLevel currentPreset) @@ -72,6 +82,7 @@ public void RestoreState(QualitySettingsAsset.QualityCustomLevel currentPreset) detailDensity = PersistentSetting.CreateFloat("DetailDensity", currentPreset.environmentSettings.detailDensity).WithSetForceDefaultValue(); grassDistance = PersistentSetting.CreateFloat("GrassDistance", currentPreset.environmentSettings.grassDistance).WithSetForceDefaultValue(); chunkCullDistance = PersistentSetting.CreateFloat("ChunkCullDistance", currentPreset.environmentSettings.chunkCullDistance).WithSetForceDefaultValue(); + maxSimultaneousVideos = PersistentSetting.CreateInt("MaxSimultaneousVideos", currentPreset.environmentSettings.lod1Threshold).WithSetForceDefaultValue(); // Apply settings SetSceneLoadRadius(sceneLoadRadius.Value); @@ -80,6 +91,7 @@ public void RestoreState(QualitySettingsAsset.QualityCustomLevel currentPreset) SetDetailDensity(detailDensity.Value); SetGrassDistance(grassDistance.Value); SetChunkCullDistance(chunkCullDistance.Value); + SetMaxSimultaneousVideos(maxSimultaneousVideos.Value); } private void SetSceneLoadRadius(int maxLoadingDistanceInParcels) @@ -90,6 +102,14 @@ private void SetSceneLoadRadius(int maxLoadingDistanceInParcels) realmPartitionSettings.MaxLoadingDistanceInParcels = maxLoadingDistanceInParcels; } + private void SetMaxSimultaneousVideos(int maxSimultaneousVideos) + { + if(videoPrioritizationSettings == null) + return; + + videoPrioritizationSettings.MaximumSimultaneousVideos = maxSimultaneousVideos; + } + private void SetLodThreshold(int lodThreshold, int index) { if (lodSettingsAsset == null) diff --git a/Explorer/Assets/DCL/Quality/Runtime/QualityRuntimeFactory.cs b/Explorer/Assets/DCL/Quality/Runtime/QualityRuntimeFactory.cs index 12a4946a7b..523386d6ea 100644 --- a/Explorer/Assets/DCL/Quality/Runtime/QualityRuntimeFactory.cs +++ b/Explorer/Assets/DCL/Quality/Runtime/QualityRuntimeFactory.cs @@ -1,5 +1,6 @@ using DCL.Landscape.Settings; using DCL.LOD; +using DCL.SDKComponents.MediaStream.Settings; using ECS.Prioritization; using System; using System.Collections.Generic; @@ -17,6 +18,7 @@ public static IQualityLevelController Create( IRendererFeaturesCache rendererFeaturesCache, QualitySettingsAsset settingsAsset, RealmPartitionSettingsAsset? realmPartitionSettings = null, + VideoPrioritizationSettings? videoPrioritizationSettings = null, ILODSettingsAsset? lodSettingsAsset = null, LandscapeData? landscapeData = null) { @@ -25,7 +27,7 @@ public static IQualityLevelController Create( runtimes.Add(CreateFogRuntime()); runtimes.Add(CreateLensFlareRuntime()); runtimes.Add(CreateGlobalVolume()); - runtimes.Add(CreateEnvironmentRuntime(realmPartitionSettings, lodSettingsAsset, landscapeData)); + runtimes.Add(CreateEnvironmentRuntime(realmPartitionSettings, videoPrioritizationSettings, lodSettingsAsset, landscapeData)); CreateRendererFeaturesRuntimes(rendererFeaturesCache, settingsAsset, runtimes); return new QualityLevelController(runtimes, settingsAsset.customSettings); @@ -39,9 +41,10 @@ private static IQualitySettingRuntime CreateFogRuntime() => private static IQualitySettingRuntime CreateEnvironmentRuntime( RealmPartitionSettingsAsset? realmPartitionSettings, + VideoPrioritizationSettings? videoPrioritizationSettings, ILODSettingsAsset? lodSettingsAsset, LandscapeData? landscapeData) => - new EnvironmentSettingsRuntime(realmPartitionSettings, lodSettingsAsset, landscapeData); + new EnvironmentSettingsRuntime(realmPartitionSettings, videoPrioritizationSettings, lodSettingsAsset, landscapeData); /// /// Create a separate class for every renderer feature type possibly available diff --git a/Explorer/Assets/DCL/Quality/Settings/EnvironmentSettings.cs b/Explorer/Assets/DCL/Quality/Settings/EnvironmentSettings.cs index 2ddb485b61..e549c8a6c8 100644 --- a/Explorer/Assets/DCL/Quality/Settings/EnvironmentSettings.cs +++ b/Explorer/Assets/DCL/Quality/Settings/EnvironmentSettings.cs @@ -11,5 +11,6 @@ public class EnvironmentSettings public float detailDensity; public float grassDistance; public float chunkCullDistance; + public int maxSimultaneousVideos; } } diff --git a/Explorer/Assets/DCL/Roads/Settings/Editor.meta b/Explorer/Assets/DCL/Roads/Settings/Editor.meta new file mode 100644 index 0000000000..9a2169520f --- /dev/null +++ b/Explorer/Assets/DCL/Roads/Settings/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e615bcead634acf43a9d86c2517d5b66 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Explorer/Assets/DCL/Roads/Settings/Editor/DCL.Roads.Settings.Editor.asmdef b/Explorer/Assets/DCL/Roads/Settings/Editor/DCL.Roads.Settings.Editor.asmdef new file mode 100644 index 0000000000..7507645fb6 --- /dev/null +++ b/Explorer/Assets/DCL/Roads/Settings/Editor/DCL.Roads.Settings.Editor.asmdef @@ -0,0 +1,19 @@ +{ + "name": "DCL.Roads.Settings.Editor", + "rootNamespace": "", + "references": [ + "GUID:54cb1906aeb4e4264bc1d2aa3818a43f", + "GUID:46c2e553ecab9ff4784aee64075136c9" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Explorer/Assets/DCL/Roads/Settings/Editor/DCL.Roads.Settings.Editor.asmdef.meta b/Explorer/Assets/DCL/Roads/Settings/Editor/DCL.Roads.Settings.Editor.asmdef.meta new file mode 100644 index 0000000000..db1425cbb9 --- /dev/null +++ b/Explorer/Assets/DCL/Roads/Settings/Editor/DCL.Roads.Settings.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 05c5e091fc59a804d8f972e6f29b0c85 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Explorer/Assets/DCL/Roads/Settings/Editor/RoadSettingsAssetEditor.cs b/Explorer/Assets/DCL/Roads/Settings/Editor/RoadSettingsAssetEditor.cs new file mode 100644 index 0000000000..6ce555841a --- /dev/null +++ b/Explorer/Assets/DCL/Roads/Settings/Editor/RoadSettingsAssetEditor.cs @@ -0,0 +1,88 @@ +using UnityEditor; +using UnityEngine; + +namespace DCL.Roads.Settings.Editor +{ + /// + /// A custom inspector that just shows a search box to make finding road descriptions easier. + /// + [CustomEditor(typeof(RoadSettingsAsset))] + internal class RoadSettingsAssetEditor : UnityEditor.Editor + { + private Vector2Int coordinatesToSearch; + private int foundElementIndex = -1; + private Vector2Int foundElementCoordinates; + private Vector3 foundElementRotation; + private string foundElementModel; + private bool showNotFoundMessage; + private bool showUpdatedMessage; + + public override void OnInspectorGUI() + { + EditorGUILayout.LabelField("Search for a Road description by its coordinates:"); + + using (var scope = new EditorGUI.ChangeCheckScope()) + { + coordinatesToSearch = EditorGUILayout.Vector2IntField(GUIContent.none, coordinatesToSearch); + + if (scope.changed) + { + foundElementIndex = -1; + showUpdatedMessage = false; + showNotFoundMessage = false; + } + } + + RoadSettingsAsset roadSettingsAsset = target as RoadSettingsAsset; + + if (GUILayout.Button("Search")) + { + for (int i = 0; i < roadSettingsAsset.RoadDescriptions.Count; ++i) + { + if (roadSettingsAsset.RoadDescriptions[i].RoadCoordinate == coordinatesToSearch) + { + foundElementIndex = i; + foundElementCoordinates = roadSettingsAsset.RoadDescriptions[i].RoadCoordinate; + foundElementRotation = roadSettingsAsset.RoadDescriptions[i].Rotation.eulerAngles; + foundElementModel = roadSettingsAsset.RoadDescriptions[i].RoadModel; + break; + } + } + + if (foundElementIndex == -1) + showNotFoundMessage = true; + } + + if (foundElementIndex > -1) + { + EditorGUILayout.LabelField("Element found at: " + foundElementIndex); + + foundElementCoordinates = EditorGUILayout.Vector2IntField(nameof(RoadDescription.RoadCoordinate), foundElementCoordinates); + foundElementRotation = EditorGUILayout.Vector3Field(nameof(RoadDescription.Rotation), foundElementRotation); + foundElementModel = EditorGUILayout.TextField(nameof(RoadDescription.RoadModel), foundElementModel); + + if (GUILayout.Button("Update road")) + { + roadSettingsAsset.RoadDescriptions[foundElementIndex] = new RoadDescription() + { + RoadModel = foundElementModel, + RoadCoordinate = foundElementCoordinates, + Rotation = Quaternion.Euler(foundElementRotation.x, foundElementRotation.y, foundElementRotation.z) + }; + + showUpdatedMessage = true; + } + } + + if (showNotFoundMessage) + EditorGUILayout.HelpBox("There is no element with coordinates " + coordinatesToSearch, MessageType.Error); + + if (showUpdatedMessage) + EditorGUILayout.HelpBox("Element updated successfully.", MessageType.Info); + + EditorGUILayout.Separator(); + + base.OnInspectorGUI(); + } + } +} diff --git a/Explorer/Assets/DCL/Roads/Settings/Editor/RoadSettingsAssetEditor.cs.meta b/Explorer/Assets/DCL/Roads/Settings/Editor/RoadSettingsAssetEditor.cs.meta new file mode 100644 index 0000000000..7a206c18f7 --- /dev/null +++ b/Explorer/Assets/DCL/Roads/Settings/Editor/RoadSettingsAssetEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4ea58085f7074da1bddc3bf2fef86c0d +timeCreated: 1732714667 \ No newline at end of file diff --git a/Explorer/Assets/DCL/SDKComponents/AvatarShape/Systems/AvatarShapeHandlerSystem.cs b/Explorer/Assets/DCL/SDKComponents/AvatarShape/Systems/AvatarShapeHandlerSystem.cs index f982a8bc5c..7a151ea00c 100644 --- a/Explorer/Assets/DCL/SDKComponents/AvatarShape/Systems/AvatarShapeHandlerSystem.cs +++ b/Explorer/Assets/DCL/SDKComponents/AvatarShape/Systems/AvatarShapeHandlerSystem.cs @@ -2,10 +2,10 @@ using Arch.System; using Arch.SystemGroups; using Arch.SystemGroups.Throttling; +using DCL.Character.Components; using DCL.Diagnostics; using DCL.ECSComponents; using ECS.Abstract; -using DCL.Utilities; using ECS.LifeCycle; using ECS.LifeCycle.Components; using ECS.Prioritization.Components; @@ -37,10 +37,10 @@ protected override void Update(float t) } [Query] - [None(typeof(SDKAvatarShapeComponent))] - private void LoadAvatarShape(in Entity entity, ref PBAvatarShape pbAvatarShape, ref PartitionComponent partitionComponent, ref TransformComponent transformComponent) + [None(typeof(SDKAvatarShapeComponent), typeof(DeleteEntityIntention))] + private void LoadAvatarShape(Entity entity, ref PBAvatarShape pbAvatarShape, ref PartitionComponent partitionComponent, ref TransformComponent transformComponent) { - World.Add(entity, new SDKAvatarShapeComponent(globalWorld.Create(pbAvatarShape, partitionComponent, transformComponent))); + World.Add(entity, new SDKAvatarShapeComponent(globalWorld.Create(pbAvatarShape, partitionComponent, new CharacterTransform(transformComponent.Transform)))); } [Query] @@ -54,32 +54,38 @@ private void UpdateAvatarShape(ref PBAvatarShape pbAvatarShape, ref SDKAvatarSha [Query] [None(typeof(PBAvatarShape), typeof(DeleteEntityIntention))] - private void HandleComponentRemoval(in Entity entity, ref SDKAvatarShapeComponent sdkAvatarShapeComponent) + private void HandleComponentRemoval(Entity entity, ref SDKAvatarShapeComponent sdkAvatarShapeComponent) { // If the component is removed at scene-world, the global-world representation should disappear entirely - globalWorld.Add(sdkAvatarShapeComponent.globalWorldEntity, new DeleteEntityIntention()); + MarkGlobalWorldEntityForDeletion(sdkAvatarShapeComponent.globalWorldEntity); World.Remove(entity); } [Query] [All(typeof(DeleteEntityIntention))] - private void HandleEntityDestruction(in Entity entity, ref SDKAvatarShapeComponent sdkAvatarShapeComponent) + private void HandleEntityDestruction(Entity entity, ref SDKAvatarShapeComponent sdkAvatarShapeComponent) { + MarkGlobalWorldEntityForDeletion(sdkAvatarShapeComponent.globalWorldEntity); World.Remove(entity); - World.Remove(entity); - globalWorld.Add(sdkAvatarShapeComponent.globalWorldEntity, new DeleteEntityIntention()); } [Query] - public void FinalizeComponents(ref SDKAvatarShapeComponent sdkAvatarShapeComponent) - { - globalWorld.Add(sdkAvatarShapeComponent.globalWorldEntity, new DeleteEntityIntention()); - } + public void FinalizeComponents(ref SDKAvatarShapeComponent sdkAvatarShapeComponent) => + MarkGlobalWorldEntityForDeletion(sdkAvatarShapeComponent.globalWorldEntity); - public void FinalizeComponents(in Query query) - { + public void FinalizeComponents(in Query query) => FinalizeComponentsQuery(World); + + public void MarkGlobalWorldEntityForDeletion(Entity globalEntity) + { + // Has to be removed, otherwise scene loading may break after teleportation (no error anywhere to know why) + globalWorld.Remove(globalEntity); + + // Has to be deferred because many times it happens that the entity is marked for deletion AFTER the + // AvatarCleanUpSystem.Update() and BEFORE the DestroyEntitiesSystem.Update(), probably has to do with + // non-synchronicity between global and scene ECS worlds. AvatarCleanUpSystem resets the DeferDeletion. + globalWorld.Add(globalEntity, new DeleteEntityIntention() { DeferDeletion = true }); } } } diff --git a/Explorer/Assets/DCL/SDKComponents/AvatarShape/Tests/AvatarShapeHandlerSystemShould.cs b/Explorer/Assets/DCL/SDKComponents/AvatarShape/Tests/AvatarShapeHandlerSystemShould.cs index 64441c52d8..ad142c8e56 100644 --- a/Explorer/Assets/DCL/SDKComponents/AvatarShape/Tests/AvatarShapeHandlerSystemShould.cs +++ b/Explorer/Assets/DCL/SDKComponents/AvatarShape/Tests/AvatarShapeHandlerSystemShould.cs @@ -1,12 +1,12 @@ using Arch.Core; using DCL.ECSComponents; -using DCL.Utilities; using ECS.LifeCycle.Components; using ECS.Prioritization.Components; using ECS.TestSuite; using ECS.Unity.AvatarShape.Components; using ECS.Unity.AvatarShape.Systems; using NUnit.Framework; +using DCL.Character.Components; namespace ECS.Unity.AvatarShape.Tests { @@ -40,7 +40,7 @@ public void ForwardSDKAvatarShapeInstantiationToGlobalWorldSystems() Assert.AreEqual(1, world.CountEntities(new QueryDescription().WithAll())); Assert.AreEqual(1, globalWorld.CountEntities(new QueryDescription().WithAll())); - globalWorld.Query(new QueryDescription().WithAll(), (ref PBAvatarShape comp) => Assert.AreEqual(pbAvatarShapeComponent.Name, comp.Name)); + globalWorld.Query(new QueryDescription().WithAll(), (ref PBAvatarShape comp) => Assert.AreEqual(pbAvatarShapeComponent.Name, comp.Name)); } [Test] diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Components/VideoStateByPriorityComponent.cs b/Explorer/Assets/DCL/SDKComponents/MediaStream/Components/VideoStateByPriorityComponent.cs new file mode 100644 index 0000000000..fafab8c78f --- /dev/null +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Components/VideoStateByPriorityComponent.cs @@ -0,0 +1,58 @@ +using Arch.Core; +using UnityEngine; + +namespace DCL.SDKComponents.MediaStream +{ + /// + /// Data related to the calculation of the priority of a video and its corresponding state (playing or paused). + /// + public struct VideoStateByPriorityComponent + { + /// + /// The final score used to determine the priority of the video. + /// + public float Score; + + /// + /// Whether the video should be playing or not, if prioritization mechanism did not exist. + /// + public bool WantsToPlay; + + /// + /// The entity that has the MediaPlayer. + /// + public readonly Entity Entity; + + /// + /// Half of the size of the mesh renderer (or mesh renderer group that consume the same video texture). + /// + public readonly float HalfSize; + + /// + /// Whether the video should be playing according to its priority. + /// + public bool IsPlaying; + + /// + /// The time when the video was played manually. + /// + public float MediaPlayStartTime; + + /// + /// A mesh renderer used for visually debugging the priority of each video. + /// + public MeshRenderer? DebugPrioritySign; + + public VideoStateByPriorityComponent(Entity entity, float halfSize, bool wantsToPlay) + { + Entity = entity; + HalfSize = halfSize; + WantsToPlay = wantsToPlay; + + Score = 0.0f; + IsPlaying = false; + MediaPlayStartTime = float.MinValue; + DebugPrioritySign = null; + } + } +} diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Components/VideoStateByPriorityComponent.cs.meta b/Explorer/Assets/DCL/SDKComponents/MediaStream/Components/VideoStateByPriorityComponent.cs.meta new file mode 100644 index 0000000000..e95f091374 --- /dev/null +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Components/VideoStateByPriorityComponent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 35cb88511432404db5b33aec0f01f483 +timeCreated: 1730466981 \ No newline at end of file diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/DCL.MediaPlayer.asmdef b/Explorer/Assets/DCL/SDKComponents/MediaStream/DCL.MediaPlayer.asmdef index eb7ea722e8..6eee3e36c1 100644 --- a/Explorer/Assets/DCL/SDKComponents/MediaStream/DCL.MediaPlayer.asmdef +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/DCL.MediaPlayer.asmdef @@ -1,5 +1,5 @@ { - "name": "DCL.AudioStream.PluginWrapper", + "name": "DCL.MediaPlayer", "rootNamespace": "", "references": [ "GUID:275e22790c04e9b47a5085d7b0c4432a", @@ -21,7 +21,9 @@ "GUID:4a12c0b1b77ec6b418a8d7bd5c925be3", "GUID:f51ebe6a0ceec4240a699833d6309b23", "GUID:fa7b3fdbb04d67549916da7bd2af58ab", - "GUID:1d75b3d8691c845b1a51082e81433dfc" + "GUID:1d75b3d8691c845b1a51082e81433dfc", + "GUID:4307f53044263cf4b835bd812fc161a4", + "GUID:fc37ca6521833154cab08ec51af097d9" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings.meta b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings.meta new file mode 100644 index 0000000000..eb537894ff --- /dev/null +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6534e056f2aa48dbbb47c8daa99a70d5 +timeCreated: 1730376111 \ No newline at end of file diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/DCL.MediaPlayer.Settings.asmdef b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/DCL.MediaPlayer.Settings.asmdef new file mode 100644 index 0000000000..58b09c5cb5 --- /dev/null +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/DCL.MediaPlayer.Settings.asmdef @@ -0,0 +1,3 @@ +{ + "name": "DCL.MediaPlayer.Settings" +} diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/DCL.MediaPlayer.Settings.asmdef.meta b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/DCL.MediaPlayer.Settings.asmdef.meta new file mode 100644 index 0000000000..c84db05663 --- /dev/null +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/DCL.MediaPlayer.Settings.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fc37ca6521833154cab08ec51af097d9 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/VideoPrioritizationSettings.asset b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/VideoPrioritizationSettings.asset new file mode 100644 index 0000000000..cfcd25e9a3 --- /dev/null +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/VideoPrioritizationSettings.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fdabaecc89a44639a539486656238701, type: 3} + m_Name: VideoPrioritizationSettings + m_EditorClassIdentifier: + maximumSimultaneousVideos: 21 + sizeInScreenWeight: 6 + distanceWeight: 4 + angleWeight: 10 + minimumSizeLimit: 0.066 + maximumDistanceLimit: 80 diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/VideoPrioritizationSettings.asset.meta b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/VideoPrioritizationSettings.asset.meta new file mode 100644 index 0000000000..e32fd22004 --- /dev/null +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/VideoPrioritizationSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 12f48d0297bd3f746b92a97878478086 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/VideoPrioritizationSettings.cs b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/VideoPrioritizationSettings.cs new file mode 100644 index 0000000000..1513f5d89f --- /dev/null +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/VideoPrioritizationSettings.cs @@ -0,0 +1,89 @@ +using UnityEngine; + +namespace DCL.SDKComponents.MediaStream.Settings +{ + /// + /// The parameters that define how the video playback prioritization mechanism behaves. They affect how priorities are calculated and which are paused. + /// + [CreateAssetMenu(fileName = "VideoPrioritizationSettings", menuName = "SO/VideoPrioritizationSettings", order = 0)] + public class VideoPrioritizationSettings : ScriptableObject + { + [Tooltip("The amount of videos that will be playing at the same time, at most, on camera.")] + [Range(1, 50.0f)] + [SerializeField] + private int maximumSimultaneousVideos; + + [Tooltip("The weight of the 'size in screen of the video renderers' factor in the calculation of video priorities.")] + [Range(0.0f, 10.0f)] + [SerializeField] + private float sizeInScreenWeight = 1.0f; + + [Tooltip("The weight of the 'distance from the camera to the video renderers' factor in the calculation of video priorities.")] + [Range(0.0f, 10.0f)] + [SerializeField] + private float distanceWeight = 1.0f; + + [Tooltip("The weight of the 'angle of the camera with respect the video renderers' factor in the calculation of video priorities.")] + [Range(0.0f, 10.0f)] + [SerializeField] + private float angleWeight = 1.0f; + + [Tooltip("A normalized value that determines which videos will be paused, without being prioritized, when their size in screen is below it.")] + [Range(0.0001f, 0.9999f)] + [SerializeField] + private float minimumSizeLimit = 0.1f; + + [Tooltip("A value that determines which videos will be paused, without being prioritized, when their distance to the camera is above it.")] + [SerializeField] + private float maximumDistanceLimit = 100.0f; + + public delegate void MaximumSimultaneousVideosChangedDelegate(int newValue); + + /// + /// Raised when the maximum simultaneous videos property changes. + /// + public event MaximumSimultaneousVideosChangedDelegate MaximumSimultaneousVideosChanged; + + /// + /// Gets or sets the amount of videos that will be playing at the same time, at most, on camera. + /// + public int MaximumSimultaneousVideos + { + get => maximumSimultaneousVideos; + + set + { + if (value != maximumSimultaneousVideos) + { + maximumSimultaneousVideos = Mathf.Clamp(value, 1, 50); + MaximumSimultaneousVideosChanged?.Invoke(value); + } + } + } + + /// + /// Gets the weight of the 'size in screen of the video renderers' factor in the calculation of video priorities. + /// + public float SizeInScreenWeight => sizeInScreenWeight; + + /// + /// Gets the weight of the 'distance from the camera to the video renderers' factor in the calculation of video priorities. + /// + public float DistanceWeight => distanceWeight; + + /// + /// Gets the weight of the 'angle of the camera with respect the video renderers' factor in the calculation of video priorities. + /// + public float AngleWeight => angleWeight; + + /// + /// Gets a normalized value that determines which videos will be paused, without being prioritized, when their size in screen is below it. + /// + public float MinimumSizeLimit => minimumSizeLimit; + + /// + /// Gets a value that determines which videos will be paused, without being prioritized, when their distance to the camera is above it. + /// + public float MaximumDistanceLimit => maximumDistanceLimit; + } +} diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/VideoPrioritizationSettings.cs.meta b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/VideoPrioritizationSettings.cs.meta new file mode 100644 index 0000000000..96a43075d7 --- /dev/null +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Settings/VideoPrioritizationSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fdabaecc89a44639a539486656238701 +timeCreated: 1730376170 \ No newline at end of file diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/CleanUpMediaPlayerSystem.cs b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/CleanUpMediaPlayerSystem.cs index 786db3679c..875a683c46 100644 --- a/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/CleanUpMediaPlayerSystem.cs +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/CleanUpMediaPlayerSystem.cs @@ -54,6 +54,7 @@ private void HandleSdkVideoPlayerComponentRemoval(Entity entity, ref VideoTextur CleanUpVideoTexture(ref textureConsumer); CleanUpMediaPlayer(ref mediaPlayer); World.Remove(entity); + World.Remove(entity); } /// @@ -69,6 +70,7 @@ private void HandleVideoPlayerWithoutConsumers(Entity entity, ref VideoTextureCo CleanUpVideoTexture(ref textureConsumer); CleanUpMediaPlayer(ref mediaPlayerComponent); World.Remove(entity); + World.Remove(entity); } } diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/CreateMediaPlayerSystem.cs b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/CreateMediaPlayerSystem.cs index 6ce346e1a3..3416d37fdd 100644 --- a/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/CreateMediaPlayerSystem.cs +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/CreateMediaPlayerSystem.cs @@ -13,9 +13,11 @@ using ECS.Abstract; using ECS.Unity.Groups; using ECS.Unity.Textures.Components; +using ECS.Unity.Transforms.Components; using RenderHeads.Media.AVProVideo; using SceneRunner.Scene; using System.Threading; +using UnityEngine; namespace DCL.SDKComponents.MediaStream { @@ -72,6 +74,11 @@ private void CreateMediaPlayer(Entity entity, string url, bool hasVolume, float if (component.State != VideoState.VsError) component.OpenMediaPromise.UrlReachabilityResolveAsync(webRequestController, component.URL, GetReportData(), component.Cts.Token).SuppressCancellationThrow().Forget(); + // There is no way to set this from the scene code, at the moment + // If the player has no transform, it will appear at 0,0,0 and nobody will hear it if it is in 3D + if (component.MediaPlayer.TryGetComponent(out AudioSource mediaPlayerAudio)) + mediaPlayerAudio.spatialBlend = World.Has(entity) ? 1.0f : 0.0f; + World.Add(entity, component); } diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/UpdateMediaPlayerPrioritizationSystem.cs b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/UpdateMediaPlayerPrioritizationSystem.cs new file mode 100644 index 0000000000..cc1e8a652d --- /dev/null +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/UpdateMediaPlayerPrioritizationSystem.cs @@ -0,0 +1,324 @@ +//#define DEBUG_VIDEO_PRIORITIES +// When the definition is enabled, a colored cube will be created next to each video's mesh renderer. Its color corresponds to the current priority of the video. +// Green means higher priority, red means lower priority. Blue means that it was prioritized but it is not allowed to play due to the maximum limit. +// Black means it has been discarded from prioritization. + +using Arch.Core; +using Arch.System; +using Arch.SystemGroups; +using Arch.SystemGroups.Throttling; +using DCL.CharacterCamera; +using DCL.Diagnostics; +using DCL.ECSComponents; +using DCL.SDKComponents.MediaStream.Settings; +using ECS.Abstract; +using ECS.Groups; +using ECS.Unity.Textures.Components; +using System.Collections.Generic; +using UnityEngine; + +namespace DCL.SDKComponents.MediaStream +{ + /// + /// A system that limits the amount of video streams that can be playing at the same time on camera. + /// Videos are streamed using MediaPlayers. MediaPlayers can be played or paused manually outside this system. Those that are played manually will be + /// prioritized. Depending on the position and priority of the renderer every the video, it will keep playing or will be "culled", which means paused + /// until its priority/position allows it to resume the stream at the current time (not at the time it was paused, as if it was never paused at all). + /// + [UpdateInGroup(typeof(SyncedPresentationSystemGroup))] + [UpdateAfter(typeof(UpdateMediaPlayerSystem))] + [LogCategory(ReportCategory.MEDIA_STREAM)] + [ThrottlingEnabled] + public partial class UpdateMediaPlayerPrioritizationSystem : BaseUnityLoopSystem + { + private readonly IExposedCameraData exposedCameraData; + private readonly VideoPrioritizationSettings videoPrioritizationSettings; + + private readonly List sortedVideoPriorities = new (); + + // Note: it was necessary to cache this in order to avoid a change in FOV when the character runs that ruins the computation of priorities + private float cachedCameraVerticalFOV; + private float cachedCameraHorizontalFOV; + private float cachedCameraTanValue; // A pre-calculated value of the tangent of half the FOV, used to calculate the size on screen + + public UpdateMediaPlayerPrioritizationSystem(World world, IExposedCameraData exposedCameraData, VideoPrioritizationSettings videoPrioritizationSettings) : base(world) + { + this.videoPrioritizationSettings = videoPrioritizationSettings; + this.exposedCameraData = exposedCameraData; + } + + public override void Initialize() + { + base.Initialize(); + + if (exposedCameraData.CinemachineBrain != null) + { + cachedCameraVerticalFOV = exposedCameraData.CinemachineBrain!.OutputCamera.fieldOfView; + cachedCameraHorizontalFOV = Camera.VerticalToHorizontalFieldOfView(exposedCameraData.CinemachineBrain.OutputCamera.fieldOfView, exposedCameraData.CinemachineBrain.OutputCamera.aspect); + float cameraHalfFov = cachedCameraVerticalFOV * 0.5f * Mathf.Deg2Rad; + cachedCameraTanValue = Mathf.Tan(cameraHalfFov); + } + else + { + ReportHub.LogError(GetReportData(), "Missing cinemachine brain while initializing UpdateMediaPlayerPrioritizationSystem!"); + } + } + + protected override void Update(float t) + { + sortedVideoPriorities.Clear(); + AddVideoStatesByPriorityQuery(World); + UpdateVideoPrioritiesQuery(World, cachedCameraVerticalFOV, cachedCameraHorizontalFOV, exposedCameraData.WorldPosition.Value, exposedCameraData.WorldRotation.Value); + UpdateVideoStateDependingOnPriorityQuery(World, videoPrioritizationSettings.MaximumSimultaneousVideos); + +#if DEBUG_VIDEO_PRIORITIES + + ReportHub.Log(GetReportData(), "" + sortedVideoPriorities.Count + ""); + + float maximumPlayingVideos = Mathf.Min(sortedVideoPriorities.Count, videoPrioritizationSettings.MaximumSimultaneousVideos); + + for (int i = 0; i < sortedVideoPriorities.Count; ++i) + { + sortedVideoPriorities[i].DebugPrioritySign.material.color = (i >= maximumPlayingVideos) ? Color.blue : + new Color(i / maximumPlayingVideos, 1.0f - i / maximumPlayingVideos, 0.0f, 1.0f); + } +#endif + } + + /// + /// Adds the VideoStateByPriorityComponent to all entities streaming a video with a MediaPlayer. + /// + [Query] + [All(typeof(PBVideoPlayer))] + [None(typeof(VideoStateByPriorityComponent))] + private void AddVideoStatesByPriority(Entity entity, in MediaPlayerComponent mediaPlayer, in VideoTextureConsumer videoTextureConsumer) + { + // Using the diagonal of the box instead of the height, meshes that occupy "the same" area on screen should have the same priority + float videoMeshLocalSize = (videoTextureConsumer.BoundsMax - videoTextureConsumer.BoundsMin).magnitude; + + VideoStateByPriorityComponent newVideoStateByPriority = new VideoStateByPriorityComponent( + entity, + videoMeshLocalSize * 0.5f, + mediaPlayer.IsPlaying); + +#if DEBUG_VIDEO_PRIORITIES + // Adds a colored cube to a corner of the video mesh renderer which shows the priority of the video + GameObject prioritySign = CreateDebugPrioritySign(); + prioritySign.transform.position = videoTextureConsumer.BoundsMax; + newVideoStateByPriority.DebugPrioritySign = prioritySign.GetComponent(); +#endif + + World.Add(entity, newVideoStateByPriority); + } + + /// + /// Calculates the priority of each video. + /// First, videos whose renderer's position is not on camera (imagine a cone in the XZ plane) will be culled; in the same way, those that are too far + /// from the camera will also be culled. The rest of the videos will be prioritized calculating a score that depends on their positions and sizes. + /// The formula of the score is: S * w0 + D * w1 + A * w2, were S, D and A are values in [0, 1] and wX are arbitrary multipliers. + /// S = The size of the video mesh renderer relative to the screen. + /// D = The distance from the camera to the video mesh renderer, with a maximum. + /// A = The angle of the camera with respect to the video mesh renderer (the nearer to the center of the screen, the higher). + /// The first M videos with the highest score will resume / keep playing (were M is the maximum amount of videos allowed), the rest will be culled. + /// Every video is stored in a list sorted by score. + /// + [Query] + private void UpdateVideoPriorities([Data] float cameraFov, [Data] float cameraHorizontalFov, + [Data] Vector3 cameraWorldPosition, [Data] Quaternion cameraWorldRotation, + in MediaPlayerComponent mediaPlayer, + ref VideoStateByPriorityComponent videoStateByPriority, + ref VideoTextureConsumer videoTextureConsumer) + { + +#if DEBUG_VIDEO_PRIORITIES + videoStateByPriority.DebugPrioritySign.transform.position = videoTextureConsumer.BoundsMax; + videoStateByPriority.DebugPrioritySign.material.color = Color.black; +#endif + // If the state of the video was changed manually... + if (videoStateByPriority.IsPlaying != mediaPlayer.MediaPlayer.Control.IsPlaying()) + { + if (mediaPlayer.MediaPlayer.Control.IsPlaying()) + { + videoStateByPriority.WantsToPlay = true; + videoStateByPriority.MediaPlayStartTime = Time.realtimeSinceStartup; + +#if DEBUG_VIDEO_PRIORITIES + ReportHub.Log(GetReportData(),"Video: PLAYED MANUALLY"); +#endif + } + else + { + videoStateByPriority.WantsToPlay = false; + +#if DEBUG_VIDEO_PRIORITIES + ReportHub.Log(GetReportData(),"Video: PAUSED MANUALLY"); +#endif + } + } + + // If the video should be playing according to external state changes... + if (videoStateByPriority.WantsToPlay) + { + Vector3 boundsMin = videoTextureConsumer.BoundsMin; + Vector3 boundsMax = videoTextureConsumer.BoundsMax; + Vector3 videoCenterPosition = (boundsMax + boundsMin) * 0.5f; + + bool isCameraInVideoBoundingBox = cameraWorldPosition.x >= boundsMin.x && cameraWorldPosition.y >= boundsMin.y && cameraWorldPosition.z >= boundsMin.z && + cameraWorldPosition.x <= boundsMax.x && cameraWorldPosition.y <= boundsMax.y && cameraWorldPosition.z <= boundsMax.z; + + Vector3 cameraToVideo = (videoCenterPosition - cameraWorldPosition).normalized; + Vector3 cameraDirection = cameraWorldRotation * Vector3.forward; + bool isVideoInCameraFrustum = false; + + if (!isCameraInVideoBoundingBox) // If the camera is inside the BB, it's not necessary to calculate anything else, the video is considered in camera + { + // Note: It was necessary to calculate a flattened version of the dot product to prevent some videos from pausing when they were big and + // the character was too close, so the height of the center of the screen did not affect the result + Vector3 cameraToVideoFlattened = new Vector3(cameraToVideo.x, 0.0f, cameraToVideo.z).normalized; + Vector3 cameraDirectionFlattened = new Vector3(cameraDirection.x, 0.0f, cameraDirection.z).normalized; + + float dotProductInXZ = Vector3.Dot(cameraToVideoFlattened, cameraDirectionFlattened); + isVideoInCameraFrustum = Mathf.Acos(dotProductInXZ) * Mathf.Rad2Deg <= cameraHorizontalFov * 0.5f; + } + + // Skips videos that are out of the camera frustum in XZ + if (isCameraInVideoBoundingBox || isVideoInCameraFrustum) + { + float distance = (videoCenterPosition - cameraWorldPosition).magnitude; + + // Skips videos that are too far + if (distance <= videoPrioritizationSettings.MaximumDistanceLimit) + { + float screenSize = Mathf.Clamp01(CalculateObjectHeightRelativeToScreenHeight(videoStateByPriority.HalfSize, distance)); + + // Skips videos that are too small on screen + if (screenSize >= videoPrioritizationSettings.MinimumSizeLimit) + { + float dotProduct = Vector3.Dot(cameraToVideo, cameraDirection); + + // Final score + videoStateByPriority.Score = (videoPrioritizationSettings.MaximumDistanceLimit - distance) / videoPrioritizationSettings.MaximumDistanceLimit * videoPrioritizationSettings.DistanceWeight + + screenSize * videoPrioritizationSettings.SizeInScreenWeight + + dotProduct * videoPrioritizationSettings.AngleWeight; + +#if DEBUG_VIDEO_PRIORITIES + ReportHub.Log(GetReportData(),$"VIDEO ENTITY[{videoStateByPriority.Entity.Id}] Dist: {distance} HSize:{videoStateByPriority.HalfSize} / {CalculateObjectHeightRelativeToScreenHeight(videoStateByPriority.HalfSize, distance)} Dot:{dotProduct} SCORE:{videoStateByPriority.Score}"); +#endif + + // Sorts the playing video list by score, on insertion + int i = 0; + + for (; i < sortedVideoPriorities.Count; ++i) + if (sortedVideoPriorities[i].Score <= videoStateByPriority.Score) + break; + + if (i <= sortedVideoPriorities.Count) + sortedVideoPriorities.Insert(i, videoStateByPriority); + } + } + } + } + } + + /// + /// Resumes or pauses every video depending on its priority. + /// + [Query] + private void UpdateVideoStateDependingOnPriority([Data] int maxSimultaneousVideos, ref VideoStateByPriorityComponent videoStateByPriority, ref MediaPlayerComponent mediaPlayer) + { + bool mustPlay = false; + int playingVideoCount = Mathf.Min(maxSimultaneousVideos, sortedVideoPriorities.Count); + double pauseDuration = 0.0f; + + // Is the current video player in the list of playing video players? And is it in the first N elements that are allowed to play at maximum? And should it be playing? + for (int i = 0; i < playingVideoCount; ++i) + { + if (sortedVideoPriorities[i].Entity == videoStateByPriority.Entity && + sortedVideoPriorities[i].WantsToPlay) + { + mustPlay = true; + pauseDuration = Time.realtimeSinceStartup - videoStateByPriority.MediaPlayStartTime; + + break; + } + } + + if (mustPlay && !videoStateByPriority.IsPlaying) + { + double seekTime = pauseDuration % mediaPlayer.Duration; + + if (!mediaPlayer.MediaPlayer.Control.IsPlaying()) + { + // Videos are resumed at the current time, not at the time it was paused + mediaPlayer.MediaPlayer.Control.Play(); + mediaPlayer.MediaPlayer.Control.Seek(seekTime); + } + + videoStateByPriority.IsPlaying = true; + +#if DEBUG_VIDEO_PRIORITIES + ReportHub.Log(GetReportData(),"VIDEO RESUMED BY PRIORITY: " + videoStateByPriority.Entity.Id + " t:" + seekTime); +#endif + } + else if(!mustPlay && (videoStateByPriority.IsPlaying || mediaPlayer.MediaPlayer.Control.IsPlaying())) + { + if (mediaPlayer.MediaPlayer.Control.IsPlaying()) + { + mediaPlayer.MediaPlayer.Control.Pause(); + } + + videoStateByPriority.IsPlaying = false; + +#if DEBUG_VIDEO_PRIORITIES + ReportHub.Log(GetReportData(),"VIDEO CULLED BY PRIORITY: " + videoStateByPriority.Entity.Id); +#endif + } + } + + /// + /// Given the height of an object, it calculates how much screen it covers in vertical. + /// + /// A half of the height of the object. + /// The distance from the camera to the object. + /// The amount of screen covered in vertical, from 0 to 1 (total coverage). + private float CalculateObjectHeightRelativeToScreenHeight(float halfHeight, float distance) + { + return halfHeight / ((distance + halfHeight) * cachedCameraTanValue); + } + + // Called when the scene is unloaded + public override void Dispose() + { +#if DEBUG_VIDEO_PRIORITIES + DestroyAllDebuggingSignsQuery(World); +#endif + base.Dispose(); + } + + [Query] + private void DestroyAllDebuggingSigns(in VideoStateByPriorityComponent videoStateByPriorityComponent) + { + GameObject.Destroy(videoStateByPriorityComponent.DebugPrioritySign?.gameObject); + } + +#if DEBUG_VIDEO_PRIORITIES + + private static GameObject CreateDebugPrioritySign() + { + GameObject plane = GameObject.CreatePrimitive(PrimitiveType.Cube); + plane.transform.localScale = Vector3.one * 0.5f; + plane.name = "DebugPrioritySign"; + + Material cubeMaterial = new Material(Shader.Find("DCL/Unlit")); + cubeMaterial.color = Color.white; + plane.GetComponent().material = cubeMaterial; + + GameObject.Destroy(plane.GetComponent()); + + return plane; + } + +#endif + + } +} diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/UpdateMediaPlayerPrioritizationSystem.cs.meta b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/UpdateMediaPlayerPrioritizationSystem.cs.meta new file mode 100644 index 0000000000..1ee205ddaf --- /dev/null +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/UpdateMediaPlayerPrioritizationSystem.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3165107914b74b9e9e589bc0528765a0 +timeCreated: 1730560564 \ No newline at end of file diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/UpdateMediaPlayerSystem.cs b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/UpdateMediaPlayerSystem.cs index b39f161104..98d7756af2 100644 --- a/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/UpdateMediaPlayerSystem.cs +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/UpdateMediaPlayerSystem.cs @@ -1,4 +1,4 @@ -using Arch.Core; +using Arch.Core; using Arch.System; using Arch.SystemGroups; using Arch.SystemGroups.Throttling; @@ -13,6 +13,7 @@ using ECS.Abstract; using ECS.Groups; using ECS.Unity.Textures.Components; +using ECS.Unity.Transforms.Components; using RenderHeads.Media.AVProVideo; using SceneRunner.Scene; using System; @@ -73,12 +74,20 @@ private void OnMasterVolumeChanged(float volume) protected override void Update(float t) { + UpdateMediaPlayerPositionQuery(World); UpdateAudioStreamQuery(World); UpdateVideoStreamQuery(World); UpdateVideoTextureQuery(World); } + [Query] + private void UpdateMediaPlayerPosition(ref MediaPlayerComponent mediaPlayer, ref TransformComponent transformComponent) + { + // Needed for positional sound + mediaPlayer.MediaPlayer.transform.position = transformComponent.Transform.position; + } + [Query] private void UpdateAudioStream(ref MediaPlayerComponent component, PBAudioStream sdkComponent) { diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Wrapper/DCL.MediaPlayer.PluginWrapper.asmdef b/Explorer/Assets/DCL/SDKComponents/MediaStream/Wrapper/DCL.MediaPlayer.PluginWrapper.asmdef index 77a58b13be..c8d23311a7 100644 --- a/Explorer/Assets/DCL/SDKComponents/MediaStream/Wrapper/DCL.MediaPlayer.PluginWrapper.asmdef +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Wrapper/DCL.MediaPlayer.PluginWrapper.asmdef @@ -1,5 +1,5 @@ { - "name": "DCL.VideoPlayer.PluginWrapper", + "name": "DCL.MediaPlayer.PluginWrapper", "rootNamespace": "", "references": [ "GUID:1b8e1e1bd01505f478f0369c04a4fb2f", @@ -18,7 +18,9 @@ "GUID:46c2e553ecab9ff4784aee64075136c9", "GUID:4a12c0b1b77ec6b418a8d7bd5c925be3", "GUID:543b8f091a5947a3880b7f2bca2358bd", - "GUID:1d75b3d8691c845b1a51082e81433dfc" + "GUID:1d75b3d8691c845b1a51082e81433dfc", + "GUID:fa7b3fdbb04d67549916da7bd2af58ab", + "GUID:fc37ca6521833154cab08ec51af097d9" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Wrapper/MediaPlayerPluginWrapper.cs b/Explorer/Assets/DCL/SDKComponents/MediaStream/Wrapper/MediaPlayerPluginWrapper.cs index de6159a680..a4eb05dee5 100644 --- a/Explorer/Assets/DCL/SDKComponents/MediaStream/Wrapper/MediaPlayerPluginWrapper.cs +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Wrapper/MediaPlayerPluginWrapper.cs @@ -1,17 +1,18 @@ -using Arch.Core; +using Arch.Core; using Arch.SystemGroups; using CrdtEcsBridge.ECSToCRDTWriter; +using DCL.CharacterCamera; using DCL.Optimization.PerformanceBudgeting; using DCL.Optimization.Pools; using DCL.ResourcesUnloading; using DCL.WebRequests; -using ECS.ComponentsPooling.Systems; using ECS.LifeCycle; using SceneRunner.Scene; using System.Collections.Generic; using UnityEngine; using RenderHeads.Media.AVProVideo; using DCL.ECSComponents; +using DCL.SDKComponents.MediaStream.Settings; using DCL.Settings; namespace DCL.SDKComponents.MediaStream.Wrapper @@ -24,6 +25,8 @@ public class MediaPlayerPluginWrapper private readonly IPerformanceBudget frameTimeBudget; private readonly GameObjectPool mediaPlayerPool; private readonly WorldVolumeMacBus worldVolumeMacBus; + private readonly IExposedCameraData exposedCameraData; + private readonly VideoPrioritizationSettings videoPrioritizationSettings; public MediaPlayerPluginWrapper( IComponentPoolsRegistry componentPoolsRegistry, @@ -32,8 +35,13 @@ public MediaPlayerPluginWrapper( IExtendedObjectPool videoTexturePool, IPerformanceBudget frameTimeBudget, MediaPlayer mediaPlayerPrefab, - WorldVolumeMacBus worldVolumeMacBus) + WorldVolumeMacBus worldVolumeMacBus, + IExposedCameraData exposedCameraData, + VideoPrioritizationSettings videoPrioritizationSettings) { + this.exposedCameraData = exposedCameraData; + this.videoPrioritizationSettings = videoPrioritizationSettings; + #if AV_PRO_PRESENT && !UNITY_EDITOR_LINUX && !UNITY_STANDALONE_LINUX this.componentPoolsRegistry = componentPoolsRegistry; this.webRequestController = webRequestController; @@ -73,6 +81,7 @@ public void InjectToWorld(ref ArchSystemsWorldBuilder builder, ISceneData CreateMediaPlayerSystem.InjectToWorld(ref builder, webRequestController, sceneData, mediaPlayerPool, sceneStateProvider, frameTimeBudget); UpdateMediaPlayerSystem.InjectToWorld(ref builder, webRequestController, sceneData, sceneStateProvider, frameTimeBudget, worldVolumeMacBus); + UpdateMediaPlayerPrioritizationSystem.InjectToWorld(ref builder, exposedCameraData, videoPrioritizationSettings); VideoEventsSystem.InjectToWorld(ref builder, ecsToCrdtWriter, sceneStateProvider, frameTimeBudget); finalizeWorldSystems.Add(CleanUpMediaPlayerSystem.InjectToWorld(ref builder, mediaPlayerPool, videoTexturePool)); diff --git a/Explorer/Assets/DCL/Settings/Configuration/DropdownModuleBinding.cs b/Explorer/Assets/DCL/Settings/Configuration/DropdownModuleBinding.cs index ddc0535092..74c5691ada 100644 --- a/Explorer/Assets/DCL/Settings/Configuration/DropdownModuleBinding.cs +++ b/Explorer/Assets/DCL/Settings/Configuration/DropdownModuleBinding.cs @@ -1,6 +1,7 @@ using DCL.Landscape.Settings; using DCL.Optimization.PerformanceBudgeting; using DCL.Quality; +using DCL.SDKComponents.MediaStream.Settings; using DCL.Settings.ModuleControllers; using DCL.Settings.ModuleViews; using DCL.Settings.Settings; @@ -29,6 +30,7 @@ public enum DropdownFeatures public override SettingsFeatureController CreateModule( Transform parent, RealmPartitionSettingsAsset realmPartitionSettingsAsset, + VideoPrioritizationSettings videoPrioritizationSettings, LandscapeData landscapeData, AudioMixer generalAudioMixer, QualitySettingsAsset qualitySettingsAsset, diff --git a/Explorer/Assets/DCL/Settings/Configuration/SettingsModuleBindings.cs b/Explorer/Assets/DCL/Settings/Configuration/SettingsModuleBindings.cs index c437130cba..25c0632fcb 100644 --- a/Explorer/Assets/DCL/Settings/Configuration/SettingsModuleBindings.cs +++ b/Explorer/Assets/DCL/Settings/Configuration/SettingsModuleBindings.cs @@ -1,6 +1,7 @@ using DCL.Landscape.Settings; using DCL.Optimization.PerformanceBudgeting; using DCL.Quality; +using DCL.SDKComponents.MediaStream.Settings; using DCL.Settings.ModuleControllers; using DCL.Settings.ModuleViews; using DCL.Settings.Settings; @@ -20,6 +21,7 @@ public abstract class SettingsModuleBindingBase public abstract SettingsFeatureController CreateModule( Transform parent, RealmPartitionSettingsAsset realmPartitionSettingsAsset, + VideoPrioritizationSettings videoPrioritizationSettings, LandscapeData landscapeData, AudioMixer generalAudioMixer, QualitySettingsAsset qualitySettingsAsset, diff --git a/Explorer/Assets/DCL/Settings/Configuration/SliderModuleBinding.cs b/Explorer/Assets/DCL/Settings/Configuration/SliderModuleBinding.cs index f3c599a6c5..3187f92515 100644 --- a/Explorer/Assets/DCL/Settings/Configuration/SliderModuleBinding.cs +++ b/Explorer/Assets/DCL/Settings/Configuration/SliderModuleBinding.cs @@ -1,6 +1,7 @@ using DCL.Landscape.Settings; using DCL.Optimization.PerformanceBudgeting; using DCL.Quality; +using DCL.SDKComponents.MediaStream.Settings; using DCL.Settings.ModuleControllers; using DCL.Settings.ModuleViews; using DCL.Settings.Settings; @@ -31,6 +32,7 @@ public enum SliderFeatures public override SettingsFeatureController CreateModule( Transform parent, RealmPartitionSettingsAsset realmPartitionSettingsAsset, + VideoPrioritizationSettings videoPrioritizationSettings, LandscapeData landscapeData, AudioMixer generalAudioMixer, QualitySettingsAsset qualitySettingsAsset, diff --git a/Explorer/Assets/DCL/Settings/Configuration/ToggleModuleBinding.cs b/Explorer/Assets/DCL/Settings/Configuration/ToggleModuleBinding.cs index 086bca7cc7..421e13c46e 100644 --- a/Explorer/Assets/DCL/Settings/Configuration/ToggleModuleBinding.cs +++ b/Explorer/Assets/DCL/Settings/Configuration/ToggleModuleBinding.cs @@ -1,6 +1,7 @@ using DCL.Landscape.Settings; using DCL.Optimization.PerformanceBudgeting; using DCL.Quality; +using DCL.SDKComponents.MediaStream.Settings; using DCL.Settings.ModuleControllers; using DCL.Settings.ModuleViews; using DCL.Settings.Settings; @@ -24,6 +25,7 @@ public enum ToggleFeatures public override SettingsFeatureController CreateModule( Transform parent, RealmPartitionSettingsAsset realmPartitionSettingsAsset, + VideoPrioritizationSettings videoPrioritizationSettings, LandscapeData landscapeData, AudioMixer generalAudioMixer, QualitySettingsAsset qualitySettingsAsset, diff --git a/Explorer/Assets/DCL/Settings/Settings.asmdef b/Explorer/Assets/DCL/Settings/Settings.asmdef index 5fea4efadd..e17bf24756 100644 --- a/Explorer/Assets/DCL/Settings/Settings.asmdef +++ b/Explorer/Assets/DCL/Settings/Settings.asmdef @@ -11,7 +11,8 @@ "GUID:21c2e77c042a2d34d8cfbf58f8217053", "GUID:f51ebe6a0ceec4240a699833d6309b23", "GUID:ba2f4073aea205344b1f48bb5111ff3b", - "GUID:3640f3c0b42946b0b8794a1ed8e06ca5" + "GUID:3640f3c0b42946b0b8794a1ed8e06ca5", + "GUID:fc37ca6521833154cab08ec51af097d9" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Explorer/Assets/DCL/Settings/SettingsController.cs b/Explorer/Assets/DCL/Settings/SettingsController.cs index 2aabd10af6..5211b05612 100644 --- a/Explorer/Assets/DCL/Settings/SettingsController.cs +++ b/Explorer/Assets/DCL/Settings/SettingsController.cs @@ -2,6 +2,7 @@ using DCL.Landscape.Settings; using DCL.Optimization.PerformanceBudgeting; using DCL.Quality; +using DCL.SDKComponents.MediaStream.Settings; using DCL.Settings.Configuration; using DCL.Settings.ModuleControllers; using DCL.Settings.Settings; @@ -21,6 +22,7 @@ public class SettingsController : ISection, IDisposable private readonly SettingsMenuConfiguration settingsMenuConfiguration; private readonly AudioMixer generalAudioMixer; private readonly RealmPartitionSettingsAsset realmPartitionSettingsAsset; + private readonly VideoPrioritizationSettings videoPrioritizationSettings; private readonly LandscapeData landscapeData; private readonly QualitySettingsAsset qualitySettingsAsset; private readonly ISystemMemoryCap memoryCap; @@ -34,6 +36,7 @@ public SettingsController( SettingsMenuConfiguration settingsMenuConfiguration, AudioMixer generalAudioMixer, RealmPartitionSettingsAsset realmPartitionSettingsAsset, + VideoPrioritizationSettings videoPrioritizationSettings, LandscapeData landscapeData, QualitySettingsAsset qualitySettingsAsset, ControlsSettingsAsset controlsSettingsAsset, @@ -49,6 +52,7 @@ public SettingsController( this.memoryCap = memoryCap; this.worldVolumeMacBus = worldVolumeMacBus; this.controlsSettingsAsset = controlsSettingsAsset; + this.videoPrioritizationSettings = videoPrioritizationSettings; rectTransform = view.transform.parent.GetComponent(); @@ -114,7 +118,7 @@ private void GenerateSettingsSection(SettingsSectionConfig sectionConfig, Transf generalGroupView.GroupTitle.text = group.GroupTitle; foreach (SettingsModuleBindingBase module in group.Modules) - controllers.Add(module?.CreateModule(generalGroupView.ModulesContainer, realmPartitionSettingsAsset, landscapeData, generalAudioMixer, qualitySettingsAsset, controlsSettingsAsset, memoryCap, worldVolumeMacBus)); + controllers.Add(module?.CreateModule(generalGroupView.ModulesContainer, realmPartitionSettingsAsset, videoPrioritizationSettings, landscapeData, generalAudioMixer, qualitySettingsAsset, controlsSettingsAsset, memoryCap, worldVolumeMacBus)); } } diff --git a/Explorer/Assets/Scripts/ECS/Unity/Materials/ReleaseMaterial.cs b/Explorer/Assets/Scripts/ECS/Unity/Materials/ReleaseMaterial.cs index 39d4a77c8d..ec06b36a88 100644 --- a/Explorer/Assets/Scripts/ECS/Unity/Materials/ReleaseMaterial.cs +++ b/Explorer/Assets/Scripts/ECS/Unity/Materials/ReleaseMaterial.cs @@ -4,6 +4,7 @@ using ECS.Unity.Materials.Components; using ECS.Unity.PrimitiveRenderer.Components; using ECS.Unity.Textures.Components; +using ECS.Unity.Textures.Utils; using UnityEngine; using Utility.Primitives; using Promise = ECS.StreamableLoading.Common.AssetPromise; @@ -25,7 +26,7 @@ public static void TryReleaseDefault(ref PrimitiveMeshRendererComponent primitiv primitiveMeshRendererComponent.DefaultMaterialIsUsed = false; } - public static void Execute(World world, ref MaterialComponent materialComponent, DestroyMaterial destroyMaterial) + public static void Execute(Entity entity, World world, ref MaterialComponent materialComponent, DestroyMaterial destroyMaterial) { switch (materialComponent.Status) { @@ -43,14 +44,14 @@ public static void Execute(World world, ref MaterialComponent materialComponent, void ReleaseTextures(ref MaterialComponent mat, bool forgetLoading) { - ReleaseIntention(world, ref mat.AlbedoTexPromise, forgetLoading); - ReleaseIntention(world, ref mat.EmissiveTexPromise, forgetLoading); - ReleaseIntention(world, ref mat.AlphaTexPromise, forgetLoading); - ReleaseIntention(world, ref mat.BumpTexPromise, forgetLoading); + ReleaseIntention(entity, world, ref mat.AlbedoTexPromise, forgetLoading); + ReleaseIntention(entity, world, ref mat.EmissiveTexPromise, forgetLoading); + ReleaseIntention(entity, world, ref mat.AlphaTexPromise, forgetLoading); + ReleaseIntention(entity, world, ref mat.BumpTexPromise, forgetLoading); } } - internal static void ReleaseIntention(World world, ref Promise? promise, bool forgetLoading) + internal static void ReleaseIntention(Entity entity, World world, ref Promise? promise, bool forgetLoading) { if (promise == null) return; @@ -60,6 +61,19 @@ internal static void ReleaseIntention(World world, ref Promise? promise, bool fo if (forgetLoading) promiseValue.ForgetLoading(world); + if (promiseValue.LoadingIntention.IsVideoTexture) + { + ref VideoTextureConsumer consumer = ref world.TryGetRef(entity, out bool hasConsumer); + + if (hasConsumer) + { + ref PrimitiveMeshRendererComponent meshRenderer = ref world.TryGetRef(entity, out bool hasMesh); + + if(hasMesh) + consumer.RemoveConsumerMeshRenderer(meshRenderer.MeshRenderer); + } + } + promiseValue.TryDereference(world); // Nullify the entity reference diff --git a/Explorer/Assets/Scripts/ECS/Unity/Materials/Systems/CleanUpMaterialsSystem.cs b/Explorer/Assets/Scripts/ECS/Unity/Materials/Systems/CleanUpMaterialsSystem.cs index 7d21e3aa1b..e62052eb5b 100644 --- a/Explorer/Assets/Scripts/ECS/Unity/Materials/Systems/CleanUpMaterialsSystem.cs +++ b/Explorer/Assets/Scripts/ECS/Unity/Materials/Systems/CleanUpMaterialsSystem.cs @@ -32,15 +32,15 @@ protected override void Update(float t) [Query] [All(typeof(DeleteEntityIntention))] - private void TryRelease(ref MaterialComponent materialComponent) + private void TryRelease(Entity entity, ref MaterialComponent materialComponent) { - ReleaseMaterial.Execute(World, ref materialComponent, destroyMaterial); + ReleaseMaterial.Execute(entity, World, ref materialComponent, destroyMaterial); } [Query] - private void ReleaseUnconditionally(ref MaterialComponent materialComponent) + private void ReleaseUnconditionally(Entity entity, ref MaterialComponent materialComponent) { - ReleaseMaterial.Execute(World, ref materialComponent, destroyMaterial); + ReleaseMaterial.Execute(entity, World, ref materialComponent, destroyMaterial); } public void FinalizeComponents(in Query query) diff --git a/Explorer/Assets/Scripts/ECS/Unity/Materials/Systems/ResetMaterialSystem.cs b/Explorer/Assets/Scripts/ECS/Unity/Materials/Systems/ResetMaterialSystem.cs index 5a26b49e35..e5c809574e 100644 --- a/Explorer/Assets/Scripts/ECS/Unity/Materials/Systems/ResetMaterialSystem.cs +++ b/Explorer/Assets/Scripts/ECS/Unity/Materials/Systems/ResetMaterialSystem.cs @@ -37,10 +37,10 @@ protected override void Update(float t) [Query] [None(typeof(PBMaterial))] - private void Reset(ref PrimitiveMeshRendererComponent meshRendererComponent, ref MaterialComponent materialComponent) + private void Reset(Entity entity, ref PrimitiveMeshRendererComponent meshRendererComponent, ref MaterialComponent materialComponent) { meshRendererComponent.SetDefaultMaterial(sceneData.Geometry.CircumscribedPlanes, sceneData.Geometry.Height); - ReleaseMaterial.Execute(World, ref materialComponent, destroyMaterial); + ReleaseMaterial.Execute(entity, World, ref materialComponent, destroyMaterial); } } } diff --git a/Explorer/Assets/Scripts/ECS/Unity/Materials/Systems/StartMaterialsLoadingSystem.cs b/Explorer/Assets/Scripts/ECS/Unity/Materials/Systems/StartMaterialsLoadingSystem.cs index 3cefb86d95..d034a212a7 100644 --- a/Explorer/Assets/Scripts/ECS/Unity/Materials/Systems/StartMaterialsLoadingSystem.cs +++ b/Explorer/Assets/Scripts/ECS/Unity/Materials/Systems/StartMaterialsLoadingSystem.cs @@ -70,29 +70,29 @@ private void InvalidateMaterialComponent(Entity entity, ref PBMaterial material, if (MaterialDataEqualityComparer.Equals(in materialComponent.Data, in materialData)) return; - InvalidatePrbInequality(ref materialComponent, ref materialData); + InvalidatePrbInequality(entity, ref materialComponent, ref materialData); MaterialData.TexturesData prevTextureData = materialComponent.Data.Textures; materialComponent.Data = materialData; materialComponent.Status = StreamableLoading.LifeCycle.LoadingInProgress; - World.Set(entity, StartNewMaterialLoad(materialComponent, in prevTextureData, partitionComponent)); + World.Set(entity, StartNewMaterialLoad(entity, materialComponent, in prevTextureData, partitionComponent)); World.AddOrGet(entity, new ShouldInstanceMaterialComponent()); } - private void InvalidatePrbInequality(ref MaterialComponent materialComponent, ref MaterialData materialData) + private void InvalidatePrbInequality(Entity entity, ref MaterialComponent materialComponent, ref MaterialData materialData) { // If isPbr is the same right the same material is reused if (materialComponent.Data.IsPbrMaterial != materialData.IsPbrMaterial) { - ReleaseMaterial.Execute(World!, ref materialComponent, destroyMaterial); + ReleaseMaterial.Execute(entity, World!, ref materialComponent, destroyMaterial); materialComponent.Result = null; } } - private MaterialComponent StartNewMaterialLoad(MaterialComponent materialComponent, in MaterialData.TexturesData prevTexturesData, PartitionComponent partitionComponent) + private MaterialComponent StartNewMaterialLoad(Entity entity, MaterialComponent materialComponent, in MaterialData.TexturesData prevTexturesData, PartitionComponent partitionComponent) { - CreateGetTexturePromises(ref materialComponent, prevTexturesData, partitionComponent); + CreateGetTexturePromises(entity, ref materialComponent, prevTexturesData, partitionComponent); return materialComponent; } @@ -105,7 +105,7 @@ private void CreateMaterialComponent(Entity entity, ref PBMaterial material, ref return; var materialComponent = new MaterialComponent(CreateMaterialData(in material)); - CreateGetTexturePromises(ref materialComponent, null, partitionComponent); + CreateGetTexturePromises(entity, ref materialComponent, null, partitionComponent); materialComponent.Status = StreamableLoading.LifeCycle.LoadingInProgress; World.Add(entity, materialComponent); @@ -148,35 +148,35 @@ private static MaterialData CreatePBRMaterialData( pbMaterial.GetEmissiveIntensity(), pbMaterial.GetDirectIntensity()); - private void CreateGetTexturePromises(ref MaterialComponent materialComponent, + private void CreateGetTexturePromises(Entity entity, ref MaterialComponent materialComponent, in MaterialData.TexturesData? oldTexturesData, PartitionComponent partitionComponent) { - TryCreateGetTexturePromise(in materialComponent.Data.Textures.AlbedoTexture, oldTexturesData?.AlbedoTexture, ref materialComponent.AlbedoTexPromise, partitionComponent); + TryCreateGetTexturePromise(entity, in materialComponent.Data.Textures.AlbedoTexture, oldTexturesData?.AlbedoTexture, ref materialComponent.AlbedoTexPromise, partitionComponent); if (materialComponent.Data.IsPbrMaterial) { - TryCreateGetTexturePromise(in materialComponent.Data.Textures.AlphaTexture, oldTexturesData?.AlphaTexture, ref materialComponent.AlphaTexPromise, partitionComponent); - TryCreateGetTexturePromise(in materialComponent.Data.Textures.EmissiveTexture, oldTexturesData?.EmissiveTexture, ref materialComponent.EmissiveTexPromise, partitionComponent); - TryCreateGetTexturePromise(in materialComponent.Data.Textures.BumpTexture, oldTexturesData?.BumpTexture, ref materialComponent.BumpTexPromise, partitionComponent); + TryCreateGetTexturePromise(entity, in materialComponent.Data.Textures.AlphaTexture, oldTexturesData?.AlphaTexture, ref materialComponent.AlphaTexPromise, partitionComponent); + TryCreateGetTexturePromise(entity, in materialComponent.Data.Textures.EmissiveTexture, oldTexturesData?.EmissiveTexture, ref materialComponent.EmissiveTexPromise, partitionComponent); + TryCreateGetTexturePromise(entity, in materialComponent.Data.Textures.BumpTexture, oldTexturesData?.BumpTexture, ref materialComponent.BumpTexPromise, partitionComponent); } else { - TryCreateGetTexturePromise(in materialComponent.Data.Textures.AlphaTexture, oldTexturesData?.AlphaTexture, ref materialComponent.AlphaTexPromise, partitionComponent); + TryCreateGetTexturePromise(entity, in materialComponent.Data.Textures.AlphaTexture, oldTexturesData?.AlphaTexture, ref materialComponent.AlphaTexPromise, partitionComponent); } } private static MaterialData CreateBasicMaterialData(in PBMaterial pbMaterial, in TextureComponent? albedoTexture, in TextureComponent? alphaTexture) => MaterialData.CreateBasicMaterial(albedoTexture, alphaTexture, pbMaterial.GetAlphaTest(), pbMaterial.GetDiffuseColor(), pbMaterial.GetCastShadows()); - private bool TryCreateGetTexturePromise(in TextureComponent? textureComponent, + private bool TryCreateGetTexturePromise(Entity entity, in TextureComponent? textureComponent, in TextureComponent? oldTextureComponent, ref Promise? promise, PartitionComponent partitionComponent) { if (textureComponent == null) { // If component is being reused forget the previous promise - ReleaseMaterial.ReleaseIntention(World, ref promise, true); + ReleaseMaterial.ReleaseIntention(entity, World, ref promise, true); return false; } @@ -188,7 +188,7 @@ private bool TryCreateGetTexturePromise(in TextureComponent? textureComponent, return false; // If component is being reused forget the previous promise - ReleaseMaterial.ReleaseIntention(World, ref promise, true); + ReleaseMaterial.ReleaseIntention(entity, World, ref promise, true); // TODO this code must be unified to be able to load video textures in a common way if (textureComponentValue.IsVideoTexture) @@ -196,7 +196,7 @@ private bool TryCreateGetTexturePromise(in TextureComponent? textureComponent, var intention = new GetTextureIntention(textureComponentValue.VideoPlayerEntity); promise = Promise.CreateFinalized(intention, - textureComponentValue.TryAddConsumer(entitiesMap, videoTexturesPool, World, out Texture2DData? tex) + textureComponentValue.TryAddConsumer(entity, entitiesMap, videoTexturesPool, World, out Texture2DData? tex) ? new StreamableLoadingResult(tex!) : new StreamableLoadingResult(GetReportCategory(), CreateException(new EcsEntityNotFoundException(textureComponentValue.VideoPlayerEntity, $"Entity {textureComponentValue.VideoPlayerEntity} not found!. VideoTexture will not be created.")))); } diff --git a/Explorer/Assets/Scripts/ECS/Unity/Tests/ECS.Unity.Tests.asmdef b/Explorer/Assets/Scripts/ECS/Unity/Tests/ECS.Unity.Tests.asmdef index 40b51062a3..c36c6e768e 100644 --- a/Explorer/Assets/Scripts/ECS/Unity/Tests/ECS.Unity.Tests.asmdef +++ b/Explorer/Assets/Scripts/ECS/Unity/Tests/ECS.Unity.Tests.asmdef @@ -1,53 +1,49 @@ { - "name": "ECS.Unity.Tests", - "rootNamespace": "", - "references": [ - "GUID:27619889b8ba8c24980f49ee34dbb44a", - "GUID:0acc523941302664db1f4e527237feb3", - "GUID:3c7b57a14671040bd8c549056adc04f5", - "GUID:a3c61f15599a43ae9de508c9c4dd5530", - "GUID:4794e238ed0f65142a4aea5848b513e5", - "GUID:1b8e1e1bd01505f478f0369c04a4fb2f", - "GUID:c2b7e3e0e95f4eb588516c8ae12e919b", - "GUID:6e2b4bed29ad1c549ab19b744f36f388", - "GUID:0f4c0f120707fb74497f5d581b9858f8", - "GUID:d414ef88f3b15f746a4b97636b50dfb4", - "GUID:286980af24684da6acc1caa413039811", - "GUID:fa7b3fdbb04d67549916da7bd2af58ab", - "GUID:f51ebe6a0ceec4240a699833d6309b23", - "GUID:101b8b6ebaf64668909b49c4b7a1420d", - "GUID:fa0cb088e184452c8a89ecdeff7c731d", - "GUID:9e24947de15b9834991c9d8411ea37cf", - "GUID:84651a3751eca9349aac36a66bba901b", - "GUID:9e314663ce958b746873cb22d57ede55", - "GUID:8322ea9340a544c59ddc56d4793eac74", - "GUID:3640f3c0b42946b0b8794a1ed8e06ca5", - "GUID:275e22790c04e9b47a5085d7b0c4432a", - "GUID:78e0b5197588c4841a6544409324031c", - "GUID:4505fcf99e744d9bba6c6de3568145fd", - "GUID:166b65e6dfc848bb9fb075f53c293a38", - "GUID:54660b0fae444b4cbfdafa9d68108f04", - "GUID:fc4fd35fb877e904d8cedee73b2256f6", - "GUID:4a12c0b1b77ec6b418a8d7bd5c925be3" - ], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": true, - "precompiledReferences": [ - "nunit.framework.dll", - "Arch.System.dll", - "Arch.dll", - "Arch.SystemGroups.dll", - "NSubstitute.dll", - "Google.Protobuf.dll" - ], - "autoReferenced": false, - "defineConstraints": [ - "UNITY_INCLUDE_TESTS" - ], - "versionDefines": [], - "noEngineReferences": false + "name": "ECS.Unity.Tests", + "rootNamespace": "", + "references": [ + "GUID:27619889b8ba8c24980f49ee34dbb44a", + "GUID:0acc523941302664db1f4e527237feb3", + "GUID:3c7b57a14671040bd8c549056adc04f5", + "GUID:a3c61f15599a43ae9de508c9c4dd5530", + "GUID:4794e238ed0f65142a4aea5848b513e5", + "GUID:1b8e1e1bd01505f478f0369c04a4fb2f", + "GUID:0f4c0f120707fb74497f5d581b9858f8", + "GUID:d414ef88f3b15f746a4b97636b50dfb4", + "GUID:286980af24684da6acc1caa413039811", + "GUID:fa7b3fdbb04d67549916da7bd2af58ab", + "GUID:f51ebe6a0ceec4240a699833d6309b23", + "GUID:9e24947de15b9834991c9d8411ea37cf", + "GUID:84651a3751eca9349aac36a66bba901b", + "GUID:9e314663ce958b746873cb22d57ede55", + "GUID:8322ea9340a544c59ddc56d4793eac74", + "GUID:3640f3c0b42946b0b8794a1ed8e06ca5", + "GUID:275e22790c04e9b47a5085d7b0c4432a", + "GUID:78e0b5197588c4841a6544409324031c", + "GUID:166b65e6dfc848bb9fb075f53c293a38", + "GUID:54660b0fae444b4cbfdafa9d68108f04", + "GUID:fc4fd35fb877e904d8cedee73b2256f6", + "GUID:4a12c0b1b77ec6b418a8d7bd5c925be3", + "GUID:c80c82a8f4e04453b85fbab973d6774a" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "nunit.framework.dll", + "Arch.System.dll", + "Arch.dll", + "Arch.SystemGroups.dll", + "NSubstitute.dll", + "Google.Protobuf.dll" + ], + "autoReferenced": false, + "defineConstraints": [ + "UNITY_INCLUDE_TESTS" + ], + "versionDefines": [], + "noEngineReferences": false } \ No newline at end of file diff --git a/Explorer/Assets/Scripts/ECS/Unity/Textures/Components/VideoTextureConsumer.cs b/Explorer/Assets/Scripts/ECS/Unity/Textures/Components/VideoTextureConsumer.cs index 106fc2eba2..274ade1652 100644 --- a/Explorer/Assets/Scripts/ECS/Unity/Textures/Components/VideoTextureConsumer.cs +++ b/Explorer/Assets/Scripts/ECS/Unity/Textures/Components/VideoTextureConsumer.cs @@ -1,11 +1,53 @@ using ECS.StreamableLoading.Textures; using System; +using System.Collections.Generic; using UnityEngine; namespace ECS.Unity.Textures.Components { public struct VideoTextureConsumer : IDisposable { + /// + /// Gets the current world position of the maximum corner of the bounding box that contains all the mesh renderers used by video consumers of one texture. + /// + public Vector3 BoundsMax + { + get + { + Vector3 boundsMax = Vector3.one * float.MinValue; + + for (int i = 0; i < renderers.Count; ++i) + { + Vector3 inputBoundsMax = renderers[i].bounds.max; + boundsMax = new Vector3(Mathf.Max(inputBoundsMax.x, boundsMax.x), Mathf.Max(inputBoundsMax.y, boundsMax.y), Mathf.Max(inputBoundsMax.z, boundsMax.z)); + } + + return boundsMax; + } + } + + /// + /// Gets the current world position of the minimum corner of the bounding box that contains all the mesh renderers used by video consumers of one texture. + /// + public Vector3 BoundsMin + { + get + { + Vector3 boundsMin = Vector3.one * float.MaxValue; + + for (int i = 0; i < renderers.Count; ++i) + { + Vector3 inputBoundsMin = renderers[i].bounds.min; + boundsMin = new Vector3(Mathf.Min(inputBoundsMin.x, boundsMin.x), Mathf.Min(inputBoundsMin.y, boundsMin.y), Mathf.Min(inputBoundsMin.z, boundsMin.z)); + } + + return boundsMin; + } + } + + // All the renderers that use the video texture + private readonly List renderers; + /// /// The single copy kept for the single Entity with VideoPlayer, /// we don't use the original texture from AVPro @@ -17,12 +59,32 @@ public struct VideoTextureConsumer : IDisposable public VideoTextureConsumer(Texture2D texture) { Texture = new Texture2DData(texture); + renderers = new List(); } public void Dispose() { // On Dispose video textures are dereferenced by material that acquired it Texture = null!; + renderers.Clear(); + } + + /// + /// Stores a reference to a renderer that consumes the same texture. + /// + /// The renderer using the video texture. + public void AddConsumerMeshRenderer(MeshRenderer renderer) + { + renderers.Add(renderer); + } + + /// + /// Removes a reference to a renderer that was consuming the same texture. + /// + /// The renderer to stop referencing to. + public void RemoveConsumerMeshRenderer(MeshRenderer renderer) + { + renderers.Remove(renderer); } } } diff --git a/Explorer/Assets/Scripts/ECS/Unity/Textures/Utils/VideoTextureUtils.cs b/Explorer/Assets/Scripts/ECS/Unity/Textures/Utils/VideoTextureUtils.cs index 8e36d25ae6..d3dd9b0e9d 100644 --- a/Explorer/Assets/Scripts/ECS/Unity/Textures/Utils/VideoTextureUtils.cs +++ b/Explorer/Assets/Scripts/ECS/Unity/Textures/Utils/VideoTextureUtils.cs @@ -1,6 +1,7 @@ using Arch.Core; using CRDT; using ECS.StreamableLoading.Textures; +using ECS.Unity.PrimitiveRenderer.Components; using ECS.Unity.Textures.Components; using System.Collections.Generic; using UnityEngine; @@ -12,6 +13,7 @@ public static class VideoTextureUtils { public static bool TryAddConsumer( this in TextureComponent textureComponent, + Entity entity, IReadOnlyDictionary entitiesMap, IObjectPool videoTexturesPool, World world, @@ -27,9 +29,14 @@ public static bool TryAddConsumer( consumer = ref world.Get(videoPlayerEntity); } - texture = consumer.Texture; texture.AddReference(); + + ref PrimitiveMeshRendererComponent meshRenderer = ref world.TryGetRef(entity, out bool hasMesh); + + if (hasMesh) + consumer.AddConsumerMeshRenderer(meshRenderer.MeshRenderer); + return true; } diff --git a/Explorer/Assets/Scripts/Global/StaticContainer.cs b/Explorer/Assets/Scripts/Global/StaticContainer.cs index f6bc7691e8..e3e627d4bf 100644 --- a/Explorer/Assets/Scripts/Global/StaticContainer.cs +++ b/Explorer/Assets/Scripts/Global/StaticContainer.cs @@ -1,4 +1,4 @@ -using Arch.Core; +using Arch.Core; using CrdtEcsBridge.Components; using Cysharp.Threading.Tasks; using DCL.AssetsProvision; @@ -229,7 +229,7 @@ await UniTask.WhenAll( container.CharacterContainer.CreateWorldPlugin(componentsContainer.ComponentPoolsRegistry), new AnimatorPlugin(), new TweenPlugin(), - new MediaPlayerPlugin(sharedDependencies, videoTexturePool, sharedDependencies.FrameTimeBudget, container.assetsProvisioner, container.WebRequestsContainer.WebRequestController, container.CacheCleaner, worldVolumeMacBus), + new MediaPlayerPlugin(sharedDependencies, videoTexturePool, sharedDependencies.FrameTimeBudget, container.assetsProvisioner, container.WebRequestsContainer.WebRequestController, container.CacheCleaner, worldVolumeMacBus, exposedGlobalDataContainer.ExposedCameraData), new CharacterTriggerAreaPlugin(globalWorld, container.MainPlayerAvatarBaseProxy, exposedGlobalDataContainer.ExposedCameraData.CameraEntityProxy, container.CharacterContainer.CharacterObject, componentsContainer.ComponentPoolsRegistry, container.assetsProvisioner, container.CacheCleaner, exposedGlobalDataContainer.ExposedCameraData, container.SceneRestrictionBusController, web3IdentityProvider), new InteractionsAudioPlugin(container.assetsProvisioner), new MapPinPlugin(globalWorld, container.FeatureFlagsCache), diff --git a/Explorer/Assets/Scripts/Global/Tests/PlayMode/Integration Tests Global Container.asset b/Explorer/Assets/Scripts/Global/Tests/PlayMode/Integration Tests Global Container.asset index 94800bf986..b3a0c2c17a 100644 --- a/Explorer/Assets/Scripts/Global/Tests/PlayMode/Integration Tests Global Container.asset +++ b/Explorer/Assets/Scripts/Global/Tests/PlayMode/Integration Tests Global Container.asset @@ -51,6 +51,11 @@ MonoBehaviour: m_SubObjectName: m_SubObjectType: m_EditorAssetChanged: 0 + k__BackingField: + m_AssetGUID: 12f48d0297bd3f746b92a97878478086 + m_SubObjectName: + m_SubObjectType: + m_EditorAssetChanged: 0 k__BackingField: m_AssetGUID: 0703f7736b8c9b244953ae7c6ff9a037 m_SubObjectName: @@ -64,16 +69,6 @@ MonoBehaviour: - rid: 6784895265395441664 type: {class: StaticSettings, ns: DCL.PluginSystem.Global, asm: DCL.Plugins} data: - k__BackingField: - m_AssetGUID: 0dd75559898ca8d4db9fc8ab99ac2269 - m_SubObjectName: - m_SubObjectType: - m_EditorAssetChanged: 0 - k__BackingField: - m_AssetGUID: 6c1c35a66af59874a8373ebcd51572a4 - m_SubObjectName: - m_SubObjectType: - m_EditorAssetChanged: 0 k__BackingField: m_AssetGUID: 8d266ff458e71f2439f9c30bd7e68d4a m_SubObjectName: @@ -84,9 +79,11 @@ MonoBehaviour: m_SubObjectName: m_SubObjectType: m_EditorAssetChanged: 0 - k__BackingField: 33 + frameTimeCap: 33 + frameTimeCapDeepProfiler: 300 k__BackingField: 100 k__BackingField: 50 + k__BackingField: 20 - rid: 6784895265412481024 type: {class: CharacterCameraSettings, ns: DCL.PluginSystem.Global, asm: DCL.Plugins} data: @@ -100,6 +97,11 @@ MonoBehaviour: m_SubObjectName: m_SubObjectType: m_EditorAssetChanged: 0 + k__BackingField: + m_AssetGUID: + m_SubObjectName: + m_SubObjectType: + m_EditorAssetChanged: 0 - rid: 6784895265412481025 type: {class: CharacterMotionSettings, ns: DCL.PluginSystem.Global, asm: DCL.Plugins} data: diff --git a/Explorer/Assets/Scripts/Global/Tests/PlayMode/Integration Tests World Container.asset b/Explorer/Assets/Scripts/Global/Tests/PlayMode/Integration Tests World Container.asset index 33b7dcd92c..c45f98717d 100644 --- a/Explorer/Assets/Scripts/Global/Tests/PlayMode/Integration Tests World Container.asset +++ b/Explorer/Assets/Scripts/Global/Tests/PlayMode/Integration Tests World Container.asset @@ -34,6 +34,11 @@ MonoBehaviour: m_SubObjectName: m_SubObjectType: m_EditorAssetChanged: 0 + VideoPrioritizationSettings: + m_AssetGUID: 12f48d0297bd3f746b92a97878478086 + m_SubObjectName: + m_SubObjectType: + m_EditorAssetChanged: 0 - rid: 758312634468794373 type: {class: AudioSourcesPlugin/AudioSourcesPluginSettings, ns: DCL.PluginSystem.World, asm: DCL.Plugins} data: diff --git a/Explorer/ProjectSettings/QualitySettings.asset b/Explorer/ProjectSettings/QualitySettings.asset index d60851f79e..34673fac21 100644 --- a/Explorer/ProjectSettings/QualitySettings.asset +++ b/Explorer/ProjectSettings/QualitySettings.asset @@ -4,7 +4,7 @@ QualitySettings: m_ObjectHideFlags: 0 serializedVersion: 5 - m_CurrentQuality: 0 + m_CurrentQuality: 2 m_QualitySettings: - serializedVersion: 3 name: Low @@ -30,7 +30,7 @@ QualitySettings: useLegacyDetailDistribution: 0 vSyncCount: 0 realtimeGICPUUsage: 25 - lodBias: 0.75 + lodBias: 1 maximumLODLevel: 0 enableLODCrossFade: 1 streamingMipmapsActive: 1 @@ -47,9 +47,9 @@ QualitySettings: customRenderPipeline: {fileID: 11400000, guid: 362b7d6d8bc7d8a4caba9aa7515a5f6d, type: 2} terrainQualityOverrides: 12 terrainPixelError: 1 - terrainDetailDensityScale: 0.3 + terrainDetailDensityScale: 0.7 terrainBasemapDistance: 1000 - terrainDetailDistance: 75 + terrainDetailDistance: 150 terrainTreeDistance: 5000 terrainBillboardStart: 50 terrainFadeLength: 5 @@ -79,7 +79,7 @@ QualitySettings: useLegacyDetailDistribution: 1 vSyncCount: 0 realtimeGICPUUsage: 25 - lodBias: 1.25 + lodBias: 1 maximumLODLevel: 0 enableLODCrossFade: 1 streamingMipmapsActive: 1 @@ -96,9 +96,9 @@ QualitySettings: customRenderPipeline: {fileID: 11400000, guid: c7655666771b41447aa2994cf82e2fc7, type: 2} terrainQualityOverrides: 0 terrainPixelError: 1 - terrainDetailDensityScale: 1 + terrainDetailDensityScale: 0.7 terrainBasemapDistance: 1000 - terrainDetailDistance: 300 + terrainDetailDistance: 150 terrainTreeDistance: 5000 terrainBillboardStart: 50 terrainFadeLength: 5