From c47a5f3f41529389eb3a551fc3d2cccb25c20fbd Mon Sep 17 00:00:00 2001 From: Fran Colarich <56565104+fcolarich@users.noreply.github.com> Date: Tue, 22 Oct 2024 11:23:36 +0200 Subject: [PATCH 01/16] fix: tweaked cursor values so they properly align with real cursor (#2526) --- Explorer/Assets/DCL/Input/Assets/Cursor.png.meta | 4 ++-- .../Assets/DCL/Input/Assets/CursorInteractive.png.meta | 4 ++-- Explorer/Assets/DCL/Input/Assets/CursorSettings.asset | 2 ++ Explorer/Assets/DCL/Input/Crosshair/Crosshair.uxml | 4 ++-- Explorer/Assets/DCL/Input/CursorSettings.cs | 3 +++ Explorer/Assets/DCL/Input/DCLCursor.cs | 10 +++++++--- .../Scripts/Global/Dynamic/DynamicWorldContainer.cs | 4 ++-- 7 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Explorer/Assets/DCL/Input/Assets/Cursor.png.meta b/Explorer/Assets/DCL/Input/Assets/Cursor.png.meta index 5e7a6f4631..fe4fc320c3 100644 --- a/Explorer/Assets/DCL/Input/Assets/Cursor.png.meta +++ b/Explorer/Assets/DCL/Input/Assets/Cursor.png.meta @@ -3,7 +3,7 @@ guid: bf22911f490866b45b81ddea869255f2 TextureImporter: internalIDToNameTable: [] externalObjects: {} - serializedVersion: 12 + serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 @@ -69,7 +69,7 @@ TextureImporter: platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform - maxTextureSize: 32 + maxTextureSize: 64 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 diff --git a/Explorer/Assets/DCL/Input/Assets/CursorInteractive.png.meta b/Explorer/Assets/DCL/Input/Assets/CursorInteractive.png.meta index ec9086344b..e32bfad7e6 100644 --- a/Explorer/Assets/DCL/Input/Assets/CursorInteractive.png.meta +++ b/Explorer/Assets/DCL/Input/Assets/CursorInteractive.png.meta @@ -3,7 +3,7 @@ guid: 23dcf75316411d344be316dc2cb0e41f TextureImporter: internalIDToNameTable: [] externalObjects: {} - serializedVersion: 12 + serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 @@ -69,7 +69,7 @@ TextureImporter: platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform - maxTextureSize: 32 + maxTextureSize: 64 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 diff --git a/Explorer/Assets/DCL/Input/Assets/CursorSettings.asset b/Explorer/Assets/DCL/Input/Assets/CursorSettings.asset index 78439f6019..379e0ef701 100644 --- a/Explorer/Assets/DCL/Input/Assets/CursorSettings.asset +++ b/Explorer/Assets/DCL/Input/Assets/CursorSettings.asset @@ -17,8 +17,10 @@ MonoBehaviour: m_SubObjectName: m_SubObjectType: m_EditorAssetChanged: 1 + k__BackingField: {x: 5, y: 3} k__BackingField: m_AssetGUID: 23dcf75316411d344be316dc2cb0e41f m_SubObjectName: m_SubObjectType: m_EditorAssetChanged: 0 + k__BackingField: {x: 9, y: 3} diff --git a/Explorer/Assets/DCL/Input/Crosshair/Crosshair.uxml b/Explorer/Assets/DCL/Input/Crosshair/Crosshair.uxml index 8a6084ff53..d1255c1922 100644 --- a/Explorer/Assets/DCL/Input/Crosshair/Crosshair.uxml +++ b/Explorer/Assets/DCL/Input/Crosshair/Crosshair.uxml @@ -1,6 +1,6 @@ - - + + diff --git a/Explorer/Assets/DCL/Input/CursorSettings.cs b/Explorer/Assets/DCL/Input/CursorSettings.cs index cf637e1544..28ffdb1f80 100644 --- a/Explorer/Assets/DCL/Input/CursorSettings.cs +++ b/Explorer/Assets/DCL/Input/CursorSettings.cs @@ -7,6 +7,9 @@ namespace DCL.Input public class CursorSettings : ScriptableObject { [field: SerializeField] public AssetReferenceTexture2D NormalCursor { get; private set; } + [field: SerializeField] public Vector2 NormalCursorHotspot { get; private set; } + [field: SerializeField] public AssetReferenceTexture2D InteractionCursor { get; private set; } + [field: SerializeField] public Vector2 InteractionCursorHotspot { get; private set; } } } diff --git a/Explorer/Assets/DCL/Input/DCLCursor.cs b/Explorer/Assets/DCL/Input/DCLCursor.cs index bba6963f86..c9a7da2464 100644 --- a/Explorer/Assets/DCL/Input/DCLCursor.cs +++ b/Explorer/Assets/DCL/Input/DCLCursor.cs @@ -14,12 +14,16 @@ public class DCLCursor : ICursor private readonly IEventSystem eventSystem; private readonly Texture2D normalCursor; private readonly Texture2D interactionCursor; + private readonly Vector2 normalCursorHotspot; + private readonly Vector2 interactionCursorHotspot; private CursorStyle cursorStyle = CursorStyle.None; - public DCLCursor(Texture2D normalCursor, Texture2D interactionCursor) + public DCLCursor(Texture2D normalCursor, Texture2D interactionCursor, Vector2 normalCursorHotspot, Vector2 interactionCursorHotspot) { this.normalCursor = normalCursor; this.interactionCursor = interactionCursor; + this.normalCursorHotspot = normalCursorHotspot; + this.interactionCursorHotspot = interactionCursorHotspot; SetStyle(CursorStyle.Normal); } @@ -51,10 +55,10 @@ public void SetStyle(CursorStyle style) switch (cursorStyle) { case CursorStyle.Normal: - Cursor.SetCursor(normalCursor, Vector2.zero, CursorMode.Auto); + Cursor.SetCursor(normalCursor, normalCursorHotspot, CursorMode.Auto); return; case CursorStyle.Interaction: - Cursor.SetCursor(interactionCursor, Vector2.zero, CursorMode.Auto); + Cursor.SetCursor(interactionCursor, interactionCursorHotspot, CursorMode.Auto); return; default: Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto); diff --git a/Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs b/Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs index f2db9d42fd..2a54f48265 100644 --- a/Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs +++ b/Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs @@ -138,7 +138,7 @@ public class DynamicWorldContainer : DCLWorldContainer public IRoomHub RoomHub { get; private set; } = null!; private MultiplayerMovementMessageBus? multiplayerMovementMessageBus; - + public override void Dispose() { @@ -196,7 +196,7 @@ async UniTask InitializeContainersAsync(IPluginSettingsContainer settingsContain ProvidedAsset multiplayerDebugSettings = await assetsProvisioner.ProvideMainAssetAsync(dynamicSettings.MultiplayerDebugSettings, ct); var unityEventSystem = new UnityEventSystem(EventSystem.current.EnsureNotNull()); - var dclCursor = new DCLCursor(normalCursorAsset.Value, interactionCursorAsset.Value); + var dclCursor = new DCLCursor(normalCursorAsset.Value, interactionCursorAsset.Value, cursorSettings.NormalCursorHotspot, cursorSettings.InteractionCursorHotspot); staticContainer.QualityContainer.AddDebugViews(debugBuilder); From 39754cdaf88e9d5332f02fb669e5f883db96a23a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 11:53:15 +0100 Subject: [PATCH 02/16] chore: sync main to dev (#2531) Signed-off-by: Ashley Canning Co-authored-by: Ashley Canning Co-authored-by: Aga --- .github/workflows/build-release-main-page.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build-release-main-page.yml b/.github/workflows/build-release-main-page.yml index 3854fb3a38..c7ff29ac2a 100644 --- a/.github/workflows/build-release-main-page.yml +++ b/.github/workflows/build-release-main-page.yml @@ -36,6 +36,9 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: 'main' - name: Apply tag to branch run: | From 2c9df4c82d6e32f9fcf54e74187166c268184188 Mon Sep 17 00:00:00 2001 From: Pravus Date: Tue, 22 Oct 2024 21:50:22 +0200 Subject: [PATCH 03/16] fix: unreliable 'playing' video event (#2474) --- .../Components/MediaPlayerComponent.cs | 2 ++ .../Systems/CreateMediaPlayerSystem.cs | 2 ++ .../MediaStream/Systems/VideoEventsSystem.cs | 34 ++++++++++++++----- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Components/MediaPlayerComponent.cs b/Explorer/Assets/DCL/SDKComponents/MediaStream/Components/MediaPlayerComponent.cs index 46dccf86e1..f6678cc273 100644 --- a/Explorer/Assets/DCL/SDKComponents/MediaStream/Components/MediaPlayerComponent.cs +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Components/MediaPlayerComponent.cs @@ -17,6 +17,8 @@ public struct MediaPlayerComponent public string URL; public VideoState State; + public double PreviousPlayingTimeCheck; + public float LastStateChangeTime; public CancellationTokenSource Cts; public OpenMediaPromise OpenMediaPromise; diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/CreateMediaPlayerSystem.cs b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/CreateMediaPlayerSystem.cs index 89239e7764..58a1759fd0 100644 --- a/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/CreateMediaPlayerSystem.cs +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/CreateMediaPlayerSystem.cs @@ -84,6 +84,8 @@ private MediaPlayerComponent CreateMediaPlayerComponent(Entity entity, string ur MediaPlayer = mediaPlayerPool.Get(), URL = url, State = url.IsValidUrl() ? VideoState.VsNone : VideoState.VsError, + PreviousPlayingTimeCheck = -1, + LastStateChangeTime = -1, Cts = new CancellationTokenSource(), OpenMediaPromise = new OpenMediaPromise(), }; diff --git a/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/VideoEventsSystem.cs b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/VideoEventsSystem.cs index e9e4326272..7f715f77cc 100644 --- a/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/VideoEventsSystem.cs +++ b/Explorer/Assets/DCL/SDKComponents/MediaStream/Systems/VideoEventsSystem.cs @@ -12,7 +12,7 @@ using ECS.Groups; using RenderHeads.Media.AVProVideo; using SceneRunner.Scene; -using System; +using UnityEngine; namespace DCL.SDKComponents.MediaStream { @@ -21,6 +21,8 @@ namespace DCL.SDKComponents.MediaStream [ThrottlingEnabled] public partial class VideoEventsSystem : BaseUnityLoopSystem { + private const float MAX_VIDEO_FROZEN_SECONDS_BEFORE_ERROR = 10f; + private readonly IECSToCRDTWriter ecsToCRDTWriter; private readonly ISceneStateProvider sceneStateProvider; private readonly IComponentPool componentPool; @@ -45,9 +47,11 @@ private void PropagateVideoEvents(ref CRDTEntity sdkEntity, ref MediaPlayerCompo { if (!frameTimeBudget.TrySpendBudget()) return; - VideoState newState = GetCurrentVideoState(mediaPlayer.MediaPlayer.Control); + VideoState newState = GetCurrentVideoState(mediaPlayer.MediaPlayer.Control, mediaPlayer.PreviousPlayingTimeCheck, mediaPlayer.LastStateChangeTime); if (mediaPlayer.State == newState) return; + mediaPlayer.LastStateChangeTime = Time.realtimeSinceStartup; + mediaPlayer.PreviousPlayingTimeCheck = mediaPlayer.MediaPlayer.Control.GetCurrentTime(); mediaPlayer.State = newState; AppendMessage(in sdkEntity, in mediaPlayer); @@ -70,17 +74,29 @@ private void AppendMessage(in CRDTEntity sdkEntity, in MediaPlayerComponent medi ); } - private static VideoState GetCurrentVideoState(IMediaControl mediaPlayerControl) + private static VideoState GetCurrentVideoState(IMediaControl mediaPlayerControl, double previousPlayingTimeCheck, float lastStateChangeTime) { - if (mediaPlayerControl.IsPlaying()) return VideoState.VsPlaying; - if (mediaPlayerControl.IsPaused()) return VideoState.VsPaused; - if (mediaPlayerControl.IsFinished()) return VideoState.VsNone; - if (mediaPlayerControl.IsBuffering()) return VideoState.VsBuffering; - if (mediaPlayerControl.IsSeeking()) return VideoState.VsSeeking; + // Important: while PLAYING or PAUSED, MediaPlayerControl may also be BUFFERING and/or SEEKING. + if (mediaPlayerControl.IsFinished()) return VideoState.VsNone; if (mediaPlayerControl.GetLastError() != ErrorCode.None) return VideoState.VsError; + if (mediaPlayerControl.IsPaused()) return VideoState.VsPaused; + + VideoState state = VideoState.VsNone; + if (mediaPlayerControl.IsPlaying()) + { + state = VideoState.VsPlaying; + + if (mediaPlayerControl.GetCurrentTime().Equals(previousPlayingTimeCheck)) // Video is frozen + { + state = mediaPlayerControl.IsSeeking() ? VideoState.VsSeeking : VideoState.VsBuffering; - return VideoState.VsNone; + // If the seeking/buffering never ends, update state with error so the scene can react + if ((Time.realtimeSinceStartup - lastStateChangeTime) > MAX_VIDEO_FROZEN_SECONDS_BEFORE_ERROR) + state = VideoState.VsError; + } + } + return state; } } } From 72c08f0d26f692afb08b3b22612cef51cbccdb99 Mon Sep 17 00:00:00 2001 From: davidejensen Date: Tue, 22 Oct 2024 22:27:39 +0200 Subject: [PATCH 04/16] Fix: avoid movement blocking to affect when closing emoji search (#2529) --- Explorer/Assets/DCL/Chat/ChatController.cs | 6 +++--- .../DCL/EmojiPanel/EmojiPanelController.cs | 5 ++--- .../DCL/EmojiPanel/EmojiSearchController.cs | 21 +------------------ 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/Explorer/Assets/DCL/Chat/ChatController.cs b/Explorer/Assets/DCL/Chat/ChatController.cs index 907b393d8e..d0603cc217 100644 --- a/Explorer/Assets/DCL/Chat/ChatController.cs +++ b/Explorer/Assets/DCL/Chat/ChatController.cs @@ -109,12 +109,12 @@ IInputBlock inputBlock protected override void OnViewInstantiated() { cameraEntity = world.CacheCamera(); - + //We start processing messages once the view is ready chatMessagesBus.MessageAdded += OnMessageAdded; chatHistory.OnMessageAdded += CreateChatEntry; chatHistory.OnCleared += ChatHistoryOnOnCleared; - + viewInstance!.OnChatViewPointerEnter += OnChatViewPointerEnter; viewInstance.OnChatViewPointerExit += OnChatViewPointerExit; viewInstance.CharacterCounter.SetMaximumLength(viewInstance.InputField.characterLimit); @@ -124,7 +124,7 @@ protected override void OnViewInstantiated() viewInstance.InputField.onDeselect.AddListener(OnInputDeselected); viewInstance.CloseChatButton.onClick.AddListener(CloseChat); viewInstance.LoopList.InitListView(0, OnGetItemByIndex); - emojiPanelController = new EmojiPanelController(viewInstance.EmojiPanel, emojiPanelConfiguration, emojiMappingJson, emojiSectionViewPrefab, emojiButtonPrefab, inputBlock); + emojiPanelController = new EmojiPanelController(viewInstance.EmojiPanel, emojiPanelConfiguration, emojiMappingJson, emojiSectionViewPrefab, emojiButtonPrefab); emojiPanelController.OnEmojiSelected += AddEmojiToInput; emojiSuggestionPanelController = new EmojiSuggestionPanel(viewInstance.EmojiSuggestionPanel, emojiSuggestionViewPrefab, dclInput); diff --git a/Explorer/Assets/DCL/EmojiPanel/EmojiPanelController.cs b/Explorer/Assets/DCL/EmojiPanel/EmojiPanelController.cs index 803e149809..57b553652a 100644 --- a/Explorer/Assets/DCL/EmojiPanel/EmojiPanelController.cs +++ b/Explorer/Assets/DCL/EmojiPanel/EmojiPanelController.cs @@ -38,14 +38,13 @@ public EmojiPanelController( EmojiPanelConfigurationSO emojiPanelConfiguration, TextAsset emojiMappingJson, EmojiSectionView emojiSectionPrefab, - EmojiButton emojiButtonPrefab, - IInputBlock inputBlock) + EmojiButton emojiButtonPrefab) { this.view = view; this.emojiPanelConfiguration = emojiPanelConfiguration; this.emojiSectionPrefab = emojiSectionPrefab; this.emojiButtonPrefab = emojiButtonPrefab; - emojiSearchController = new EmojiSearchController(view.SearchPanelView, view.EmojiSearchedContent, emojiButtonPrefab, inputBlock); + emojiSearchController = new EmojiSearchController(view.SearchPanelView, view.EmojiSearchedContent, emojiButtonPrefab); emojiSearchController.OnSearchTextChanged += OnSearchTextChanged; emojiSearchController.OnEmojiSelected += emoji => OnEmojiSelected?.Invoke(emoji); foreach (var emojiData in JsonConvert.DeserializeObject>(emojiMappingJson.text)) diff --git a/Explorer/Assets/DCL/EmojiPanel/EmojiSearchController.cs b/Explorer/Assets/DCL/EmojiPanel/EmojiSearchController.cs index 9487826c37..2b44cf5461 100644 --- a/Explorer/Assets/DCL/EmojiPanel/EmojiSearchController.cs +++ b/Explorer/Assets/DCL/EmojiPanel/EmojiSearchController.cs @@ -19,16 +19,12 @@ public class EmojiSearchController private CancellationTokenSource cts; private readonly IObjectPool searchItemsPool; private readonly List usedPoolItems = new (); - private readonly IInputBlock inputBlock; - public EmojiSearchController(SearchBarView view, Transform parent, EmojiButton emojiButton, IInputBlock inputBlock) + public EmojiSearchController(SearchBarView view, Transform parent, EmojiButton emojiButton) { this.view = view; - this.inputBlock = inputBlock; view.inputField.onValueChanged.AddListener(OnValueChanged); - view.inputField.onSelect.AddListener(BlockUnwantedInputs); - view.inputField.onDeselect.AddListener(UnblockUnwantedInputs); view.clearSearchButton.onClick.AddListener(ClearSearch); view.clearSearchButton.gameObject.SetActive(false); @@ -44,24 +40,9 @@ public void Dispose() { ReleaseAllSearchResults(); view.inputField.onValueChanged.RemoveListener(OnValueChanged); - view.inputField.onSelect.RemoveListener(BlockUnwantedInputs); - view.inputField.onDeselect.RemoveListener(UnblockUnwantedInputs); view.clearSearchButton.onClick.RemoveListener(ClearSearch); } - private void BlockUnwantedInputs(string _) - { - inputBlock.Disable(InputMapComponent.Kind.SHORTCUTS , InputMapComponent.Kind.PLAYER); - } - - private void UnblockUnwantedInputs(string _) => - UnblockUnwantedInputs(); - - private void UnblockUnwantedInputs() - { - inputBlock.Enable(InputMapComponent.Kind.SHORTCUTS , InputMapComponent.Kind.PLAYER); - } - private EmojiButton CreatePoolElements(Transform parent, EmojiButton emojiButton) { EmojiButton poolElement = Object.Instantiate(emojiButton, parent); From 1e3a49a6d35193931779dc8c2a58b13e2a054bf9 Mon Sep 17 00:00:00 2001 From: Vitaly Popuzin <35366872+popuz@users.noreply.github.com> Date: Wed, 23 Oct 2024 10:20:12 +0300 Subject: [PATCH 05/16] Fix: zero lookAt rotation in multiplayer (#2540) ## What does this PR change? additional check for zero vector doesn't produces spikes anymore ![image](https://github.com/user-attachments/assets/c75188ca-4eec-492c-943c-c12fc25eed45) ## How to test the changes? just fast smoke test --- .../Assets/DCL/Multiplayer/Movement/Interpolation.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Explorer/Assets/DCL/Multiplayer/Movement/Interpolation.cs b/Explorer/Assets/DCL/Multiplayer/Movement/Interpolation.cs index 3b72863442..88c5c920fe 100644 --- a/Explorer/Assets/DCL/Multiplayer/Movement/Interpolation.cs +++ b/Explorer/Assets/DCL/Multiplayer/Movement/Interpolation.cs @@ -40,15 +40,11 @@ public static float Execute(float deltaTime, ref CharacterTransform transComp, r private static void LookAt(float dt, ref CharacterTransform transComp, Vector3 lookDirection, float rotationSpeed, float yRotation, bool instant, bool useMessageRotation) { - Quaternion lookRotation; + lookDirection.y = 0; // Flattened to have ground plane direction only (XZ) - if (lookDirection != Vector3.zero) - { - lookDirection.y = 0; // Flattened to have ground plane direction only (XZ) - lookRotation = Quaternion.LookRotation(lookDirection, Vector3.up); - } - else - lookRotation = transComp.Transform.rotation; + Quaternion lookRotation = lookDirection != Vector3.zero + ? Quaternion.LookRotation(lookDirection, Vector3.up) + : transComp.Transform.rotation; if (useMessageRotation) lookRotation.eulerAngles = new Vector3(lookRotation.eulerAngles.x, yRotation, lookRotation.eulerAngles.z); From 59f0c4100c79f9bc83c5ffb355937132a47eae97 Mon Sep 17 00:00:00 2001 From: davidejensen Date: Wed, 23 Oct 2024 11:10:21 +0200 Subject: [PATCH 06/16] fix: removed rich text from chat (#2544) --- Explorer/Assets/DCL/Chat/Assets/Chat.prefab | 6 +++--- Explorer/Assets/DCL/Chat/Assets/ChatEntry.prefab | 2 +- Explorer/Assets/DCL/Chat/Assets/ChatEntryOwn.prefab | 2 +- Explorer/Assets/DCL/NameTags/Assets/NametagObject.prefab | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Explorer/Assets/DCL/Chat/Assets/Chat.prefab b/Explorer/Assets/DCL/Chat/Assets/Chat.prefab index 0589dd369c..5614eccb6c 100644 --- a/Explorer/Assets/DCL/Chat/Assets/Chat.prefab +++ b/Explorer/Assets/DCL/Chat/Assets/Chat.prefab @@ -213,7 +213,7 @@ MonoBehaviour: m_TargetGraphic: {fileID: 2680055985081135439} m_HandleRect: {fileID: 7426884741399343867} m_Direction: 2 - m_Value: 1 + m_Value: 0 m_Size: 1 m_NumberOfSteps: 0 m_OnValueChanged: @@ -505,7 +505,7 @@ MonoBehaviour: m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 1 checkPaddingRequired: 0 - m_isRichText: 1 + m_isRichText: 0 m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 @@ -1379,7 +1379,7 @@ MonoBehaviour: m_CaretBlinkRate: 0.85 m_CaretWidth: 2 m_ReadOnly: 0 - m_RichText: 1 + m_RichText: 0 m_GlobalFontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_OnFocusSelectAll: 0 m_ResetOnDeActivation: 1 diff --git a/Explorer/Assets/DCL/Chat/Assets/ChatEntry.prefab b/Explorer/Assets/DCL/Chat/Assets/ChatEntry.prefab index 1313e194e1..a1c5e5a867 100644 --- a/Explorer/Assets/DCL/Chat/Assets/ChatEntry.prefab +++ b/Explorer/Assets/DCL/Chat/Assets/ChatEntry.prefab @@ -801,7 +801,7 @@ MonoBehaviour: m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 - m_isRichText: 1 + m_isRichText: 0 m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 diff --git a/Explorer/Assets/DCL/Chat/Assets/ChatEntryOwn.prefab b/Explorer/Assets/DCL/Chat/Assets/ChatEntryOwn.prefab index bf2ef47098..44a59827b7 100644 --- a/Explorer/Assets/DCL/Chat/Assets/ChatEntryOwn.prefab +++ b/Explorer/Assets/DCL/Chat/Assets/ChatEntryOwn.prefab @@ -207,7 +207,7 @@ MonoBehaviour: m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 - m_isRichText: 1 + m_isRichText: 0 m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 diff --git a/Explorer/Assets/DCL/NameTags/Assets/NametagObject.prefab b/Explorer/Assets/DCL/NameTags/Assets/NametagObject.prefab index 84a371ce52..1f93afeca2 100644 --- a/Explorer/Assets/DCL/NameTags/Assets/NametagObject.prefab +++ b/Explorer/Assets/DCL/NameTags/Assets/NametagObject.prefab @@ -396,7 +396,7 @@ MonoBehaviour: m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 - m_isRichText: 1 + m_isRichText: 0 m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 0 @@ -539,7 +539,7 @@ SpriteRenderer: m_Size: {x: 0.6, y: 0.6} m_AdaptiveModeThreshold: 0.5 m_SpriteTileMode: 0 - m_WasSpriteAssigned: 1 + m_WasSpriteAssigned: 0 m_MaskInteraction: 0 m_SpriteSortPoint: 0 --- !u!1 &8873411207359884927 From 12012c7fb2fc2eb17f72ffb7b5f47f89d6225cba Mon Sep 17 00:00:00 2001 From: Alex Villalba Date: Wed, 23 Oct 2024 11:52:21 +0200 Subject: [PATCH 07/16] fix: The outline of text shapes is wrong when created (#2537) When the cached TextMeshPro instances were reused and the new outline width equaled zero, it tried to disable the outline shader keyword which does not exist in the shader (so the previous values related to outline stayed the same and were still used). Now it also resets the values of the related properties. --- .../TextShape/TMPProSdkExtensions.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Explorer/Assets/DCL/SDKComponents/TextShape/TMPProSdkExtensions.cs b/Explorer/Assets/DCL/SDKComponents/TextShape/TMPProSdkExtensions.cs index 8798d6fd88..58c3073600 100644 --- a/Explorer/Assets/DCL/SDKComponents/TextShape/TMPProSdkExtensions.cs +++ b/Explorer/Assets/DCL/SDKComponents/TextShape/TMPProSdkExtensions.cs @@ -64,8 +64,12 @@ public static void Apply(this TextMeshPro tmpText, PBTextShape textShape, IFonts materialPropertyBlock.SetColor(ID_OUTLINE_COLOR, textShape.OutlineColor?.ToUnityColor() ?? Color.white); materialPropertyBlock.SetFloat(ID_OUTLINE_WIDTH, textShape.OutlineWidth); } - else if (tmpText.fontMaterial.IsKeywordEnabled(OUTLINE_ON_KEYWORD)) + else + { tmpText.fontMaterial.DisableKeyword(OUTLINE_ON_KEYWORD); + materialPropertyBlock.SetColor(ID_OUTLINE_COLOR, Color.clear); + materialPropertyBlock.SetFloat(ID_OUTLINE_WIDTH, 0.0f); + } if (textShape.ShadowOffsetX != 0 || textShape.ShadowOffsetY != 0) { @@ -75,8 +79,15 @@ public static void Apply(this TextMeshPro tmpText, PBTextShape textShape, IFonts materialPropertyBlock.SetFloat(ID_UNDERLAY_OFFSET_X, textShape.ShadowOffsetX); materialPropertyBlock.SetFloat(ID_UNDERLAY_OFFSET_Y, textShape.ShadowOffsetY); } - else if (tmpText.fontMaterial.IsKeywordEnabled(UNDERLAY_ON_KEYWORD)) + else + { tmpText.fontMaterial.DisableKeyword(UNDERLAY_ON_KEYWORD); + materialPropertyBlock.SetColor(ID_UNDERLAY_COLOR, Color.clear); + materialPropertyBlock.SetFloat(ID_UNDERLAY_SOFTNESS, 0.0f); + materialPropertyBlock.SetFloat(ID_UNDERLAY_OFFSET_X, 0.0f); + materialPropertyBlock.SetFloat(ID_UNDERLAY_OFFSET_Y, 0.0f); + } + tmpText.renderer.SetPropertyBlock(materialPropertyBlock); } From e781f90615f747cd3b1ebebd0d12b36a5a5feeb7 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Molteni Date: Wed, 23 Oct 2024 10:10:11 -0300 Subject: [PATCH 08/16] fix: Asset bundle material leak (LOD) (#2533) --- .../Assets/DCL/LOD/Components/LODCacheInfo.cs | 4 ---- Explorer/Assets/DCL/LOD/Systems/LODUtils.cs | 2 +- .../DCL/LOD/Systems/UpdateSceneLODInfoSystem.cs | 6 +++--- .../AssetBundleMissingMainAssetException.cs | 16 ++++++++++++++++ .../AssetBundles/GetAssetBundleIntention.cs | 14 +++++++++++--- .../AssetBundles/LoadAssetBundleSystem.cs | 12 +++++++++++- .../Asset/Tests/GltfContainerTestResources.cs | 2 +- 7 files changed, 43 insertions(+), 13 deletions(-) diff --git a/Explorer/Assets/DCL/LOD/Components/LODCacheInfo.cs b/Explorer/Assets/DCL/LOD/Components/LODCacheInfo.cs index eff765c7fd..fc65f7d9e5 100644 --- a/Explorer/Assets/DCL/LOD/Components/LODCacheInfo.cs +++ b/Explorer/Assets/DCL/LOD/Components/LODCacheInfo.cs @@ -1,9 +1,5 @@ using System; -using ECS.StreamableLoading.AssetBundles; -using Segment.Concurrent; using UnityEngine; -using UnityEngine.Serialization; -using Utility; namespace DCL.LOD.Components { diff --git a/Explorer/Assets/DCL/LOD/Systems/LODUtils.cs b/Explorer/Assets/DCL/LOD/Systems/LODUtils.cs index 4a036ed10b..75d5e804f8 100644 --- a/Explorer/Assets/DCL/LOD/Systems/LODUtils.cs +++ b/Explorer/Assets/DCL/LOD/Systems/LODUtils.cs @@ -29,7 +29,7 @@ public static IReadOnlyList LODManifests(IDecentraland .ToArray(); private static readonly ListObjectPool TEXTURE_ARRAY_SLOTS = new (listInstanceDefaultCapacity: 10, defaultCapacity: 20); - public static string LOD_SHADER = "DCL/Scene_TexArray"; + private static string LOD_SHADER = "DCL/Scene_TexArray"; private static readonly List TEMP_MATERIALS = new (3); public static TextureArraySlot?[] ApplyTextureArrayToLOD(string sceneID, Vector2Int baseCoordinate, GameObject instantiatedLOD, TextureArrayContainer lodTextureArrayContainer) diff --git a/Explorer/Assets/DCL/LOD/Systems/UpdateSceneLODInfoSystem.cs b/Explorer/Assets/DCL/LOD/Systems/UpdateSceneLODInfoSystem.cs index 4b3f322fc9..0920feae3b 100644 --- a/Explorer/Assets/DCL/LOD/Systems/UpdateSceneLODInfoSystem.cs +++ b/Explorer/Assets/DCL/LOD/Systems/UpdateSceneLODInfoSystem.cs @@ -5,8 +5,6 @@ using DCL.Diagnostics; using DCL.LOD.Components; using DCL.Multiplayer.Connections.DecentralandUrls; -using DCL.Optimization.PerformanceBudgeting; -using DCL.PluginSystem.Global; using ECS.Abstract; using ECS.LifeCycle.Components; using ECS.Prioritization.Components; @@ -73,7 +71,9 @@ private void StartLODPromise(ref SceneLODInfo sceneLODInfo, ref PartitionCompone platformLODKey, permittedSources: AssetSource.ALL, customEmbeddedSubDirectory: LODUtils.LOD_EMBEDDED_SUBDIRECTORIES, - manifest: manifest); + manifest: manifest, + lookForShaderAsset: true + ); sceneLODInfo.CurrentLODPromise = Promise.Create(World, assetBundleIntention, partitionComponent); sceneLODInfo.CurrentLODLevelPromise = level; diff --git a/Explorer/Assets/Scripts/ECS/StreamableLoading/AssetBundles/AssetBundleMissingMainAssetException.cs b/Explorer/Assets/Scripts/ECS/StreamableLoading/AssetBundles/AssetBundleMissingMainAssetException.cs index 99f4e90d5a..a066d6a460 100644 --- a/Explorer/Assets/Scripts/ECS/StreamableLoading/AssetBundles/AssetBundleMissingMainAssetException.cs +++ b/Explorer/Assets/Scripts/ECS/StreamableLoading/AssetBundles/AssetBundleMissingMainAssetException.cs @@ -19,4 +19,20 @@ public AssetBundleMissingMainAssetException(string sourceName, Type type) : base public override string ToString() => $"{sourceName} doesn't contain assets with {type} extensions"; } + + /// + /// Indicates that a given source does not contain root assets of the specified type (and thus can't be used further) + /// + public class AssetBundleContainsShaderException : Exception + { + private readonly string sourceName; + + public AssetBundleContainsShaderException(string sourceName) : base($"{sourceName} contains a shader in it when it should be a dependecy. This will cause a leak") + { + this.sourceName = sourceName; + } + + public override string ToString() => + $"{sourceName} contains a shader in it when it should be a dependecy. This will cause a leak"; + } } diff --git a/Explorer/Assets/Scripts/ECS/StreamableLoading/AssetBundles/GetAssetBundleIntention.cs b/Explorer/Assets/Scripts/ECS/StreamableLoading/AssetBundles/GetAssetBundleIntention.cs index 30b27f870d..d9291837a6 100644 --- a/Explorer/Assets/Scripts/ECS/StreamableLoading/AssetBundles/GetAssetBundleIntention.cs +++ b/Explorer/Assets/Scripts/ECS/StreamableLoading/AssetBundles/GetAssetBundleIntention.cs @@ -40,10 +40,17 @@ public struct GetAssetBundleIntention : ILoadingIntention, IEquatable /// /// + + /// + // /// Used to check if the asset bundle has shader assets in it + // /// + public bool LookForShaderAssets; + private GetAssetBundleIntention(Type? expectedObjectType, string? name = null, string? hash = null, AssetSource permittedSources = AssetSource.ALL, SceneAssetBundleManifest? assetBundleManifest = null, URLSubdirectory customEmbeddedSubDirectory = default, + bool lookForShaderAssets = false, CancellationTokenSource cancellationTokenSource = null) { Name = name; @@ -55,6 +62,7 @@ private GetAssetBundleIntention(Type? expectedObjectType, string? name = null, CommonArguments = new CommonLoadingArguments(URLAddress.EMPTY, customEmbeddedSubDirectory, permittedSources: permittedSources, cancellationTokenSource: cancellationTokenSource); cacheHash = null; Manifest = assetBundleManifest; + LookForShaderAssets = lookForShaderAssets; } internal GetAssetBundleIntention(CommonLoadingArguments commonArguments) : this() @@ -69,12 +77,12 @@ public bool Equals(GetAssetBundleIntention other) => public CancellationTokenSource CancellationTokenSource => CommonArguments.CancellationTokenSource; - public static GetAssetBundleIntention FromHash(Type? expectedAssetType, string hash, AssetSource permittedSources = AssetSource.ALL, SceneAssetBundleManifest? manifest = null, URLSubdirectory customEmbeddedSubDirectory = default) => - new (expectedAssetType, hash: hash, permittedSources: permittedSources, assetBundleManifest: manifest, customEmbeddedSubDirectory: customEmbeddedSubDirectory); + public static GetAssetBundleIntention FromHash(Type? expectedAssetType, string hash, AssetSource permittedSources = AssetSource.ALL, SceneAssetBundleManifest? manifest = null, URLSubdirectory customEmbeddedSubDirectory = default, bool lookForShaderAsset = false) => + new (expectedAssetType, hash: hash, permittedSources: permittedSources, assetBundleManifest: manifest, customEmbeddedSubDirectory: customEmbeddedSubDirectory, lookForShaderAssets:lookForShaderAsset); public static GetAssetBundleIntention FromHash(Type expectedAssetType, string hash, CancellationTokenSource cancellationTokenSource, AssetSource permittedSources = AssetSource.ALL, SceneAssetBundleManifest? manifest = null, URLSubdirectory customEmbeddedSubDirectory = default) => - new (expectedAssetType, hash: hash, permittedSources: permittedSources, assetBundleManifest: manifest, customEmbeddedSubDirectory: customEmbeddedSubDirectory, cancellationTokenSource: cancellationTokenSource); + new (expectedAssetType, hash: hash, permittedSources: permittedSources, assetBundleManifest: manifest, customEmbeddedSubDirectory: customEmbeddedSubDirectory,cancellationTokenSource: cancellationTokenSource); public static GetAssetBundleIntention Create(Type? expectedAssetType, string hash, string name,AssetSource permittedSources = AssetSource.ALL, SceneAssetBundleManifest? manifest = null, URLSubdirectory customEmbeddedSubDirectory = default) => new (expectedAssetType, hash: hash, name: name,permittedSources: permittedSources, assetBundleManifest: manifest, customEmbeddedSubDirectory: customEmbeddedSubDirectory); diff --git a/Explorer/Assets/Scripts/ECS/StreamableLoading/AssetBundles/LoadAssetBundleSystem.cs b/Explorer/Assets/Scripts/ECS/StreamableLoading/AssetBundles/LoadAssetBundleSystem.cs index bc8c175b91..6d743d0eee 100644 --- a/Explorer/Assets/Scripts/ECS/StreamableLoading/AssetBundles/LoadAssetBundleSystem.cs +++ b/Explorer/Assets/Scripts/ECS/StreamableLoading/AssetBundles/LoadAssetBundleSystem.cs @@ -111,7 +111,7 @@ protected override async UniTask> FlowI string source = intention.CommonArguments.CurrentSource.ToStringNonAlloc(); // if the type was not specified don't load any assets - return await CreateAssetBundleDataAsync(assetBundle, metrics, intention.ExpectedObjectType, mainAsset, loadingMutex, dependencies, GetReportData(), version, source, ct); + return await CreateAssetBundleDataAsync(assetBundle, metrics, intention.ExpectedObjectType, mainAsset, loadingMutex, dependencies, GetReportData(), version, source, intention.LookForShaderAssets, ct); } catch (Exception e) { @@ -134,11 +134,21 @@ public static async UniTask> CreateAsse ReportData reportCategory, string version, string source, + bool lookForShaderAssets, CancellationToken ct) { // if the type was not specified don't load any assets if (expectedObjType == null) return new StreamableLoadingResult(new AssetBundleData(assetBundle, metrics, dependencies)); + + if (lookForShaderAssets && expectedObjType == typeof(GameObject)) + { + //If there are no dependencies, it means that this gameobject asset bundle has the shader in it. + //All gameobject asset bundles ahould at least have the dependency on the shader. + //This will cause a material leak, as the same material will be loaded again. This needs to be solved at asset bundle level + if (dependencies.Length == 0) + throw new AssetBundleContainsShaderException(assetBundle.name); + } Object? asset = await LoadAllAssetsAsync(assetBundle, expectedObjType, mainAsset, loadingMutex, reportCategory, ct); diff --git a/Explorer/Assets/Scripts/ECS/Unity/GLTFContainer/Asset/Tests/GltfContainerTestResources.cs b/Explorer/Assets/Scripts/ECS/Unity/GLTFContainer/Asset/Tests/GltfContainerTestResources.cs index 6cd2a93a2f..76d9296b1f 100644 --- a/Explorer/Assets/Scripts/ECS/Unity/GLTFContainer/Asset/Tests/GltfContainerTestResources.cs +++ b/Explorer/Assets/Scripts/ECS/Unity/GLTFContainer/Asset/Tests/GltfContainerTestResources.cs @@ -40,7 +40,7 @@ public async UniTask> LoadAssetBundle(s try { assetBundleData = await LoadAssetBundleSystem.CreateAssetBundleDataAsync(assetBundle, null, typeof(GameObject), "", new AssetBundleLoadingMutex(), Array.Empty(), - ReportCategory.ASSET_BUNDLES, "", "", CancellationToken.None); + ReportCategory.ASSET_BUNDLES, "", "", false, CancellationToken.None); return assetBundleData; } catch (Exception e) { return new StreamableLoadingResult(ReportCategory.ASSET_BUNDLES, e); } From 9519982aa1c2660362d0e7e51b08aa217f943f25 Mon Sep 17 00:00:00 2001 From: Nicolas Lorusso <56365551+lorux0@users.noreply.github.com> Date: Wed, 23 Oct 2024 10:10:35 -0300 Subject: [PATCH 09/16] fix: unequip force render (#2525) --- .../ApplicationParametersWearablesProvider.cs | 89 +++++++++++++++++++ ...icationParametersWearablesProvider.cs.meta | 3 + .../Wearables/Wearables.asmdef | 68 +++++++------- .../BackpackBus/BackpackBusController.cs | 9 ++ .../DCL/Backpack/BackpackSlotsController.cs | 6 +- .../Dynamic/DebugSettings/DebugSettings.cs | 4 + .../Global/Dynamic/DynamicWorldContainer.cs | 7 +- .../Scripts/Global/Dynamic/MainSceneLoader.cs | 8 +- 8 files changed, 152 insertions(+), 42 deletions(-) create mode 100644 Explorer/Assets/DCL/AvatarRendering/Wearables/ApplicationParametersWearablesProvider.cs create mode 100644 Explorer/Assets/DCL/AvatarRendering/Wearables/ApplicationParametersWearablesProvider.cs.meta diff --git a/Explorer/Assets/DCL/AvatarRendering/Wearables/ApplicationParametersWearablesProvider.cs b/Explorer/Assets/DCL/AvatarRendering/Wearables/ApplicationParametersWearablesProvider.cs new file mode 100644 index 0000000000..acdb3d9f13 --- /dev/null +++ b/Explorer/Assets/DCL/AvatarRendering/Wearables/ApplicationParametersWearablesProvider.cs @@ -0,0 +1,89 @@ +using Arch.Core; +using CommunicationData.URLHelpers; +using Cysharp.Threading.Tasks; +using DCL.AvatarRendering.Loading.Components; +using DCL.AvatarRendering.Wearables.Components; +using DCL.AvatarRendering.Wearables.Helpers; +using ECS.Prioritization.Components; +using ECS.StreamableLoading.Common; +using Global.AppArgs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using WearablePromise = ECS.StreamableLoading.Common.AssetPromise; + +namespace DCL.AvatarRendering.Wearables +{ + public class ApplicationParametersWearablesProvider : IWearablesProvider + { + private readonly IAppArgs applicationParametersParser; + private readonly IWearablesProvider source; + private readonly World world; + private readonly string[] allWearableCategories = WearablesConstants.CATEGORIES_PRIORITY.ToArray(); + private readonly List resultWearablesBuffer = new (); + + public ApplicationParametersWearablesProvider(IAppArgs applicationParametersParser, + IWearablesProvider source, + World world) + { + this.applicationParametersParser = applicationParametersParser; + this.source = source; + this.world = world; + } + + public async UniTask<(IReadOnlyList results, int totalAmount)> GetAsync(int pageSize, int pageNumber, CancellationToken ct, + IWearablesProvider.SortingField sortingField = IWearablesProvider.SortingField.Date, + IWearablesProvider.OrderBy orderBy = IWearablesProvider.OrderBy.Descending, + string? category = null, + IWearablesProvider.CollectionType collectionType = IWearablesProvider.CollectionType.All, + string? name = null, + List? results = null) + { + if (!applicationParametersParser.TryGetValue("self-preview-wearables", out string? wearablesCsv)) + return await source.GetAsync(pageSize, pageNumber, ct, sortingField, orderBy, category, collectionType, name, results); + + URN[] pointers = wearablesCsv!.Split(',', StringSplitOptions.RemoveEmptyEntries) + .Select(s => new URN(s)).ToArray(); + + IReadOnlyCollection? maleWearables = await RequestPointersAsync(pointers, BodyShape.MALE, ct); + IReadOnlyCollection? femaleWearables = await RequestPointersAsync(pointers, BodyShape.FEMALE, ct); + + lock (resultWearablesBuffer) + { + resultWearablesBuffer.Clear(); + + if (maleWearables != null) + resultWearablesBuffer.AddRange(maleWearables); + + if (femaleWearables != null) + resultWearablesBuffer.AddRange(femaleWearables); + + int pageIndex = pageNumber - 1; + return (resultWearablesBuffer.Skip(pageIndex * pageSize).Take(pageSize).ToArray(), resultWearablesBuffer.Count); + } + } + + private async UniTask?> RequestPointersAsync(IReadOnlyCollection pointers, + BodyShape bodyShape, + CancellationToken ct) + { + var promise = WearablePromise.Create(world, + // We pass all categories as force renderer to force the download of all of them + // Otherwise they will be skipped if any wearable is hiding the category + WearableComponentsUtils.CreateGetWearablesByPointersIntention(bodyShape, pointers, allWearableCategories), + PartitionComponent.TOP_PRIORITY); + + promise = await promise.ToUniTaskAsync(world, cancellationToken: ct); + + if (!promise.TryGetResult(world, out var result)) + return null; + + if (!result.Succeeded) + return null; + + return result.Asset.Wearables; + } + } +} diff --git a/Explorer/Assets/DCL/AvatarRendering/Wearables/ApplicationParametersWearablesProvider.cs.meta b/Explorer/Assets/DCL/AvatarRendering/Wearables/ApplicationParametersWearablesProvider.cs.meta new file mode 100644 index 0000000000..2b56ac62a2 --- /dev/null +++ b/Explorer/Assets/DCL/AvatarRendering/Wearables/ApplicationParametersWearablesProvider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: aeab2504dec845c38c5f6091e513a1a1 +timeCreated: 1729521989 \ No newline at end of file diff --git a/Explorer/Assets/DCL/AvatarRendering/Wearables/Wearables.asmdef b/Explorer/Assets/DCL/AvatarRendering/Wearables/Wearables.asmdef index 075e59a6eb..6f3e260763 100644 --- a/Explorer/Assets/DCL/AvatarRendering/Wearables/Wearables.asmdef +++ b/Explorer/Assets/DCL/AvatarRendering/Wearables/Wearables.asmdef @@ -1,36 +1,36 @@ { - "name": "Wearables", - "rootNamespace": "", - "references": [ - "GUID:9e314663ce958b746873cb22d57ede55", - "GUID:f51ebe6a0ceec4240a699833d6309b23", - "GUID:286980af24684da6acc1caa413039811", - "GUID:1b8e1e1bd01505f478f0369c04a4fb2f", - "GUID:fa7b3fdbb04d67549916da7bd2af58ab", - "GUID:101b8b6ebaf64668909b49c4b7a1420d", - "GUID:3c7b57a14671040bd8c549056adc04f5", - "GUID:e0eedfa2deb9406daf86fd8368728e39", - "GUID:8322ea9340a544c59ddc56d4793eac74", - "GUID:4794e238ed0f65142a4aea5848b513e5", - "GUID:3640f3c0b42946b0b8794a1ed8e06ca5", - "GUID:275e22790c04e9b47a5085d7b0c4432a", - "GUID:4a12c0b1b77ec6b418a8d7bd5c925be3", - "GUID:b46779583a009f04ba9f5f31d0e7e6ac", - "GUID:56e8195b069a4dca9c4c4f313c65f526", - "GUID:e25ef972de004615a22937e739de2def", - "GUID:ca4e81cdd6a34d1aa54c32ad41fc5b3b", - "GUID:5ab29fa8ae5769b49ab29e390caca7a4", - "GUID:91cf8206af184dac8e30eb46747e9939", - "GUID:543b8f091a5947a3880b7f2bca2358bd", - "GUID:e5a23cdae0ef4d86aafc237a73280975" - ], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false + "name": "Wearables", + "rootNamespace": "", + "references": [ + "GUID:9e314663ce958b746873cb22d57ede55", + "GUID:f51ebe6a0ceec4240a699833d6309b23", + "GUID:286980af24684da6acc1caa413039811", + "GUID:1b8e1e1bd01505f478f0369c04a4fb2f", + "GUID:fa7b3fdbb04d67549916da7bd2af58ab", + "GUID:3c7b57a14671040bd8c549056adc04f5", + "GUID:e0eedfa2deb9406daf86fd8368728e39", + "GUID:8322ea9340a544c59ddc56d4793eac74", + "GUID:4794e238ed0f65142a4aea5848b513e5", + "GUID:3640f3c0b42946b0b8794a1ed8e06ca5", + "GUID:275e22790c04e9b47a5085d7b0c4432a", + "GUID:4a12c0b1b77ec6b418a8d7bd5c925be3", + "GUID:b46779583a009f04ba9f5f31d0e7e6ac", + "GUID:56e8195b069a4dca9c4c4f313c65f526", + "GUID:e25ef972de004615a22937e739de2def", + "GUID:ca4e81cdd6a34d1aa54c32ad41fc5b3b", + "GUID:5ab29fa8ae5769b49ab29e390caca7a4", + "GUID:91cf8206af184dac8e30eb46747e9939", + "GUID:543b8f091a5947a3880b7f2bca2358bd", + "GUID:e5a23cdae0ef4d86aafc237a73280975", + "GUID:8baf705856414dad9a73b3f382f1bc8b" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false } \ No newline at end of file diff --git a/Explorer/Assets/DCL/Backpack/BackpackBus/BackpackBusController.cs b/Explorer/Assets/DCL/Backpack/BackpackBus/BackpackBusController.cs index 0b13fef71f..d754266298 100644 --- a/Explorer/Assets/DCL/Backpack/BackpackBus/BackpackBusController.cs +++ b/Explorer/Assets/DCL/Backpack/BackpackBus/BackpackBusController.cs @@ -19,6 +19,7 @@ public class BackpackBusController : IDisposable private readonly IBackpackCommandBus backpackCommandBus; private readonly IEquippedEmotes equippedEmotes; private readonly IEmoteStorage emoteStorage; + private readonly HashSet forceRender = new (15); private int currentEmoteSlot = -1; private readonly IReadOnlyEquippedWearables equippedWearables; @@ -190,6 +191,9 @@ private void HandleUnEquipWearableCommand(BackpackUnEquipWearableCommand command } backpackEventBus.SendUnEquipWearable(wearable); + + forceRender.Remove(wearable.GetCategory()); + backpackEventBus.SendForceRender(forceRender); } private void HandleUnEquipEmoteCommand(BackpackUnEquipEmoteCommand command) @@ -218,6 +222,11 @@ private void HandleSelectEmoteCommand(BackpackSelectEmoteCommand command) private void HandleHideCommand(BackpackHideCommand command) { + forceRender.Clear(); + + foreach (string category in command.ForceRender) + forceRender.Add(category); + backpackEventBus.SendForceRender(command.ForceRender); } diff --git a/Explorer/Assets/DCL/Backpack/BackpackSlotsController.cs b/Explorer/Assets/DCL/Backpack/BackpackSlotsController.cs index dd9e4410e9..2a4450c457 100644 --- a/Explorer/Assets/DCL/Backpack/BackpackSlotsController.cs +++ b/Explorer/Assets/DCL/Backpack/BackpackSlotsController.cs @@ -51,11 +51,7 @@ public BackpackSlotsController( avatarSlotView.OnSlotButtonPressed += OnSlotButtonPressed; avatarSlotView.OverrideHide.onClick.AddListener(() => RemoveForceRender(avatarSlotView.Category)); avatarSlotView.NoOverride.onClick.AddListener(() => AddForceRender(avatarSlotView.Category)); - avatarSlotView.UnequipButton.onClick.AddListener(() => - { - RemoveForceRender(avatarSlotView.Category); - backpackCommandBus.SendCommand(new BackpackUnEquipWearableCommand(avatarSlotView.SlotWearableUrn)); - }); + avatarSlotView.UnequipButton.onClick.AddListener(() => backpackCommandBus.SendCommand(new BackpackUnEquipWearableCommand(avatarSlotView.SlotWearableUrn))); } } diff --git a/Explorer/Assets/Scripts/Global/Dynamic/DebugSettings/DebugSettings.cs b/Explorer/Assets/Scripts/Global/Dynamic/DebugSettings/DebugSettings.cs index 8080b8c724..1387558c91 100644 --- a/Explorer/Assets/Scripts/Global/Dynamic/DebugSettings/DebugSettings.cs +++ b/Explorer/Assets/Scripts/Global/Dynamic/DebugSettings/DebugSettings.cs @@ -33,6 +33,8 @@ [SerializeField] [Tooltip("Make sure the ENS put here will be loaded as a Global private bool overrideConnectionQuality; [SerializeField] private ConnectionQuality connectionQuality; + [SerializeField] + private string[] appParameters; public static DebugSettings Release() => new () @@ -49,6 +51,7 @@ public static DebugSettings Release() => connectionQuality = ConnectionQuality.QualityExcellent, enableRemotePortableExperiences = true, emotesToAddToUserProfile = null, + appParameters = Array.Empty(), }; // To avoid configuration issues, force full flow on build (Application.isEditor is always true in Editor, but in profile builds (i.e. when set to Development) we will have the expected release flow too. @@ -64,5 +67,6 @@ public static DebugSettings Release() => public bool EnableEmulateNoLivekitConnection => Application.isEditor? this.enableEmulateNoLivekitConnection : RELEASE_SETTINGS.enableEmulateNoLivekitConnection; public bool OverrideConnectionQuality => Application.isEditor ? this.overrideConnectionQuality : RELEASE_SETTINGS.overrideConnectionQuality; public ConnectionQuality ConnectionQuality => Application.isEditor ? this.connectionQuality : RELEASE_SETTINGS.connectionQuality; + public string[] AppParameters => appParameters; } } diff --git a/Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs b/Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs index 2a54f48265..f21e5a552f 100644 --- a/Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs +++ b/Explorer/Assets/Scripts/Global/Dynamic/DynamicWorldContainer.cs @@ -100,7 +100,7 @@ public class DynamicWorldContainer : DCLWorldContainer private ECSReloadScene? reloadSceneController; private LocalSceneDevelopmentController? localSceneDevelopmentController; - private ECSWearablesProvider? wearablesProvider; + private IWearablesProvider? wearablesProvider; public IMVCManager MvcManager { get; private set; } = null!; @@ -220,7 +220,6 @@ async UniTask InitializeContainersAsync(IPluginSettingsContainer settingsContain var nftInfoAPIClient = new OpenSeaAPIClient(staticContainer.WebRequestsContainer.WebRequestController, bootstrapContainer.DecentralandUrlsSource); var wearableCatalog = new WearableStorage(); - container.wearablesProvider = new ECSWearablesProvider(identityCache, globalWorld); var characterPreviewFactory = new CharacterPreviewFactory(staticContainer.ComponentsContainer.ComponentPoolsRegistry); IWebBrowser webBrowser = bootstrapContainer.WebBrowser; ChatEntryConfigurationSO chatEntryConfiguration = (await assetsProvisioner.ProvideMainAssetAsync(dynamicSettings.ChatEntryConfiguration, ct)).Value; @@ -259,6 +258,10 @@ IMultiPool MultiPoolFactory() => IEmoteProvider emoteProvider = new EcsEmoteProvider(globalWorld, staticContainer.RealmData); + container.wearablesProvider = new ApplicationParametersWearablesProvider(appArgs, + new ECSWearablesProvider(identityCache, globalWorld), + globalWorld); + container.SceneRoomMetaDataSource = new SceneRoomMetaDataSource(staticContainer.RealmData, staticContainer.CharacterContainer.Transform, placesAPIService, dynamicWorldParams.IsolateScenesCommunication); var metaDataSource = new SceneRoomLogMetaDataSource(container.SceneRoomMetaDataSource); diff --git a/Explorer/Assets/Scripts/Global/Dynamic/MainSceneLoader.cs b/Explorer/Assets/Scripts/Global/Dynamic/MainSceneLoader.cs index 9ebf478388..80513de018 100644 --- a/Explorer/Assets/Scripts/Global/Dynamic/MainSceneLoader.cs +++ b/Explorer/Assets/Scripts/Global/Dynamic/MainSceneLoader.cs @@ -89,7 +89,13 @@ private void OnDestroy() private async UniTask InitializeFlowAsync(CancellationToken ct) { - var applicationParametersParser = new ApplicationParametersParser(Environment.GetCommandLineArgs()); + var applicationParametersParser = new ApplicationParametersParser( +#if UNITY_EDITOR + debugSettings.AppParameters +#else + Environment.GetCommandLineArgs() +#endif + ); ISystemMemoryCap memoryCap = new SystemMemoryCap(MemoryCapMode.MAX_SYSTEM_MEMORY); // we use max memory on the loading screen settings.ApplyConfig(applicationParametersParser); From 3657360f7206091029d5644046488e46eebbf3eb Mon Sep 17 00:00:00 2001 From: Vitaly Popuzin <35366872+popuz@users.noreply.github.com> Date: Wed, 23 Oct 2024 16:28:44 +0300 Subject: [PATCH 10/16] temporarly disable performance analytics (#2546) --- .../Analytics/Systems/PerformanceAnalyticsSystem.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Analytics/Systems/PerformanceAnalyticsSystem.cs b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Analytics/Systems/PerformanceAnalyticsSystem.cs index 35651e9d38..e822217ae7 100644 --- a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Analytics/Systems/PerformanceAnalyticsSystem.cs +++ b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Analytics/Systems/PerformanceAnalyticsSystem.cs @@ -53,6 +53,8 @@ IJsonObjectBuilder jsonObjectBuilder protected override void Update(float t) { + return; + if (!realmData.Configured) return; lastReportTime += t; From d29bd1baad39c898d3ec61822bccd503101e2f7b Mon Sep 17 00:00:00 2001 From: Juan Ignacio Molteni Date: Wed, 23 Oct 2024 11:02:53 -0300 Subject: [PATCH 11/16] fix: Connect to fake room (#2542) --- .../Connections/Archipelago/Rooms/ForkGlobalRealmRoom.cs | 2 +- .../Connections/Rooms/Connective/IConnectiveRoom.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Explorer/Assets/DCL/Multiplayer/Connections/Archipelago/Rooms/ForkGlobalRealmRoom.cs b/Explorer/Assets/DCL/Multiplayer/Connections/Archipelago/Rooms/ForkGlobalRealmRoom.cs index 7f992117a7..56f6cb3f5f 100644 --- a/Explorer/Assets/DCL/Multiplayer/Connections/Archipelago/Rooms/ForkGlobalRealmRoom.cs +++ b/Explorer/Assets/DCL/Multiplayer/Connections/Archipelago/Rooms/ForkGlobalRealmRoom.cs @@ -35,7 +35,7 @@ public async UniTask StartAsync() else if (adapterUrl.Contains("https://")) current = httpsRoomFactory(); else if (adapterUrl.Contains("offline:offline")) - current = new IConnectiveRoom.Fake(); + current = new IConnectiveRoom.Null(); else throw new InvalidOperationException($"Cannot determine the protocol from the about url: {adapterUrl}"); diff --git a/Explorer/Assets/DCL/Multiplayer/Connections/Rooms/Connective/IConnectiveRoom.cs b/Explorer/Assets/DCL/Multiplayer/Connections/Rooms/Connective/IConnectiveRoom.cs index 3d5160f4fe..4b569c9e53 100644 --- a/Explorer/Assets/DCL/Multiplayer/Connections/Rooms/Connective/IConnectiveRoom.cs +++ b/Explorer/Assets/DCL/Multiplayer/Connections/Rooms/Connective/IConnectiveRoom.cs @@ -21,16 +21,16 @@ enum State IRoom Room(); - class Fake : IConnectiveRoom + class Null : IConnectiveRoom { public UniTask StartAsync() => - UniTask.FromResult(false); + UniTask.FromResult(true); public UniTask StopAsync() => UniTask.CompletedTask; public State CurrentState() => - State.Stopped; + State.Running; public IRoom Room() => NullRoom.INSTANCE; From 46f8d7b9aa7464912e53e54b0cf32b753b6556ea Mon Sep 17 00:00:00 2001 From: Pravus Date: Wed, 23 Oct 2024 18:15:41 +0200 Subject: [PATCH 12/16] fix: raw gltf external dependencies deeper path (#2541) --- .../GLTF/GltFastDownloadProvider.cs | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Explorer/Assets/Scripts/ECS/StreamableLoading/GLTF/GltFastDownloadProvider.cs b/Explorer/Assets/Scripts/ECS/StreamableLoading/GLTF/GltFastDownloadProvider.cs index 5c0c53900c..f97e1b0e14 100644 --- a/Explorer/Assets/Scripts/ECS/StreamableLoading/GLTF/GltFastDownloadProvider.cs +++ b/Explorer/Assets/Scripts/ECS/StreamableLoading/GLTF/GltFastDownloadProvider.cs @@ -1,4 +1,5 @@ using Arch.Core; +using CommunicationData.URLHelpers; using Cysharp.Threading.Tasks; using DCL.Optimization.PerformanceBudgeting; using ECS.Prioritization.Components; @@ -21,12 +22,11 @@ internal class GltFastDownloadProvider : IDownloadProvider, IDisposable { private const int ATTEMPTS_COUNT = 6; - private string targetGltfOriginalPath; - private string targetGltfDirectoryPath; - private ISceneData sceneData; - private World world; - private IPartitionComponent partitionComponent; private readonly IAcquiredBudget acquiredBudget; + private readonly string targetGltfOriginalPath; + private readonly ISceneData sceneData; + private readonly World world; + private readonly IPartitionComponent partitionComponent; public GltFastDownloadProvider(World world, ISceneData sceneData, IPartitionComponent partitionComponent, string targetGltfOriginalPath, IAcquiredBudget acquiredBudget) { @@ -35,7 +35,11 @@ public GltFastDownloadProvider(World world, ISceneData sceneData, IPartitionComp this.partitionComponent = partitionComponent; this.targetGltfOriginalPath = targetGltfOriginalPath; this.acquiredBudget = acquiredBudget; - targetGltfDirectoryPath = targetGltfOriginalPath.Remove(targetGltfOriginalPath.LastIndexOf('/') + 1); + } + + public void Dispose() + { + acquiredBudget.Release(); } // RequestAsync is used for fetching the GLTF file itself + some external textures. Whenever this @@ -43,18 +47,18 @@ public GltFastDownloadProvider(World world, ISceneData sceneData, IPartitionComp public async Task RequestAsync(Uri uri) { bool isBaseGltfFetch = uri.OriginalString.Equals(targetGltfOriginalPath); - string originalFilePath = string.Concat(targetGltfDirectoryPath, GetFileNameFromUri(uri)); + string originalFilePath = GetFileOriginalPathFromUri(uri); - if (!sceneData.SceneContent.TryGetContentUrl(originalFilePath, out var tryGetContentUrlResult)) + if (!sceneData.SceneContent.TryGetContentUrl(originalFilePath, out URLAddress tryGetContentUrlResult)) { if (isBaseGltfFetch) acquiredBudget.Release(); - throw new Exception($"Error on GLTF download ({targetGltfOriginalPath} - {uri}): NOT FOUND"); + throw new Exception($"Error on GLTF download ({targetGltfOriginalPath} - {originalFilePath}): NOT FOUND"); } uri = new Uri(tryGetContentUrlResult); // TODO: Replace for WebRequestController (Planned in PR #1670) - using (UnityWebRequest webRequest = new UnityWebRequest(uri)) + using (var webRequest = new UnityWebRequest(uri)) { webRequest.downloadHandler = new DownloadHandlerBuffer(); @@ -74,8 +78,8 @@ public async Task RequestAsync(Uri uri) public async Task RequestTextureAsync(Uri uri, bool nonReadable, bool forceLinear) { - string textureOriginalPath = string.Concat(targetGltfDirectoryPath, GetFileNameFromUri(uri)); - sceneData.SceneContent.TryGetContentUrl(textureOriginalPath, out var tryGetContentUrlResult); + string textureOriginalPath = GetFileOriginalPathFromUri(uri); + sceneData.SceneContent.TryGetContentUrl(textureOriginalPath, out URLAddress tryGetContentUrlResult); var texturePromise = Promise.Create(world, new GetTextureIntention { @@ -83,7 +87,7 @@ public async Task RequestTextureAsync(Uri uri, bool nonReadabl }, partitionComponent); // The textures fetching need to finish before the GLTF loading can continue its flow... - var promiseResult = await texturePromise.ToUniTaskAsync(world, cancellationToken: new CancellationToken()); + Promise promiseResult = await texturePromise.ToUniTaskAsync(world, cancellationToken: new CancellationToken()); if (promiseResult.Result is { Succeeded: false }) throw new Exception($"Error on GLTF Texture download: {promiseResult.Result.Value.Exception!.Message}"); @@ -95,16 +99,11 @@ public async Task RequestTextureAsync(Uri uri, bool nonReadabl }; } - public void Dispose() - { - acquiredBudget.Release(); - } - - private string GetFileNameFromUri(Uri uri) + private string GetFileOriginalPathFromUri(Uri uri) { // On windows the URI may come with some invalid '\' in parts of the path string patchedUri = uri.OriginalString.Replace('\\', '/'); - return patchedUri.Substring(patchedUri.LastIndexOf('/') + 1); + return patchedUri.Replace(sceneData.SceneContent.ContentBaseUrl.Value, string.Empty); } } @@ -116,9 +115,11 @@ public struct GltfDownloadResult : IDownload public string Error { get; set; } public byte[] Data { get; set; } public string Text { get; set; } + public bool? IsBinary { - get { + get + { if (Data == null) return false; var gltfBinarySignature = BitConverter.ToUInt32(Data, 0); return gltfBinarySignature == GLB_SIGNATURE; @@ -142,13 +143,12 @@ public struct TextureDownloadResult : ITextureDownload public TextureDownloadResult(Texture2D? texture) { - Texture = new DisposableTexture() { Texture = texture }; + Texture = new DisposableTexture { Texture = texture }; Error = null!; Success = false; } - public IDisposableTexture GetTexture(bool forceSampleLinear) => - Texture; + public IDisposableTexture GetTexture(bool forceSampleLinear) => Texture; public void Dispose() => Texture.Dispose(); } From a9e1570d75a426b7bb4ff031a9d15737df66e0c8 Mon Sep 17 00:00:00 2001 From: Vitaly Popuzin <35366872+popuz@users.noreply.github.com> Date: Thu, 24 Oct 2024 04:13:05 +0300 Subject: [PATCH 13/16] Fix:performance analytics spikes (#2569) --- .../PartitionGlobalAssetEntitiesSystem.cs | 2 - .../Systems/PerformanceAnalyticsSystem.cs | 173 +++++++++--------- .../Profiling/ECS/DebugViewProfilingSystem.cs | 8 +- .../Profiling/FrameTimesRecorder.cs | 120 ++++++++++++ .../Profiling/FrameTimesRecorder.cs.meta | 3 + .../Profiling/IAnalyticsReportProfiler.cs | 52 ------ .../IAnalyticsReportProfiler.cs.meta | 11 -- .../Profiling/IBudgetProfiler.cs | 6 +- .../Profiling/IDebugViewProfiler.cs | 8 - .../Profiling/IMemoryProfiler.cs | 1 + .../Profiling/IProfiler.cs | 11 ++ ...ViewProfiler.cs.meta => IProfiler.cs.meta} | 0 .../Profiling/Profiler.cs | 78 ++------ .../PluginSystem/Global/AnalyticsPlugin.cs | 4 +- .../PluginSystem/Global/ProfilingPlugin.cs | 4 +- 15 files changed, 253 insertions(+), 228 deletions(-) create mode 100644 Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/FrameTimesRecorder.cs create mode 100644 Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/FrameTimesRecorder.cs.meta delete mode 100644 Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IAnalyticsReportProfiler.cs delete mode 100644 Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IAnalyticsReportProfiler.cs.meta delete mode 100644 Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IDebugViewProfiler.cs create mode 100644 Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IProfiler.cs rename Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/{IDebugViewProfiler.cs.meta => IProfiler.cs.meta} (100%) diff --git a/Explorer/Assets/DCL/ECS/GlobalPartitioning/PartitionGlobalAssetEntitiesSystem.cs b/Explorer/Assets/DCL/ECS/GlobalPartitioning/PartitionGlobalAssetEntitiesSystem.cs index 757260232a..27ed065801 100644 --- a/Explorer/Assets/DCL/ECS/GlobalPartitioning/PartitionGlobalAssetEntitiesSystem.cs +++ b/Explorer/Assets/DCL/ECS/GlobalPartitioning/PartitionGlobalAssetEntitiesSystem.cs @@ -6,12 +6,10 @@ using DCL.ECSComponents; using DCL.Optimization.Pools; using DCL.Profiles; -using Decentraland.Kernel.Apis; using ECS.Abstract; using ECS.Prioritization; using ECS.Prioritization.Components; using ECS.Unity.Systems; -using ECS.Unity.Transforms.Components; using UnityEngine; // ReSharper disable once CheckNamespace (Code generation issues) diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Analytics/Systems/PerformanceAnalyticsSystem.cs b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Analytics/Systems/PerformanceAnalyticsSystem.cs index e822217ae7..5223503010 100644 --- a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Analytics/Systems/PerformanceAnalyticsSystem.cs +++ b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Analytics/Systems/PerformanceAnalyticsSystem.cs @@ -20,15 +20,21 @@ namespace DCL.Analytics.Systems [UpdateAfter(typeof(DebugViewProfilingSystem))] public partial class PerformanceAnalyticsSystem : BaseUnityLoopSystem { - private readonly int[] percentiles = { 5, 10, 20, 50, 75, 80, 90, 95 }; + private const int FRAMES_SAMPLES_CAPACITY = 1024; + private readonly AnalyticsConfiguration config; private readonly IAnalyticsController analytics; + private readonly IJsonObjectBuilder jsonObjectBuilder; + private readonly IRealmData realmData; - private readonly IAnalyticsReportProfiler profiler; + + private readonly IProfiler profiler; private readonly V8ActiveEngines v8ActiveEngines; - private readonly IScenesCache scenesCache; - private readonly AnalyticsConfiguration config; - private readonly IJsonObjectBuilder jsonObjectBuilder; + + // private readonly IScenesCache scenesCache; + + private readonly FrameTimesRecorder mainThreadFrameTimes = new (FRAMES_SAMPLES_CAPACITY); + private readonly FrameTimesRecorder gpuFrameTimes = new (FRAMES_SAMPLES_CAPACITY); private float lastReportTime; @@ -36,7 +42,7 @@ public PerformanceAnalyticsSystem( World world, IAnalyticsController analytics, IRealmData realmData, - IAnalyticsReportProfiler profiler, + IProfiler profiler, V8ActiveEngines v8ActiveEngines, IScenesCache scenesCache, IJsonObjectBuilder jsonObjectBuilder @@ -45,7 +51,8 @@ IJsonObjectBuilder jsonObjectBuilder this.realmData = realmData; this.profiler = profiler; this.v8ActiveEngines = v8ActiveEngines; - this.scenesCache = scenesCache; + + // this.scenesCache = scenesCache; this.analytics = analytics; this.jsonObjectBuilder = jsonObjectBuilder; config = analytics.Configuration; @@ -53,93 +60,95 @@ IJsonObjectBuilder jsonObjectBuilder protected override void Update(float t) { - return; - if (!realmData.Configured) return; + mainThreadFrameTimes.AddFrameTime(profiler.LastFrameTimeValueNs); + gpuFrameTimes.AddFrameTime(profiler.LastGpuFrameTimeValueNs); + lastReportTime += t; if (lastReportTime > config.PerformanceReportInterval) { - ReportPerformanceMetrics(); + ReportPerformanceMetrics(lastReportTime); lastReportTime = 0; + + mainThreadFrameTimes.Clear(); + gpuFrameTimes.Clear(); } } - private void ReportPerformanceMetrics() + private void ReportPerformanceMetrics(float measureTime) { - (AnalyticsFrameTimeReport? gpuFrameTimeReport, AnalyticsFrameTimeReport? mainThreadReport, string samplesArray) - = profiler.GetFrameTimesNs(percentiles); - - if (!mainThreadReport.HasValue || !gpuFrameTimeReport.HasValue) - return; - - bool isCurrentScene = scenesCache is { CurrentScene: { SceneStateProvider: { IsCurrent: true } } }; - JsMemorySizeInfo totalJsMemoryData = v8ActiveEngines.GetEnginesSumMemoryData(); - JsMemorySizeInfo currentSceneJsMemoryData = isCurrentScene ? v8ActiveEngines.GetEnginesMemoryDataForScene(scenesCache.CurrentScene.Info) : new JsMemorySizeInfo(); - - { - // TODO (Vit): include more detailed quality information (renderFeatures, fog, etc). Probably from QualitySettingsAsset.cs - jsonObjectBuilder.Set("quality_level", QualitySettings.names[QualitySettings.GetQualityLevel()]); - jsonObjectBuilder.Set("player_count", 0); // TODO (Vit): How many users where nearby the current user - - // JS runtime memory - jsonObjectBuilder.Set("jsheap_used", totalJsMemoryData.UsedHeapSizeMB); - jsonObjectBuilder.Set("jsheap_total", totalJsMemoryData.TotalHeapSizeMB); - jsonObjectBuilder.Set("jsheap_total_executable", totalJsMemoryData.TotalHeapSizeExecutableMB); - jsonObjectBuilder.Set("jsheap_limit", totalJsMemoryData.HeapSizeLimitMB); - jsonObjectBuilder.Set("jsheap_used_current_scene", !isCurrentScene ? -1f : currentSceneJsMemoryData.UsedHeapSizeMB); - jsonObjectBuilder.Set("jsheap_total_current_scene", !isCurrentScene ? -1f : currentSceneJsMemoryData.TotalHeapSizeMB); - jsonObjectBuilder.Set("jsheap_total_executable_current_scene", !isCurrentScene ? -1f : currentSceneJsMemoryData.TotalHeapSizeExecutableMB); - jsonObjectBuilder.Set("running_v8_engines", v8ActiveEngines.Count); - - // Memory - jsonObjectBuilder.Set("total_used_memory", ((ulong)profiler.TotalUsedMemoryInBytes).ByteToMB()); - jsonObjectBuilder.Set("system_used_memory", ((ulong)profiler.SystemUsedMemoryInBytes).ByteToMB()); - jsonObjectBuilder.Set("gc_used_memory", ((ulong)profiler.GcUsedMemoryInBytes).ByteToMB()); - jsonObjectBuilder.Set("total_gc_alloc", ((ulong)profiler.TotalGcAlloc).ByteToMB()); - - // MainThread - jsonObjectBuilder.Set("samples", samplesArray); - jsonObjectBuilder.Set("samples_amount", mainThreadReport.Value.Samples); - jsonObjectBuilder.Set("total_time", mainThreadReport.Value.SumTime * NS_TO_MS); - jsonObjectBuilder.Set("hiccups_in_thousand_frames", mainThreadReport.Value.Stats.HiccupCount); - jsonObjectBuilder.Set("hiccups_time", mainThreadReport.Value.HiccupsReport.HiccupsTime * NS_TO_MS); - jsonObjectBuilder.Set("hiccups_avg", mainThreadReport.Value.HiccupsReport.HiccupsAvg * NS_TO_MS); - jsonObjectBuilder.Set("hiccups_min", mainThreadReport.Value.HiccupsReport.HiccupsMin * NS_TO_MS); - jsonObjectBuilder.Set("hiccups_max", mainThreadReport.Value.HiccupsReport.HiccupsMax * NS_TO_MS); - jsonObjectBuilder.Set("min_frame_time", mainThreadReport.Value.Stats.MinFrameTime * NS_TO_MS); - jsonObjectBuilder.Set("max_frame_time", mainThreadReport.Value.Stats.MaxFrameTime * NS_TO_MS); - jsonObjectBuilder.Set("mean_frame_time", mainThreadReport.Value.Average * NS_TO_MS); - jsonObjectBuilder.Set("frame_time_percentile_5", mainThreadReport.Value.Percentiles[0] * NS_TO_MS); - jsonObjectBuilder.Set("frame_time_percentile_10", mainThreadReport.Value.Percentiles[1] * NS_TO_MS); - jsonObjectBuilder.Set("frame_time_percentile_20", mainThreadReport.Value.Percentiles[2] * NS_TO_MS); - jsonObjectBuilder.Set("frame_time_percentile_50", mainThreadReport.Value.Percentiles[3] * NS_TO_MS); - jsonObjectBuilder.Set("frame_time_percentile_75", mainThreadReport.Value.Percentiles[4] * NS_TO_MS); - jsonObjectBuilder.Set("frame_time_percentile_80", mainThreadReport.Value.Percentiles[5] * NS_TO_MS); - jsonObjectBuilder.Set("frame_time_percentile_90", mainThreadReport.Value.Percentiles[6] * NS_TO_MS); - jsonObjectBuilder.Set("frame_time_percentile_95", mainThreadReport.Value.Percentiles[7] * NS_TO_MS); - - // GPU - jsonObjectBuilder.Set("gpu_hiccups_in_thousand_frames", gpuFrameTimeReport.Value.Stats.HiccupCount); - jsonObjectBuilder.Set("gpu_hiccups_time", gpuFrameTimeReport.Value.HiccupsReport.HiccupsTime * NS_TO_MS); - jsonObjectBuilder.Set("gpu_hiccups_avg", gpuFrameTimeReport.Value.HiccupsReport.HiccupsAvg * NS_TO_MS); - jsonObjectBuilder.Set("gpu_hiccups_min", gpuFrameTimeReport.Value.HiccupsReport.HiccupsMin * NS_TO_MS); - jsonObjectBuilder.Set("gpu_hiccups_max", gpuFrameTimeReport.Value.HiccupsReport.HiccupsMax * NS_TO_MS); - jsonObjectBuilder.Set("gpu_min_frame_time", gpuFrameTimeReport.Value.Stats.MinFrameTime * NS_TO_MS); - jsonObjectBuilder.Set("gpu_max_frame_time", gpuFrameTimeReport.Value.Stats.MaxFrameTime * NS_TO_MS); - jsonObjectBuilder.Set("gpu_mean_frame_time", gpuFrameTimeReport.Value.Average * NS_TO_MS); - jsonObjectBuilder.Set("gpu_frame_time_percentile_5", gpuFrameTimeReport.Value.Percentiles[0] * NS_TO_MS); - jsonObjectBuilder.Set("gpu_frame_time_percentile_10", gpuFrameTimeReport.Value.Percentiles[1] * NS_TO_MS); - jsonObjectBuilder.Set("gpu_frame_time_percentile_20", gpuFrameTimeReport.Value.Percentiles[2] * NS_TO_MS); - jsonObjectBuilder.Set("gpu_frame_time_percentile_50", gpuFrameTimeReport.Value.Percentiles[3] * NS_TO_MS); - jsonObjectBuilder.Set("gpu_frame_time_percentile_75", gpuFrameTimeReport.Value.Percentiles[4] * NS_TO_MS); - jsonObjectBuilder.Set("gpu_frame_time_percentile_80", gpuFrameTimeReport.Value.Percentiles[5] * NS_TO_MS); - jsonObjectBuilder.Set("gpu_frame_time_percentile_90", gpuFrameTimeReport.Value.Percentiles[6] * NS_TO_MS); - jsonObjectBuilder.Set("gpu_frame_time_percentile_95", gpuFrameTimeReport.Value.Percentiles[7] * NS_TO_MS); - } + jsonObjectBuilder.Set("total_time", measureTime); + + // TODO (Vit): include more detailed quality information (renderFeatures, fog, etc). Probably from QualitySettingsAsset.cs + jsonObjectBuilder.Set("quality_level", QualitySettings.names[QualitySettings.GetQualityLevel()]); + jsonObjectBuilder.Set("player_count", 0); // TODO (Vit): How many users where nearby the current user + + // JS runtime memory + // bool isCurrentScene = scenesCache is { CurrentScene: { SceneStateProvider: { IsCurrent: true } } }; + // JsMemorySizeInfo totalJsMemoryData = v8ActiveEngines.GetEnginesSumMemoryData(); + // JsMemorySizeInfo currentSceneJsMemoryData = isCurrentScene ? v8ActiveEngines.GetEnginesMemoryDataForScene(scenesCache.CurrentScene.Info) : new JsMemorySizeInfo(); + // jsonObjectBuilder.Set("jsheap_used", totalJsMemoryData.UsedHeapSizeMB); + // jsonObjectBuilder.Set("jsheap_total", totalJsMemoryData.TotalHeapSizeMB); + // jsonObjectBuilder.Set("jsheap_total_executable", totalJsMemoryData.TotalHeapSizeExecutableMB); + // jsonObjectBuilder.Set("jsheap_limit", totalJsMemoryData.HeapSizeLimitMB); + // jsonObjectBuilder.Set("jsheap_used_current_scene", !isCurrentScene ? -1f : currentSceneJsMemoryData.UsedHeapSizeMB); + // jsonObjectBuilder.Set("jsheap_total_current_scene", !isCurrentScene ? -1f : currentSceneJsMemoryData.TotalHeapSizeMB); + // jsonObjectBuilder.Set("jsheap_total_executable_current_scene", !isCurrentScene ? -1f : currentSceneJsMemoryData.TotalHeapSizeExecutableMB); + jsonObjectBuilder.Set("running_v8_engines", v8ActiveEngines.Count); + + // Memory + jsonObjectBuilder.Set("total_used_memory", ((ulong)profiler.TotalUsedMemoryInBytes).ByteToMB()); + jsonObjectBuilder.Set("system_used_memory", ((ulong)profiler.SystemUsedMemoryInBytes).ByteToMB()); + jsonObjectBuilder.Set("gc_used_memory", ((ulong)profiler.GcUsedMemoryInBytes).ByteToMB()); + jsonObjectBuilder.Set("total_gc_alloc", ((ulong)profiler.TotalGcAlloc).ByteToMB()); + + // MainThread + (bool hasValue, long count, long sumTime, long min, long max, float avg) hiccups = profiler.CalculateMainThreadHiccups(); + jsonObjectBuilder.Set("hiccups_in_thousand_frames", !hiccups.hasValue ? 0 : hiccups.count); + jsonObjectBuilder.Set("hiccups_time", !hiccups.hasValue ? 0 : hiccups.sumTime * NS_TO_MS); + jsonObjectBuilder.Set("hiccups_min", !hiccups.hasValue ? 0 : hiccups.min * NS_TO_MS); + jsonObjectBuilder.Set("hiccups_max", !hiccups.hasValue ? 0 : hiccups.max * NS_TO_MS); + jsonObjectBuilder.Set("hiccups_avg", !hiccups.hasValue ? 0 : hiccups.avg * NS_TO_MS); + + jsonObjectBuilder.Set("min_frame_time", mainThreadFrameTimes.Min * NS_TO_MS); + jsonObjectBuilder.Set("max_frame_time", mainThreadFrameTimes.Max * NS_TO_MS); + jsonObjectBuilder.Set("mean_frame_time", mainThreadFrameTimes.Avg * NS_TO_MS); + jsonObjectBuilder.Set("frame_time_percentile_5", mainThreadFrameTimes.Percentile(5) * NS_TO_MS); + jsonObjectBuilder.Set("frame_time_percentile_10", mainThreadFrameTimes.Percentile(10) * NS_TO_MS); + jsonObjectBuilder.Set("frame_time_percentile_20", mainThreadFrameTimes.Percentile(20) * NS_TO_MS); + jsonObjectBuilder.Set("frame_time_percentile_50", mainThreadFrameTimes.Percentile(50) * NS_TO_MS); + jsonObjectBuilder.Set("frame_time_percentile_75", mainThreadFrameTimes.Percentile(75) * NS_TO_MS); + jsonObjectBuilder.Set("frame_time_percentile_80", mainThreadFrameTimes.Percentile(80) * NS_TO_MS); + jsonObjectBuilder.Set("frame_time_percentile_90", mainThreadFrameTimes.Percentile(90) * NS_TO_MS); + jsonObjectBuilder.Set("frame_time_percentile_95", mainThreadFrameTimes.Percentile(95) * NS_TO_MS); + + jsonObjectBuilder.Set("samples", mainThreadFrameTimes.GetSamplesArrayAsString()); + jsonObjectBuilder.Set("samples_amount", mainThreadFrameTimes.SamplesAmount); + + // GPU + hiccups = profiler.CalculateGpuHiccups(); + jsonObjectBuilder.Set("gpu_hiccups_in_thousand_frames", !hiccups.hasValue ? 0 : hiccups.count); + jsonObjectBuilder.Set("gpu_hiccups_time", !hiccups.hasValue ? 0 : hiccups.sumTime * NS_TO_MS); + jsonObjectBuilder.Set("gpu_hiccups_min", !hiccups.hasValue ? 0 : hiccups.min * NS_TO_MS); + jsonObjectBuilder.Set("gpu_hiccups_max", !hiccups.hasValue ? 0 : hiccups.max * NS_TO_MS); + jsonObjectBuilder.Set("gpu_hiccups_avg", !hiccups.hasValue ? 0 : hiccups.avg * NS_TO_MS); + + jsonObjectBuilder.Set("gpu_min_frame_time", gpuFrameTimes.Min * NS_TO_MS); + jsonObjectBuilder.Set("gpu_max_frame_time", gpuFrameTimes.Max * NS_TO_MS); + jsonObjectBuilder.Set("gpu_mean_frame_time", gpuFrameTimes.Avg * NS_TO_MS); + jsonObjectBuilder.Set("gpu_frame_time_percentile_5", gpuFrameTimes.Percentile(5) * NS_TO_MS); + jsonObjectBuilder.Set("gpu_frame_time_percentile_10", gpuFrameTimes.Percentile(10) * NS_TO_MS); + jsonObjectBuilder.Set("gpu_frame_time_percentile_20", gpuFrameTimes.Percentile(20) * NS_TO_MS); + jsonObjectBuilder.Set("gpu_frame_time_percentile_50", gpuFrameTimes.Percentile(50) * NS_TO_MS); + jsonObjectBuilder.Set("gpu_frame_time_percentile_75", gpuFrameTimes.Percentile(75) * NS_TO_MS); + jsonObjectBuilder.Set("gpu_frame_time_percentile_80", gpuFrameTimes.Percentile(80) * NS_TO_MS); + jsonObjectBuilder.Set("gpu_frame_time_percentile_90", gpuFrameTimes.Percentile(90) * NS_TO_MS); + jsonObjectBuilder.Set("gpu_frame_time_percentile_95", gpuFrameTimes.Percentile(95) * NS_TO_MS); + + using PooledJsonObject pooled = jsonObjectBuilder.BuildPooled(); - using var pooled = jsonObjectBuilder.BuildPooled(); analytics.Track(General.PERFORMANCE_REPORT, pooled.Json); } } diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/ECS/DebugViewProfilingSystem.cs b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/ECS/DebugViewProfilingSystem.cs index 3ba8dacce3..69df879434 100644 --- a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/ECS/DebugViewProfilingSystem.cs +++ b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/ECS/DebugViewProfilingSystem.cs @@ -23,7 +23,7 @@ public partial class DebugViewProfilingSystem : BaseUnityLoopSystem private const float FRAME_STATS_COOLDOWN = 30; // update each frames (statistic buffer == 1000) private readonly IRealmData realmData; - private readonly IDebugViewProfiler profiler; + private readonly IProfiler profiler; private readonly MemoryBudget memoryBudget; private readonly V8ActiveEngines v8ActiveEngines; private readonly IScenesCache scenesCache; @@ -64,7 +64,7 @@ public partial class DebugViewProfilingSystem : BaseUnityLoopSystem private bool frameTimingsEnabled; private bool sceneMetricsEnabled; - private DebugViewProfilingSystem(World world, IRealmData realmData, IDebugViewProfiler profiler, MemoryBudget memoryBudget, IDebugContainerBuilder debugBuilder, + private DebugViewProfilingSystem(World world, IRealmData realmData, IProfiler profiler, MemoryBudget memoryBudget, IDebugContainerBuilder debugBuilder, V8ActiveEngines v8ActiveEngines, IScenesCache scenesCache) : base(world) { this.realmData = realmData; @@ -128,7 +128,7 @@ protected override void Update(float t) if (performanceVisibilityBinding.IsExpanded) { - SetFPS(fps, profiler.LastFrameTimeValueNs); + SetFPS(fps, (long)profiler.LastFrameTimeValueNs); if (framesSinceMetricsUpdate > FRAME_STATS_COOLDOWN) { @@ -198,7 +198,7 @@ string GetMemoryUsageColor() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void UpdateFrameStatisticsView(IDebugViewProfiler debugProfiler) + private void UpdateFrameStatisticsView(IProfiler debugProfiler) { FrameTimeStats? frameTimeStats = debugProfiler.CalculateMainThreadFrameTimesNs(); diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/FrameTimesRecorder.cs b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/FrameTimesRecorder.cs new file mode 100644 index 0000000000..666416ec11 --- /dev/null +++ b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/FrameTimesRecorder.cs @@ -0,0 +1,120 @@ +using System; +using System.Text; +using UnityEngine; + +namespace DCL.Profiling +{ + /// + /// Calculated in Nanoseconds (if not specified) + /// + /// Can be further optimized by taking into account ulong + public class FrameTimesRecorder + { + private readonly StringBuilder stringBuilder = new (); + + private int capacity; + private ulong[] samples; + + private ulong totalRecordedTime; + + public int SamplesAmount { get; private set; } + public float Avg => SamplesAmount == 0 ? 0 : totalRecordedTime / (float)SamplesAmount; + public ulong Min => samples[0]; + public ulong Max => SamplesAmount == 0 ? samples[0] : samples[SamplesAmount - 1]; + + public FrameTimesRecorder(int capacity) + { + this.capacity = capacity; + samples = new ulong[capacity]; + SamplesAmount = 0; + } + + public void AddFrameTime(ulong frameTime) + { + totalRecordedTime += frameTime; + InsertSampleSorted(frameTime); + } + + private void InsertSampleSorted(ulong frameTime) + { + if (SamplesAmount == capacity) + GrowArray(); + + int insertIndex = BinarySearchForInsertionPosition(frameTime); + + if (insertIndex < SamplesAmount) + Array.Copy(samples, insertIndex, samples, insertIndex + 1, SamplesAmount - insertIndex); + + samples[insertIndex] = frameTime; + SamplesAmount++; + } + + private void GrowArray() + { + int newCapacity = capacity * 2; + var newArray = new ulong[newCapacity]; + + Array.Copy(samples, newArray, SamplesAmount); + + samples = newArray; + capacity = newCapacity; + } + + private int BinarySearchForInsertionPosition(ulong value) + { + var left = 0; + int right = SamplesAmount - 1; + + while (left <= right) + { + int mid = left + ((right - left) / 2); + + if (samples[mid] == value) + return mid; + + if (samples[mid] < value) + left = mid + 1; + else + right = mid - 1; + } + + return left; + } + + public ulong Percentile(float value) + { + if (SamplesAmount == 0) + return 0; + + var index = (int)Math.Ceiling(value / 100f * SamplesAmount); + index = Math.Min(index, SamplesAmount) - 1; + return samples[index]; + } + + public string GetSamplesArrayAsString() + { + const float NS_TO_MS = 1e-6f; + + stringBuilder.Clear(); + stringBuilder.Append("["); + + for (var i = 0; i < SamplesAmount; i++) + { + stringBuilder.Append(Mathf.Round(samples[i] * NS_TO_MS)); + + if (i < SamplesAmount - 1) + stringBuilder.Append(","); + } + + stringBuilder.Append("]"); + + return stringBuilder.ToString(); + } + + public void Clear() + { + SamplesAmount = 0; + totalRecordedTime = 0; + } + } +} diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/FrameTimesRecorder.cs.meta b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/FrameTimesRecorder.cs.meta new file mode 100644 index 0000000000..6aa6dbdf4c --- /dev/null +++ b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/FrameTimesRecorder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 60fb5ea8ff7d465abb539bdcbc786c07 +timeCreated: 1729674279 \ No newline at end of file diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IAnalyticsReportProfiler.cs b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IAnalyticsReportProfiler.cs deleted file mode 100644 index 32a15e01dc..0000000000 --- a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IAnalyticsReportProfiler.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using Unity.Profiling; - -namespace DCL.Profiling -{ - public interface IAnalyticsReportProfiler : IMemoryProfiler - { - (AnalyticsFrameTimeReport? gpuFrameTime, AnalyticsFrameTimeReport? mainThreadFrameTime, string mainThreadSamples) - GetFrameTimesNs(int[] percentile); - - float TotalGcAlloc { get; } - } - - public readonly struct AnalyticsFrameTimeReport - { - public readonly int Samples; - public readonly long SumTime; - public readonly long Average; - public readonly long[] Percentiles; - public readonly FrameTimeStats Stats; - public readonly HiccupsReport HiccupsReport; - - public AnalyticsFrameTimeReport(FrameTimeStats stats, long[] percentiles, long sumTime, int samples, HiccupsReport hiccupsReport) - { - Samples = samples; - SumTime = sumTime; - - Average = sumTime / samples; - Percentiles = percentiles; - Stats = stats; - - HiccupsReport = hiccupsReport; - } - } - - public readonly struct HiccupsReport - { - public readonly long HiccupsTime; - public readonly long HiccupsMin; - public readonly long HiccupsMax; - public readonly long HiccupsAvg; - - public HiccupsReport(long hiccupsTime, long hiccupsMin, long hiccupsMax, long hiccupsAvg) - { - HiccupsTime = hiccupsTime; - HiccupsMin = hiccupsMin; - HiccupsMax = hiccupsMax; - HiccupsAvg = hiccupsAvg; - } - } -} diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IAnalyticsReportProfiler.cs.meta b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IAnalyticsReportProfiler.cs.meta deleted file mode 100644 index e2ef9db601..0000000000 --- a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IAnalyticsReportProfiler.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fb54576f819147f0892d38083520974d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IBudgetProfiler.cs b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IBudgetProfiler.cs index 78fd7d0b66..30f70f1144 100644 --- a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IBudgetProfiler.cs +++ b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IBudgetProfiler.cs @@ -5,8 +5,12 @@ namespace DCL.Profiling public interface IBudgetProfiler : IDisposable { long TotalUsedMemoryInBytes { get; } - ulong CurrentFrameTimeValueNs { get; } long SystemUsedMemoryInBytes { get; } + + ulong CurrentFrameTimeValueNs { get; } + + ulong LastFrameTimeValueNs { get; } + ulong LastGpuFrameTimeValueNs { get; } } public readonly struct FrameTimeStats diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IDebugViewProfiler.cs b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IDebugViewProfiler.cs deleted file mode 100644 index a4432da384..0000000000 --- a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IDebugViewProfiler.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace DCL.Profiling -{ - public interface IDebugViewProfiler : IMemoryProfiler - { - long LastFrameTimeValueNs { get; } - FrameTimeStats? CalculateMainThreadFrameTimesNs(); - } -} diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IMemoryProfiler.cs b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IMemoryProfiler.cs index 7fc78741c4..ed082a1ea1 100644 --- a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IMemoryProfiler.cs +++ b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IMemoryProfiler.cs @@ -4,5 +4,6 @@ public interface IMemoryProfiler : IBudgetProfiler { long SystemUsedMemoryInBytes { get; } long GcUsedMemoryInBytes { get; } + float TotalGcAlloc { get; } } } diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IProfiler.cs b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IProfiler.cs new file mode 100644 index 0000000000..ec951dc002 --- /dev/null +++ b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IProfiler.cs @@ -0,0 +1,11 @@ +namespace DCL.Profiling +{ + public interface IProfiler : IMemoryProfiler + { + FrameTimeStats? CalculateMainThreadFrameTimesNs(); + + (bool hasValue, long count, long sumTime, long min, long max, float avg) CalculateMainThreadHiccups(); + + (bool hasValue, long count, long sumTime, long min, long max, float avg) CalculateGpuHiccups(); + } +} diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IDebugViewProfiler.cs.meta b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IProfiler.cs.meta similarity index 100% rename from Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IDebugViewProfiler.cs.meta rename to Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/IProfiler.cs.meta diff --git a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/Profiler.cs b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/Profiler.cs index 1bcaf778ad..d667e633f9 100644 --- a/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/Profiler.cs +++ b/Explorer/Assets/DCL/PerformanceAndDiagnostics/Profiling/Profiler.cs @@ -1,6 +1,4 @@ -using System; using System.Collections.Generic; -using System.Text; using Unity.Profiling; namespace DCL.Profiling @@ -9,13 +7,11 @@ namespace DCL.Profiling /// Profiling provider to provide in game metrics. Profiler recorder returns values in NS, so to stay consistent with it, /// our most used metric is going to be NS /// - public class Profiler : IDebugViewProfiler, IAnalyticsReportProfiler + public class Profiler : IProfiler { - private const float NS_TO_MS = 1e-6f; // nanoseconds to milliseconds private const int HICCUP_THRESHOLD_IN_NS = 50_000_000; // 50 ms ~ 20 FPS private const int FRAME_BUFFER_SIZE = 1_000; // 1000 samples: for 30 FPS it's 33 seconds gameplay, for 60 FPS it's 16.6 seconds - private static readonly ProfilerRecorderSampleComparer PROFILER_SAMPLES_COMPARER = new (); private readonly List samples = new (FRAME_BUFFER_SIZE); // Memory footprint of your application as seen by the operating system. @@ -30,12 +26,12 @@ public class Profiler : IDebugViewProfiler, IAnalyticsReportProfiler public long TotalUsedMemoryInBytes => totalUsedMemoryRecorder.CurrentValue; public long SystemUsedMemoryInBytes => systemUsedMemoryRecorder.CurrentValue; public long GcUsedMemoryInBytes => gcUsedMemoryRecorder.CurrentValue; + public float TotalGcAlloc => GetRecorderSamplesSum(gcAllocatedInFrameRecorder); public ulong CurrentFrameTimeValueNs => (ulong)mainThreadTimeRecorder.CurrentValue; - public long LastFrameTimeValueNs => mainThreadTimeRecorder.LastValue; - public float TotalGcAlloc => GetRecorderSamplesSum(gcAllocatedInFrameRecorder); - private readonly StringBuilder stringBuilder = new (); + public ulong LastFrameTimeValueNs => (ulong)mainThreadTimeRecorder.LastValue; + public ulong LastGpuFrameTimeValueNs => (ulong)gpuFrameTimeRecorder.LastValue; public void Dispose() { @@ -60,6 +56,7 @@ public void Dispose() long minFrameTime = long.MaxValue; long maxFrameTime = long.MinValue; + long hiccupCount = 0; samples.Clear(); @@ -77,48 +74,24 @@ public void Dispose() return new FrameTimeStats(minFrameTime, maxFrameTime, hiccupCount); } - public (AnalyticsFrameTimeReport? gpuFrameTime, AnalyticsFrameTimeReport? mainThreadFrameTime, string mainThreadSamples) GetFrameTimesNs(int[] percentile) - { - var gpuReport = GetFrameStatsWithPercentiles(gpuFrameTimeRecorder, percentile); - // Main thread should be last to calculate, so Samples reflects mainThread FrameData and not GPU FrameData - var mainThreadReport = GetFrameStatsWithPercentiles(mainThreadTimeRecorder, percentile); - - return (gpuReport,mainThreadReport, GetSamplesArrayAsString()); - - string GetSamplesArrayAsString() - { - stringBuilder.Clear(); - stringBuilder.Append("["); - - for (var i = 0; i < samples.Count; i++) - { - stringBuilder.AppendFormat("{0:0.000}", samples[i].Value * NS_TO_MS); - - if (i < samples.Count - 1) - stringBuilder.Append(","); - } + public (bool hasValue, long count, long sumTime, long min, long max, float avg) CalculateMainThreadHiccups() => + CalculateThreadHiccups(mainThreadTimeRecorder); - stringBuilder.Append("]"); - - return stringBuilder.ToString(); - } - } + public (bool hasValue, long count, long sumTime, long min, long max, float avg) CalculateGpuHiccups() => + CalculateThreadHiccups(gpuFrameTimeRecorder); - // Exclusive percentile calculation variant, it rounds to nearest (in contrast to inclusive approach) - private AnalyticsFrameTimeReport? GetFrameStatsWithPercentiles(ProfilerRecorder recorder, int[] percentile) + private (bool hasValue, long count, long sumTime, long min, long max, float avg) CalculateThreadHiccups(ProfilerRecorder recorder) { - int samplesCount = recorder.Capacity; + int availableSamples = recorder.Capacity; - if (samplesCount == 0) - return null; + if (availableSamples == 0) + return (false, 0, 0, 0, 0, 0); long hiccupCount = 0; long hiccupTotalTime = 0; long hiccupMin = -1; long hiccupMax = -1; - long sumTime = 0; - samples.Clear(); recorder.CopyTo(samples); @@ -126,8 +99,6 @@ string GetSamplesArrayAsString() { long frameTime = samples[i].Value; - sumTime += frameTime; - if (frameTime > HICCUP_THRESHOLD_IN_NS) { hiccupCount++; @@ -140,22 +111,7 @@ string GetSamplesArrayAsString() } } - samples.Sort(PROFILER_SAMPLES_COMPARER); - var result = new long[percentile.Length]; - - for (var i = 0; i < percentile.Length; i++) - { - var index = (int)Math.Ceiling(percentile[i] / 100f * samplesCount); - index = Math.Min(index, samplesCount - 1); - result[i] = samples[index - 1].Value; - } - - return - new AnalyticsFrameTimeReport( - new FrameTimeStats(samples[0].Value, samples[samplesCount - 1].Value, hiccupCount), - result, sumTime, samplesCount, - hiccupCount != 0 ? new HiccupsReport(hiccupTotalTime, hiccupMin, hiccupMax, hiccupTotalTime / hiccupCount) : new HiccupsReport(0, 0, 0, 0) - ); + return (true, hiccupCount, hiccupTotalTime, hiccupMin, hiccupMax, hiccupCount == 0 ? 0 : hiccupTotalTime / (float)hiccupCount); } private float GetRecorderSamplesSum(ProfilerRecorder recorder) @@ -175,11 +131,5 @@ private float GetRecorderSamplesSum(ProfilerRecorder recorder) return r; } - - private class ProfilerRecorderSampleComparer : IComparer - { - public int Compare(ProfilerRecorderSample x, ProfilerRecorderSample y) => - x.Value.CompareTo(y.Value); - } } } diff --git a/Explorer/Assets/DCL/PluginSystem/Global/AnalyticsPlugin.cs b/Explorer/Assets/DCL/PluginSystem/Global/AnalyticsPlugin.cs index cbbfef0a6a..01308ee1a1 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/AnalyticsPlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/AnalyticsPlugin.cs @@ -17,7 +17,7 @@ namespace DCL.PluginSystem.Global { public class AnalyticsPlugin : IDCLGlobalPlugin { - private readonly IAnalyticsReportProfiler profiler; + private readonly IProfiler profiler; private readonly IRealmNavigator realmNavigator; private readonly IRealmData realmData; private readonly IScenesCache scenesCache; @@ -27,7 +27,7 @@ public class AnalyticsPlugin : IDCLGlobalPlugin private readonly WalkedDistanceAnalytics walkedDistanceAnalytics; - public AnalyticsPlugin(IAnalyticsController analytics, IAnalyticsReportProfiler profiler, IRealmNavigator realmNavigator, IRealmData realmData, IScenesCache scenesCache, + public AnalyticsPlugin(IAnalyticsController analytics, IProfiler profiler, IRealmNavigator realmNavigator, IRealmData realmData, IScenesCache scenesCache, ObjectProxy mainPlayerAvatarBaseProxy, IWeb3IdentityCache identityCache, IDebugContainerBuilder debugContainerBuilder) { this.analytics = analytics; diff --git a/Explorer/Assets/DCL/PluginSystem/Global/ProfilingPlugin.cs b/Explorer/Assets/DCL/PluginSystem/Global/ProfilingPlugin.cs index 3e686f6a2b..eb3fef5862 100644 --- a/Explorer/Assets/DCL/PluginSystem/Global/ProfilingPlugin.cs +++ b/Explorer/Assets/DCL/PluginSystem/Global/ProfilingPlugin.cs @@ -11,13 +11,13 @@ namespace DCL.PluginSystem.Global { public class ProfilingPlugin : IDCLGlobalPluginWithoutSettings { - private readonly IDebugViewProfiler profiler; + private readonly IProfiler profiler; private readonly IRealmData realmData; private readonly MemoryBudget memoryBudget; private readonly IDebugContainerBuilder debugContainerBuilder; private readonly IScenesCache scenesCache; - public ProfilingPlugin(IDebugViewProfiler profiler, IRealmData realmData, MemoryBudget memoryBudget, IDebugContainerBuilder debugContainerBuilder, IScenesCache scenesCache) + public ProfilingPlugin(IProfiler profiler, IRealmData realmData, MemoryBudget memoryBudget, IDebugContainerBuilder debugContainerBuilder, IScenesCache scenesCache) { this.profiler = profiler; this.realmData = realmData; From 2e697f25a0072465482a512a1fdd6ffc8783b9dc Mon Sep 17 00:00:00 2001 From: Fran Colarich <56565104+fcolarich@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:20:40 +0200 Subject: [PATCH 14/16] fix: scenes not switching to LOD properly. (#2572) * Fix for candidate state check * Added additional check --- Explorer/Assets/DCL/LOD/Systems/VisualSceneStateResolver.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Explorer/Assets/DCL/LOD/Systems/VisualSceneStateResolver.cs b/Explorer/Assets/DCL/LOD/Systems/VisualSceneStateResolver.cs index f3e8c52422..6e05f16d36 100644 --- a/Explorer/Assets/DCL/LOD/Systems/VisualSceneStateResolver.cs +++ b/Explorer/Assets/DCL/LOD/Systems/VisualSceneStateResolver.cs @@ -30,12 +30,13 @@ public void ResolveVisualSceneState(ref VisualSceneState visualSceneState, Parti else if (!sceneDefinitionComponent.IsSDK7) visualSceneState.CandidateVisualSceneState = visualSceneState.CurrentVisualSceneState = VisualSceneStateEnum.SHOWING_LOD; else { - visualSceneState.CandidateVisualSceneState = partition.Bucket < lodSettingsAsset.SDK7LodThreshold + var candidateVisualSceneState = partition.Bucket < lodSettingsAsset.SDK7LodThreshold ? VisualSceneStateEnum.SHOWING_SCENE : VisualSceneStateEnum.SHOWING_LOD; - if (visualSceneState.CandidateVisualSceneState != visualSceneState.CurrentVisualSceneState) + if (visualSceneState.CandidateVisualSceneState != candidateVisualSceneState && candidateVisualSceneState != visualSceneState.CurrentVisualSceneState) { + visualSceneState.CandidateVisualSceneState = candidateVisualSceneState; visualSceneState.IsDirty = true; visualSceneState.TimeToChange = 0; } From 4d1a16cad82610aaef9226c25a4125f9550befb9 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Molteni Date: Thu, 24 Oct 2024 07:57:17 -0300 Subject: [PATCH 15/16] fix: Scene was not initializing correctly (#2581) --- .../Assets/DCL/LOD/Systems/VisualSceneStateResolver.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Explorer/Assets/DCL/LOD/Systems/VisualSceneStateResolver.cs b/Explorer/Assets/DCL/LOD/Systems/VisualSceneStateResolver.cs index 6e05f16d36..57b9e01b7f 100644 --- a/Explorer/Assets/DCL/LOD/Systems/VisualSceneStateResolver.cs +++ b/Explorer/Assets/DCL/LOD/Systems/VisualSceneStateResolver.cs @@ -34,7 +34,14 @@ public void ResolveVisualSceneState(ref VisualSceneState visualSceneState, Parti ? VisualSceneStateEnum.SHOWING_SCENE : VisualSceneStateEnum.SHOWING_LOD; - if (visualSceneState.CandidateVisualSceneState != candidateVisualSceneState && candidateVisualSceneState != visualSceneState.CurrentVisualSceneState) + if (visualSceneState.CurrentVisualSceneState == VisualSceneStateEnum.UNINITIALIZED) + { + visualSceneState.CandidateVisualSceneState = candidateVisualSceneState; + visualSceneState.CurrentVisualSceneState = candidateVisualSceneState; + visualSceneState.IsDirty = true; + } + else if (visualSceneState.CandidateVisualSceneState != candidateVisualSceneState && + candidateVisualSceneState != visualSceneState.CurrentVisualSceneState) { visualSceneState.CandidateVisualSceneState = candidateVisualSceneState; visualSceneState.IsDirty = true; From 9ad45d57d94467e50a492a2a473d7072f1828a0a Mon Sep 17 00:00:00 2001 From: Aga Date: Thu, 24 Oct 2024 13:08:47 +0200 Subject: [PATCH 16/16] fix: wrong tag version on dev (#2580) --- .github/workflows/build-unitycloud.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-unitycloud.yml b/.github/workflows/build-unitycloud.yml index 393a8e4682..62b253eb47 100644 --- a/.github/workflows/build-unitycloud.yml +++ b/.github/workflows/build-unitycloud.yml @@ -102,7 +102,8 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - + ref: 'main' + - name: Get version id: get_version if: ${{ github.event.inputs.version == '' && inputs.version == '' }}