Merge remote-tracking branch 'origin/master' into 1.13
# Conflicts: # Content/Shaders/Editor/Grid.flax # Content/Shaders/GBuffer.flax # Content/Shaders/GlobalSignDistanceField.flax # Content/Shaders/ProbesFilter.flax # Content/Shaders/SSR.flax # Content/Shaders/VolumetricFog.flax # Development/Documentation/mono.md # Source/Editor/Modules/ContentDatabaseModule.cs
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.GUI.Docking;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor
|
||||
@@ -89,8 +91,20 @@ namespace FlaxEditor
|
||||
{
|
||||
Editor.Instance.Windows.AddToRestore(this);
|
||||
}
|
||||
Window.Close();
|
||||
Window.Dispose();
|
||||
Window.Close(ClosingReason.ScriptsReload);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reattaches the window control to existing floating window.
|
||||
/// </summary>
|
||||
/// <param name="windowHandle">The window handle.</param>
|
||||
/// <param name="state">Initial window state.</param>
|
||||
/// <param name="toDock">The panel to dock to, if any.</param>
|
||||
/// <param name="autoSelect">Only used if <paramref name="toDock"/> is set. If true the window will be selected after docking it.</param>
|
||||
/// <param name="splitterValue">The splitter value to use if toDock is not null. If not specified, a default value will be used.</param>
|
||||
public void Restore(IntPtr windowHandle, DockState state = DockState.Float, DockPanel toDock = null, bool autoSelect = true, float? splitterValue = null)
|
||||
{
|
||||
_win.Restore(windowHandle, state, toDock, autoSelect, splitterValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -322,7 +322,11 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
// Deselect
|
||||
if (_value != null && button1Rect.Contains(ref location))
|
||||
{
|
||||
Focus();
|
||||
Value = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Picker dropdown menu
|
||||
if (_supportsPickDropDown && (isSelected ? button2Rect : button1Rect).Contains(ref location))
|
||||
@@ -372,6 +376,18 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
if (_hasValidDragOver)
|
||||
_hasValidDragOver = false;
|
||||
}
|
||||
if (button == MouseButton.Middle)
|
||||
{
|
||||
// Clear value
|
||||
Focus();
|
||||
Value = null;
|
||||
return true;
|
||||
}
|
||||
if (button == MouseButton.Right && _supportsPickDropDown)
|
||||
{
|
||||
// Show picker
|
||||
ShowDropDownMenu();
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
@@ -642,9 +642,11 @@ int32 Editor::LoadProduct()
|
||||
}
|
||||
}
|
||||
|
||||
#if !FLAX_TESTS
|
||||
// Update the last opened project path
|
||||
if (lastProjectPath.Compare(Project->ProjectFolderPath) != 0)
|
||||
File::WriteAllText(lastProjectSettingPath, Project->ProjectFolderPath, Encoding::UTF8);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -299,6 +299,7 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
else if (Button1Rect.Contains(location))
|
||||
{
|
||||
// Show picker
|
||||
Focus();
|
||||
OnSubmit();
|
||||
}
|
||||
@@ -318,6 +319,18 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
}
|
||||
if (button == MouseButton.Middle && IconRect.Contains(ref location))
|
||||
{
|
||||
// Clear value
|
||||
Focus();
|
||||
Validator.SelectedItem = null;
|
||||
}
|
||||
if (button == MouseButton.Right && IconRect.Contains(ref location))
|
||||
{
|
||||
// Show picker
|
||||
Focus();
|
||||
OnSubmit();
|
||||
}
|
||||
|
||||
// Handled
|
||||
return true;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Xml;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Assertions;
|
||||
using FlaxEngine.GUI;
|
||||
@@ -50,7 +52,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this window is docked.
|
||||
/// </summary>
|
||||
public bool IsDocked => _dockedTo != null;
|
||||
public bool IsDocked => _dockedTo != null && _dockedTo.TabsCount > 1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this window is selected.
|
||||
@@ -232,6 +234,46 @@ namespace FlaxEditor.GUI.Docking
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reattaches the window control to existing floating window.
|
||||
/// </summary>
|
||||
/// <param name="windowHandle">The window handle.</param>
|
||||
/// <param name="state">Initial window state.</param>
|
||||
/// <param name="toDock">Panel to dock to it.</param>
|
||||
/// <param name="autoSelect">Only used if <paramref name="toDock"/> is set. If true the window will be selected after docking it.</param>
|
||||
/// <param name="splitterValue">Only used if <paramref name="toDock"/> is set. The splitter value to use. If not specified, a default value will be used.</param>
|
||||
public void Restore(IntPtr windowHandle, DockState state = DockState.Float, DockPanel toDock = null, bool autoSelect = true, float? splitterValue = null)
|
||||
{
|
||||
if (state != DockState.Float)
|
||||
{
|
||||
Show(state, toDock, autoSelect, splitterValue);
|
||||
return;
|
||||
}
|
||||
|
||||
Undock();
|
||||
|
||||
// Find the existing window and remove all controls from it
|
||||
var window = Editor.GetWindows().First(x => x.NativePtr == windowHandle);
|
||||
var windowGUI = window.GUI;
|
||||
while (windowGUI.Children.Count > 0)
|
||||
windowGUI.Children[^1].Dispose();
|
||||
windowGUI.EndTrackingMouse();
|
||||
|
||||
// Create dock panel for the window
|
||||
var dockPanel = new FloatWindowDockPanel(_masterPanel, windowGUI);
|
||||
dockPanel.DockWindowInternal(DockState.DockFill, this);
|
||||
|
||||
// Perform layout
|
||||
Visible = true;
|
||||
windowGUI.UnlockChildrenRecursive();
|
||||
windowGUI.PerformLayout();
|
||||
|
||||
OnShow();
|
||||
|
||||
// Perform layout again
|
||||
windowGUI.PerformLayout();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the window.
|
||||
/// </summary>
|
||||
@@ -332,6 +374,12 @@ namespace FlaxEditor.GUI.Docking
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reason == ClosingReason.ScriptsReload && _dockedTo is FloatWindowDockPanel floatPanel)
|
||||
{
|
||||
// Unlink the window to keep it alive during scripts reload
|
||||
floatPanel.UnlinkWindow();
|
||||
}
|
||||
|
||||
// Undock
|
||||
Undock();
|
||||
|
||||
@@ -488,7 +536,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
base.Focus();
|
||||
|
||||
SelectTab(false);
|
||||
BringToFront();
|
||||
_dockedTo?.RootWindow?.Focus();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
|
||||
private MasterDockPanel _masterPanel;
|
||||
private WindowRootControl _window;
|
||||
private bool _showDecorations;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the master panel.
|
||||
@@ -65,6 +66,31 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// </summary>
|
||||
public bool IsDragging { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Shows client-side window decorations around this panel.
|
||||
/// </summary>
|
||||
public bool ShowDecorations
|
||||
{
|
||||
get => _showDecorations;
|
||||
set
|
||||
{
|
||||
if (value == _showDecorations)
|
||||
return;
|
||||
_showDecorations = value;
|
||||
if (value)
|
||||
{
|
||||
var decorations = Parent.AddChild(new FloatWindowDecorations(this));
|
||||
decorations.SetAnchorPreset(AnchorPresets.HorizontalStretchTop, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var decorations = Parent.GetChild<FloatWindowDecorations>();
|
||||
if (decorations != null)
|
||||
decorations.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FloatWindowDockPanel"/> class.
|
||||
/// </summary>
|
||||
@@ -82,10 +108,16 @@ namespace FlaxEditor.GUI.Docking
|
||||
_window.Window.Closing += OnClosing;
|
||||
_window.Window.LeftButtonHit += OnLeftButtonHit;
|
||||
|
||||
if (Utilities.Utils.UseCustomWindowDecorations())
|
||||
ShowDecorations = Utilities.Utils.UseCustomWindowDecorations();
|
||||
}
|
||||
|
||||
internal void UnlinkWindow()
|
||||
{
|
||||
if (_window != null)
|
||||
{
|
||||
var decorations = Parent.AddChild(new FloatWindowDecorations(this));
|
||||
decorations.SetAnchorPreset(AnchorPresets.HorizontalStretchTop, false);
|
||||
_window.Window.Closing -= OnClosing;
|
||||
_window.Window.LeftButtonHit -= OnLeftButtonHit;
|
||||
_window = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,13 +126,10 @@ namespace FlaxEditor.GUI.Docking
|
||||
{
|
||||
base.PerformLayoutBeforeChildren();
|
||||
|
||||
var decorations = Parent.GetChild<FloatWindowDecorations>();
|
||||
if (decorations != null)
|
||||
{
|
||||
// Apply offset for the title bar
|
||||
foreach (var child in Children)
|
||||
child.Bounds = child.Bounds with { Y = decorations.Height, Height = Parent.Height - decorations.Height };
|
||||
}
|
||||
// Apply offset for the title bar
|
||||
var decorationsHeight = Parent.GetChild<FloatWindowDecorations>()?.Height ?? 0;
|
||||
foreach (var child in Children)
|
||||
child.Bounds = child.Bounds with { Y = decorationsHeight, Height = Parent.Height - decorationsHeight };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -191,9 +220,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
}
|
||||
|
||||
// Unlink
|
||||
_window.Window.Closing -= OnClosing;
|
||||
_window.Window.LeftButtonHit = null;
|
||||
_window = null;
|
||||
UnlinkWindow();
|
||||
|
||||
// Remove object
|
||||
FlaxEngine.Assertions.Assert.IsTrue(TabsCount == 0 && ChildPanelsCount == 0);
|
||||
@@ -244,6 +271,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
{
|
||||
_masterPanel?.FloatingPanels.Remove(this);
|
||||
|
||||
UnlinkWindow();
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -748,21 +748,27 @@ namespace FlaxEditor.Modules
|
||||
if (item.Path.Contains(".Build.cs", StringComparison.Ordinal) && item.ItemType == ContentItemType.Script)
|
||||
Editor.Instance.CodeEditing.RemoveModule(item.Path);
|
||||
|
||||
// Check if it's an asset
|
||||
if (item.IsAsset)
|
||||
{
|
||||
// Delete asset by using content pool
|
||||
FlaxEngine.Content.DeleteAsset(path);
|
||||
}
|
||||
else if (item is ScriptItem)
|
||||
{
|
||||
FlaxEngine.Content.DeleteScript(path);
|
||||
}
|
||||
else if (deletedByUser)
|
||||
{
|
||||
// Delete file
|
||||
if (File.Exists(path))
|
||||
File.Delete(path);
|
||||
// Delete asset file only if it was explicitly deleted by the user.
|
||||
// Some applications might modify the file by deleting the original and replacing
|
||||
// it with a new file which sometimes is caught in the middle of these operations.
|
||||
if (deletedByUser)
|
||||
{
|
||||
// Check if it's an asset
|
||||
if (item.IsAsset)
|
||||
{
|
||||
// Delete asset by using content pool
|
||||
FlaxEngine.Content.DeleteAsset(path);
|
||||
}
|
||||
else if (item is ScriptItem)
|
||||
{
|
||||
FlaxEngine.Content.DeleteScript(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Delete file
|
||||
if (File.Exists(path))
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Unlink from the parent
|
||||
@@ -826,23 +832,29 @@ namespace FlaxEditor.Modules
|
||||
var startTime = Platform.TimeSeconds;
|
||||
_rebuildFlag = false;
|
||||
_rebuildInitFlag = false;
|
||||
_enableEvents = false;
|
||||
|
||||
// Load all folders
|
||||
// TODO: we should create async task for gathering content and whole workspace contents if it takes too long
|
||||
// TODO: create progress bar in content window and after end we should enable events and update it
|
||||
_enableEvents = false;
|
||||
_isDuringFastSetup = true;
|
||||
var startItems = _itemsCreated;
|
||||
foreach (var project in Projects)
|
||||
try
|
||||
{
|
||||
if (project.Content != null)
|
||||
LoadFolder(project.Content, true);
|
||||
if (project.Source != null)
|
||||
LoadFolder(project.Source, true);
|
||||
// Load all folders
|
||||
// TODO: we should create async task for gathering content and whole workspace contents if it takes too long
|
||||
// TODO: create progress bar in content window and after end we should enable events and update it
|
||||
foreach (var project in Projects)
|
||||
{
|
||||
if (project.Content != null)
|
||||
LoadFolder(project.Content, true);
|
||||
if (project.Source != null)
|
||||
LoadFolder(project.Source, true);
|
||||
}
|
||||
}
|
||||
_isDuringFastSetup = false;
|
||||
|
||||
_enableEvents = enableEvents;
|
||||
finally
|
||||
{
|
||||
_isDuringFastSetup = false;
|
||||
_enableEvents = enableEvents;
|
||||
}
|
||||
|
||||
var endTime = Platform.TimeSeconds;
|
||||
Editor.Log(string.Format("Project database created in {0} ms. Items count: {1}", (int)((endTime - startTime) * 1000.0), _itemsCreated - startItems));
|
||||
Profiler.EndEvent();
|
||||
@@ -1340,39 +1352,44 @@ namespace FlaxEditor.Modules
|
||||
_enableEvents = false;
|
||||
_isDuringFastSetup = true;
|
||||
var startItems = _itemsCreated;
|
||||
foreach (var project in Projects)
|
||||
try
|
||||
{
|
||||
if (project.Content != null)
|
||||
foreach (var project in Projects)
|
||||
{
|
||||
//Dispose(project.Content.Folder);
|
||||
for (int i = 0; i < project.Content.Folder.Children.Count; i++)
|
||||
if (project.Content != null)
|
||||
{
|
||||
Dispose(project.Content.Folder.Children[i]);
|
||||
i--;
|
||||
//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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (project.Source != null)
|
||||
|
||||
List<ContentProxy> removeProxies = new List<ContentProxy>();
|
||||
foreach (var proxy in Editor.Instance.ContentDatabase.Proxy)
|
||||
{
|
||||
//Dispose(project.Source.Folder);
|
||||
for (int i = 0; i < project.Source.Folder.Children.Count; i++)
|
||||
{
|
||||
Dispose(project.Source.Folder.Children[i]);
|
||||
i--;
|
||||
}
|
||||
if (proxy.GetType().IsCollectible)
|
||||
removeProxies.Add(proxy);
|
||||
}
|
||||
foreach (var proxy in removeProxies)
|
||||
RemoveProxy(proxy, false);
|
||||
}
|
||||
|
||||
List<ContentProxy> removeProxies = new List<ContentProxy>();
|
||||
foreach (var proxy in Editor.Instance.ContentDatabase.Proxy)
|
||||
finally
|
||||
{
|
||||
if (proxy.GetType().IsCollectible)
|
||||
removeProxies.Add(proxy);
|
||||
_isDuringFastSetup = false;
|
||||
_enableEvents = enabledEvents;
|
||||
}
|
||||
foreach (var proxy in removeProxies)
|
||||
RemoveProxy(proxy, false);
|
||||
|
||||
_isDuringFastSetup = false;
|
||||
_enableEvents = enabledEvents;
|
||||
}
|
||||
|
||||
private void OnScriptsReloadEnd()
|
||||
@@ -1383,18 +1400,22 @@ namespace FlaxEditor.Modules
|
||||
/// <inheritdoc />
|
||||
public override void OnUpdate()
|
||||
{
|
||||
// Update all dirty content tree nodes
|
||||
lock (_dirtyNodes)
|
||||
// Check for updates only when the editor is focused to only check once for all changes done in background.
|
||||
if (FlaxEngine.Engine.HasFocus)
|
||||
{
|
||||
Profiler.BeginEvent("ContentDatabase.Refresh");
|
||||
foreach (var node in _dirtyNodes)
|
||||
// Update all dirty content tree nodes
|
||||
lock (_dirtyNodes)
|
||||
{
|
||||
LoadFolder(node, true);
|
||||
Profiler.BeginEvent("ContentDatabase.Refresh");
|
||||
foreach (var node in _dirtyNodes)
|
||||
{
|
||||
LoadFolder(node, true);
|
||||
}
|
||||
if (_enableEvents && _dirtyNodes.Count != 0)
|
||||
WorkspaceModified?.Invoke();
|
||||
_dirtyNodes.Clear();
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
if (_enableEvents && _dirtyNodes.Count != 0)
|
||||
WorkspaceModified?.Invoke();
|
||||
_dirtyNodes.Clear();
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
// Lazy-rebuilds
|
||||
|
||||
@@ -505,7 +505,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
||||
base.OnUpdate();
|
||||
|
||||
// Automatic project files generation after workspace modifications
|
||||
if (_autoGenerateScriptsProjectFiles && ScriptsBuilder.IsSourceWorkspaceDirty && !ScriptsBuilder.IsCompiling)
|
||||
if (_autoGenerateScriptsProjectFiles && ScriptsBuilder.IsSourceWorkspaceDirty && !ScriptsBuilder.IsCompiling && Engine.HasFocus)
|
||||
{
|
||||
// Try to delay generation when a lot of files are added at once
|
||||
if (ScriptsBuilder.IsSourceDirtyFor(TimeSpan.FromMilliseconds(150)))
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
@@ -33,11 +34,12 @@ namespace FlaxEditor.Modules
|
||||
private float _projectIconScreenshotTimeout = -1;
|
||||
private string _windowsLayoutPath;
|
||||
|
||||
private struct WindowRestoreData
|
||||
private class WindowRestoreData
|
||||
{
|
||||
public string AssemblyName;
|
||||
public string TypeName;
|
||||
|
||||
public IntPtr WindowHandle;
|
||||
public DockState DockState;
|
||||
public DockPanel DockedTo;
|
||||
public int DockedTabIndex;
|
||||
@@ -45,20 +47,10 @@ namespace FlaxEditor.Modules
|
||||
|
||||
public bool SelectOnShow = false;
|
||||
|
||||
public bool Maximize;
|
||||
public bool Minimize;
|
||||
public Float2 FloatSize;
|
||||
public Float2 FloatPosition;
|
||||
|
||||
public Guid AssetItemID;
|
||||
|
||||
// Constructor, to allow for default values
|
||||
public WindowRestoreData()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<WindowRestoreData> _restoreWindows = new List<WindowRestoreData>();
|
||||
private readonly Dictionary<Guid, WindowRestoreData> _restoreWindows = new();
|
||||
|
||||
/// <summary>
|
||||
/// The main editor window.
|
||||
@@ -818,10 +810,14 @@ namespace FlaxEditor.Modules
|
||||
|
||||
internal void AddToRestore(AssetEditorWindow win)
|
||||
{
|
||||
AddToRestore(win, win.GetType(), new WindowRestoreData
|
||||
var assetItemId = win.Item.ID;
|
||||
if (!_restoreWindows.TryGetValue(assetItemId, out var winData))
|
||||
{
|
||||
AssetItemID = win.Item.ID,
|
||||
});
|
||||
winData = new WindowRestoreData();
|
||||
_restoreWindows.Add(assetItemId, winData);
|
||||
}
|
||||
winData.AssetItemID = assetItemId;
|
||||
AddToRestore(win, win.GetType(), winData);
|
||||
}
|
||||
|
||||
internal void AddToRestore(CustomEditorWindow win)
|
||||
@@ -832,62 +828,65 @@ namespace FlaxEditor.Modules
|
||||
if (constructor == null || type.IsGenericType)
|
||||
return;
|
||||
|
||||
AddToRestore(win.Window, type, new WindowRestoreData());
|
||||
// TODO: Restore data for custom editors
|
||||
var assetItemId = Guid.NewGuid();
|
||||
if (!_restoreWindows.TryGetValue(assetItemId, out var winData))
|
||||
{
|
||||
winData = new WindowRestoreData();
|
||||
_restoreWindows.Add(assetItemId, winData);
|
||||
}
|
||||
winData.AssetItemID = assetItemId;
|
||||
AddToRestore(win.Window, type, winData);
|
||||
}
|
||||
|
||||
private void AddToRestore(EditorWindow win, Type type, WindowRestoreData winData)
|
||||
{
|
||||
// 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.
|
||||
var window = win.RootWindow?.Window;
|
||||
var panel = win.ParentDockPanel;
|
||||
winData.SelectOnShow = panel.SelectedTab == win;
|
||||
winData.DockedTabIndex = 0;
|
||||
if (panel is FloatWindowDockPanel && window != null && panel.TabsCount == 1)
|
||||
winData.AssemblyName = type.Assembly.GetName().Name;
|
||||
winData.TypeName = type.FullName;
|
||||
if (panel is FloatWindowDockPanel)
|
||||
{
|
||||
winData.DockState = DockState.Float;
|
||||
winData.FloatPosition = window.Position;
|
||||
winData.FloatSize = window.ClientSize;
|
||||
winData.Maximize = window.IsMaximized;
|
||||
winData.Minimize = window.IsMinimized;
|
||||
winData.DockedTo = panel;
|
||||
// Populate data for other tabs now, the tab index may change after tab is destroyed
|
||||
if (winData.DockedTo == null)
|
||||
{
|
||||
for (int i = 0; i < panel.Tabs.Count; i++)
|
||||
{
|
||||
if (panel.Tabs[i] is AssetEditorWindow assetEditorWindow)
|
||||
{
|
||||
window ??= assetEditorWindow.RootWindow?.Window; // The window handle is sometimes missing in some tabs
|
||||
var assetItemId = assetEditorWindow.Item.ID;
|
||||
if (!_restoreWindows.TryGetValue(assetItemId, out var tabWinData))
|
||||
{
|
||||
tabWinData = new WindowRestoreData();
|
||||
_restoreWindows.Add(assetItemId, tabWinData);
|
||||
}
|
||||
|
||||
tabWinData.DockedTabIndex = i;
|
||||
tabWinData.SelectOnShow = panel.SelectedTab == assetEditorWindow;
|
||||
tabWinData.DockState = DockState.DockFill;
|
||||
tabWinData.DockedTo = panel;
|
||||
}
|
||||
}
|
||||
winData.DockState = DockState.Float;
|
||||
winData.WindowHandle = window?.NativePtr ?? IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
winData.DockState = panel.TryGetDockState(out var splitterValue);
|
||||
winData.DockedTo = panel.ParentDockPanel;
|
||||
winData.SplitterValue = splitterValue;
|
||||
}
|
||||
winData.DockState = panel.TryGetDockState(out var splitterValue);
|
||||
winData.DockedTo = panel.ParentDockPanel;
|
||||
winData.SplitterValue = splitterValue;
|
||||
}
|
||||
winData.AssemblyName = type.Assembly.GetName().Name;
|
||||
winData.TypeName = type.FullName;
|
||||
_restoreWindows.Add(winData);
|
||||
}
|
||||
|
||||
private void OnWorkspaceRebuilt()
|
||||
{
|
||||
// Go in reverse order to create floating Prefab windows first before docked windows
|
||||
for (int i = _restoreWindows.Count - 1; i >= 0; i--)
|
||||
var assetEditorWindows = new Dictionary<Guid, AssetEditorWindow>();
|
||||
|
||||
// Create float windows first, then add docked windows in order of the tabs
|
||||
foreach (var (_, winData) in _restoreWindows)
|
||||
{
|
||||
var winData = _restoreWindows[i];
|
||||
|
||||
try
|
||||
{
|
||||
var assembly = Utils.GetAssemblyByName(winData.AssemblyName);
|
||||
@@ -904,75 +903,24 @@ namespace FlaxEditor.Modules
|
||||
var assetType = assetItem.GetType();
|
||||
var ctor = type.GetConstructor(new Type[] { typeof(Editor), assetType });
|
||||
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);
|
||||
var previouslyDockedTo = winData.DockedTo;
|
||||
win.Restore(winData.WindowHandle, winData.DockState, winData.DockState != DockState.Float ? winData.DockedTo : null, winData.SelectOnShow, winData.SplitterValue);
|
||||
if (winData.DockState == DockState.Float)
|
||||
{
|
||||
var window = win.RootWindow.Window;
|
||||
window.Position = winData.FloatPosition;
|
||||
if (winData.Maximize)
|
||||
{
|
||||
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))
|
||||
foreach (var key in _restoreWindows.Keys)
|
||||
{
|
||||
if (otherData.DockedTo == winData.DockedTo)
|
||||
ref var otherData = ref CollectionsMarshal.GetValueRefOrNullRef(_restoreWindows, key);
|
||||
if (otherData.DockedTo == previouslyDockedTo)
|
||||
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++;
|
||||
}
|
||||
panel.PerformLayout(true);
|
||||
assetEditorWindows.Add(winData.AssetItemID, win);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
win.Restore(winData.WindowHandle, winData.DockState, winData.DockedTo, winData.SelectOnShow, winData.SplitterValue);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -981,6 +929,46 @@ namespace FlaxEditor.Modules
|
||||
Editor.LogWarning(string.Format("Failed to restore window {0} (assembly: {1})", winData.TypeName, winData.AssemblyName));
|
||||
}
|
||||
}
|
||||
|
||||
// Reorder tabs to previous order
|
||||
foreach (var (_, winData) in _restoreWindows)
|
||||
{
|
||||
var win = assetEditorWindows.GetValueOrDefault(winData.AssetItemID);
|
||||
if (win == null)
|
||||
continue;
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore last selected tab
|
||||
foreach (var (_, winData) in _restoreWindows)
|
||||
{
|
||||
var win = assetEditorWindows.GetValueOrDefault(winData.AssetItemID);
|
||||
if (win != null && winData.SelectOnShow)
|
||||
{
|
||||
win.ParentDockPanel.SelectTab(win, false);
|
||||
win.ParentDockPanel.PerformLayout(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Restored windows stole the focus from Editor
|
||||
if (_restoreWindows.Count > 0)
|
||||
|
||||
@@ -159,11 +159,11 @@ namespace FlaxEditor.States
|
||||
SceneDuplicated?.Invoke();
|
||||
RestoreSelection();
|
||||
|
||||
Time.Synchronize(true);
|
||||
|
||||
Editor.OnPlayBegin();
|
||||
IsPlayModeStarting = false;
|
||||
Profiler.EndEvent();
|
||||
|
||||
Time.Synchronize(true);
|
||||
}
|
||||
|
||||
private void SetupEditorEnvOptions()
|
||||
|
||||
@@ -76,6 +76,11 @@ namespace FlaxEditor.Surface
|
||||
/// The footer rectangle (local space).
|
||||
/// </summary>
|
||||
protected Rectangle _footerRect;
|
||||
|
||||
/// <summary>
|
||||
/// The last mouse down position.
|
||||
/// </summary>
|
||||
protected Float2 _mouseDownMousePosition;
|
||||
|
||||
/// <summary>
|
||||
/// The node archetype.
|
||||
@@ -163,8 +168,6 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
protected virtual Color ArchetypeColor => GroupArchetype.Color;
|
||||
|
||||
private Float2 mouseDownMousePosition;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the size of the node including header, footer, and margins.
|
||||
/// </summary>
|
||||
@@ -1166,10 +1169,9 @@ namespace FlaxEditor.Surface
|
||||
if (base.OnMouseDown(location, button))
|
||||
return true;
|
||||
|
||||
_mouseDownMousePosition = location;
|
||||
if (button == MouseButton.Left && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location))
|
||||
return true;
|
||||
if (button == MouseButton.Right)
|
||||
mouseDownMousePosition = Input.Mouse.Position;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1180,18 +1182,22 @@ namespace FlaxEditor.Surface
|
||||
if (base.OnMouseUp(location, button))
|
||||
return true;
|
||||
|
||||
// Close/ delete
|
||||
bool canDelete = !Surface.IsConnecting && !Surface.WasSelecting && !Surface.WasMovingSelection;
|
||||
if (button == MouseButton.Left && canDelete && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location))
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
Surface.Delete(this);
|
||||
return true;
|
||||
// Close/delete
|
||||
bool canDelete = !Surface.IsConnecting && !Surface.WasSelecting && !Surface.WasMovingSelection;
|
||||
if (canDelete && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 &&
|
||||
_closeButtonRect.Contains(ref location) && _closeButtonRect.Contains(ref _mouseDownMousePosition))
|
||||
{
|
||||
Surface.Delete(this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Secondary Context Menu
|
||||
if (button == MouseButton.Right)
|
||||
{
|
||||
float distance = Float2.Distance(mouseDownMousePosition, Input.Mouse.Position);
|
||||
float distance = Float2.Distance(_mouseDownMousePosition, location);
|
||||
if (distance > 2.5f)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -287,6 +287,7 @@ namespace FlaxEditor.Surface
|
||||
|
||||
// Reset instigator list
|
||||
_connectionInstigators.Clear();
|
||||
EndMouseCapture();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
Save();
|
||||
}
|
||||
Editor.Instance.Windows.AddToRestore(this);
|
||||
Close();
|
||||
Close(ClosingReason.ScriptsReload);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -274,7 +274,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
base.OnScriptsReloadBegin();
|
||||
|
||||
// TODO: impl hot-reload for BT to nicely refresh state (save asset, clear undo/properties, reload surface)
|
||||
Close();
|
||||
Close(ClosingReason.ScriptsReload);
|
||||
}
|
||||
|
||||
private void UpdateKnowledge()
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
protected override void OnScriptsReloadBegin()
|
||||
{
|
||||
base.OnScriptsReloadBegin();
|
||||
Close();
|
||||
Close(ClosingReason.ScriptsReload);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -366,7 +366,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
_viewport.Prefab = null;
|
||||
_undo?.Clear(); // TODO: maybe don't clear undo?
|
||||
|
||||
Close();
|
||||
Close(ClosingReason.ScriptsReload);
|
||||
}
|
||||
|
||||
private void OnUndoEvent(IUndoAction action)
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using FlaxEditor.Gizmo;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Docking;
|
||||
using FlaxEditor.GUI.Input;
|
||||
using FlaxEditor.Modules;
|
||||
using FlaxEditor.Options;
|
||||
@@ -132,6 +133,8 @@ namespace FlaxEditor.Windows
|
||||
private float _gameStartTime;
|
||||
private GUI.Docking.DockState _maximizeRestoreDockState;
|
||||
private GUI.Docking.DockPanel _maximizeRestoreDockTo;
|
||||
private GUI.Docking.DockPanel _maximizeRestoreDockToParent;
|
||||
private float _maximizeRestoreSplitterValue;
|
||||
private CursorLockMode _cursorLockMode = CursorLockMode.None;
|
||||
|
||||
// Viewport scaling variables
|
||||
@@ -295,7 +298,10 @@ namespace FlaxEditor.Windows
|
||||
if (value)
|
||||
{
|
||||
_maximizeRestoreDockTo = _dockedTo;
|
||||
_maximizeRestoreDockState = _dockedTo.TryGetDockState(out _);
|
||||
_maximizeRestoreDockToParent = _dockedTo.ParentDockPanel;
|
||||
_maximizeRestoreDockState = _dockedTo.TryGetDockState(out _maximizeRestoreSplitterValue);
|
||||
if (_dockedTo.Tabs.Count > 1)
|
||||
_maximizeRestoreDockState = DockState.DockFill;
|
||||
if (_maximizeRestoreDockState != GUI.Docking.DockState.Float)
|
||||
{
|
||||
var monitorBounds = Platform.GetMonitorBounds(PointToScreen(Size * 0.5f));
|
||||
@@ -309,9 +315,11 @@ namespace FlaxEditor.Windows
|
||||
// Restore
|
||||
if (rootWindow != null)
|
||||
rootWindow.Restore();
|
||||
if (_maximizeRestoreDockTo != null && _maximizeRestoreDockTo.IsDisposing)
|
||||
_maximizeRestoreDockTo = null;
|
||||
Show(_maximizeRestoreDockState, _maximizeRestoreDockTo);
|
||||
var dockTo = _maximizeRestoreDockTo;
|
||||
if (dockTo != null && dockTo.IsDisposing)
|
||||
dockTo = _maximizeRestoreDockToParent;
|
||||
if (_dockedTo != dockTo)
|
||||
Show(_maximizeRestoreDockState, dockTo, splitterValue: _maximizeRestoreSplitterValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -331,6 +339,9 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
IsFloating = true;
|
||||
var rootWindow = RootWindow;
|
||||
var floatWin = rootWindow.GetChild<FloatWindowDockPanel>();
|
||||
if (floatWin != null && floatWin.ShowDecorations)
|
||||
floatWin.ShowDecorations = false;
|
||||
var monitorBounds = Platform.GetMonitorBounds(rootWindow.RootWindow.Window.ClientPosition);
|
||||
rootWindow.Window.Position = monitorBounds.Location;
|
||||
rootWindow.Window.SetBorderless(true);
|
||||
@@ -338,6 +349,9 @@ namespace FlaxEditor.Windows
|
||||
}
|
||||
else
|
||||
{
|
||||
var floatWin = RootWindow.GetChild<FloatWindowDockPanel>();
|
||||
if (floatWin != null && !floatWin.ShowDecorations && Utilities.Utils.UseCustomWindowDecorations())
|
||||
floatWin.ShowDecorations = true;
|
||||
IsFloating = false;
|
||||
}
|
||||
}
|
||||
@@ -658,9 +672,10 @@ namespace FlaxEditor.Windows
|
||||
IsBorderless = false;
|
||||
Cursor = CursorType.Default;
|
||||
Screen.CursorLock = CursorLockMode.None;
|
||||
if (Screen.MainWindow.IsMouseTracking)
|
||||
Screen.MainWindow.EndTrackingMouse();
|
||||
RootControl.GameRoot.EndMouseCapture();
|
||||
var mainWindow = Screen.MainWindow;
|
||||
if (mainWindow != null && mainWindow.IsMouseTracking)
|
||||
mainWindow.EndTrackingMouse();
|
||||
RootControl.GameRoot?.EndMouseCapture();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -899,7 +914,7 @@ namespace FlaxEditor.Windows
|
||||
/// </summary>
|
||||
public void FocusGameViewport()
|
||||
{
|
||||
if (!IsDocked)
|
||||
if (ParentDockPanel == null)
|
||||
{
|
||||
ShowFloating();
|
||||
}
|
||||
@@ -1004,7 +1019,7 @@ namespace FlaxEditor.Windows
|
||||
Screen.CursorVisible = true;
|
||||
Screen.CursorLock = CursorLockMode.None;
|
||||
|
||||
if (Editor.IsPlayMode && IsDocked && IsSelected && RootWindow.FocusedControl == null)
|
||||
if (Editor.IsPlayMode && ParentDockPanel != null && IsSelected && RootWindow.FocusedControl == null)
|
||||
{
|
||||
// Game UI cleared focus so regain it to maintain UI navigation just like game window does
|
||||
FlaxEngine.Scripting.InvokeOnUpdate(Focus);
|
||||
|
||||
@@ -122,11 +122,8 @@ FlaxStorageReference ContentStorageManager::EnsureAccess(const StringView& path)
|
||||
// Note: because we want to create new storage package it may exists.
|
||||
// So let's check if any storage container is referencing that location and try to close it.
|
||||
auto storage = TryGetStorage(path);
|
||||
if (storage && storage->IsLoaded())
|
||||
{
|
||||
LOG(Info, "File \'{0}\' is in use. Trying to release handle to it.", path);
|
||||
storage->CloseFileHandles();
|
||||
}
|
||||
if (storage && storage->IsLoaded() && storage->CloseFileHandles())
|
||||
LOG(Warning, "Cannot release content storage handle for '{0}'.", path);
|
||||
return storage;
|
||||
}
|
||||
|
||||
|
||||
@@ -1438,10 +1438,6 @@ FileReadStream* FlaxStorage::OpenFile()
|
||||
|
||||
bool FlaxStorage::CloseFileHandles()
|
||||
{
|
||||
// Guard the whole process so if new thread wants to lock the chunks will need to wait for this to end
|
||||
Platform::InterlockedIncrement(&_isUnloadingData);
|
||||
SCOPE_EXIT{ Platform::InterlockedDecrement(&_isUnloadingData); };
|
||||
|
||||
if (Platform::AtomicRead(&_chunksLock) == 0 && Platform::AtomicRead(&_files) == 0)
|
||||
return false; // Early out when no files are opened
|
||||
PROFILE_CPU();
|
||||
@@ -1469,7 +1465,13 @@ bool FlaxStorage::CloseFileHandles()
|
||||
}
|
||||
}
|
||||
}
|
||||
waitTime = 100;
|
||||
|
||||
// Guard the whole process so if new thread wants to lock the chunks will need to wait for this to end
|
||||
Platform::InterlockedIncrement(&_isUnloadingData);
|
||||
SCOPE_EXIT{ Platform::InterlockedDecrement(&_isUnloadingData); };
|
||||
|
||||
// Wait for chunks lock again (with larger timeout for longer tasks)
|
||||
waitTime = 1000;
|
||||
while (Platform::AtomicRead(&_chunksLock) != 0 && waitTime-- > 0)
|
||||
Platform::Sleep(1);
|
||||
if (Platform::AtomicRead(&_chunksLock) != 0)
|
||||
|
||||
@@ -901,20 +901,21 @@ namespace FlaxEngine.Interop
|
||||
|
||||
Assembly assembly;
|
||||
#if FLAX_EDITOR
|
||||
// Load assembly from loaded bytes to prevent file locking in Editor
|
||||
var assemblyBytes = File.ReadAllBytes(assemblyPath);
|
||||
using MemoryStream stream = new MemoryStream(assemblyBytes);
|
||||
// Load assembly with stream to prevent runtime from locking the assembly file
|
||||
using FileStream stream = new FileStream(assemblyPath, FileMode.Open, FileAccess.Read);
|
||||
var pdbPath = Path.ChangeExtension(assemblyPath, "pdb");
|
||||
if (File.Exists(pdbPath))
|
||||
{
|
||||
// Load including debug symbols
|
||||
using FileStream pdbStream = new FileStream(Path.ChangeExtension(assemblyPath, "pdb"), FileMode.Open);
|
||||
using FileStream pdbStream = new FileStream(Path.ChangeExtension(assemblyPath, "pdb"), FileMode.Open, FileAccess.Read);
|
||||
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream, pdbStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream);
|
||||
}
|
||||
|
||||
// TODO: Use new .NET 11 AssemblyLoadContext.SetAssemblyLocationOverride to specify correct Assembly.Location
|
||||
#else
|
||||
// Load assembly from file
|
||||
assembly = scriptingAssemblyLoadContext.LoadFromAssemblyPath(assemblyPath);
|
||||
|
||||
@@ -197,7 +197,7 @@ bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, const Float3* ve
|
||||
|
||||
bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, const Float3* vertices, const uint32* triangles, const Float3* normals, const Float3* tangents, const Float2* uvs, const Color32* colors)
|
||||
{
|
||||
return ::UpdateMesh(this, vertexCount, triangleCount, PixelFormat::R16_UInt, vertices, triangles, normals, tangents, uvs, colors);
|
||||
return ::UpdateMesh(this, vertexCount, triangleCount, PixelFormat::R32_UInt, vertices, triangles, normals, tangents, uvs, colors);
|
||||
}
|
||||
|
||||
bool Mesh::Load(uint32 vertices, uint32 triangles, const void* vb0, const void* vb1, const void* vb2, const void* ib, bool use16BitIndexBuffer)
|
||||
|
||||
@@ -305,7 +305,7 @@ bool SkinnedMesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, const Flo
|
||||
|
||||
bool SkinnedMesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, const Float3* vertices, const uint32* triangles, const Int4* blendIndices, const Float4* blendWeights, const Float3* normals, const Float3* tangents, const Float2* uvs, const Color32* colors)
|
||||
{
|
||||
return ::UpdateMesh(this, vertexCount, triangleCount, PixelFormat::R16_UInt, vertices, triangles, blendIndices, blendWeights, normals, tangents, uvs, colors);
|
||||
return ::UpdateMesh(this, vertexCount, triangleCount, PixelFormat::R32_UInt, vertices, triangles, blendIndices, blendWeights, normals, tangents, uvs, colors);
|
||||
}
|
||||
|
||||
void SkinnedMesh::Draw(const RenderContext& renderContext, const SkinnedMeshBones& pose, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals, DrawPass drawModes, float perInstanceRandom, int8 sortOrder, uint8 stencilValue) const
|
||||
|
||||
@@ -28,6 +28,11 @@ API_ENUM() enum class ClosingReason
|
||||
/// The close event.
|
||||
/// </summary>
|
||||
CloseEvent,
|
||||
|
||||
/// <summary>
|
||||
/// The scripts reload event.
|
||||
/// </summary>
|
||||
ScriptsReload,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#if USE_EDITOR
|
||||
#define COMPILE_WITH_ASSETS_IMPORTER 1 // Hack to use shaders importing in this module
|
||||
#include "Engine/ContentImporters/AssetsImportingManager.h"
|
||||
#include "Engine/Content/Storage/ContentStorageManager.h"
|
||||
#include "Engine/Utilities/Encryption.h"
|
||||
#include "Engine/Platform/FileSystemWatcher.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
@@ -499,6 +501,37 @@ String ShadersCompilation::CompactShaderPath(StringView path)
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
bool ShadersCompilation::IsShaderSourceAssetUpToDate(const StringView& sourcePath, const StringView& assetPath)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
StringAnsi source;
|
||||
if (File::ReadAllText(sourcePath, source))
|
||||
return false;
|
||||
if (!source.HasChars() || source[source.Length() - 1] != '\n')
|
||||
source.Append('\n');
|
||||
|
||||
const auto storage = ContentStorageManager::GetStorage(assetPath);
|
||||
AssetInitData data;
|
||||
if (!storage
|
||||
|| storage->GetEntriesCount() != 1
|
||||
|| storage->GetEntry(0).TypeName != Shader::TypeName
|
||||
|| storage->LoadAssetHeader(0, data)
|
||||
|| data.SerializedVersion != Shader::SerializedVersion)
|
||||
return false;
|
||||
|
||||
FlaxChunk* sourceChunk = data.Header.Chunks[SHADER_FILE_CHUNK_SOURCE];
|
||||
if (!sourceChunk || storage->LoadAssetChunk(sourceChunk) || !sourceChunk->Data.IsValid())
|
||||
return false;
|
||||
|
||||
BytesContainer embeddedSource;
|
||||
embeddedSource.Copy(sourceChunk->Data);
|
||||
if (embeddedSource.Length() != source.Length() + 1)
|
||||
return false;
|
||||
Encryption::DecryptBytes(embeddedSource.Get(), embeddedSource.Length());
|
||||
embeddedSource.Get()[embeddedSource.Length() - 1] = 0;
|
||||
return Platform::MemoryCompare(embeddedSource.Get(), source.Get(), source.Length()) == 0;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
Array<FileSystemWatcher*> ShadersSourcesWatchers;
|
||||
@@ -515,6 +548,13 @@ namespace
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ImportShaderIfChanged(const StringView& sourcePath, const StringView& assetPath, Guid& assetId)
|
||||
{
|
||||
if (ShadersCompilation::IsShaderSourceAssetUpToDate(sourcePath, assetPath))
|
||||
return false;
|
||||
return AssetsImportingManager::Import(sourcePath, assetPath, assetId);
|
||||
}
|
||||
|
||||
void OnWatcherShadersEvent(const String& path, FileSystemAction action)
|
||||
{
|
||||
if (action == FileSystemAction::Delete || !path.EndsWith(TEXT(".shader")))
|
||||
@@ -538,7 +578,7 @@ namespace
|
||||
const String name = StringUtils::GetPathWithoutExtension(localPath);
|
||||
const String outputPath = shadersAssetsPath / name + ASSET_FILES_EXTENSION_WITH_DOT;
|
||||
Guid id = GetShaderAssetId(name);
|
||||
AssetsImportingManager::ImportIfEdited(path, outputPath, id);
|
||||
ImportShaderIfChanged(path, outputPath, id);
|
||||
}
|
||||
|
||||
void RegisterShaderWatchers(const ProjectInfo* project, HashSet<const ProjectInfo*>& projects)
|
||||
@@ -567,7 +607,7 @@ namespace
|
||||
const String name = StringUtils::GetPathWithoutExtension(localPath);
|
||||
const String outputPath = shadersAssetsPath / name + ASSET_FILES_EXTENSION_WITH_DOT;
|
||||
Guid id = GetShaderAssetId(name);
|
||||
AssetsImportingManager::ImportIfEdited(path, outputPath, id);
|
||||
ImportShaderIfChanged(path, outputPath, id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,16 @@ public:
|
||||
// Compacts the full shader file path into portable format with project name prefix such as './<ProjectName>/ShaderFile.hlsl'.
|
||||
static String CompactShaderPath(StringView path);
|
||||
|
||||
#if USE_EDITOR
|
||||
/// <summary>
|
||||
/// Checks whether a shader asset embeds the current source file contents.
|
||||
/// </summary>
|
||||
/// <param name="sourcePath">The shader source file path.</param>
|
||||
/// <param name="assetPath">The shader asset file path.</param>
|
||||
/// <returns>True when the embedded source matches, otherwise false.</returns>
|
||||
static bool IsShaderSourceAssetUpToDate(const StringView& sourcePath, const StringView& assetPath);
|
||||
#endif
|
||||
|
||||
private:
|
||||
static ShaderCompiler* RequestCompiler(ShaderProfile profile, PlatformType platform);
|
||||
static void FreeCompiler(ShaderCompiler* compiler);
|
||||
|
||||
@@ -26,6 +26,29 @@ namespace FlaxEngine.Tests
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class RemovingControl : MyControl
|
||||
{
|
||||
private readonly Control[] _controlsToRemove;
|
||||
|
||||
public RemovingControl(float x, float y, float width, float height, params Control[] controlsToRemove)
|
||||
: base(x, y, width, height)
|
||||
{
|
||||
_controlsToRemove = controlsToRemove;
|
||||
}
|
||||
|
||||
public override void OnMouseEnter(Float2 location)
|
||||
{
|
||||
for (int i = 0; i < _controlsToRemove.Length; i++)
|
||||
{
|
||||
var control = _controlsToRemove[i];
|
||||
if (control.Parent == Parent)
|
||||
control.Parent = null;
|
||||
}
|
||||
|
||||
base.OnMouseEnter(location);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChildren()
|
||||
{
|
||||
@@ -53,6 +76,25 @@ namespace FlaxEngine.Tests
|
||||
Assert.AreEqual(cc1.GetChildAt(new Vector2(15, 5)), cc2);
|
||||
Assert.AreEqual(cc1.GetChildAtRecursive(new Vector2(35, 25)), c3);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMouseMoveAllowsChildrenRemoval()
|
||||
{
|
||||
var container = new MyContainerControl(0, 0, 100, 100);
|
||||
var first = new MyControl(0, 0, 100, 100);
|
||||
var second = new MyControl(0, 0, 100, 100);
|
||||
var removing = new RemovingControl(0, 0, 100, 100, first, second);
|
||||
container.AddChild(first);
|
||||
container.AddChild(second);
|
||||
container.AddChild(removing);
|
||||
|
||||
// The top-most child removes multiple siblings during input dispatch.
|
||||
// Traversal must not use the now-stale next index.
|
||||
container.OnMouseMove(new Float2(50, 50));
|
||||
|
||||
Assert.AreEqual(1, container.ChildrenCount);
|
||||
Assert.AreEqual(removing, container.GetChild(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "Engine/Core/ScopeExit.h"
|
||||
#include "Engine/Core/Types/DataContainer.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/ShadersCompilation/ShadersCompilation.h"
|
||||
#include <ThirdParty/catch2/catch.hpp>
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER && USE_EDITOR
|
||||
|
||||
TEST_CASE("Shader source asset synchronization ignores timestamps")
|
||||
{
|
||||
const String sourcePath = Globals::StartupFolder / TEXT("Source/Shaders/VolumetricFog.shader");
|
||||
const String assetPath = Globals::EngineContentFolder / TEXT("Shaders/VolumetricFog.flax");
|
||||
REQUIRE(FileSystem::FileExists(sourcePath));
|
||||
REQUIRE(FileSystem::FileExists(assetPath));
|
||||
CHECK(ShadersCompilation::IsShaderSourceAssetUpToDate(sourcePath, assetPath));
|
||||
|
||||
const String tempRoot = Globals::TemporaryFolder / (TEXT("ShaderSourceSync-") + Guid::New().ToString(Guid::FormatType::N));
|
||||
REQUIRE(!FileSystem::CreateDirectory(tempRoot));
|
||||
SCOPE_EXIT
|
||||
{
|
||||
FileSystem::DeleteDirectory(tempRoot, true);
|
||||
};
|
||||
|
||||
DataContainer<byte> assetData;
|
||||
StringAnsi modifiedSource;
|
||||
REQUIRE(!File::ReadAllBytes(assetPath, assetData));
|
||||
REQUIRE(!File::ReadAllText(sourcePath, modifiedSource));
|
||||
modifiedSource.Append("// Deliberately different source\n");
|
||||
|
||||
const String tempSourcePath = tempRoot / TEXT("VolumetricFog.shader");
|
||||
const String tempAssetPath = tempRoot / TEXT("VolumetricFog.flax");
|
||||
REQUIRE(!File::WriteAllBytes(tempSourcePath, modifiedSource.Get(), modifiedSource.Length()));
|
||||
REQUIRE(!File::WriteAllBytes(tempAssetPath, assetData.Get(), assetData.Length()));
|
||||
CHECK_FALSE(FileSystem::GetFileLastEditTime(tempSourcePath) > FileSystem::GetFileLastEditTime(tempAssetPath));
|
||||
CHECK_FALSE(ShadersCompilation::IsShaderSourceAssetUpToDate(tempSourcePath, tempAssetPath));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -21,6 +21,7 @@ public class Tests : EngineModule
|
||||
base.Setup(options);
|
||||
|
||||
options.PrivateDependencies.Add("ModelTool");
|
||||
options.PrivateDependencies.Add("ShadersCompilation");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -20,26 +20,29 @@
|
||||
#include <ThirdParty/assimp/scene.h>
|
||||
#include <ThirdParty/assimp/version.h>
|
||||
#include <ThirdParty/assimp/postprocess.h>
|
||||
#include <ThirdParty/assimp/LogStream.hpp>
|
||||
#include <ThirdParty/assimp/DefaultLogger.hpp>
|
||||
#include <ThirdParty/assimp/Logger.hpp>
|
||||
|
||||
class AssimpLogStream : public Assimp::LogStream
|
||||
class AssimpLogger final : public Assimp::Logger
|
||||
{
|
||||
public:
|
||||
AssimpLogStream()
|
||||
AssimpLogger()
|
||||
: Logger(NORMAL)
|
||||
{
|
||||
Assimp::DefaultLogger::create("");
|
||||
Assimp::DefaultLogger::get()->attachStream(this);
|
||||
}
|
||||
|
||||
~AssimpLogStream()
|
||||
bool attachStream(Assimp::LogStream*, unsigned int) override
|
||||
{
|
||||
Assimp::DefaultLogger::get()->detachStream(this);
|
||||
Assimp::DefaultLogger::kill();
|
||||
return false;
|
||||
}
|
||||
|
||||
void write(const char* message) override
|
||||
bool detachStream(Assimp::LogStream*, unsigned int) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
static void Write(const Char* type, const char* message)
|
||||
{
|
||||
String s(message);
|
||||
if (s.Length() <= 0)
|
||||
@@ -52,10 +55,49 @@ public:
|
||||
else if (c >= 255)
|
||||
c = '?';
|
||||
}
|
||||
LOG(Info, "[Assimp]: {0}", s);
|
||||
LOG(Info, "[Assimp]: {0}: {1}", type, s);
|
||||
}
|
||||
|
||||
void OnDebug(const char* message) override
|
||||
{
|
||||
if (m_Severity >= DEBUGGING)
|
||||
Write(TEXT("Debug"), message);
|
||||
}
|
||||
|
||||
void OnVerboseDebug(const char* message) override
|
||||
{
|
||||
if (m_Severity >= VERBOSE)
|
||||
Write(TEXT("Debug"), message);
|
||||
}
|
||||
|
||||
void OnInfo(const char* message) override
|
||||
{
|
||||
Write(TEXT("Info"), message);
|
||||
}
|
||||
|
||||
void OnWarn(const char* message) override
|
||||
{
|
||||
Write(TEXT("Warn"), message);
|
||||
}
|
||||
|
||||
void OnError(const char* message) override
|
||||
{
|
||||
Write(TEXT("Error"), message);
|
||||
}
|
||||
};
|
||||
|
||||
Assimp::Logger* GetAssimpLogger()
|
||||
{
|
||||
static Assimp::Logger* logger = []()
|
||||
{
|
||||
auto result = new AssimpLogger();
|
||||
Assimp::DefaultLogger::set(result);
|
||||
LOG(Info, "Assimp {0}.{1}.{2}", aiGetVersionMajor(), aiGetVersionMinor(), aiGetVersionRevision());
|
||||
return result;
|
||||
}();
|
||||
return logger;
|
||||
}
|
||||
|
||||
Float2 ToFloat2(const aiVector2D& v)
|
||||
{
|
||||
return Float2(v.x, v.y);
|
||||
@@ -148,7 +190,6 @@ struct AssimpBone
|
||||
struct AssimpImporterData
|
||||
{
|
||||
Assimp::Importer AssimpImporter;
|
||||
AssimpLogStream AssimpLogStream;
|
||||
const String Path;
|
||||
const aiScene* Scene = nullptr;
|
||||
const ModelTool::Options& Options;
|
||||
@@ -705,12 +746,7 @@ void ImportAnimation(int32 index, ModelData& data, AssimpImporterData& importerD
|
||||
|
||||
bool ModelTool::ImportDataAssimp(const String& path, ModelData& data, Options& options, String& errorMsg)
|
||||
{
|
||||
static bool AssimpInited = false;
|
||||
if (!AssimpInited)
|
||||
{
|
||||
AssimpInited = true;
|
||||
LOG(Info, "Assimp {0}.{1}.{2}", aiGetVersionMajor(), aiGetVersionMinor(), aiGetVersionRevision());
|
||||
}
|
||||
GetAssimpLogger();
|
||||
bool importMeshes = EnumHasAnyFlags(options.ImportTypes, ImportDataTypes::Geometry);
|
||||
bool importAnimations = EnumHasAnyFlags(options.ImportTypes, ImportDataTypes::Animations);
|
||||
AssimpImporterData context(path, options);
|
||||
|
||||
@@ -910,7 +910,7 @@ namespace FlaxEngine.GUI
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible)
|
||||
@@ -928,7 +928,7 @@ namespace FlaxEngine.GUI
|
||||
public override void OnMouseEnter(Float2 location)
|
||||
{
|
||||
// Check all children collisions with mouse and fire events for them
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled)
|
||||
@@ -948,7 +948,7 @@ namespace FlaxEngine.GUI
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
// Check all children collisions with mouse and fire events for them
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled)
|
||||
@@ -998,7 +998,7 @@ namespace FlaxEngine.GUI
|
||||
public override bool OnMouseWheel(Float2 location, float delta)
|
||||
{
|
||||
// Check all children collisions with mouse and fire events for them
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled)
|
||||
@@ -1019,7 +1019,7 @@ namespace FlaxEngine.GUI
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
// Check all children collisions with mouse and fire events for them
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled)
|
||||
@@ -1040,7 +1040,7 @@ namespace FlaxEngine.GUI
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
// Check all children collisions with mouse and fire events for them
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled)
|
||||
@@ -1061,7 +1061,7 @@ namespace FlaxEngine.GUI
|
||||
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
|
||||
{
|
||||
// Check all children collisions with mouse and fire events for them
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled)
|
||||
@@ -1096,7 +1096,7 @@ namespace FlaxEngine.GUI
|
||||
/// <inheritdoc />
|
||||
public override void OnTouchEnter(Float2 location, int pointerId)
|
||||
{
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled && !child.IsTouchPointerOver(pointerId))
|
||||
@@ -1114,7 +1114,7 @@ namespace FlaxEngine.GUI
|
||||
/// <inheritdoc />
|
||||
public override bool OnTouchDown(Float2 location, int pointerId)
|
||||
{
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled)
|
||||
@@ -1139,7 +1139,7 @@ namespace FlaxEngine.GUI
|
||||
/// <inheritdoc />
|
||||
public override void OnTouchMove(Float2 location, int pointerId)
|
||||
{
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled)
|
||||
@@ -1168,7 +1168,7 @@ namespace FlaxEngine.GUI
|
||||
/// <inheritdoc />
|
||||
public override bool OnTouchUp(Float2 location, int pointerId)
|
||||
{
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled && child.IsTouchPointerOver(pointerId))
|
||||
@@ -1250,7 +1250,7 @@ namespace FlaxEngine.GUI
|
||||
var result = base.OnDragEnter(ref location, data);
|
||||
|
||||
// Check all children collisions with mouse and fire events for them
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled)
|
||||
@@ -1275,7 +1275,7 @@ namespace FlaxEngine.GUI
|
||||
var result = base.OnDragMove(ref location, data);
|
||||
|
||||
// Check all children collisions with mouse and fire events for them
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled)
|
||||
@@ -1333,7 +1333,7 @@ namespace FlaxEngine.GUI
|
||||
var result = base.OnDragDrop(ref location, data);
|
||||
|
||||
// Check all children collisions with mouse and fire events for them
|
||||
for (int i = _children.Count - 1; i >= 0 && _children.Count > 0; i--)
|
||||
for (int i = _children.Count - 1; i >= 0 && i < _children.Count; i--)
|
||||
{
|
||||
var child = _children[i];
|
||||
if (child.Visible && child.Enabled)
|
||||
|
||||
@@ -42,6 +42,7 @@ META_VS_IN_ELEMENT(POSITION, 0, R32G32B32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true)
|
||||
VertexOutput VS_Grid(ModelInput input)
|
||||
{
|
||||
VertexOutput output;
|
||||
input.Position.xyz += float3(ViewPos.x, 0, ViewPos.z);
|
||||
output.WorldPosition = input.Position.xyz + ViewOrigin;
|
||||
float3 geoPosition = input.Position.xyz - float3(0, ViewOrigin.y, 0);
|
||||
output.Position = mul(float4(geoPosition, 1), ViewProjectionMatrix);
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace Flax.Build
|
||||
/// <summary>
|
||||
/// The maximum SDK version.
|
||||
/// </summary>
|
||||
public static Version MaximumVersion => new Version(10, 0);
|
||||
public static Version MaximumVersion => new Version(8, 0);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override TargetPlatform[] Platforms
|
||||
|
||||
@@ -110,6 +110,11 @@ namespace Flax.Build.NativeCpp
|
||||
return libFolder;
|
||||
|
||||
// Try to find nearest framework folder
|
||||
if (Framework.StartsWith("netcoreapp"))
|
||||
{
|
||||
var version = System.Version.Parse(Framework.Substring(10));
|
||||
return string.Empty;
|
||||
}
|
||||
if (Framework.StartsWith("net"))
|
||||
{
|
||||
var baseVersion = int.Parse(Framework.Substring(3, Framework.IndexOf('.') - 3));
|
||||
@@ -144,7 +149,10 @@ namespace Flax.Build.NativeCpp
|
||||
var dlls = Directory.Exists(libFolder) ? Directory.GetFiles(libFolder, "*.dll", SearchOption.TopDirectoryOnly) : [];
|
||||
if (dlls.Length == 0)
|
||||
{
|
||||
Log.Error($"Missing NuGet package \"{Name}, {Version}, {Framework}\" binaries (folder: {libFolder})");
|
||||
if (!File.Exists(Path.Combine(libFolder, "_._"))) // Skip error for packages without a binary (eg. Microsoft.NET.Test.Sdk)
|
||||
{
|
||||
Log.Error($"Missing NuGet package \"{Name}, {Version}, {Framework}\" binaries (folder: {libFolder})");
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
return dlls[0];
|
||||
|
||||
@@ -330,9 +330,7 @@ namespace Flax.Build.Projects.VisualStudio
|
||||
foreach (var analyzer in configuration.TargetBuildOptions.ScriptingAPI.Analyzers)
|
||||
{
|
||||
csProjectFileContent.AppendLine(string.Format(" <ItemGroup Condition=\" '$(Configuration)|$(Platform)' == '{0}' \">", configuration.Name));
|
||||
csProjectFileContent.AppendLine(string.Format(" <Analyzer Include=\"{0}\">", Path.GetFileNameWithoutExtension(analyzer)));
|
||||
csProjectFileContent.AppendLine(string.Format(" <HintPath>{0}</HintPath>", Utilities.MakePathRelativeTo(analyzer, projectDirectory).Replace('/', '\\')));
|
||||
csProjectFileContent.AppendLine(" </Analyzer>");
|
||||
csProjectFileContent.AppendLine(string.Format(" <Analyzer Include=\"{0}\" />", Utilities.MakePathRelativeTo(analyzer, projectDirectory).Replace('/', '\\')));
|
||||
csProjectFileContent.AppendLine(" </ItemGroup>");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user