Merge branch 'unload_alc_fix' of https://github.com/GoaLitiuM/FlaxEngine into GoaLitiuM-unload_alc_fix
This commit is contained in:
@@ -196,6 +196,15 @@ namespace FlaxEditor.CustomEditors
|
|||||||
Presenter.AfterLayout?.Invoke(layout);
|
Presenter.AfterLayout?.Invoke(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Deinitialize()
|
||||||
|
{
|
||||||
|
Editor = null;
|
||||||
|
_overrideEditor = null;
|
||||||
|
|
||||||
|
base.Deinitialize();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnModified()
|
protected override void OnModified()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
if (_linkedPrefabId != Guid.Empty)
|
if (_linkedPrefabId != Guid.Empty)
|
||||||
{
|
{
|
||||||
_linkedPrefabId = Guid.Empty;
|
_linkedPrefabId = Guid.Empty;
|
||||||
Editor.Instance.Prefabs.PrefabApplied -= OnPrefabApplying;
|
Editor.Instance.Prefabs.PrefabApplying -= OnPrefabApplying;
|
||||||
Editor.Instance.Prefabs.PrefabApplied -= OnPrefabApplied;
|
Editor.Instance.Prefabs.PrefabApplied -= OnPrefabApplied;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1057,6 +1057,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
protected override void Deinitialize()
|
protected override void Deinitialize()
|
||||||
{
|
{
|
||||||
_scriptToggles = null;
|
_scriptToggles = null;
|
||||||
|
_scripts.Clear();
|
||||||
|
|
||||||
base.Deinitialize();
|
base.Deinitialize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -819,6 +819,15 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
OnGroupsEnd();
|
OnGroupsEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Deinitialize()
|
||||||
|
{
|
||||||
|
_visibleIfCaches = null;
|
||||||
|
_visibleIfPropertiesListsCache = null;
|
||||||
|
|
||||||
|
base.Deinitialize();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Refresh()
|
public override void Refresh()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -464,7 +464,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
{
|
{
|
||||||
base.Focus();
|
base.Focus();
|
||||||
|
|
||||||
SelectTab();
|
SelectTab(false);
|
||||||
BringToFront();
|
BringToFront();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace FlaxEditor.Modules
|
|||||||
private bool _enableEvents;
|
private bool _enableEvents;
|
||||||
private bool _isDuringFastSetup;
|
private bool _isDuringFastSetup;
|
||||||
private bool _rebuildFlag;
|
private bool _rebuildFlag;
|
||||||
|
private bool _rebuildInitFlag;
|
||||||
private int _itemsCreated;
|
private int _itemsCreated;
|
||||||
private int _itemsDeleted;
|
private int _itemsDeleted;
|
||||||
private readonly HashSet<MainContentTreeNode> _dirtyNodes = new HashSet<MainContentTreeNode>();
|
private readonly HashSet<MainContentTreeNode> _dirtyNodes = new HashSet<MainContentTreeNode>();
|
||||||
@@ -61,7 +62,7 @@ namespace FlaxEditor.Modules
|
|||||||
public event Action WorkspaceModified;
|
public event Action WorkspaceModified;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when workspace has will be rebuilt.
|
/// Occurs when workspace will be rebuilt.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action WorkspaceRebuilding;
|
public event Action WorkspaceRebuilding;
|
||||||
|
|
||||||
@@ -88,6 +89,9 @@ namespace FlaxEditor.Modules
|
|||||||
|
|
||||||
// Register AssetItems serialization helper (serialize ref ID only)
|
// Register AssetItems serialization helper (serialize ref ID only)
|
||||||
FlaxEngine.Json.JsonSerializer.Settings.Converters.Add(new AssetItemConverter());
|
FlaxEngine.Json.JsonSerializer.Settings.Converters.Add(new AssetItemConverter());
|
||||||
|
|
||||||
|
ScriptsBuilder.ScriptsReload += OnScriptsReload;
|
||||||
|
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnContentAssetDisposing(Asset asset)
|
private void OnContentAssetDisposing(Asset asset)
|
||||||
@@ -817,6 +821,7 @@ namespace FlaxEditor.Modules
|
|||||||
Profiler.BeginEvent("ContentDatabase.Rebuild");
|
Profiler.BeginEvent("ContentDatabase.Rebuild");
|
||||||
var startTime = Platform.TimeSeconds;
|
var startTime = Platform.TimeSeconds;
|
||||||
_rebuildFlag = false;
|
_rebuildFlag = false;
|
||||||
|
_rebuildInitFlag = false;
|
||||||
_enableEvents = false;
|
_enableEvents = false;
|
||||||
|
|
||||||
// Load all folders
|
// Load all folders
|
||||||
@@ -1230,8 +1235,6 @@ namespace FlaxEditor.Modules
|
|||||||
LoadProjects(Game.Project);
|
LoadProjects(Game.Project);
|
||||||
}
|
}
|
||||||
|
|
||||||
RebuildInternal();
|
|
||||||
|
|
||||||
Editor.ContentImporting.ImportFileEnd += (obj, failed) =>
|
Editor.ContentImporting.ImportFileEnd += (obj, failed) =>
|
||||||
{
|
{
|
||||||
var path = obj.ResultUrl;
|
var path = obj.ResultUrl;
|
||||||
@@ -1239,6 +1242,15 @@ namespace FlaxEditor.Modules
|
|||||||
FlaxEngine.Scripting.InvokeOnUpdate(() => OnImportFileDone(path));
|
FlaxEngine.Scripting.InvokeOnUpdate(() => OnImportFileDone(path));
|
||||||
};
|
};
|
||||||
_enableEvents = true;
|
_enableEvents = true;
|
||||||
|
_rebuildInitFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnEndInit()
|
||||||
|
{
|
||||||
|
// Handle init when project was loaded without scripts loading ()
|
||||||
|
if (_rebuildInitFlag)
|
||||||
|
RebuildInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnImportFileDone(string path)
|
private void OnImportFileDone(string path)
|
||||||
@@ -1313,6 +1325,52 @@ namespace FlaxEditor.Modules
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnScriptsReload()
|
||||||
|
{
|
||||||
|
var enabledEvents = _enableEvents;
|
||||||
|
_enableEvents = false;
|
||||||
|
_isDuringFastSetup = true;
|
||||||
|
var startItems = _itemsCreated;
|
||||||
|
foreach (var project in Projects)
|
||||||
|
{
|
||||||
|
if (project.Content != null)
|
||||||
|
{
|
||||||
|
//Dispose(project.Content.Folder);
|
||||||
|
for (int i = 0; i < project.Content.Folder.Children.Count; i++)
|
||||||
|
{
|
||||||
|
Dispose(project.Content.Folder.Children[i]);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (project.Source != null)
|
||||||
|
{
|
||||||
|
//Dispose(project.Source.Folder);
|
||||||
|
for (int i = 0; i < project.Source.Folder.Children.Count; i++)
|
||||||
|
{
|
||||||
|
Dispose(project.Source.Folder.Children[i]);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ContentProxy> removeProxies = new List<ContentProxy>();
|
||||||
|
foreach (var proxy in Editor.Instance.ContentDatabase.Proxy)
|
||||||
|
{
|
||||||
|
if (proxy.GetType().IsCollectible)
|
||||||
|
removeProxies.Add(proxy);
|
||||||
|
}
|
||||||
|
foreach (var proxy in removeProxies)
|
||||||
|
RemoveProxy(proxy, false);
|
||||||
|
|
||||||
|
_isDuringFastSetup = false;
|
||||||
|
_enableEvents = enabledEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnScriptsReloadEnd()
|
||||||
|
{
|
||||||
|
RebuildInternal();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnUpdate()
|
public override void OnUpdate()
|
||||||
{
|
{
|
||||||
@@ -1340,6 +1398,8 @@ namespace FlaxEditor.Modules
|
|||||||
public override void OnExit()
|
public override void OnExit()
|
||||||
{
|
{
|
||||||
FlaxEngine.Content.AssetDisposing -= OnContentAssetDisposing;
|
FlaxEngine.Content.AssetDisposing -= OnContentAssetDisposing;
|
||||||
|
ScriptsBuilder.ScriptsReload -= OnScriptsReload;
|
||||||
|
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
||||||
|
|
||||||
// Disable events
|
// Disable events
|
||||||
_enableEvents = false;
|
_enableEvents = false;
|
||||||
|
|||||||
@@ -391,6 +391,20 @@ namespace FlaxEditor.Modules
|
|||||||
public override void OnInit()
|
public override void OnInit()
|
||||||
{
|
{
|
||||||
ImportFileEntry.RegisterDefaultTypes();
|
ImportFileEntry.RegisterDefaultTypes();
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnScriptsReloadBegin()
|
||||||
|
{
|
||||||
|
// Remove import file types from scripting assemblies
|
||||||
|
List<string> removeFileTypes = new List<string>();
|
||||||
|
foreach (var pair in ImportFileEntry.FileTypes)
|
||||||
|
{
|
||||||
|
if (pair.Value.Method.IsCollectible || (pair.Value.Target != null && pair.Value.Target.GetType().IsCollectible))
|
||||||
|
removeFileTypes.Add(pair.Key);
|
||||||
|
}
|
||||||
|
foreach (var fileType in removeFileTypes)
|
||||||
|
ImportFileEntry.FileTypes.Remove(fileType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -451,6 +465,7 @@ namespace FlaxEditor.Modules
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnExit()
|
public override void OnExit()
|
||||||
{
|
{
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||||
EndWorker();
|
EndWorker();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ namespace FlaxEditor.Modules
|
|||||||
: base(editor)
|
: base(editor)
|
||||||
{
|
{
|
||||||
// After editor cache but before the windows
|
// After editor cache but before the windows
|
||||||
InitOrder = -900;
|
InitOrder = -800;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ namespace FlaxEditor.Modules
|
|||||||
internal UIModule(Editor editor)
|
internal UIModule(Editor editor)
|
||||||
: base(editor)
|
: base(editor)
|
||||||
{
|
{
|
||||||
InitOrder = -90;
|
InitOrder = -70;
|
||||||
VisjectSurfaceBackground = FlaxEngine.Content.LoadAsyncInternal<Texture>("Editor/VisjectSurface");
|
VisjectSurfaceBackground = FlaxEngine.Content.LoadAsyncInternal<Texture>("Editor/VisjectSurface");
|
||||||
ColorValueBox.ShowPickColorDialog += ShowPickColorDialog;
|
ColorValueBox.ShowPickColorDialog += ShowPickColorDialog;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ using System.Collections.Generic;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using FlaxEditor.Content;
|
using FlaxEditor.Content;
|
||||||
using FlaxEditor.GUI.Dialogs;
|
using FlaxEditor.GUI.Dialogs;
|
||||||
|
using FlaxEditor.GUI.Docking;
|
||||||
using FlaxEditor.Windows;
|
using FlaxEditor.Windows;
|
||||||
using FlaxEditor.Windows.Assets;
|
using FlaxEditor.Windows.Assets;
|
||||||
using FlaxEditor.Windows.Profiler;
|
using FlaxEditor.Windows.Profiler;
|
||||||
@@ -39,6 +41,7 @@ namespace FlaxEditor.Modules
|
|||||||
|
|
||||||
public DockState DockState;
|
public DockState DockState;
|
||||||
public DockPanel DockedTo;
|
public DockPanel DockedTo;
|
||||||
|
public int DockedTabIndex;
|
||||||
public float? SplitterValue = null;
|
public float? SplitterValue = null;
|
||||||
|
|
||||||
public bool SelectOnShow = false;
|
public bool SelectOnShow = false;
|
||||||
@@ -48,6 +51,8 @@ namespace FlaxEditor.Modules
|
|||||||
public Float2 FloatSize;
|
public Float2 FloatSize;
|
||||||
public Float2 FloatPosition;
|
public Float2 FloatPosition;
|
||||||
|
|
||||||
|
public Guid AssetItemID;
|
||||||
|
|
||||||
// Constructor, to allow for default values
|
// Constructor, to allow for default values
|
||||||
public WindowRestoreData()
|
public WindowRestoreData()
|
||||||
{
|
{
|
||||||
@@ -803,43 +808,64 @@ namespace FlaxEditor.Modules
|
|||||||
Level.SceneSaving += OnSceneSaving;
|
Level.SceneSaving += OnSceneSaving;
|
||||||
Level.SceneUnloaded += OnSceneUnloaded;
|
Level.SceneUnloaded += OnSceneUnloaded;
|
||||||
Level.SceneUnloading += OnSceneUnloading;
|
Level.SceneUnloading += OnSceneUnloading;
|
||||||
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
|
Editor.ContentDatabase.WorkspaceRebuilt += OnWorkspaceRebuilt;
|
||||||
Editor.StateMachine.StateChanged += OnEditorStateChanged;
|
Editor.StateMachine.StateChanged += OnEditorStateChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void AddToRestore(AssetEditorWindow win)
|
||||||
|
{
|
||||||
|
AddToRestore(win, win.GetType(), new WindowRestoreData
|
||||||
|
{
|
||||||
|
AssetItemID = win.Item.ID,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
internal void AddToRestore(CustomEditorWindow win)
|
internal void AddToRestore(CustomEditorWindow win)
|
||||||
{
|
{
|
||||||
var type = win.GetType();
|
AddToRestore(win.Window, win.GetType(), new WindowRestoreData());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddToRestore(EditorWindow win, Type type, WindowRestoreData winData)
|
||||||
|
{
|
||||||
// Validate if can restore type
|
// Validate if can restore type
|
||||||
var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
|
var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
|
||||||
if (constructor == null || type.IsGenericType)
|
if (constructor == null || type.IsGenericType)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var winData = new WindowRestoreData();
|
var panel = win.ParentDockPanel;
|
||||||
var panel = win.Window.ParentDockPanel;
|
|
||||||
|
|
||||||
// Ensure that this window is only selected following recompilation
|
// Ensure that this window is only selected following recompilation
|
||||||
// if it was the active tab in its dock panel. Otherwise, there is a
|
// if it was the active tab in its dock panel. Otherwise, there is a
|
||||||
// risk of interrupting the user's workflow by potentially selecting
|
// risk of interrupting the user's workflow by potentially selecting
|
||||||
// background tabs.
|
// background tabs.
|
||||||
winData.SelectOnShow = panel.SelectedTab == win.Window;
|
var window = win.RootWindow.Window;
|
||||||
if (panel is FloatWindowDockPanel)
|
winData.SelectOnShow = panel.SelectedTab == win;
|
||||||
|
winData.DockedTabIndex = 0;
|
||||||
|
if (panel is FloatWindowDockPanel && window != null && panel.TabsCount == 1)
|
||||||
{
|
{
|
||||||
winData.DockState = DockState.Float;
|
winData.DockState = DockState.Float;
|
||||||
var window = win.Window.RootWindow.Window;
|
|
||||||
winData.FloatPosition = window.Position;
|
winData.FloatPosition = window.Position;
|
||||||
winData.FloatSize = window.ClientSize;
|
winData.FloatSize = window.ClientSize;
|
||||||
winData.Maximize = window.IsMaximized;
|
winData.Maximize = window.IsMaximized;
|
||||||
winData.Minimize = window.IsMinimized;
|
winData.Minimize = window.IsMinimized;
|
||||||
|
winData.DockedTo = panel;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
for (int i = 0; i < panel.Tabs.Count; i++)
|
||||||
|
{
|
||||||
|
if (panel.Tabs[i] == win)
|
||||||
|
{
|
||||||
|
winData.DockedTabIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (panel.TabsCount > 1)
|
if (panel.TabsCount > 1)
|
||||||
{
|
{
|
||||||
winData.DockState = DockState.DockFill;
|
winData.DockState = DockState.DockFill;
|
||||||
winData.DockedTo = panel;
|
winData.DockedTo = panel;
|
||||||
}else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
winData.DockState = panel.TryGetDockState(out var splitterValue);
|
winData.DockState = panel.TryGetDockState(out var splitterValue);
|
||||||
winData.DockedTo = panel.ParentDockPanel;
|
winData.DockedTo = panel.ParentDockPanel;
|
||||||
@@ -851,38 +877,93 @@ namespace FlaxEditor.Modules
|
|||||||
_restoreWindows.Add(winData);
|
_restoreWindows.Add(winData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnScriptsReloadEnd()
|
private void OnWorkspaceRebuilt()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _restoreWindows.Count; i++)
|
// Go in reverse order to create floating Prefab windows first before docked windows
|
||||||
|
for (int i = _restoreWindows.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var winData = _restoreWindows[i];
|
var winData = _restoreWindows[i];
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var assembly = Utils.GetAssemblyByName(winData.AssemblyName);
|
var assembly = Utils.GetAssemblyByName(winData.AssemblyName);
|
||||||
if (assembly != null)
|
if (assembly == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var type = assembly.GetType(winData.TypeName);
|
||||||
|
if (type == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (type.IsAssignableTo(typeof(AssetEditorWindow)))
|
||||||
{
|
{
|
||||||
var type = assembly.GetType(winData.TypeName);
|
var ctor = type.GetConstructor(new Type[] { typeof(Editor), typeof(AssetItem) });
|
||||||
if (type != null)
|
var assetItem = Editor.ContentDatabase.FindAsset(winData.AssetItemID);
|
||||||
|
var win = (AssetEditorWindow)ctor.Invoke(new object[] { Editor.Instance, assetItem });
|
||||||
|
win.Show(winData.DockState, winData.DockState != DockState.Float ? winData.DockedTo : null, winData.SelectOnShow, winData.SplitterValue);
|
||||||
|
if (winData.DockState == DockState.Float)
|
||||||
{
|
{
|
||||||
var win = (CustomEditorWindow)Activator.CreateInstance(type);
|
var window = win.RootWindow.Window;
|
||||||
win.Show(winData.DockState, winData.DockedTo, winData.SelectOnShow, winData.SplitterValue);
|
window.Position = winData.FloatPosition;
|
||||||
if (winData.DockState == DockState.Float)
|
if (winData.Maximize)
|
||||||
{
|
{
|
||||||
var window = win.Window.RootWindow.Window;
|
window.Maximize();
|
||||||
window.Position = winData.FloatPosition;
|
}
|
||||||
if (winData.Maximize)
|
else if (winData.Minimize)
|
||||||
{
|
{
|
||||||
window.Maximize();
|
window.Minimize();
|
||||||
}
|
}
|
||||||
else if (winData.Minimize)
|
else
|
||||||
{
|
{
|
||||||
window.Minimize();
|
window.ClientSize = winData.FloatSize;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
// Update panel reference in other windows docked to this panel
|
||||||
window.ClientSize = winData.FloatSize;
|
foreach (ref var otherData in CollectionsMarshal.AsSpan(_restoreWindows))
|
||||||
}
|
{
|
||||||
|
if (otherData.DockedTo == winData.DockedTo)
|
||||||
|
otherData.DockedTo = win.ParentDockPanel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var panel = win.ParentDockPanel;
|
||||||
|
int currentTabIndex = 0;
|
||||||
|
for (int pi = 0; pi < panel.TabsCount; pi++)
|
||||||
|
{
|
||||||
|
if (panel.Tabs[pi] == win)
|
||||||
|
{
|
||||||
|
currentTabIndex = pi;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (currentTabIndex > winData.DockedTabIndex)
|
||||||
|
{
|
||||||
|
win.ParentDockPanel.MoveTabLeft(currentTabIndex);
|
||||||
|
currentTabIndex--;
|
||||||
|
}
|
||||||
|
while (currentTabIndex < winData.DockedTabIndex)
|
||||||
|
{
|
||||||
|
win.ParentDockPanel.MoveTabRight(currentTabIndex);
|
||||||
|
currentTabIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var win = (CustomEditorWindow)Activator.CreateInstance(type);
|
||||||
|
win.Show(winData.DockState, winData.DockedTo, winData.SelectOnShow, winData.SplitterValue);
|
||||||
|
if (winData.DockState == DockState.Float)
|
||||||
|
{
|
||||||
|
var window = win.Window.RootWindow.Window;
|
||||||
|
window.Position = winData.FloatPosition;
|
||||||
|
if (winData.Maximize)
|
||||||
|
{
|
||||||
|
window.Maximize();
|
||||||
|
}
|
||||||
|
else if (winData.Minimize)
|
||||||
|
{
|
||||||
|
window.Minimize();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window.ClientSize = winData.FloatSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -893,6 +974,11 @@ namespace FlaxEditor.Modules
|
|||||||
Editor.LogWarning(string.Format("Failed to restore window {0} (assembly: {1})", winData.TypeName, winData.AssemblyName));
|
Editor.LogWarning(string.Format("Failed to restore window {0} (assembly: {1})", winData.TypeName, winData.AssemblyName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restored windows stole the focus from Editor
|
||||||
|
if (_restoreWindows.Count > 0)
|
||||||
|
Editor.Instance.Windows.MainWindow.Focus();
|
||||||
|
|
||||||
_restoreWindows.Clear();
|
_restoreWindows.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1048,7 +1134,7 @@ namespace FlaxEditor.Modules
|
|||||||
Level.SceneSaving -= OnSceneSaving;
|
Level.SceneSaving -= OnSceneSaving;
|
||||||
Level.SceneUnloaded -= OnSceneUnloaded;
|
Level.SceneUnloaded -= OnSceneUnloaded;
|
||||||
Level.SceneUnloading -= OnSceneUnloading;
|
Level.SceneUnloading -= OnSceneUnloading;
|
||||||
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
Editor.ContentDatabase.WorkspaceRebuilt -= OnWorkspaceRebuilt;
|
||||||
Editor.StateMachine.StateChanged -= OnEditorStateChanged;
|
Editor.StateMachine.StateChanged -= OnEditorStateChanged;
|
||||||
|
|
||||||
// Close main window
|
// Close main window
|
||||||
|
|||||||
@@ -469,6 +469,7 @@ namespace FlaxEditor.SceneGraph
|
|||||||
{
|
{
|
||||||
ChildNodes[i].OnDispose();
|
ChildNodes[i].OnDispose();
|
||||||
}
|
}
|
||||||
|
ChildNodes.Clear();
|
||||||
|
|
||||||
SceneGraphFactory.Nodes.Remove(ID);
|
SceneGraphFactory.Nodes.Remove(ID);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ namespace FlaxEditor.Surface
|
|||||||
|
|
||||||
private void OnScriptsReloadBegin()
|
private void OnScriptsReloadBegin()
|
||||||
{
|
{
|
||||||
|
_nodesCache.Clear();
|
||||||
|
|
||||||
// Check if any of the nodes comes from the game scripts - those can be reloaded at runtime so prevent crashes
|
// Check if any of the nodes comes from the game scripts - those can be reloaded at runtime so prevent crashes
|
||||||
bool hasTypeFromGameScripts = Editor.Instance.CodeEditing.AnimGraphNodes.HasTypeFromGameScripts;
|
bool hasTypeFromGameScripts = Editor.Instance.CodeEditing.AnimGraphNodes.HasTypeFromGameScripts;
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace FlaxEditor.Surface
|
|||||||
public BehaviorTreeSurface(IVisjectSurfaceOwner owner, Action onSave, FlaxEditor.Undo undo)
|
public BehaviorTreeSurface(IVisjectSurfaceOwner owner, Action onSave, FlaxEditor.Undo undo)
|
||||||
: base(owner, onSave, undo, CreateStyle())
|
: base(owner, onSave, undo, CreateStyle())
|
||||||
{
|
{
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SurfaceStyle CreateStyle()
|
private static SurfaceStyle CreateStyle()
|
||||||
@@ -35,6 +36,11 @@ namespace FlaxEditor.Surface
|
|||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnScriptsReloadBegin()
|
||||||
|
{
|
||||||
|
_nodesCache.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
private static void DrawBox(Box box)
|
private static void DrawBox(Box box)
|
||||||
{
|
{
|
||||||
var rect = new Rectangle(Float2.Zero, box.Size);
|
var rect = new Rectangle(Float2.Zero, box.Size);
|
||||||
@@ -186,6 +192,7 @@ namespace FlaxEditor.Surface
|
|||||||
{
|
{
|
||||||
if (IsDisposing)
|
if (IsDisposing)
|
||||||
return;
|
return;
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||||
_nodesCache.Wait();
|
_nodesCache.Wait();
|
||||||
|
|
||||||
base.OnDestroy();
|
base.OnDestroy();
|
||||||
|
|||||||
@@ -415,6 +415,15 @@ namespace FlaxEditor.Surface
|
|||||||
// Init drag handlers
|
// Init drag handlers
|
||||||
DragHandlers.Add(_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem));
|
DragHandlers.Add(_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem));
|
||||||
DragHandlers.Add(_dragParameters = new DragNames<DragDropEventArgs>(SurfaceParameter.DragPrefix, ValidateDragParameter));
|
DragHandlers.Add(_dragParameters = new DragNames<DragDropEventArgs>(SurfaceParameter.DragPrefix, ValidateDragParameter));
|
||||||
|
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnScriptsReloadBegin()
|
||||||
|
{
|
||||||
|
_activeVisjectCM = null;
|
||||||
|
_cmPrimaryMenu?.Dispose();
|
||||||
|
_cmPrimaryMenu = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1023,6 +1032,8 @@ namespace FlaxEditor.Surface
|
|||||||
_activeVisjectCM = null;
|
_activeVisjectCM = null;
|
||||||
_cmPrimaryMenu?.Dispose();
|
_cmPrimaryMenu?.Dispose();
|
||||||
|
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||||
|
|
||||||
base.OnDestroy();
|
base.OnDestroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,12 @@ namespace FlaxEditor.Surface
|
|||||||
{
|
{
|
||||||
_supportsImplicitCastFromObjectToBoolean = true;
|
_supportsImplicitCastFromObjectToBoolean = true;
|
||||||
DragHandlers.Add(_dragActors = new DragActors(ValidateDragActor));
|
DragHandlers.Add(_dragActors = new DragActors(ValidateDragActor));
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnScriptsReloadBegin()
|
||||||
|
{
|
||||||
|
_nodesCache.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ValidateDragActor(ActorNode actor)
|
private bool ValidateDragActor(ActorNode actor)
|
||||||
@@ -631,6 +637,7 @@ namespace FlaxEditor.Surface
|
|||||||
{
|
{
|
||||||
if (IsDisposing)
|
if (IsDisposing)
|
||||||
return;
|
return;
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||||
_nodesCache.Wait();
|
_nodesCache.Wait();
|
||||||
|
|
||||||
base.OnDestroy();
|
base.OnDestroy();
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
InputActions.Add(options => options.Save, Save);
|
InputActions.Add(options => options.Save, Save);
|
||||||
|
|
||||||
UpdateTitle();
|
UpdateTitle();
|
||||||
|
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -151,6 +153,8 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnDestroy()
|
public override void OnDestroy()
|
||||||
{
|
{
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||||
|
|
||||||
if (_item != null)
|
if (_item != null)
|
||||||
{
|
{
|
||||||
// Ensure to remove linkage to the item
|
// Ensure to remove linkage to the item
|
||||||
@@ -160,6 +164,15 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
base.OnDestroy();
|
base.OnDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected virtual void OnScriptsReloadBegin()
|
||||||
|
{
|
||||||
|
if (!IsHidden)
|
||||||
|
{
|
||||||
|
Editor.Instance.Windows.AddToRestore(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#region IEditable Implementation
|
#region IEditable Implementation
|
||||||
|
|
||||||
private bool _isEdited;
|
private bool _isEdited;
|
||||||
|
|||||||
@@ -268,8 +268,11 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
UpdateKnowledge();
|
UpdateKnowledge();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnScriptsReloadBegin()
|
/// <inheritdoc />
|
||||||
|
protected override void OnScriptsReloadBegin()
|
||||||
{
|
{
|
||||||
|
base.OnScriptsReloadBegin();
|
||||||
|
|
||||||
// TODO: impl hot-reload for BT to nicely refresh state (save asset, clear undo/properties, reload surface)
|
// TODO: impl hot-reload for BT to nicely refresh state (save asset, clear undo/properties, reload surface)
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,8 +124,10 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
UpdateToolstrip();
|
UpdateToolstrip();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnScriptsReloadBegin()
|
/// <inheritdoc />
|
||||||
|
protected override void OnScriptsReloadBegin()
|
||||||
{
|
{
|
||||||
|
base.OnScriptsReloadBegin();
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -198,7 +198,6 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
Editor.Prefabs.PrefabApplied += OnPrefabApplied;
|
Editor.Prefabs.PrefabApplied += OnPrefabApplied;
|
||||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||||
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
|
|
||||||
|
|
||||||
// Setup input actions
|
// Setup input actions
|
||||||
InputActions.Add(options => options.Undo, () =>
|
InputActions.Add(options => options.Undo, () =>
|
||||||
@@ -291,8 +290,10 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnScriptsReloadBegin()
|
/// <inheritdoc />
|
||||||
|
protected override void OnScriptsReloadBegin()
|
||||||
{
|
{
|
||||||
|
base.OnScriptsReloadBegin();
|
||||||
_isScriptsReloading = true;
|
_isScriptsReloading = true;
|
||||||
|
|
||||||
if (_asset == null || !_asset.IsLoaded)
|
if (_asset == null || !_asset.IsLoaded)
|
||||||
@@ -320,19 +321,8 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
Graph.MainActor = null;
|
Graph.MainActor = null;
|
||||||
_viewport.Prefab = null;
|
_viewport.Prefab = null;
|
||||||
_undo?.Clear(); // TODO: maybe don't clear undo?
|
_undo?.Clear(); // TODO: maybe don't clear undo?
|
||||||
}
|
|
||||||
|
|
||||||
private void OnScriptsReloadEnd()
|
Close();
|
||||||
{
|
|
||||||
_isScriptsReloading = false;
|
|
||||||
|
|
||||||
if (_asset == null || !_asset.IsLoaded)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Restore
|
|
||||||
OnPrefabOpened();
|
|
||||||
_undo.Clear();
|
|
||||||
ClearEditedFlag();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUndoEvent(IUndoAction action)
|
private void OnUndoEvent(IUndoAction action)
|
||||||
@@ -551,7 +541,6 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
{
|
{
|
||||||
Editor.Prefabs.PrefabApplied -= OnPrefabApplied;
|
Editor.Prefabs.PrefabApplied -= OnPrefabApplied;
|
||||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||||
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
|
||||||
|
|
||||||
_undo.Dispose();
|
_undo.Dispose();
|
||||||
Graph.Dispose();
|
Graph.Dispose();
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace FlaxEditor.Windows
|
|||||||
private const string ProjectDataLastViewedFolder = "LastViewedFolder";
|
private const string ProjectDataLastViewedFolder = "LastViewedFolder";
|
||||||
private bool _isWorkspaceDirty;
|
private bool _isWorkspaceDirty;
|
||||||
private string _workspaceRebuildLocation;
|
private string _workspaceRebuildLocation;
|
||||||
|
private string _lastViewedFolderBeforeReload;
|
||||||
private SplitPanel _split;
|
private SplitPanel _split;
|
||||||
private Panel _contentViewPanel;
|
private Panel _contentViewPanel;
|
||||||
private Panel _contentTreePanel;
|
private Panel _contentTreePanel;
|
||||||
@@ -144,26 +145,6 @@ namespace FlaxEditor.Windows
|
|||||||
|
|
||||||
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
||||||
|
|
||||||
// Content database events
|
|
||||||
editor.ContentDatabase.WorkspaceModified += () => _isWorkspaceDirty = true;
|
|
||||||
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;
|
var options = Editor.Options;
|
||||||
options.OptionsChanged += OnOptionsChanged;
|
options.OptionsChanged += OnOptionsChanged;
|
||||||
|
|
||||||
@@ -1036,6 +1017,61 @@ namespace FlaxEditor.Windows
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnInit()
|
public override void OnInit()
|
||||||
|
{
|
||||||
|
// Content database events
|
||||||
|
Editor.ContentDatabase.WorkspaceModified += () => _isWorkspaceDirty = true;
|
||||||
|
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 if (_root != null)
|
||||||
|
ShowRoot();
|
||||||
|
};
|
||||||
|
|
||||||
|
Refresh();
|
||||||
|
|
||||||
|
// Load last viewed folder
|
||||||
|
if (Editor.ProjectCache.TryGetCustomData(ProjectDataLastViewedFolder, out string lastViewedFolder))
|
||||||
|
{
|
||||||
|
if (Editor.ContentDatabase.Find(lastViewedFolder) is ContentFolder folder)
|
||||||
|
_tree.Select(folder.Node);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||||
|
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnScriptsReloadBegin()
|
||||||
|
{
|
||||||
|
var lastViewedFolder = _tree.Selection.Count == 1 ? _tree.SelectedNode as ContentTreeNode : null;
|
||||||
|
_lastViewedFolderBeforeReload = lastViewedFolder?.Path ?? string.Empty;
|
||||||
|
|
||||||
|
_tree.RemoveChild(_root);
|
||||||
|
_root = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnScriptsReloadEnd()
|
||||||
|
{
|
||||||
|
Refresh();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(_lastViewedFolderBeforeReload))
|
||||||
|
{
|
||||||
|
if (Editor.ContentDatabase.Find(_lastViewedFolderBeforeReload) is ContentFolder folder)
|
||||||
|
_tree.Select(folder.Node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Refresh()
|
||||||
{
|
{
|
||||||
// Setup content root node
|
// Setup content root node
|
||||||
_root = new RootContentTreeNode
|
_root = new RootContentTreeNode
|
||||||
@@ -1072,13 +1108,6 @@ namespace FlaxEditor.Windows
|
|||||||
// Update UI layout
|
// Update UI layout
|
||||||
_isLayoutLocked = false;
|
_isLayoutLocked = false;
|
||||||
PerformLayout();
|
PerformLayout();
|
||||||
|
|
||||||
// Load last viewed folder
|
|
||||||
if (Editor.ProjectCache.TryGetCustomData(ProjectDataLastViewedFolder, out string lastViewedFolder))
|
|
||||||
{
|
|
||||||
if (Editor.ContentDatabase.Find(lastViewedFolder) is ContentFolder folder)
|
|
||||||
_tree.Select(folder.Node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -1226,6 +1255,8 @@ namespace FlaxEditor.Windows
|
|||||||
_viewDropdown = null;
|
_viewDropdown = null;
|
||||||
|
|
||||||
Editor.Options.OptionsChanged -= OnOptionsChanged;
|
Editor.Options.OptionsChanged -= OnOptionsChanged;
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||||
|
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
||||||
|
|
||||||
base.OnDestroy();
|
base.OnDestroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,6 +150,22 @@ namespace FlaxEditor.Windows
|
|||||||
_searchBox.Clear();
|
_searchBox.Clear();
|
||||||
_groupSearch.DisposeChildren();
|
_groupSearch.DisposeChildren();
|
||||||
_groupSearch.PerformLayout();
|
_groupSearch.PerformLayout();
|
||||||
|
|
||||||
|
// Remove tabs
|
||||||
|
var tabs = new List<Tab>();
|
||||||
|
foreach (var child in _actorGroups.Children)
|
||||||
|
{
|
||||||
|
if (child is Tab tab)
|
||||||
|
{
|
||||||
|
if (tab.Text != "Search")
|
||||||
|
tabs.Add(tab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var tab in tabs)
|
||||||
|
{
|
||||||
|
var group = _actorGroups.Children.Find(T => T == tab);
|
||||||
|
group.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnScriptsReloadEnd()
|
private void OnScriptsReloadEnd()
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ namespace FlaxEngine.Interop
|
|||||||
_managedHandle.Free();
|
_managedHandle.Free();
|
||||||
_unmanagedData = IntPtr.Zero;
|
_unmanagedData = IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
_arrayType = _elementType = null;
|
||||||
ManagedArrayPool.Put(this);
|
ManagedArrayPool.Put(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,22 +443,25 @@ namespace FlaxEngine.Interop
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to free all references to old weak handles so GC can collect them.
|
/// Tries to free all references to old weak handles so GC can collect them.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static void TryCollectWeakHandles()
|
internal static void TryCollectWeakHandles(bool force = false)
|
||||||
{
|
{
|
||||||
if (weakHandleAccumulator < nextWeakPoolCollection)
|
if (!force)
|
||||||
return;
|
{
|
||||||
|
if (weakHandleAccumulator < nextWeakPoolCollection)
|
||||||
|
return;
|
||||||
|
|
||||||
nextWeakPoolCollection = weakHandleAccumulator + 1000;
|
nextWeakPoolCollection = weakHandleAccumulator + 1000;
|
||||||
|
|
||||||
// Try to swap pools after garbage collection or whenever the pool gets too large
|
// Try to swap pools after garbage collection or whenever the pool gets too large
|
||||||
var gc0CollectionCount = GC.CollectionCount(0);
|
var gc0CollectionCount = GC.CollectionCount(0);
|
||||||
if (gc0CollectionCount < nextWeakPoolGCCollection && weakPool.Count < WeakPoolCollectionSizeThreshold)
|
if (gc0CollectionCount < nextWeakPoolGCCollection && weakPool.Count < WeakPoolCollectionSizeThreshold)
|
||||||
return;
|
return;
|
||||||
nextWeakPoolGCCollection = gc0CollectionCount + 1;
|
nextWeakPoolGCCollection = gc0CollectionCount + 1;
|
||||||
|
|
||||||
// Prevent huge allocations from swapping the pools in the middle of the operation
|
// Prevent huge allocations from swapping the pools in the middle of the operation
|
||||||
if (System.Diagnostics.Stopwatch.GetElapsedTime(lastWeakPoolCollectionTime).TotalMilliseconds < WeakPoolCollectionTimeThreshold)
|
if (System.Diagnostics.Stopwatch.GetElapsedTime(lastWeakPoolCollectionTime).TotalMilliseconds < WeakPoolCollectionTimeThreshold)
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
lastWeakPoolCollectionTime = System.Diagnostics.Stopwatch.GetTimestamp();
|
lastWeakPoolCollectionTime = System.Diagnostics.Stopwatch.GetTimestamp();
|
||||||
|
|
||||||
// Swap the pools and release the oldest pool for GC
|
// Swap the pools and release the oldest pool for GC
|
||||||
|
|||||||
@@ -1054,7 +1054,49 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static void ReloadScriptingAssemblyLoadContext()
|
internal static void CreateScriptingAssemblyLoadContext()
|
||||||
|
{
|
||||||
|
#if FLAX_EDITOR
|
||||||
|
if (scriptingAssemblyLoadContext != null)
|
||||||
|
{
|
||||||
|
// Wait for previous ALC to finish unloading, track it without holding strong references to it
|
||||||
|
GCHandle weakRef = GCHandle.Alloc(scriptingAssemblyLoadContext, GCHandleType.WeakTrackResurrection);
|
||||||
|
scriptingAssemblyLoadContext = null;
|
||||||
|
#if true
|
||||||
|
// In case the ALC doesn't unload properly: https://learn.microsoft.com/en-us/dotnet/standard/assembly/unloadability#debug-unloading-issues
|
||||||
|
while (true)
|
||||||
|
#else
|
||||||
|
for (int attempts = 5; attempts > 0; attempts--)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
GC.Collect();
|
||||||
|
GC.WaitForPendingFinalizers();
|
||||||
|
|
||||||
|
if (!IsHandleAlive(weakRef))
|
||||||
|
break;
|
||||||
|
System.Threading.Thread.Sleep(1);
|
||||||
|
}
|
||||||
|
if (IsHandleAlive(weakRef))
|
||||||
|
Debug.LogWarning("Scripting AssemblyLoadContext was not unloaded.");
|
||||||
|
weakRef.Free();
|
||||||
|
|
||||||
|
static bool IsHandleAlive(GCHandle weakRef)
|
||||||
|
{
|
||||||
|
// Checking the target in scope somehow holds a reference to it...?
|
||||||
|
return weakRef.Target != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptingAssemblyLoadContext = new AssemblyLoadContext("Flax", isCollectible: true);
|
||||||
|
scriptingAssemblyLoadContext.Resolving += OnScriptingAssemblyLoadContextResolving;
|
||||||
|
#else
|
||||||
|
scriptingAssemblyLoadContext = new AssemblyLoadContext("Flax", isCollectible: false);
|
||||||
|
#endif
|
||||||
|
DelegateHelpers.InitMethods();
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
internal static void UnloadScriptingAssemblyLoadContext()
|
||||||
{
|
{
|
||||||
#if FLAX_EDITOR
|
#if FLAX_EDITOR
|
||||||
// Clear all caches which might hold references to assemblies in collectible ALC
|
// Clear all caches which might hold references to assemblies in collectible ALC
|
||||||
@@ -1072,24 +1114,87 @@ namespace FlaxEngine.Interop
|
|||||||
handle.Free();
|
handle.Free();
|
||||||
propertyHandleCacheCollectible.Clear();
|
propertyHandleCacheCollectible.Clear();
|
||||||
|
|
||||||
|
foreach (var key in assemblyHandles.Keys.Where(x => x.IsCollectible))
|
||||||
|
assemblyHandles.Remove(key);
|
||||||
|
foreach (var key in assemblyOwnedNativeLibraries.Keys.Where(x => x.IsCollectible))
|
||||||
|
assemblyOwnedNativeLibraries.Remove(key);
|
||||||
|
|
||||||
_typeSizeCache.Clear();
|
_typeSizeCache.Clear();
|
||||||
|
|
||||||
foreach (var pair in classAttributesCacheCollectible)
|
foreach (var pair in classAttributesCacheCollectible)
|
||||||
pair.Value.Free();
|
pair.Value.Free();
|
||||||
classAttributesCacheCollectible.Clear();
|
classAttributesCacheCollectible.Clear();
|
||||||
|
|
||||||
|
ArrayFactory.marshalledTypes.Clear();
|
||||||
|
ArrayFactory.arrayTypes.Clear();
|
||||||
|
ArrayFactory.createArrayDelegates.Clear();
|
||||||
|
|
||||||
FlaxEngine.Json.JsonSerializer.ResetCache();
|
FlaxEngine.Json.JsonSerializer.ResetCache();
|
||||||
|
DelegateHelpers.Release();
|
||||||
|
|
||||||
|
// Ensure both pools are empty
|
||||||
|
ManagedHandle.ManagedHandlePool.TryCollectWeakHandles(true);
|
||||||
|
ManagedHandle.ManagedHandlePool.TryCollectWeakHandles(true);
|
||||||
|
|
||||||
|
GC.Collect();
|
||||||
|
GC.WaitForPendingFinalizers();
|
||||||
|
|
||||||
|
{
|
||||||
|
// HACK: Workaround for TypeDescriptor holding references to collectible types (https://github.com/dotnet/runtime/issues/30656)
|
||||||
|
|
||||||
|
Type TypeDescriptionProviderType = typeof(System.ComponentModel.TypeDescriptionProvider);
|
||||||
|
MethodInfo clearCacheMethod = TypeDescriptionProviderType?.Assembly.GetType("System.ComponentModel.ReflectionCachesUpdateHandler")?.GetMethod("ClearCache");
|
||||||
|
if (clearCacheMethod != null)
|
||||||
|
clearCacheMethod.Invoke(null, new object[] { null });
|
||||||
|
|
||||||
|
Type TypeDescriptorType = typeof(System.ComponentModel.TypeDescriptor);
|
||||||
|
object s_providerTable = TypeDescriptorType?.GetField("s_providerTable", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)?.GetValue(null);
|
||||||
|
|
||||||
|
// Added in .NET runtime 8.0.10, used as the main locking object
|
||||||
|
object s_commonSyncObject = TypeDescriptorType?.GetField("s_commonSyncObject", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)?.GetValue(null);
|
||||||
|
if (s_commonSyncObject == null)
|
||||||
|
s_commonSyncObject = s_providerTable;
|
||||||
|
|
||||||
|
// Removed in .NET runtime 8.0.7
|
||||||
|
object s_internalSyncObject = TypeDescriptorType?.GetField("s_internalSyncObject", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)?.GetValue(null);
|
||||||
|
object s_defaultProviders = TypeDescriptorType?.GetField("s_defaultProviders", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)?.GetValue(null);
|
||||||
|
if (s_internalSyncObject != null && s_defaultProviders != null)
|
||||||
|
{
|
||||||
|
lock (s_internalSyncObject)
|
||||||
|
InvokeClear(s_defaultProviders);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replaces s_defaultProviders in 8.0.7
|
||||||
|
object s_defaultProviderInitialized = TypeDescriptorType?.GetField("s_defaultProviderInitialized", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)?.GetValue(null);
|
||||||
|
if (s_commonSyncObject != null && s_defaultProviderInitialized != null)
|
||||||
|
{
|
||||||
|
lock (s_commonSyncObject)
|
||||||
|
InvokeClear(s_defaultProviderInitialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
object s_providerTypeTable = TypeDescriptorType?.GetField("s_providerTypeTable", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)?.GetValue(null);
|
||||||
|
if (s_providerTable != null && s_providerTypeTable != null)
|
||||||
|
{
|
||||||
|
lock (s_commonSyncObject)
|
||||||
|
InvokeClear(s_providerTypeTable);
|
||||||
|
InvokeClear(s_providerTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InvokeClear(object instance)
|
||||||
|
{
|
||||||
|
Type type = instance.GetType();
|
||||||
|
FlaxEngine.Assertions.Assert.IsTrue(type.Name == "ConcurrentDictionary`2" || type.Name == "Hashtable" || type.Name == "WeakHashtable");
|
||||||
|
type.GetMethods(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault(x => x.Name == "Clear")
|
||||||
|
?.Invoke(instance, new object[] { });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Unload the ALC
|
// Unload the ALC
|
||||||
bool unloading = true;
|
|
||||||
scriptingAssemblyLoadContext.Unloading += (alc) => { unloading = false; };
|
|
||||||
scriptingAssemblyLoadContext.Unload();
|
scriptingAssemblyLoadContext.Unload();
|
||||||
|
scriptingAssemblyLoadContext.Resolving -= OnScriptingAssemblyLoadContextResolving;
|
||||||
|
|
||||||
while (unloading)
|
GC.Collect();
|
||||||
System.Threading.Thread.Sleep(1);
|
GC.WaitForPendingFinalizers();
|
||||||
|
|
||||||
InitScriptingAssemblyLoadContext();
|
|
||||||
DelegateHelpers.InitMethods();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,19 +73,6 @@ namespace FlaxEngine.Interop
|
|||||||
return nativeLibrary;
|
return nativeLibrary;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void InitScriptingAssemblyLoadContext()
|
|
||||||
{
|
|
||||||
#if FLAX_EDITOR
|
|
||||||
var isCollectible = true;
|
|
||||||
#else
|
|
||||||
var isCollectible = false;
|
|
||||||
#endif
|
|
||||||
scriptingAssemblyLoadContext = new AssemblyLoadContext("Flax", isCollectible);
|
|
||||||
#if FLAX_EDITOR
|
|
||||||
scriptingAssemblyLoadContext.Resolving += OnScriptingAssemblyLoadContextResolving;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static unsafe void Init()
|
internal static unsafe void Init()
|
||||||
{
|
{
|
||||||
@@ -97,8 +84,6 @@ namespace FlaxEngine.Interop
|
|||||||
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
||||||
System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||||
|
|
||||||
InitScriptingAssemblyLoadContext();
|
|
||||||
DelegateHelpers.InitMethods();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FLAX_EDITOR
|
#if FLAX_EDITOR
|
||||||
@@ -1475,11 +1460,11 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
internal static class ArrayFactory
|
internal static class ArrayFactory
|
||||||
{
|
{
|
||||||
private delegate Array CreateArrayDelegate(long size);
|
internal delegate Array CreateArrayDelegate(long size);
|
||||||
|
|
||||||
private static ConcurrentDictionary<Type, Type> marshalledTypes = new ConcurrentDictionary<Type, Type>(1, 3);
|
internal static ConcurrentDictionary<Type, Type> marshalledTypes = new ConcurrentDictionary<Type, Type>(1, 3);
|
||||||
private static ConcurrentDictionary<Type, Type> arrayTypes = new ConcurrentDictionary<Type, Type>(1, 3);
|
internal static ConcurrentDictionary<Type, Type> arrayTypes = new ConcurrentDictionary<Type, Type>(1, 3);
|
||||||
private static ConcurrentDictionary<Type, CreateArrayDelegate> createArrayDelegates = new ConcurrentDictionary<Type, CreateArrayDelegate>(1, 3);
|
internal static ConcurrentDictionary<Type, CreateArrayDelegate> createArrayDelegates = new ConcurrentDictionary<Type, CreateArrayDelegate>(1, 3);
|
||||||
|
|
||||||
internal static Type GetMarshalledType(Type elementType)
|
internal static Type GetMarshalledType(Type elementType)
|
||||||
{
|
{
|
||||||
@@ -1645,17 +1630,6 @@ namespace FlaxEngine.Interop
|
|||||||
return RegisterType(type, true).typeHolder;
|
return RegisterType(type, true).typeHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static (TypeHolder typeHolder, ManagedHandle handle) GetTypeHolderAndManagedHandle(Type type)
|
|
||||||
{
|
|
||||||
if (managedTypes.TryGetValue(type, out (TypeHolder typeHolder, ManagedHandle handle) tuple))
|
|
||||||
return tuple;
|
|
||||||
#if FLAX_EDITOR
|
|
||||||
if (managedTypesCollectible.TryGetValue(type, out tuple))
|
|
||||||
return tuple;
|
|
||||||
#endif
|
|
||||||
return RegisterType(type, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a static ManagedHandle to TypeHolder for given Type, and caches it if needed.
|
/// Returns a static ManagedHandle to TypeHolder for given Type, and caches it if needed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1781,6 +1755,14 @@ namespace FlaxEngine.Interop
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void Release()
|
||||||
|
{
|
||||||
|
MakeNewCustomDelegateFunc = null;
|
||||||
|
#if FLAX_EDITOR
|
||||||
|
MakeNewCustomDelegateFuncCollectible = null;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
internal static Type MakeNewCustomDelegate(Type[] parameters)
|
internal static Type MakeNewCustomDelegate(Type[] parameters)
|
||||||
{
|
{
|
||||||
#if FLAX_EDITOR
|
#if FLAX_EDITOR
|
||||||
|
|||||||
@@ -45,9 +45,16 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
static void UnloadEngine();
|
static void UnloadEngine();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the assembly load context for assemblies used by Scripting.
|
||||||
|
/// </summary>
|
||||||
|
static void CreateScriptingAssemblyLoadContext();
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
// Called by Scripting in a middle of hot-reload (after unloading modules but before loading them again).
|
/// <summary>
|
||||||
static void ReloadScriptingAssemblyLoadContext();
|
/// Called by Scripting in a middle of hot-reload (after unloading modules but before loading them again).
|
||||||
|
/// </summary>
|
||||||
|
static void UnloadScriptingAssemblyLoadContext();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -330,9 +330,15 @@ void MCore::UnloadEngine()
|
|||||||
ShutdownHostfxr();
|
ShutdownHostfxr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MCore::CreateScriptingAssemblyLoadContext()
|
||||||
|
{
|
||||||
|
static void* CreateScriptingAssemblyLoadContextPtr = GetStaticMethodPointer(TEXT("CreateScriptingAssemblyLoadContext"));
|
||||||
|
CallStaticMethod<void>(CreateScriptingAssemblyLoadContextPtr);
|
||||||
|
}
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
|
||||||
void MCore::ReloadScriptingAssemblyLoadContext()
|
void MCore::UnloadScriptingAssemblyLoadContext()
|
||||||
{
|
{
|
||||||
// Clear any cached class attributes (see https://github.com/FlaxEngine/FlaxEngine/issues/1108)
|
// Clear any cached class attributes (see https://github.com/FlaxEngine/FlaxEngine/issues/1108)
|
||||||
for (auto e : CachedClassHandles)
|
for (auto e : CachedClassHandles)
|
||||||
@@ -377,8 +383,8 @@ void MCore::ReloadScriptingAssemblyLoadContext()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* ReloadScriptingAssemblyLoadContextPtr = GetStaticMethodPointer(TEXT("ReloadScriptingAssemblyLoadContext"));
|
static void* UnloadScriptingAssemblyLoadContextPtr = GetStaticMethodPointer(TEXT("UnloadScriptingAssemblyLoadContext"));
|
||||||
CallStaticMethod<void>(ReloadScriptingAssemblyLoadContextPtr);
|
CallStaticMethod<void>(UnloadScriptingAssemblyLoadContextPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -715,9 +715,13 @@ void MCore::UnloadEngine()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MCore::CreateScriptingAssemblyLoadContext()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
|
||||||
void MCore::ReloadScriptingAssemblyLoadContext()
|
void MCore::UnloadScriptingAssemblyLoadContext()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,9 +58,13 @@ void MCore::UnloadEngine()
|
|||||||
MRootDomain = nullptr;
|
MRootDomain = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MCore::CreateScriptingAssemblyLoadContext()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
|
||||||
void MCore::ReloadScriptingAssemblyLoadContext()
|
void MCore::UnloadScriptingAssemblyLoadContext()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -182,6 +182,8 @@ bool ScriptingService::Init()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MCore::CreateScriptingAssemblyLoadContext();
|
||||||
|
|
||||||
// Cache root domain
|
// Cache root domain
|
||||||
_rootDomain = MCore::GetRootDomain();
|
_rootDomain = MCore::GetRootDomain();
|
||||||
|
|
||||||
@@ -710,7 +712,8 @@ void Scripting::Reload(bool canTriggerSceneReload)
|
|||||||
_hasGameModulesLoaded = false;
|
_hasGameModulesLoaded = false;
|
||||||
|
|
||||||
// Release and create a new assembly load context for user assemblies
|
// Release and create a new assembly load context for user assemblies
|
||||||
MCore::ReloadScriptingAssemblyLoadContext();
|
MCore::UnloadScriptingAssemblyLoadContext();
|
||||||
|
MCore::CreateScriptingAssemblyLoadContext();
|
||||||
|
|
||||||
// Give GC a try to cleanup old user objects and the other mess
|
// Give GC a try to cleanup old user objects and the other mess
|
||||||
MCore::GC::Collect();
|
MCore::GC::Collect();
|
||||||
|
|||||||
@@ -170,6 +170,10 @@ namespace FlaxEngine
|
|||||||
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
|
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
|
||||||
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
|
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
|
||||||
Localization.LocalizationChanged += OnLocalizationChanged;
|
Localization.LocalizationChanged += OnLocalizationChanged;
|
||||||
|
#if FLAX_EDITOR
|
||||||
|
FlaxEditor.ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||||
|
FlaxEditor.ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
|
||||||
|
#endif
|
||||||
|
|
||||||
OnLocalizationChanged();
|
OnLocalizationChanged();
|
||||||
if (!Engine.IsEditor)
|
if (!Engine.IsEditor)
|
||||||
@@ -178,6 +182,19 @@ namespace FlaxEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FLAX_EDITOR
|
||||||
|
private static void OnScriptsReloadBegin()
|
||||||
|
{
|
||||||
|
// Tooltip might hold references to scripting assemblies
|
||||||
|
Style.Current.SharedTooltip = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnScriptsReloadEnd()
|
||||||
|
{
|
||||||
|
Style.Current.SharedTooltip = new Tooltip();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private static void OnLocalizationChanged()
|
private static void OnLocalizationChanged()
|
||||||
{
|
{
|
||||||
// Invariant-globalization only (see InitHostfxr with Mono)
|
// Invariant-globalization only (see InitHostfxr with Mono)
|
||||||
@@ -359,6 +376,10 @@ namespace FlaxEngine
|
|||||||
|
|
||||||
MainThreadTaskScheduler.Dispose();
|
MainThreadTaskScheduler.Dispose();
|
||||||
Json.JsonSerializer.Dispose();
|
Json.JsonSerializer.Dispose();
|
||||||
|
#if FLAX_EDITOR
|
||||||
|
FlaxEditor.ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||||
|
FlaxEditor.ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ namespace FlaxEngine.GUI
|
|||||||
// Unlink
|
// Unlink
|
||||||
IsLayoutLocked = true;
|
IsLayoutLocked = true;
|
||||||
Parent = null;
|
Parent = null;
|
||||||
|
_showTarget = null;
|
||||||
|
|
||||||
// Close window
|
// Close window
|
||||||
if (_window)
|
if (_window)
|
||||||
|
|||||||
Reference in New Issue
Block a user