From 086e4c9835001e3188313cbf41be4e45de0f7a39 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 15 Jun 2023 09:51:26 +0200 Subject: [PATCH] Add content proxy modifications function and workspace rebuilding for custom asset types extensions --- .../Editor/Modules/ContentDatabaseModule.cs | 146 +++++++++++++++--- Source/Editor/Windows/ContentWindow.cs | 21 ++- 2 files changed, 143 insertions(+), 24 deletions(-) diff --git a/Source/Editor/Modules/ContentDatabaseModule.cs b/Source/Editor/Modules/ContentDatabaseModule.cs index 430774048..04e630381 100644 --- a/Source/Editor/Modules/ContentDatabaseModule.cs +++ b/Source/Editor/Modules/ContentDatabaseModule.cs @@ -20,6 +20,7 @@ namespace FlaxEditor.Modules { private bool _enableEvents; private bool _isDuringFastSetup; + private bool _rebuildFlag; private int _itemsCreated; private int _itemsDeleted; private readonly HashSet _dirtyNodes = new HashSet(); @@ -40,9 +41,9 @@ namespace FlaxEditor.Modules public readonly List Projects = new List(); /// - /// The list with all content items proxy objects. + /// The list with all content items proxy objects. Use and to modify this or to refresh database when adding new item proxy types. /// - public readonly List Proxy = new List(64); + public readonly List Proxy = new List(128); /// /// Occurs when new items is added to the workspace content database. @@ -59,6 +60,16 @@ namespace FlaxEditor.Modules /// public event Action WorkspaceModified; + /// + /// Occurs when workspace has will be rebuilt. + /// + public event Action WorkspaceRebuilding; + + /// + /// Occurs when workspace has been rebuilt. + /// + public event Action WorkspaceRebuilt; + /// /// Gets the amount of created items. /// @@ -708,6 +719,100 @@ namespace FlaxEditor.Modules WorkspaceModified?.Invoke(); } + /// + /// Adds the proxy. + /// + /// The proxy type. + public void AddProxy(ContentProxy proxy) + { + Proxy.Insert(0, proxy); + Rebuild(); + } + + /// + /// Removes the proxy. + /// + /// The proxy type. + public void RemoveProxy(ContentProxy proxy) + { + Proxy.Remove(proxy); + Rebuild(); + } + + /// + /// Rebuilds the whole database (eg. when adding custom item types from plugin). + /// + /// True if rebuild num, otherwise will be scheduled for the next editor update (eg. to batch multiple rebuilds within a frame). + public void Rebuild(bool immediate = false) + { + _rebuildFlag = true; + if (immediate) + RebuildInternal(); + } + + private void RebuildInternal() + { + var enableEvents = _enableEvents; + if (enableEvents) + { + WorkspaceRebuilding?.Invoke(); + } + + Profiler.BeginEvent("ContentDatabase.Rebuild"); + var startTime = Platform.TimeSeconds; + _rebuildFlag = false; + _enableEvents = false; + + // Load all folders + // TODO: we should create async task for gathering content and whole workspace contents if it takes too long + // TODO: create progress bar in content window and after end we should enable events and update it + _isDuringFastSetup = true; + var startItems = _itemsCreated; + foreach (var project in Projects) + { + if (project.Content != null) + LoadFolder(project.Content, true); + if (project.Source != null) + LoadFolder(project.Source, true); + } + _isDuringFastSetup = false; + + _enableEvents = enableEvents; + var endTime = Platform.TimeSeconds; + Editor.Log(string.Format("Project database created in {0} ms. Items count: {1}", (int)((endTime - startTime) * 1000.0), _itemsCreated - startItems)); + Profiler.EndEvent(); + + if (enableEvents) + { + WorkspaceModified?.Invoke(); + WorkspaceRebuilt?.Invoke(); + } + } + + private void Dispose(ContentItem item) + { + if (_enableEvents) + ItemRemoved?.Invoke(item); + + if (item is ContentFolder folder) + { + if (folder.Children.Count > 0) + { + var children = folder.Children.ToArray(); + for (int i = 0; i < children.Length; i++) + Dispose(children[i]); + } + + item.ParentFolder = null; + folder.Node.Dispose(); + } + else + { + item.ParentFolder = null; + item.Dispose(); + } + } + private void LoadFolder(ContentTreeNode node, bool checkSubDirs) { if (node == null) @@ -717,9 +822,18 @@ namespace FlaxEditor.Modules var folder = node.Folder; var path = folder.Path; - // Check for missing files/folders (skip it during fast tree setup) - if (!_isDuringFastSetup) + if (_isDuringFastSetup) { + // Remove any spawned children + for (int i = 0; i < folder.Children.Count; i++) + { + Dispose(folder.Children[i]); + i--; + } + } + else + { + // Check for missing files/folders (skip it during fast tree setup) for (int i = 0; i < folder.Children.Count; i++) { var child = folder.Children[i]; @@ -974,7 +1088,6 @@ namespace FlaxEditor.Modules Proxy.Add(new GenericJsonAssetProxy()); // Create content folders nodes - var startTime = Platform.TimeSeconds; Engine = new ProjectTreeNode(Editor.EngineProject) { Content = new MainContentTreeNode(Engine, ContentFolderType.Content, Globals.EngineContentFolder), @@ -998,25 +1111,10 @@ namespace FlaxEditor.Modules LoadProjects(Game.Project); } - // Load all folders - // TODO: we should create async task for gathering content and whole workspace contents if it takes too long - // TODO: create progress bar in content window and after end we should enable events and update it - _isDuringFastSetup = true; - foreach (var project in Projects) - { - if (project.Content != null) - LoadFolder(project.Content, true); - if (project.Source != null) - LoadFolder(project.Source, true); - } - _isDuringFastSetup = false; + RebuildInternal(); - // Enable events - _enableEvents = true; Editor.ContentImporting.ImportFileEnd += ContentImporting_ImportFileDone; - var endTime = Platform.TimeSeconds; - - Editor.Log(string.Format("Project database created in {0} ms. Items count: {1}", (int)((endTime - startTime) * 1000.0), _itemsCreated)); + _enableEvents = true; } private void ContentImporting_ImportFileDone(IFileEntryAction obj, bool failed) @@ -1102,6 +1200,10 @@ namespace FlaxEditor.Modules } _dirtyNodes.Clear(); } + + // Lazy-rebuilds + if (_rebuildFlag) + RebuildInternal(); } /// diff --git a/Source/Editor/Windows/ContentWindow.cs b/Source/Editor/Windows/ContentWindow.cs index a44c35cb3..f993b79f9 100644 --- a/Source/Editor/Windows/ContentWindow.cs +++ b/Source/Editor/Windows/ContentWindow.cs @@ -27,6 +27,7 @@ namespace FlaxEditor.Windows { private const string ProjectDataLastViewedFolder = "LastViewedFolder"; private bool _isWorkspaceDirty; + private string _workspaceRebuildLocation; private SplitPanel _split; private Panel _contentViewPanel; private Panel _contentTreePanel; @@ -75,7 +76,23 @@ namespace FlaxEditor.Windows // Content database events editor.ContentDatabase.WorkspaceModified += () => _isWorkspaceDirty = true; - editor.ContentDatabase.ItemRemoved += ContentDatabaseOnItemRemoved; + editor.ContentDatabase.ItemRemoved += OnContentDatabaseItemRemoved; + editor.ContentDatabase.WorkspaceRebuilding += () => { _workspaceRebuildLocation = SelectedNode?.Path; }; + editor.ContentDatabase.WorkspaceRebuilt += () => + { + var selected = Editor.ContentDatabase.Find(_workspaceRebuildLocation); + if (selected is ContentFolder selectedFolder) + { + _navigationUnlocked = false; + RefreshView(selectedFolder.Node); + _tree.Select(selectedFolder.Node); + UpdateItemsSearch(); + _navigationUnlocked = true; + UpdateUI(); + } + else + ShowRoot(); + }; var options = Editor.Options; options.OptionsChanged += OnOptionsChanged; @@ -737,7 +754,7 @@ namespace FlaxEditor.Windows } } - private void ContentDatabaseOnItemRemoved(ContentItem contentItem) + private void OnContentDatabaseItemRemoved(ContentItem contentItem) { if (contentItem is ContentFolder folder) {