diff --git a/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs b/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs index 0b975f912..1f5eddc75 100644 --- a/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs @@ -655,7 +655,9 @@ namespace FlaxEditor.CustomEditors.Dedicated if (uiControl.Name.StartsWith(previousName)) { string newName = controlType.Name + uiControl.Name.Substring(previousName.Length); - uiControl.Name = Utilities.Utils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null); + if (uiControl.Parent != null) + newName = Utilities.Utils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null); + uiControl.Name = newName; } } diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index e3c71fba8..6ad621a7a 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -358,11 +358,19 @@ namespace FlaxEditor { // Check if prefab root control is this UIControl var loadingPreview = Viewport.Previews.PrefabPreview.LoadingPreview; - if (loadingPreview != null) + var activePreviews = Viewport.Previews.PrefabPreview.ActivePreviews; + if (activePreviews != null) { - // Link it to the prefab preview to see it in the editor - loadingPreview.customControlLinked = control; - return loadingPreview; + foreach (var preview in activePreviews) + { + if (preview == loadingPreview || + (preview.Instance != null && (preview.Instance == control || preview.Instance.HasActorInHierarchy(control)))) + { + // Link it to the prefab preview to see it in the editor + preview.customControlLinked = control; + return preview; + } + } } return null; } diff --git a/Source/Editor/Viewport/Previews/PrefabPreview.cs b/Source/Editor/Viewport/Previews/PrefabPreview.cs index b02cd6f4a..514a3e50b 100644 --- a/Source/Editor/Viewport/Previews/PrefabPreview.cs +++ b/Source/Editor/Viewport/Previews/PrefabPreview.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; +using System.Collections.Generic; using FlaxEngine; using Object = FlaxEngine.Object; @@ -13,10 +14,15 @@ namespace FlaxEditor.Viewport.Previews public class PrefabPreview : AssetPreview { /// - /// The preview that is during prefab instance spawning. Used to link some actors such as UIControl to preview scene and view. + /// The currently spawned prefab instance owner. Used to link some actors such as UIControl to preview scene and view. /// internal static PrefabPreview LoadingPreview; + /// + /// The list of active prefab previews. Used to link some actors such as UIControl to preview scene and view. + /// + internal static List ActivePreviews; + private Prefab _prefab; private Actor _instance; internal UIControl customControlLinked; @@ -48,13 +54,13 @@ namespace FlaxEditor.Viewport.Previews _prefab.WaitForLoaded(); // Spawn prefab - var prevPreview = LoadingPreview; LoadingPreview = this; var instance = PrefabManager.SpawnPrefab(_prefab, null); - LoadingPreview = prevPreview; + LoadingPreview = null; if (instance == null) { _prefab = null; + ActivePreviews.Remove(this); throw new Exception("Failed to spawn a prefab for the preview."); } @@ -120,6 +126,9 @@ namespace FlaxEditor.Viewport.Previews public PrefabPreview(bool useWidgets) : base(useWidgets) { + if (ActivePreviews == null) + ActivePreviews = new List(); + ActivePreviews.Add(this); } /// @@ -137,6 +146,7 @@ namespace FlaxEditor.Viewport.Previews /// public override void OnDestroy() { + ActivePreviews.Remove(this); Prefab = null; base.OnDestroy(); diff --git a/Source/Editor/Windows/Profiler/CPU.cs b/Source/Editor/Windows/Profiler/CPU.cs index d10646da0..36fbf21f4 100644 --- a/Source/Editor/Windows/Profiler/CPU.cs +++ b/Source/Editor/Windows/Profiler/CPU.cs @@ -197,7 +197,7 @@ namespace FlaxEditor.Windows.Profiler if (_tableRowsCache == null) _tableRowsCache = new List(); - var viewRange = GetEventsViewRange(); + var viewRange = _showOnlyLastUpdateEvents ? GetMainThreadUpdateRange() : ViewRange.Full; UpdateTimeline(ref viewRange); UpdateTable(ref viewRange); } @@ -235,36 +235,27 @@ namespace FlaxEditor.Windows.Profiler } } - private ViewRange GetEventsViewRange() + private ViewRange GetMainThreadUpdateRange() { - if (_showOnlyLastUpdateEvents) + if (_events != null && _events.Count != 0) { - // Find root event named 'Update' and use it as a view range - if (_events != null && _events.Count != 0) + var threads = _events.Get(_mainChart.SelectedSampleIndex); + if (threads != null) { - var data = _events.Get(_mainChart.SelectedSampleIndex); - if (data != null) + for (int j = 0; j < threads.Length; j++) { - for (int j = 0; j < data.Length; j++) + var thread = threads[j]; + if (thread.Name != "Main" || thread.Events == null) + continue; + for (int i = 0; i < thread.Events.Length; i++) { - var events = data[j].Events; - if (events == null) - continue; - - for (int i = 0; i < events.Length; i++) - { - var e = events[i]; - - if (e.Depth == 0 && e.Name == "Update") - { - return new ViewRange(ref e); - } - } + ref var e = ref thread.Events[i]; + if (e.Depth == 0 && e.Name == "Update") + return new ViewRange(ref e); } } } } - return ViewRange.Full; } @@ -352,13 +343,28 @@ namespace FlaxEditor.Windows.Profiler // Find the first event start time (for the timeline start time) double startTime = double.MaxValue; - for (int i = 0; i < data.Length; i++) + if (viewRange.Start > 0) { - if (data[i].Events != null && data[i].Events.Length != 0) - startTime = Math.Min(startTime, data[i].Events[0].Start); + startTime = viewRange.Start; + } + else + { + var r = GetMainThreadUpdateRange(); + if (r.Start > 0) + { + startTime = r.Start; + } + else + { + for (int i = 0; i < data.Length; i++) + { + if (data[i].Events != null && data[i].Events.Length != 0) + startTime = Math.Min(startTime, data[i].Events[0].Start); + } + if (startTime >= double.MaxValue) + return 0; + } } - if (startTime >= double.MaxValue) - return 0; var container = _timeline.EventsContainer; diff --git a/Source/Engine/Content/Asset.h b/Source/Engine/Content/Asset.h index b48219573..2d2ba4b3f 100644 --- a/Source/Engine/Content/Asset.h +++ b/Source/Engine/Content/Asset.h @@ -25,7 +25,7 @@ API_CLASS(Abstract, NoSpawn) class FLAXENGINE_API Asset : public ManagedScriptin { DECLARE_SCRIPTING_TYPE_NO_SPAWN(Asset); friend Content; - friend class LoadAssetTask; + friend LoadAssetTask; friend class ContentService; public: /// diff --git a/Source/Engine/Content/Loading/Tasks/LoadAssetTask.h b/Source/Engine/Content/Loading/Tasks/LoadAssetTask.h index 911f44226..5ee384769 100644 --- a/Source/Engine/Content/Loading/Tasks/LoadAssetTask.h +++ b/Source/Engine/Content/Loading/Tasks/LoadAssetTask.h @@ -69,9 +69,24 @@ protected: return Result::Ok; } + void OnFail() override + { + if (Asset) + { + Asset->_loadingTask = nullptr; + Asset = nullptr; + } + + // Base + ContentLoadTask::OnFail(); + } void OnEnd() override { - Asset = nullptr; + if (Asset) + { + Asset->_loadingTask = nullptr; + Asset = nullptr; + } // Base ContentLoadTask::OnEnd(); diff --git a/Source/Engine/Content/Types.h b/Source/Engine/Content/Types.h index a64162501..c62a029e0 100644 --- a/Source/Engine/Content/Types.h +++ b/Source/Engine/Content/Types.h @@ -7,5 +7,6 @@ struct AssetInfo; class Content; class Asset; class ContentLoadTask; +class LoadAssetTask; template class AssetReference; diff --git a/Source/Engine/Platform/Linux/LinuxPlatform.cpp b/Source/Engine/Platform/Linux/LinuxPlatform.cpp index cdd7800f7..23267b193 100644 --- a/Source/Engine/Platform/Linux/LinuxPlatform.cpp +++ b/Source/Engine/Platform/Linux/LinuxPlatform.cpp @@ -2048,12 +2048,12 @@ bool LinuxPlatform::Init() // Get user locale string setlocale(LC_ALL, ""); const char* locale = setlocale(LC_CTYPE, NULL); - if (strcmp(locale, "C") == 0) - locale = ""; UserLocale = String(locale); if (UserLocale.FindLast('.') != -1) UserLocale = UserLocale.Left(UserLocale.Find('.')); UserLocale.Replace('_', '-'); + if (UserLocale == TEXT("C")) + UserLocale = TEXT("en"); // Get computer name string gethostname(buffer, UNIX_APP_BUFF_SIZE); diff --git a/Source/Engine/Profiler/ProfilerCPU.cpp b/Source/Engine/Profiler/ProfilerCPU.cpp index 0198ed7bc..417178747 100644 --- a/Source/Engine/Profiler/ProfilerCPU.cpp +++ b/Source/Engine/Profiler/ProfilerCPU.cpp @@ -24,7 +24,7 @@ ProfilerCPU::EventBuffer::~EventBuffer() DeleteArray(_data, _capacity); } -void ProfilerCPU::EventBuffer::Extract(Array& data, bool withRemove) +void ProfilerCPU::EventBuffer::Extract(Array& data, bool withRemoval) { data.Clear(); @@ -36,6 +36,13 @@ void ProfilerCPU::EventBuffer::Extract(Array& data, bool withRemove) if (count == 0) return; + // Fix iterators when buffer is full (begin == end) + if (count == capacity) + { + _count--; + count--; + } + // Find the first item (skip non-root events) Iterator firstEvent = Begin(); for (auto i = firstEvent; i.IsNotEnd(); ++i) @@ -55,7 +62,7 @@ void ProfilerCPU::EventBuffer::Extract(Array& data, bool withRemove) Iterator lastEndedRoot = End(); for (auto i = Last(); i != firstEvent; --i) { - if (i.Event().Depth == 0 && i.Event().End != 0) + if (i.Event().Depth == 0 && i.Event().End > 0) { lastEndedRoot = i; break; @@ -71,31 +78,27 @@ void ProfilerCPU::EventBuffer::Extract(Array& data, bool withRemove) const double lastRootEventEndTime = lastEndedRoot.Event().End; for (auto i = --End(); i != lastEndedRoot; --i) { - if (i.Event().End != 0 && i.Event().End <= lastRootEventEndTime) + if (i.Event().End > 0 && i.Event().End <= lastRootEventEndTime) { lastEvent = i; break; } } - if (withRemove) + if (withRemoval) { // Remove all the events between [Begin(), lastEvent] _count -= (lastEvent.Index() - Begin().Index()) & _capacityMask; } // Extract all the events between [firstEvent, lastEvent] - const int32 head = (lastEvent.Index() + 1) & _capacityMask; count = (lastEvent.Index() - firstEvent.Index() + 1) & _capacityMask; - data.Resize(count, false); - - int32 tail = (head - count) & _capacityMask; - int32 spaceLeft = capacity - tail; - int32 spaceLeftCount = Math::Min(spaceLeft, count); - int32 overflow = count - spaceLeft; - + const int32 tail = (head - count) & _capacityMask; + const int32 spaceLeft = capacity - tail; + const int32 spaceLeftCount = Math::Min(spaceLeft, count); + const int32 overflow = count - spaceLeft; Platform::MemoryCopy(data.Get(), &_data[tail], spaceLeftCount * sizeof(Event)); if (overflow > 0) Platform::MemoryCopy(data.Get() + spaceLeftCount, &_data[0], overflow * sizeof(Event)); diff --git a/Source/Engine/Profiler/ProfilerCPU.h b/Source/Engine/Profiler/ProfilerCPU.h index 000e41ccb..124082c9b 100644 --- a/Source/Engine/Profiler/ProfilerCPU.h +++ b/Source/Engine/Profiler/ProfilerCPU.h @@ -106,8 +106,8 @@ public: /// Extracts the buffer data (only ended events starting from the root level with depth=0). /// /// The output data. - /// True if also remove extracted events to prevent double-gather, false if don't modify the buffer data. - void Extract(Array& data, bool withRemove); + /// True if also remove extracted events to prevent double-gather, false if don't modify the buffer data. + void Extract(Array& data, bool withRemoval); public: /// diff --git a/Source/Engine/Profiler/ProfilingTools.cpp b/Source/Engine/Profiler/ProfilingTools.cpp index 632915048..6ce8082ba 100644 --- a/Source/Engine/Profiler/ProfilingTools.cpp +++ b/Source/Engine/Profiler/ProfilingTools.cpp @@ -57,13 +57,13 @@ void ProfilingToolsService::Update() ProfilingTools::EventsCPU.EnsureCapacity(threads.Count()); for (int32 i = 0; i < threads.Count(); i++) { - auto t = threads[i]; - if (t == nullptr) + ProfilerCPU::Thread* thread = threads[i]; + if (thread == nullptr) continue; ProfilingTools::ThreadStats* pt = nullptr; for (auto& e : ProfilingTools::EventsCPU) { - if (e.Name == t->GetName()) + if (e.Name == thread->GetName()) { pt = &e; break; @@ -72,10 +72,10 @@ void ProfilingToolsService::Update() if (!pt) { pt = &ProfilingTools::EventsCPU.AddOne(); - pt->Name = t->GetName(); + pt->Name = thread->GetName(); } - t->Buffer.Extract(pt->Events, true); + thread->Buffer.Extract(pt->Events, true); } #if 0