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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
Editor = null;
|
||||
_overrideEditor = null;
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnModified()
|
||||
{
|
||||
|
||||
@@ -205,7 +205,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
if (_linkedPrefabId != Guid.Empty)
|
||||
{
|
||||
_linkedPrefabId = Guid.Empty;
|
||||
Editor.Instance.Prefabs.PrefabApplied -= OnPrefabApplying;
|
||||
Editor.Instance.Prefabs.PrefabApplying -= OnPrefabApplying;
|
||||
Editor.Instance.Prefabs.PrefabApplied -= OnPrefabApplied;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1057,6 +1057,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
_scriptToggles = null;
|
||||
_scripts.Clear();
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
|
||||
@@ -819,6 +819,15 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
OnGroupsEnd();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
_visibleIfCaches = null;
|
||||
_visibleIfPropertiesListsCache = null;
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
|
||||
@@ -464,7 +464,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
{
|
||||
base.Focus();
|
||||
|
||||
SelectTab();
|
||||
SelectTab(false);
|
||||
BringToFront();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace FlaxEditor.Modules
|
||||
private bool _enableEvents;
|
||||
private bool _isDuringFastSetup;
|
||||
private bool _rebuildFlag;
|
||||
private bool _rebuildInitFlag;
|
||||
private int _itemsCreated;
|
||||
private int _itemsDeleted;
|
||||
private readonly HashSet<MainContentTreeNode> _dirtyNodes = new HashSet<MainContentTreeNode>();
|
||||
@@ -61,7 +62,7 @@ namespace FlaxEditor.Modules
|
||||
public event Action WorkspaceModified;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when workspace has will be rebuilt.
|
||||
/// Occurs when workspace will be rebuilt.
|
||||
/// </summary>
|
||||
public event Action WorkspaceRebuilding;
|
||||
|
||||
@@ -88,6 +89,9 @@ namespace FlaxEditor.Modules
|
||||
|
||||
// Register AssetItems serialization helper (serialize ref ID only)
|
||||
FlaxEngine.Json.JsonSerializer.Settings.Converters.Add(new AssetItemConverter());
|
||||
|
||||
ScriptsBuilder.ScriptsReload += OnScriptsReload;
|
||||
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
|
||||
}
|
||||
|
||||
private void OnContentAssetDisposing(Asset asset)
|
||||
@@ -817,6 +821,7 @@ namespace FlaxEditor.Modules
|
||||
Profiler.BeginEvent("ContentDatabase.Rebuild");
|
||||
var startTime = Platform.TimeSeconds;
|
||||
_rebuildFlag = false;
|
||||
_rebuildInitFlag = false;
|
||||
_enableEvents = false;
|
||||
|
||||
// Load all folders
|
||||
@@ -1230,8 +1235,6 @@ namespace FlaxEditor.Modules
|
||||
LoadProjects(Game.Project);
|
||||
}
|
||||
|
||||
RebuildInternal();
|
||||
|
||||
Editor.ContentImporting.ImportFileEnd += (obj, failed) =>
|
||||
{
|
||||
var path = obj.ResultUrl;
|
||||
@@ -1239,6 +1242,15 @@ namespace FlaxEditor.Modules
|
||||
FlaxEngine.Scripting.InvokeOnUpdate(() => OnImportFileDone(path));
|
||||
};
|
||||
_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)
|
||||
@@ -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 />
|
||||
public override void OnUpdate()
|
||||
{
|
||||
@@ -1340,6 +1398,8 @@ namespace FlaxEditor.Modules
|
||||
public override void OnExit()
|
||||
{
|
||||
FlaxEngine.Content.AssetDisposing -= OnContentAssetDisposing;
|
||||
ScriptsBuilder.ScriptsReload -= OnScriptsReload;
|
||||
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
||||
|
||||
// Disable events
|
||||
_enableEvents = false;
|
||||
|
||||
@@ -391,6 +391,20 @@ namespace FlaxEditor.Modules
|
||||
public override void OnInit()
|
||||
{
|
||||
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 />
|
||||
@@ -451,6 +465,7 @@ namespace FlaxEditor.Modules
|
||||
/// <inheritdoc />
|
||||
public override void OnExit()
|
||||
{
|
||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
EndWorker();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace FlaxEditor.Modules
|
||||
: base(editor)
|
||||
{
|
||||
// After editor cache but before the windows
|
||||
InitOrder = -900;
|
||||
InitOrder = -800;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -160,7 +160,7 @@ namespace FlaxEditor.Modules
|
||||
internal UIModule(Editor editor)
|
||||
: base(editor)
|
||||
{
|
||||
InitOrder = -90;
|
||||
InitOrder = -70;
|
||||
VisjectSurfaceBackground = FlaxEngine.Content.LoadAsyncInternal<Texture>("Editor/VisjectSurface");
|
||||
ColorValueBox.ShowPickColorDialog += ShowPickColorDialog;
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.GUI.Dialogs;
|
||||
using FlaxEditor.GUI.Docking;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
using FlaxEditor.Windows.Profiler;
|
||||
@@ -39,6 +41,7 @@ namespace FlaxEditor.Modules
|
||||
|
||||
public DockState DockState;
|
||||
public DockPanel DockedTo;
|
||||
public int DockedTabIndex;
|
||||
public float? SplitterValue = null;
|
||||
|
||||
public bool SelectOnShow = false;
|
||||
@@ -48,6 +51,8 @@ namespace FlaxEditor.Modules
|
||||
public Float2 FloatSize;
|
||||
public Float2 FloatPosition;
|
||||
|
||||
public Guid AssetItemID;
|
||||
|
||||
// Constructor, to allow for default values
|
||||
public WindowRestoreData()
|
||||
{
|
||||
@@ -803,43 +808,64 @@ namespace FlaxEditor.Modules
|
||||
Level.SceneSaving += OnSceneSaving;
|
||||
Level.SceneUnloaded += OnSceneUnloaded;
|
||||
Level.SceneUnloading += OnSceneUnloading;
|
||||
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
|
||||
Editor.ContentDatabase.WorkspaceRebuilt += OnWorkspaceRebuilt;
|
||||
Editor.StateMachine.StateChanged += OnEditorStateChanged;
|
||||
}
|
||||
|
||||
internal void AddToRestore(AssetEditorWindow win)
|
||||
{
|
||||
AddToRestore(win, win.GetType(), new WindowRestoreData
|
||||
{
|
||||
AssetItemID = win.Item.ID,
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
|
||||
if (constructor == null || type.IsGenericType)
|
||||
return;
|
||||
|
||||
var winData = new WindowRestoreData();
|
||||
var panel = win.Window.ParentDockPanel;
|
||||
var panel = win.ParentDockPanel;
|
||||
|
||||
// Ensure that this window is only selected following recompilation
|
||||
// if it was the active tab in its dock panel. Otherwise, there is a
|
||||
// risk of interrupting the user's workflow by potentially selecting
|
||||
// background tabs.
|
||||
winData.SelectOnShow = panel.SelectedTab == win.Window;
|
||||
if (panel is FloatWindowDockPanel)
|
||||
var window = win.RootWindow.Window;
|
||||
winData.SelectOnShow = panel.SelectedTab == win;
|
||||
winData.DockedTabIndex = 0;
|
||||
if (panel is FloatWindowDockPanel && window != null && panel.TabsCount == 1)
|
||||
{
|
||||
winData.DockState = DockState.Float;
|
||||
var window = win.Window.RootWindow.Window;
|
||||
winData.FloatPosition = window.Position;
|
||||
winData.FloatSize = window.ClientSize;
|
||||
winData.Maximize = window.IsMaximized;
|
||||
winData.Minimize = window.IsMinimized;
|
||||
winData.DockedTo = panel;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < panel.Tabs.Count; i++)
|
||||
{
|
||||
if (panel.Tabs[i] == win)
|
||||
{
|
||||
winData.DockedTabIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (panel.TabsCount > 1)
|
||||
{
|
||||
winData.DockState = DockState.DockFill;
|
||||
winData.DockedTo = panel;
|
||||
}else
|
||||
}
|
||||
else
|
||||
{
|
||||
winData.DockState = panel.TryGetDockState(out var splitterValue);
|
||||
winData.DockedTo = panel.ParentDockPanel;
|
||||
@@ -851,38 +877,93 @@ namespace FlaxEditor.Modules
|
||||
_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];
|
||||
|
||||
try
|
||||
{
|
||||
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);
|
||||
if (type != null)
|
||||
var ctor = type.GetConstructor(new Type[] { typeof(Editor), typeof(AssetItem) });
|
||||
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);
|
||||
win.Show(winData.DockState, winData.DockedTo, winData.SelectOnShow, winData.SplitterValue);
|
||||
if (winData.DockState == DockState.Float)
|
||||
var window = win.RootWindow.Window;
|
||||
window.Position = winData.FloatPosition;
|
||||
if (winData.Maximize)
|
||||
{
|
||||
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;
|
||||
}
|
||||
window.Maximize();
|
||||
}
|
||||
else if (winData.Minimize)
|
||||
{
|
||||
window.Minimize();
|
||||
}
|
||||
else
|
||||
{
|
||||
window.ClientSize = winData.FloatSize;
|
||||
}
|
||||
|
||||
// Update panel reference in other windows docked to this panel
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
// Restored windows stole the focus from Editor
|
||||
if (_restoreWindows.Count > 0)
|
||||
Editor.Instance.Windows.MainWindow.Focus();
|
||||
|
||||
_restoreWindows.Clear();
|
||||
}
|
||||
|
||||
@@ -1048,7 +1134,7 @@ namespace FlaxEditor.Modules
|
||||
Level.SceneSaving -= OnSceneSaving;
|
||||
Level.SceneUnloaded -= OnSceneUnloaded;
|
||||
Level.SceneUnloading -= OnSceneUnloading;
|
||||
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
||||
Editor.ContentDatabase.WorkspaceRebuilt -= OnWorkspaceRebuilt;
|
||||
Editor.StateMachine.StateChanged -= OnEditorStateChanged;
|
||||
|
||||
// Close main window
|
||||
|
||||
@@ -469,6 +469,7 @@ namespace FlaxEditor.SceneGraph
|
||||
{
|
||||
ChildNodes[i].OnDispose();
|
||||
}
|
||||
ChildNodes.Clear();
|
||||
|
||||
SceneGraphFactory.Nodes.Remove(ID);
|
||||
}
|
||||
|
||||
@@ -161,6 +161,8 @@ namespace FlaxEditor.Surface
|
||||
|
||||
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
|
||||
bool hasTypeFromGameScripts = Editor.Instance.CodeEditing.AnimGraphNodes.HasTypeFromGameScripts;
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace FlaxEditor.Surface
|
||||
public BehaviorTreeSurface(IVisjectSurfaceOwner owner, Action onSave, FlaxEditor.Undo undo)
|
||||
: base(owner, onSave, undo, CreateStyle())
|
||||
{
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
}
|
||||
|
||||
private static SurfaceStyle CreateStyle()
|
||||
@@ -35,6 +36,11 @@ namespace FlaxEditor.Surface
|
||||
return style;
|
||||
}
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
{
|
||||
_nodesCache.Clear();
|
||||
}
|
||||
|
||||
private static void DrawBox(Box box)
|
||||
{
|
||||
var rect = new Rectangle(Float2.Zero, box.Size);
|
||||
@@ -186,6 +192,7 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
if (IsDisposing)
|
||||
return;
|
||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
_nodesCache.Wait();
|
||||
|
||||
base.OnDestroy();
|
||||
|
||||
@@ -415,6 +415,15 @@ namespace FlaxEditor.Surface
|
||||
// Init drag handlers
|
||||
DragHandlers.Add(_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem));
|
||||
DragHandlers.Add(_dragParameters = new DragNames<DragDropEventArgs>(SurfaceParameter.DragPrefix, ValidateDragParameter));
|
||||
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
}
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
{
|
||||
_activeVisjectCM = null;
|
||||
_cmPrimaryMenu?.Dispose();
|
||||
_cmPrimaryMenu = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1023,6 +1032,8 @@ namespace FlaxEditor.Surface
|
||||
_activeVisjectCM = null;
|
||||
_cmPrimaryMenu?.Dispose();
|
||||
|
||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,12 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
_supportsImplicitCastFromObjectToBoolean = true;
|
||||
DragHandlers.Add(_dragActors = new DragActors(ValidateDragActor));
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
}
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
{
|
||||
_nodesCache.Clear();
|
||||
}
|
||||
|
||||
private bool ValidateDragActor(ActorNode actor)
|
||||
@@ -631,6 +637,7 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
if (IsDisposing)
|
||||
return;
|
||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
_nodesCache.Wait();
|
||||
|
||||
base.OnDestroy();
|
||||
|
||||
@@ -58,6 +58,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
InputActions.Add(options => options.Save, Save);
|
||||
|
||||
UpdateTitle();
|
||||
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -151,6 +153,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
|
||||
if (_item != null)
|
||||
{
|
||||
// Ensure to remove linkage to the item
|
||||
@@ -160,6 +164,15 @@ namespace FlaxEditor.Windows.Assets
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected virtual void OnScriptsReloadBegin()
|
||||
{
|
||||
if (!IsHidden)
|
||||
{
|
||||
Editor.Instance.Windows.AddToRestore(this);
|
||||
}
|
||||
}
|
||||
|
||||
#region IEditable Implementation
|
||||
|
||||
private bool _isEdited;
|
||||
|
||||
@@ -268,8 +268,11 @@ namespace FlaxEditor.Windows.Assets
|
||||
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)
|
||||
Close();
|
||||
}
|
||||
|
||||
@@ -124,8 +124,10 @@ namespace FlaxEditor.Windows.Assets
|
||||
UpdateToolstrip();
|
||||
}
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
/// <inheritdoc />
|
||||
protected override void OnScriptsReloadBegin()
|
||||
{
|
||||
base.OnScriptsReloadBegin();
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
@@ -198,7 +198,6 @@ namespace FlaxEditor.Windows.Assets
|
||||
|
||||
Editor.Prefabs.PrefabApplied += OnPrefabApplied;
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
|
||||
|
||||
// Setup input actions
|
||||
InputActions.Add(options => options.Undo, () =>
|
||||
@@ -291,8 +290,10 @@ namespace FlaxEditor.Windows.Assets
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
/// <inheritdoc />
|
||||
protected override void OnScriptsReloadBegin()
|
||||
{
|
||||
base.OnScriptsReloadBegin();
|
||||
_isScriptsReloading = true;
|
||||
|
||||
if (_asset == null || !_asset.IsLoaded)
|
||||
@@ -320,19 +321,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
Graph.MainActor = null;
|
||||
_viewport.Prefab = null;
|
||||
_undo?.Clear(); // TODO: maybe don't clear undo?
|
||||
}
|
||||
|
||||
private void OnScriptsReloadEnd()
|
||||
{
|
||||
_isScriptsReloading = false;
|
||||
|
||||
if (_asset == null || !_asset.IsLoaded)
|
||||
return;
|
||||
|
||||
// Restore
|
||||
OnPrefabOpened();
|
||||
_undo.Clear();
|
||||
ClearEditedFlag();
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnUndoEvent(IUndoAction action)
|
||||
@@ -551,7 +541,6 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
Editor.Prefabs.PrefabApplied -= OnPrefabApplied;
|
||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
||||
|
||||
_undo.Dispose();
|
||||
Graph.Dispose();
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace FlaxEditor.Windows
|
||||
private const string ProjectDataLastViewedFolder = "LastViewedFolder";
|
||||
private bool _isWorkspaceDirty;
|
||||
private string _workspaceRebuildLocation;
|
||||
private string _lastViewedFolderBeforeReload;
|
||||
private SplitPanel _split;
|
||||
private Panel _contentViewPanel;
|
||||
private Panel _contentTreePanel;
|
||||
@@ -144,26 +145,6 @@ namespace FlaxEditor.Windows
|
||||
|
||||
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;
|
||||
options.OptionsChanged += OnOptionsChanged;
|
||||
|
||||
@@ -1036,6 +1017,61 @@ namespace FlaxEditor.Windows
|
||||
|
||||
/// <inheritdoc />
|
||||
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
|
||||
_root = new RootContentTreeNode
|
||||
@@ -1072,13 +1108,6 @@ namespace FlaxEditor.Windows
|
||||
// Update UI layout
|
||||
_isLayoutLocked = false;
|
||||
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 />
|
||||
@@ -1226,6 +1255,8 @@ namespace FlaxEditor.Windows
|
||||
_viewDropdown = null;
|
||||
|
||||
Editor.Options.OptionsChanged -= OnOptionsChanged;
|
||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
@@ -150,6 +150,22 @@ namespace FlaxEditor.Windows
|
||||
_searchBox.Clear();
|
||||
_groupSearch.DisposeChildren();
|
||||
_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()
|
||||
|
||||
@@ -176,6 +176,7 @@ namespace FlaxEngine.Interop
|
||||
_managedHandle.Free();
|
||||
_unmanagedData = IntPtr.Zero;
|
||||
}
|
||||
_arrayType = _elementType = null;
|
||||
ManagedArrayPool.Put(this);
|
||||
}
|
||||
|
||||
@@ -442,22 +443,25 @@ namespace FlaxEngine.Interop
|
||||
/// <summary>
|
||||
/// Tries to free all references to old weak handles so GC can collect them.
|
||||
/// </summary>
|
||||
internal static void TryCollectWeakHandles()
|
||||
internal static void TryCollectWeakHandles(bool force = false)
|
||||
{
|
||||
if (weakHandleAccumulator < nextWeakPoolCollection)
|
||||
return;
|
||||
if (!force)
|
||||
{
|
||||
if (weakHandleAccumulator < nextWeakPoolCollection)
|
||||
return;
|
||||
|
||||
nextWeakPoolCollection = weakHandleAccumulator + 1000;
|
||||
nextWeakPoolCollection = weakHandleAccumulator + 1000;
|
||||
|
||||
// Try to swap pools after garbage collection or whenever the pool gets too large
|
||||
var gc0CollectionCount = GC.CollectionCount(0);
|
||||
if (gc0CollectionCount < nextWeakPoolGCCollection && weakPool.Count < WeakPoolCollectionSizeThreshold)
|
||||
return;
|
||||
nextWeakPoolGCCollection = gc0CollectionCount + 1;
|
||||
// Try to swap pools after garbage collection or whenever the pool gets too large
|
||||
var gc0CollectionCount = GC.CollectionCount(0);
|
||||
if (gc0CollectionCount < nextWeakPoolGCCollection && weakPool.Count < WeakPoolCollectionSizeThreshold)
|
||||
return;
|
||||
nextWeakPoolGCCollection = gc0CollectionCount + 1;
|
||||
|
||||
// Prevent huge allocations from swapping the pools in the middle of the operation
|
||||
if (System.Diagnostics.Stopwatch.GetElapsedTime(lastWeakPoolCollectionTime).TotalMilliseconds < WeakPoolCollectionTimeThreshold)
|
||||
return;
|
||||
// Prevent huge allocations from swapping the pools in the middle of the operation
|
||||
if (System.Diagnostics.Stopwatch.GetElapsedTime(lastWeakPoolCollectionTime).TotalMilliseconds < WeakPoolCollectionTimeThreshold)
|
||||
return;
|
||||
}
|
||||
lastWeakPoolCollectionTime = System.Diagnostics.Stopwatch.GetTimestamp();
|
||||
|
||||
// Swap the pools and release the oldest pool for GC
|
||||
|
||||
@@ -1054,7 +1054,49 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
|
||||
[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
|
||||
// Clear all caches which might hold references to assemblies in collectible ALC
|
||||
@@ -1072,24 +1114,87 @@ namespace FlaxEngine.Interop
|
||||
handle.Free();
|
||||
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();
|
||||
|
||||
foreach (var pair in classAttributesCacheCollectible)
|
||||
pair.Value.Free();
|
||||
classAttributesCacheCollectible.Clear();
|
||||
|
||||
ArrayFactory.marshalledTypes.Clear();
|
||||
ArrayFactory.arrayTypes.Clear();
|
||||
ArrayFactory.createArrayDelegates.Clear();
|
||||
|
||||
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
|
||||
bool unloading = true;
|
||||
scriptingAssemblyLoadContext.Unloading += (alc) => { unloading = false; };
|
||||
scriptingAssemblyLoadContext.Unload();
|
||||
scriptingAssemblyLoadContext.Resolving -= OnScriptingAssemblyLoadContextResolving;
|
||||
|
||||
while (unloading)
|
||||
System.Threading.Thread.Sleep(1);
|
||||
|
||||
InitScriptingAssemblyLoadContext();
|
||||
DelegateHelpers.InitMethods();
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -73,19 +73,6 @@ namespace FlaxEngine.Interop
|
||||
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]
|
||||
internal static unsafe void Init()
|
||||
{
|
||||
@@ -97,8 +84,6 @@ namespace FlaxEngine.Interop
|
||||
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
|
||||
InitScriptingAssemblyLoadContext();
|
||||
DelegateHelpers.InitMethods();
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
@@ -1475,11 +1460,11 @@ namespace FlaxEngine.Interop
|
||||
|
||||
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);
|
||||
private 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, Type> marshalledTypes = new ConcurrentDictionary<Type, Type>(1, 3);
|
||||
internal static ConcurrentDictionary<Type, Type> arrayTypes = new ConcurrentDictionary<Type, Type>(1, 3);
|
||||
internal static ConcurrentDictionary<Type, CreateArrayDelegate> createArrayDelegates = new ConcurrentDictionary<Type, CreateArrayDelegate>(1, 3);
|
||||
|
||||
internal static Type GetMarshalledType(Type elementType)
|
||||
{
|
||||
@@ -1645,17 +1630,6 @@ namespace FlaxEngine.Interop
|
||||
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>
|
||||
/// Returns a static ManagedHandle to TypeHolder for given Type, and caches it if needed.
|
||||
/// </summary>
|
||||
@@ -1781,6 +1755,14 @@ namespace FlaxEngine.Interop
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void Release()
|
||||
{
|
||||
MakeNewCustomDelegateFunc = null;
|
||||
#if FLAX_EDITOR
|
||||
MakeNewCustomDelegateFuncCollectible = null;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static Type MakeNewCustomDelegate(Type[] parameters)
|
||||
{
|
||||
#if FLAX_EDITOR
|
||||
|
||||
@@ -45,9 +45,16 @@ public:
|
||||
/// </summary>
|
||||
static void UnloadEngine();
|
||||
|
||||
/// <summary>
|
||||
/// Creates the assembly load context for assemblies used by Scripting.
|
||||
/// </summary>
|
||||
static void CreateScriptingAssemblyLoadContext();
|
||||
|
||||
#if USE_EDITOR
|
||||
// Called by Scripting in a middle of hot-reload (after unloading modules but before loading them again).
|
||||
static void ReloadScriptingAssemblyLoadContext();
|
||||
/// <summary>
|
||||
/// Called by Scripting in a middle of hot-reload (after unloading modules but before loading them again).
|
||||
/// </summary>
|
||||
static void UnloadScriptingAssemblyLoadContext();
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
@@ -330,9 +330,15 @@ void MCore::UnloadEngine()
|
||||
ShutdownHostfxr();
|
||||
}
|
||||
|
||||
void MCore::CreateScriptingAssemblyLoadContext()
|
||||
{
|
||||
static void* CreateScriptingAssemblyLoadContextPtr = GetStaticMethodPointer(TEXT("CreateScriptingAssemblyLoadContext"));
|
||||
CallStaticMethod<void>(CreateScriptingAssemblyLoadContextPtr);
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void MCore::ReloadScriptingAssemblyLoadContext()
|
||||
void MCore::UnloadScriptingAssemblyLoadContext()
|
||||
{
|
||||
// Clear any cached class attributes (see https://github.com/FlaxEngine/FlaxEngine/issues/1108)
|
||||
for (auto e : CachedClassHandles)
|
||||
@@ -377,8 +383,8 @@ void MCore::ReloadScriptingAssemblyLoadContext()
|
||||
}
|
||||
}
|
||||
|
||||
static void* ReloadScriptingAssemblyLoadContextPtr = GetStaticMethodPointer(TEXT("ReloadScriptingAssemblyLoadContext"));
|
||||
CallStaticMethod<void>(ReloadScriptingAssemblyLoadContextPtr);
|
||||
static void* UnloadScriptingAssemblyLoadContextPtr = GetStaticMethodPointer(TEXT("UnloadScriptingAssemblyLoadContext"));
|
||||
CallStaticMethod<void>(UnloadScriptingAssemblyLoadContextPtr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -715,9 +715,13 @@ void MCore::UnloadEngine()
|
||||
#endif
|
||||
}
|
||||
|
||||
void MCore::CreateScriptingAssemblyLoadContext()
|
||||
{
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void MCore::ReloadScriptingAssemblyLoadContext()
|
||||
void MCore::UnloadScriptingAssemblyLoadContext()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -58,9 +58,13 @@ void MCore::UnloadEngine()
|
||||
MRootDomain = nullptr;
|
||||
}
|
||||
|
||||
void MCore::CreateScriptingAssemblyLoadContext()
|
||||
{
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void MCore::ReloadScriptingAssemblyLoadContext()
|
||||
void MCore::UnloadScriptingAssemblyLoadContext()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -182,6 +182,8 @@ bool ScriptingService::Init()
|
||||
return true;
|
||||
}
|
||||
|
||||
MCore::CreateScriptingAssemblyLoadContext();
|
||||
|
||||
// Cache root domain
|
||||
_rootDomain = MCore::GetRootDomain();
|
||||
|
||||
@@ -710,7 +712,8 @@ void Scripting::Reload(bool canTriggerSceneReload)
|
||||
_hasGameModulesLoaded = false;
|
||||
|
||||
// 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
|
||||
MCore::GC::Collect();
|
||||
|
||||
@@ -170,6 +170,10 @@ namespace FlaxEngine
|
||||
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
|
||||
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
|
||||
Localization.LocalizationChanged += OnLocalizationChanged;
|
||||
#if FLAX_EDITOR
|
||||
FlaxEditor.ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
FlaxEditor.ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
|
||||
#endif
|
||||
|
||||
OnLocalizationChanged();
|
||||
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()
|
||||
{
|
||||
// Invariant-globalization only (see InitHostfxr with Mono)
|
||||
@@ -359,6 +376,10 @@ namespace FlaxEngine
|
||||
|
||||
MainThreadTaskScheduler.Dispose();
|
||||
Json.JsonSerializer.Dispose();
|
||||
#if FLAX_EDITOR
|
||||
FlaxEditor.ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
FlaxEditor.ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -120,6 +120,7 @@ namespace FlaxEngine.GUI
|
||||
// Unlink
|
||||
IsLayoutLocked = true;
|
||||
Parent = null;
|
||||
_showTarget = null;
|
||||
|
||||
// Close window
|
||||
if (_window)
|
||||
|
||||
Reference in New Issue
Block a user