Merge remote-tracking branch 'origin/master' into 1.7
This commit is contained in:
@@ -25,9 +25,20 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
// All selected particle effects use the same system
|
// All selected particle effects use the same system
|
||||||
var effect = (ParticleEffect)Values[0];
|
var effect = Values[0] as ParticleEffect;
|
||||||
var system = effect.ParticleSystem;
|
var system = effect ? effect.ParticleSystem : null;
|
||||||
return system != null && Values.TrueForAll(x => (x as ParticleEffect)?.ParticleSystem == system);
|
if (system && Values.TrueForAll(x => x is ParticleEffect fx && fx && fx.ParticleSystem == system))
|
||||||
|
{
|
||||||
|
// All parameters can be accessed
|
||||||
|
var parameters = effect.Parameters;
|
||||||
|
foreach (var parameter in parameters)
|
||||||
|
{
|
||||||
|
if (!parameter)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using FlaxEditor.CustomEditors.GUI;
|
||||||
|
using FlaxEditor.GUI;
|
||||||
|
using FlaxEditor.GUI.ContextMenu;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
|
||||||
|
|
||||||
namespace FlaxEditor.CustomEditors.Editors
|
namespace FlaxEditor.CustomEditors.Editors
|
||||||
{
|
{
|
||||||
@@ -12,7 +14,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
[CustomEditor(typeof(InputEvent)), DefaultEditor]
|
[CustomEditor(typeof(InputEvent)), DefaultEditor]
|
||||||
public class InputEventEditor : CustomEditor
|
public class InputEventEditor : CustomEditor
|
||||||
{
|
{
|
||||||
private Dropdown _dropdown;
|
private ComboBox _comboBox;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||||
@@ -20,23 +22,30 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Initialize(LayoutElementsContainer layout)
|
public override void Initialize(LayoutElementsContainer layout)
|
||||||
{
|
{
|
||||||
var dropdownElement = layout.Custom<Dropdown>();
|
LinkedLabel.SetupContextMenu += OnSetupContextMenu;
|
||||||
_dropdown = dropdownElement.CustomControl;
|
var comboBoxElement = layout.ComboBox();
|
||||||
var names = new List<LocalizedString>();
|
_comboBox = comboBoxElement.ComboBox;
|
||||||
|
var names = new List<string>();
|
||||||
foreach (var mapping in Input.ActionMappings)
|
foreach (var mapping in Input.ActionMappings)
|
||||||
{
|
{
|
||||||
if (!names.Contains(mapping.Name))
|
if (!names.Contains(mapping.Name))
|
||||||
names.Add(mapping.Name);
|
names.Add(mapping.Name);
|
||||||
}
|
}
|
||||||
_dropdown.Items = names;
|
_comboBox.Items = names;
|
||||||
if (Values[0] is InputEvent inputEvent && names.Contains(inputEvent.Name))
|
if (Values[0] is InputEvent inputEvent && names.Contains(inputEvent.Name))
|
||||||
_dropdown.SelectedItem = inputEvent.Name;
|
_comboBox.SelectedItem = inputEvent.Name;
|
||||||
_dropdown.SelectedIndexChanged += OnSelectedIndexChanged;
|
_comboBox.SelectedIndexChanged += OnSelectedIndexChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSelectedIndexChanged(Dropdown dropdown)
|
private void OnSetupContextMenu(PropertyNameLabel label, ContextMenu menu, CustomEditor linkededitor)
|
||||||
{
|
{
|
||||||
SetValue(new InputEvent(dropdown.SelectedItem));
|
var button = menu.AddButton("Set to null");
|
||||||
|
button.Clicked += () => _comboBox.SelectedItem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSelectedIndexChanged(ComboBox comboBox)
|
||||||
|
{
|
||||||
|
SetValue(comboBox.SelectedItem == null ? null : new InputEvent(comboBox.SelectedItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -49,17 +58,21 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Values[0] is InputEvent inputEvent && _dropdown.Items.Contains(inputEvent.Name))
|
if (Values[0] is InputEvent inputEvent && _comboBox.Items.Contains(inputEvent.Name))
|
||||||
_dropdown.SelectedItem = inputEvent.Name;
|
_comboBox.SelectedItem = inputEvent.Name;
|
||||||
|
else
|
||||||
|
_comboBox.SelectedItem = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Deinitialize()
|
protected override void Deinitialize()
|
||||||
{
|
{
|
||||||
if (_dropdown != null)
|
if (LinkedLabel != null)
|
||||||
_dropdown.SelectedIndexChanged -= OnSelectedIndexChanged;
|
LinkedLabel.SetupContextMenu -= OnSetupContextMenu;
|
||||||
_dropdown = null;
|
if (_comboBox != null)
|
||||||
|
_comboBox.SelectedIndexChanged -= OnSelectedIndexChanged;
|
||||||
|
_comboBox = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +82,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
[CustomEditor(typeof(InputAxis)), DefaultEditor]
|
[CustomEditor(typeof(InputAxis)), DefaultEditor]
|
||||||
public class InputAxisEditor : CustomEditor
|
public class InputAxisEditor : CustomEditor
|
||||||
{
|
{
|
||||||
private Dropdown _dropdown;
|
private ComboBox _comboBox;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||||
@@ -77,23 +90,30 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Initialize(LayoutElementsContainer layout)
|
public override void Initialize(LayoutElementsContainer layout)
|
||||||
{
|
{
|
||||||
var dropdownElement = layout.Custom<Dropdown>();
|
LinkedLabel.SetupContextMenu += OnSetupContextMenu;
|
||||||
_dropdown = dropdownElement.CustomControl;
|
var comboBoxElement = layout.ComboBox();
|
||||||
var names = new List<LocalizedString>();
|
_comboBox = comboBoxElement.ComboBox;
|
||||||
|
var names = new List<string>();
|
||||||
foreach (var mapping in Input.AxisMappings)
|
foreach (var mapping in Input.AxisMappings)
|
||||||
{
|
{
|
||||||
if (!names.Contains(mapping.Name))
|
if (!names.Contains(mapping.Name))
|
||||||
names.Add(mapping.Name);
|
names.Add(mapping.Name);
|
||||||
}
|
}
|
||||||
_dropdown.Items = names;
|
_comboBox.Items = names;
|
||||||
if (Values[0] is InputAxis inputAxis && names.Contains(inputAxis.Name))
|
if (Values[0] is InputAxis inputAxis && names.Contains(inputAxis.Name))
|
||||||
_dropdown.SelectedItem = inputAxis.Name;
|
_comboBox.SelectedItem = inputAxis.Name;
|
||||||
_dropdown.SelectedIndexChanged += OnSelectedIndexChanged;
|
_comboBox.SelectedIndexChanged += OnSelectedIndexChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSelectedIndexChanged(Dropdown dropdown)
|
private void OnSetupContextMenu(PropertyNameLabel label, ContextMenu menu, CustomEditor linkededitor)
|
||||||
{
|
{
|
||||||
SetValue(new InputAxis(dropdown.SelectedItem));
|
var button = menu.AddButton("Set to null");
|
||||||
|
button.Clicked += () => _comboBox.SelectedItem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSelectedIndexChanged(ComboBox comboBox)
|
||||||
|
{
|
||||||
|
SetValue(comboBox.SelectedItem == null ? null : new InputAxis(comboBox.SelectedItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -106,17 +126,21 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Values[0] is InputAxis inputAxis && _dropdown.Items.Contains(inputAxis.Name))
|
if (Values[0] is InputAxis inputAxis && _comboBox.Items.Contains(inputAxis.Name))
|
||||||
_dropdown.SelectedItem = inputAxis.Name;
|
_comboBox.SelectedItem = inputAxis.Name;
|
||||||
|
else
|
||||||
|
_comboBox.SelectedItem = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Deinitialize()
|
protected override void Deinitialize()
|
||||||
{
|
{
|
||||||
if (_dropdown != null)
|
if (LinkedLabel != null)
|
||||||
_dropdown.SelectedIndexChanged -= OnSelectedIndexChanged;
|
LinkedLabel.SetupContextMenu -= OnSetupContextMenu;
|
||||||
_dropdown = null;
|
if (_comboBox != null)
|
||||||
|
_comboBox.SelectedIndexChanged -= OnSelectedIndexChanged;
|
||||||
|
_comboBox = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -674,9 +674,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Values[0] is Tag[])
|
if (Values[0] is Tag[] || Values.Type.Type == typeof(Tag[]))
|
||||||
SetValue(value);
|
SetValue(value);
|
||||||
if (Values[0] is List<Tag>)
|
else if (Values[0] is List<Tag> || Values.Type.Type == typeof(List<Tag>))
|
||||||
SetValue(new List<Tag>(value));
|
SetValue(new List<Tag>(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -290,7 +290,11 @@ namespace FlaxEditor.GUI.Dialogs
|
|||||||
OnCancel();
|
OnCancel();
|
||||||
return true;
|
return true;
|
||||||
case KeyboardKeys.Tab:
|
case KeyboardKeys.Tab:
|
||||||
Root?.Navigate(NavDirection.Next);
|
if (Root != null)
|
||||||
|
{
|
||||||
|
bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
|
||||||
|
Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -221,6 +221,23 @@ namespace FlaxEditor.Surface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_middleMouseDown)
|
||||||
|
{
|
||||||
|
// Calculate delta
|
||||||
|
var delta = location - _middleMouseDownPos;
|
||||||
|
if (delta.LengthSquared > 0.01f)
|
||||||
|
{
|
||||||
|
// Move view
|
||||||
|
_mouseMoveAmount += delta.Length;
|
||||||
|
_rootControl.Location += delta;
|
||||||
|
_middleMouseDownPos = location;
|
||||||
|
Cursor = CursorType.SizeAll;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handled
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if user is selecting or moving node(s)
|
// Check if user is selecting or moving node(s)
|
||||||
if (_leftMouseDown)
|
if (_leftMouseDown)
|
||||||
{
|
{
|
||||||
@@ -280,6 +297,11 @@ namespace FlaxEditor.Surface
|
|||||||
_rightMouseDown = false;
|
_rightMouseDown = false;
|
||||||
Cursor = CursorType.Default;
|
Cursor = CursorType.Default;
|
||||||
}
|
}
|
||||||
|
if (_middleMouseDown)
|
||||||
|
{
|
||||||
|
_middleMouseDown = false;
|
||||||
|
Cursor = CursorType.Default;
|
||||||
|
}
|
||||||
_isMovingSelection = false;
|
_isMovingSelection = false;
|
||||||
ConnectingEnd(null);
|
ConnectingEnd(null);
|
||||||
|
|
||||||
@@ -391,6 +413,7 @@ namespace FlaxEditor.Surface
|
|||||||
_isMovingSelection = false;
|
_isMovingSelection = false;
|
||||||
_rightMouseDown = false;
|
_rightMouseDown = false;
|
||||||
_leftMouseDown = false;
|
_leftMouseDown = false;
|
||||||
|
_middleMouseDown = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,6 +433,11 @@ namespace FlaxEditor.Surface
|
|||||||
_rightMouseDown = true;
|
_rightMouseDown = true;
|
||||||
_rightMouseDownPos = location;
|
_rightMouseDownPos = location;
|
||||||
}
|
}
|
||||||
|
if (button == MouseButton.Middle)
|
||||||
|
{
|
||||||
|
_middleMouseDown = true;
|
||||||
|
_middleMouseDownPos = location;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if any node is under the mouse
|
// Check if any node is under the mouse
|
||||||
SurfaceControl controlUnderMouse = GetControlUnderMouse();
|
SurfaceControl controlUnderMouse = GetControlUnderMouse();
|
||||||
@@ -455,7 +483,7 @@ namespace FlaxEditor.Surface
|
|||||||
Focus();
|
Focus();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (_rightMouseDown)
|
if (_rightMouseDown || _middleMouseDown)
|
||||||
{
|
{
|
||||||
// Start navigating
|
// Start navigating
|
||||||
StartMouseCapture();
|
StartMouseCapture();
|
||||||
@@ -524,6 +552,13 @@ namespace FlaxEditor.Surface
|
|||||||
}
|
}
|
||||||
_mouseMoveAmount = 0;
|
_mouseMoveAmount = 0;
|
||||||
}
|
}
|
||||||
|
if (_middleMouseDown && button == MouseButton.Middle)
|
||||||
|
{
|
||||||
|
_middleMouseDown = false;
|
||||||
|
EndMouseCapture();
|
||||||
|
Cursor = CursorType.Default;
|
||||||
|
_mouseMoveAmount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Base
|
// Base
|
||||||
bool handled = base.OnMouseUp(location, button);
|
bool handled = base.OnMouseUp(location, button);
|
||||||
@@ -534,6 +569,7 @@ namespace FlaxEditor.Surface
|
|||||||
// Clear flags
|
// Clear flags
|
||||||
_rightMouseDown = false;
|
_rightMouseDown = false;
|
||||||
_leftMouseDown = false;
|
_leftMouseDown = false;
|
||||||
|
_middleMouseDown = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,11 @@ namespace FlaxEditor.Surface
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected bool _rightMouseDown;
|
protected bool _rightMouseDown;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The middle mouse down flag.
|
||||||
|
/// </summary>
|
||||||
|
protected bool _middleMouseDown;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The left mouse down position.
|
/// The left mouse down position.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -70,6 +75,11 @@ namespace FlaxEditor.Surface
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected Float2 _rightMouseDownPos = Float2.Minimum;
|
protected Float2 _rightMouseDownPos = Float2.Minimum;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The middle mouse down position.
|
||||||
|
/// </summary>
|
||||||
|
protected Float2 _middleMouseDownPos = Float2.Minimum;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The mouse position.
|
/// The mouse position.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace FlaxEditor.Windows
|
|||||||
private TextBox _itemsSearchBox;
|
private TextBox _itemsSearchBox;
|
||||||
private ViewDropdown _viewDropdown;
|
private ViewDropdown _viewDropdown;
|
||||||
private SortType _sortType;
|
private SortType _sortType;
|
||||||
private bool _showEngineFiles = true, _showPluginsFiles = true, _showAllFiles = true;
|
private bool _showEngineFiles = true, _showPluginsFiles = true, _showAllFiles = true, _showGeneratedFiles = false;
|
||||||
|
|
||||||
private RootContentTreeNode _root;
|
private RootContentTreeNode _root;
|
||||||
|
|
||||||
@@ -106,6 +106,19 @@ namespace FlaxEditor.Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool ShowGeneratedFiles
|
||||||
|
{
|
||||||
|
get => _showGeneratedFiles;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_showGeneratedFiles != value)
|
||||||
|
{
|
||||||
|
_showGeneratedFiles = value;
|
||||||
|
RefreshView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal bool ShowAllFiles
|
internal bool ShowAllFiles
|
||||||
{
|
{
|
||||||
get => _showAllFiles;
|
get => _showAllFiles;
|
||||||
@@ -314,6 +327,12 @@ namespace FlaxEditor.Windows
|
|||||||
b.Checked = ShowPluginsFiles;
|
b.Checked = ShowPluginsFiles;
|
||||||
b.CloseMenuOnClick = false;
|
b.CloseMenuOnClick = false;
|
||||||
b.AutoCheck = true;
|
b.AutoCheck = true;
|
||||||
|
|
||||||
|
b = show.ContextMenu.AddButton("Generated files", () => ShowGeneratedFiles = !ShowGeneratedFiles);
|
||||||
|
b.TooltipText = "Shows generated files";
|
||||||
|
b.Checked = ShowGeneratedFiles;
|
||||||
|
b.CloseMenuOnClick = false;
|
||||||
|
b.AutoCheck = true;
|
||||||
|
|
||||||
b = show.ContextMenu.AddButton("All files", () => ShowAllFiles = !ShowAllFiles);
|
b = show.ContextMenu.AddButton("All files", () => ShowAllFiles = !ShowAllFiles);
|
||||||
b.TooltipText = "Shows all files including other than assets and source code";
|
b.TooltipText = "Shows all files including other than assets and source code";
|
||||||
@@ -973,6 +992,8 @@ namespace FlaxEditor.Windows
|
|||||||
var items = target.Folder.Children;
|
var items = target.Folder.Children;
|
||||||
if (!_showAllFiles)
|
if (!_showAllFiles)
|
||||||
items = items.Where(x => !(x is FileItem)).ToList();
|
items = items.Where(x => !(x is FileItem)).ToList();
|
||||||
|
if (!_showGeneratedFiles)
|
||||||
|
items = items.Where(x => !(x.Path.EndsWith(".Gen.cs", StringComparison.Ordinal) || x.Path.EndsWith(".Gen.h", StringComparison.Ordinal) || x.Path.EndsWith(".Gen.cpp", StringComparison.Ordinal) || x.Path.EndsWith(".csproj", StringComparison.Ordinal) || x.Path.Contains(".CSharp"))).ToList();
|
||||||
_view.ShowItems(items, _sortType, false, true);
|
_view.ShowItems(items, _sortType, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1149,6 +1170,7 @@ namespace FlaxEditor.Windows
|
|||||||
writer.WriteAttributeString("ShowEngineFiles", ShowEngineFiles.ToString());
|
writer.WriteAttributeString("ShowEngineFiles", ShowEngineFiles.ToString());
|
||||||
writer.WriteAttributeString("ShowPluginsFiles", ShowPluginsFiles.ToString());
|
writer.WriteAttributeString("ShowPluginsFiles", ShowPluginsFiles.ToString());
|
||||||
writer.WriteAttributeString("ShowAllFiles", ShowAllFiles.ToString());
|
writer.WriteAttributeString("ShowAllFiles", ShowAllFiles.ToString());
|
||||||
|
writer.WriteAttributeString("ShowGeneratedFiles", ShowGeneratedFiles.ToString());
|
||||||
writer.WriteAttributeString("ViewType", _view.ViewType.ToString());
|
writer.WriteAttributeString("ViewType", _view.ViewType.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1166,6 +1188,8 @@ namespace FlaxEditor.Windows
|
|||||||
ShowPluginsFiles = value2;
|
ShowPluginsFiles = value2;
|
||||||
if (bool.TryParse(node.GetAttribute("ShowAllFiles"), out value2))
|
if (bool.TryParse(node.GetAttribute("ShowAllFiles"), out value2))
|
||||||
ShowAllFiles = value2;
|
ShowAllFiles = value2;
|
||||||
|
if (bool.TryParse(node.GetAttribute("ShowGeneratedFiles"), out value2))
|
||||||
|
ShowGeneratedFiles = value2;
|
||||||
if (Enum.TryParse(node.GetAttribute("ViewType"), out ContentViewType viewType))
|
if (Enum.TryParse(node.GetAttribute("ViewType"), out ContentViewType viewType))
|
||||||
_view.ViewType = viewType;
|
_view.ViewType = viewType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,6 +192,13 @@ namespace FlaxEditor.Windows
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool OnKeyDown(KeyboardKeys key)
|
public override bool OnKeyDown(KeyboardKeys key)
|
||||||
{
|
{
|
||||||
|
// Prevent closing the editor window when using RMB + Ctrl + W to slow down the camera flight
|
||||||
|
if (Editor.Options.Options.Input.CloseTab.Process(this, key))
|
||||||
|
{
|
||||||
|
if (Root.GetMouseButton(MouseButton.Right))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (base.OnKeyDown(key))
|
if (base.OnKeyDown(key))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -207,7 +214,8 @@ namespace FlaxEditor.Windows
|
|||||||
case KeyboardKeys.Tab:
|
case KeyboardKeys.Tab:
|
||||||
if (CanUseNavigation && Root != null)
|
if (CanUseNavigation && Root != null)
|
||||||
{
|
{
|
||||||
Root.Navigate(NavDirection.Next);
|
bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
|
||||||
|
Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -429,21 +429,8 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
private void UpdateTable(ref ViewRange viewRange)
|
private void UpdateTable(ref ViewRange viewRange)
|
||||||
{
|
{
|
||||||
_table.IsLayoutLocked = true;
|
_table.IsLayoutLocked = true;
|
||||||
int idx = 0;
|
|
||||||
while (_table.Children.Count > idx)
|
|
||||||
{
|
|
||||||
var child = _table.Children[idx];
|
|
||||||
if (child is Row row)
|
|
||||||
{
|
|
||||||
_tableRowsCache.Add(row);
|
|
||||||
child.Parent = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
RecycleTableRows(_table, _tableRowsCache);
|
||||||
UpdateTableInner(ref viewRange);
|
UpdateTableInner(ref viewRange);
|
||||||
|
|
||||||
_table.UnlockChildrenRecursive();
|
_table.UnlockChildrenRecursive();
|
||||||
|
|||||||
@@ -298,21 +298,7 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
private void UpdateTable()
|
private void UpdateTable()
|
||||||
{
|
{
|
||||||
_table.IsLayoutLocked = true;
|
_table.IsLayoutLocked = true;
|
||||||
int idx = 0;
|
RecycleTableRows(_table, _tableRowsCache);
|
||||||
while (_table.Children.Count > idx)
|
|
||||||
{
|
|
||||||
var child = _table.Children[idx];
|
|
||||||
if (child is Row row)
|
|
||||||
{
|
|
||||||
_tableRowsCache.Add(row);
|
|
||||||
child.Parent = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_table.LockChildrenRecursive();
|
|
||||||
|
|
||||||
UpdateTableInner();
|
UpdateTableInner();
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,32 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using FlaxEditor.GUI;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
|
namespace FlaxEngine
|
||||||
|
{
|
||||||
|
partial class ProfilingTools
|
||||||
|
{
|
||||||
|
partial struct NetworkEventStat
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the event name.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe string Name
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
fixed (byte* name = Name0)
|
||||||
|
return System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new IntPtr(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace FlaxEditor.Windows.Profiler
|
namespace FlaxEditor.Windows.Profiler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -13,6 +37,10 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
{
|
{
|
||||||
private readonly SingleChart _dataSentChart;
|
private readonly SingleChart _dataSentChart;
|
||||||
private readonly SingleChart _dataReceivedChart;
|
private readonly SingleChart _dataReceivedChart;
|
||||||
|
private readonly Table _tableRpc;
|
||||||
|
private readonly Table _tableRep;
|
||||||
|
private SamplesBuffer<ProfilingTools.NetworkEventStat[]> _events;
|
||||||
|
private List<Row> _tableRowsCache;
|
||||||
private FlaxEngine.Networking.NetworkDriverStats _prevStats;
|
private FlaxEngine.Networking.NetworkDriverStats _prevStats;
|
||||||
|
|
||||||
public Network()
|
public Network()
|
||||||
@@ -48,11 +76,10 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
Parent = layout,
|
Parent = layout,
|
||||||
};
|
};
|
||||||
_dataReceivedChart.SelectedSampleChanged += OnSelectedSampleChanged;
|
_dataReceivedChart.SelectedSampleChanged += OnSelectedSampleChanged;
|
||||||
}
|
|
||||||
|
|
||||||
private static string FormatSampleBytes(float v)
|
// Tables
|
||||||
{
|
_tableRpc = InitTable(layout, "RPC Name");
|
||||||
return Utilities.Utils.FormatBytesCount((ulong)v);
|
_tableRep = InitTable(layout, "Replication Name");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -60,21 +87,30 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
{
|
{
|
||||||
_dataSentChart.Clear();
|
_dataSentChart.Clear();
|
||||||
_dataReceivedChart.Clear();
|
_dataReceivedChart.Clear();
|
||||||
|
_events?.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Update(ref SharedUpdateData sharedData)
|
public override void Update(ref SharedUpdateData sharedData)
|
||||||
{
|
{
|
||||||
var peer = FlaxEngine.Networking.NetworkManager.Peer;
|
// Gather peer stats
|
||||||
if (peer == null)
|
var peers = FlaxEngine.Networking.NetworkPeer.Peers;
|
||||||
|
var stats = new FlaxEngine.Networking.NetworkDriverStats();
|
||||||
|
foreach (var peer in peers)
|
||||||
{
|
{
|
||||||
_prevStats = new FlaxEngine.Networking.NetworkDriverStats();
|
var peerStats = peer.NetworkDriver.GetStats();
|
||||||
return;
|
stats.TotalDataSent += peerStats.TotalDataSent;
|
||||||
|
stats.TotalDataReceived += peerStats.TotalDataReceived;
|
||||||
}
|
}
|
||||||
var stats = peer.NetworkDriver.GetStats();
|
|
||||||
_dataSentChart.AddSample(Mathf.Max((long)stats.TotalDataSent - (long)_prevStats.TotalDataSent, 0));
|
_dataSentChart.AddSample(Mathf.Max((long)stats.TotalDataSent - (long)_prevStats.TotalDataSent, 0));
|
||||||
_dataReceivedChart.AddSample(Mathf.Max((long)stats.TotalDataReceived - (long)_prevStats.TotalDataReceived, 0));
|
_dataReceivedChart.AddSample(Mathf.Max((long)stats.TotalDataReceived - (long)_prevStats.TotalDataReceived, 0));
|
||||||
_prevStats = stats;
|
_prevStats = stats;
|
||||||
|
|
||||||
|
// Gather network events
|
||||||
|
var events = ProfilingTools.EventsNetwork;
|
||||||
|
if (_events == null)
|
||||||
|
_events = new SamplesBuffer<ProfilingTools.NetworkEventStat[]>();
|
||||||
|
_events.Add(events);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -82,6 +118,159 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
{
|
{
|
||||||
_dataSentChart.SelectedSampleIndex = selectedFrame;
|
_dataSentChart.SelectedSampleIndex = selectedFrame;
|
||||||
_dataReceivedChart.SelectedSampleIndex = selectedFrame;
|
_dataReceivedChart.SelectedSampleIndex = selectedFrame;
|
||||||
|
|
||||||
|
// Update events tables
|
||||||
|
if (_events != null)
|
||||||
|
{
|
||||||
|
if (_tableRowsCache == null)
|
||||||
|
_tableRowsCache = new List<Row>();
|
||||||
|
_tableRpc.IsLayoutLocked = true;
|
||||||
|
_tableRep.IsLayoutLocked = true;
|
||||||
|
RecycleTableRows(_tableRpc, _tableRowsCache);
|
||||||
|
RecycleTableRows(_tableRep, _tableRowsCache);
|
||||||
|
|
||||||
|
var events = _events.Get(selectedFrame);
|
||||||
|
var rowCount = Int2.Zero;
|
||||||
|
if (events != null && events.Length != 0)
|
||||||
|
{
|
||||||
|
var rowColor2 = Style.Current.Background * 1.4f;
|
||||||
|
for (int i = 0; i < events.Length; i++)
|
||||||
|
{
|
||||||
|
var e = events[i];
|
||||||
|
var name = e.Name;
|
||||||
|
var isRpc = name.Contains("::", StringComparison.Ordinal);
|
||||||
|
|
||||||
|
Row row;
|
||||||
|
if (_tableRowsCache.Count != 0)
|
||||||
|
{
|
||||||
|
var last = _tableRowsCache.Count - 1;
|
||||||
|
row = _tableRowsCache[last];
|
||||||
|
_tableRowsCache.RemoveAt(last);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row = new Row
|
||||||
|
{
|
||||||
|
Values = new object[5],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Name
|
||||||
|
row.Values[0] = name;
|
||||||
|
|
||||||
|
// Count
|
||||||
|
row.Values[1] = (int)e.Count;
|
||||||
|
|
||||||
|
// Data Size
|
||||||
|
row.Values[2] = (int)e.DataSize;
|
||||||
|
|
||||||
|
// Message Size
|
||||||
|
row.Values[3] = (int)e.MessageSize;
|
||||||
|
|
||||||
|
// Receivers
|
||||||
|
row.Values[4] = (float)e.Receivers / (float)e.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
var table = isRpc ? _tableRpc : _tableRep;
|
||||||
|
row.Width = table.Width;
|
||||||
|
row.BackgroundColor = rowCount[isRpc ? 0 : 1] % 2 == 0 ? rowColor2 : Color.Transparent;
|
||||||
|
row.Parent = table;
|
||||||
|
if (isRpc)
|
||||||
|
rowCount.X++;
|
||||||
|
else
|
||||||
|
rowCount.Y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_tableRpc.Visible = rowCount.X != 0;
|
||||||
|
_tableRep.Visible = rowCount.Y != 0;
|
||||||
|
_tableRpc.Children.Sort(SortRows);
|
||||||
|
_tableRep.Children.Sort(SortRows);
|
||||||
|
|
||||||
|
_tableRpc.UnlockChildrenRecursive();
|
||||||
|
_tableRpc.PerformLayout();
|
||||||
|
_tableRep.UnlockChildrenRecursive();
|
||||||
|
_tableRep.PerformLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnDestroy()
|
||||||
|
{
|
||||||
|
_tableRowsCache?.Clear();
|
||||||
|
|
||||||
|
base.OnDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Table InitTable(ContainerControl parent, string name)
|
||||||
|
{
|
||||||
|
var headerColor = Style.Current.LightBackground;
|
||||||
|
var table = new Table
|
||||||
|
{
|
||||||
|
Columns = new[]
|
||||||
|
{
|
||||||
|
new ColumnDefinition
|
||||||
|
{
|
||||||
|
UseExpandCollapseMode = true,
|
||||||
|
CellAlignment = TextAlignment.Near,
|
||||||
|
Title = name,
|
||||||
|
TitleBackgroundColor = headerColor,
|
||||||
|
},
|
||||||
|
new ColumnDefinition
|
||||||
|
{
|
||||||
|
Title = "Count",
|
||||||
|
TitleBackgroundColor = headerColor,
|
||||||
|
},
|
||||||
|
new ColumnDefinition
|
||||||
|
{
|
||||||
|
Title = "Data Size",
|
||||||
|
TitleBackgroundColor = headerColor,
|
||||||
|
FormatValue = FormatCellBytes,
|
||||||
|
},
|
||||||
|
new ColumnDefinition
|
||||||
|
{
|
||||||
|
Title = "Message Size",
|
||||||
|
TitleBackgroundColor = headerColor,
|
||||||
|
FormatValue = FormatCellBytes,
|
||||||
|
},
|
||||||
|
new ColumnDefinition
|
||||||
|
{
|
||||||
|
Title = "Receivers",
|
||||||
|
TitleBackgroundColor = headerColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Splits = new[]
|
||||||
|
{
|
||||||
|
0.40f,
|
||||||
|
0.15f,
|
||||||
|
0.15f,
|
||||||
|
0.15f,
|
||||||
|
0.15f,
|
||||||
|
},
|
||||||
|
Parent = parent,
|
||||||
|
};
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatSampleBytes(float v)
|
||||||
|
{
|
||||||
|
return Utilities.Utils.FormatBytesCount((ulong)v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatCellBytes(object x)
|
||||||
|
{
|
||||||
|
return Utilities.Utils.FormatBytesCount((int)x);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int SortRows(Control x, Control y)
|
||||||
|
{
|
||||||
|
if (x is Row xRow && y is Row yRow)
|
||||||
|
{
|
||||||
|
var xDataSize = (int)xRow.Values[2];
|
||||||
|
var yDataSize = (int)yRow.Values[2];
|
||||||
|
return yDataSize - xDataSize;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using FlaxEditor.GUI;
|
||||||
using FlaxEditor.GUI.Tabs;
|
using FlaxEditor.GUI.Tabs;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
|
||||||
@@ -135,5 +137,28 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
{
|
{
|
||||||
SelectedSampleChanged?.Invoke(frameIndex);
|
SelectedSampleChanged?.Invoke(frameIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Recycles all table rows to be reused.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">The table.</param>
|
||||||
|
/// <param name="rowsCache">The output cache.</param>
|
||||||
|
protected static void RecycleTableRows(Table table, List<Row> rowsCache)
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
while (table.Children.Count > idx)
|
||||||
|
{
|
||||||
|
var child = table.Children[idx];
|
||||||
|
if (child is Row row)
|
||||||
|
{
|
||||||
|
rowsCache.Add(row);
|
||||||
|
child.Parent = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
_liveRecordingButton = toolstrip.AddButton(editor.Icons.Play64);
|
_liveRecordingButton = toolstrip.AddButton(editor.Icons.Play64);
|
||||||
_liveRecordingButton.LinkTooltip("Live profiling events recording");
|
_liveRecordingButton.LinkTooltip("Live profiling events recording");
|
||||||
_liveRecordingButton.AutoCheck = true;
|
_liveRecordingButton.AutoCheck = true;
|
||||||
_liveRecordingButton.Clicked += () => _liveRecordingButton.Icon = LiveRecording ? editor.Icons.Stop64 : editor.Icons.Play64;
|
_liveRecordingButton.Clicked += OnLiveRecordingChanged;
|
||||||
_clearButton = toolstrip.AddButton(editor.Icons.Rotate32, Clear);
|
_clearButton = toolstrip.AddButton(editor.Icons.Rotate32, Clear);
|
||||||
_clearButton.LinkTooltip("Clear data");
|
_clearButton.LinkTooltip("Clear data");
|
||||||
toolstrip.AddSeparator();
|
toolstrip.AddSeparator();
|
||||||
@@ -118,6 +118,12 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
_tabs.SelectedTabChanged += OnSelectedTabChanged;
|
_tabs.SelectedTabChanged += OnSelectedTabChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnLiveRecordingChanged()
|
||||||
|
{
|
||||||
|
_liveRecordingButton.Icon = LiveRecording ? Editor.Icons.Stop64 : Editor.Icons.Play64;
|
||||||
|
ProfilingTools.Enabled = LiveRecording;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the mode.
|
/// Adds the mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
/// <returns>The sample value</returns>
|
/// <returns>The sample value</returns>
|
||||||
public T Get(int index)
|
public T Get(int index)
|
||||||
{
|
{
|
||||||
|
if (index >= _data.Length || _data.Length == 0)
|
||||||
|
return default;
|
||||||
return index == -1 ? _data[_count - 1] : _data[index];
|
return index == -1 ? _data[_count - 1] : _data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,14 +32,21 @@ CreateAssetResult ImportShader::Import(CreateAssetContext& context)
|
|||||||
LOG(Warning, "Empty shader source file.");
|
LOG(Warning, "Empty shader source file.");
|
||||||
return CreateAssetResult::Error;
|
return CreateAssetResult::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure the source code has an empty line at the end (expected by glslang)
|
||||||
|
auto sourceCodeChunkSize = sourceCodeSize + 1;
|
||||||
|
if (sourceCodeText[sourceCodeSize - 1] != '\n')
|
||||||
|
sourceCodeChunkSize++;
|
||||||
|
|
||||||
const auto& sourceCodeChunk = context.Data.Header.Chunks[SourceCodeChunk];
|
const auto& sourceCodeChunk = context.Data.Header.Chunks[SourceCodeChunk];
|
||||||
sourceCodeChunk->Data.Allocate(sourceCodeSize + 1);
|
sourceCodeChunk->Data.Allocate(sourceCodeChunkSize);
|
||||||
const auto sourceCode = sourceCodeChunk->Get();
|
const auto sourceCode = sourceCodeChunk->Get();
|
||||||
Platform::MemoryCopy(sourceCode, sourceCodeText.Get(), sourceCodeSize);
|
Platform::MemoryCopy(sourceCode, sourceCodeText.Get(), sourceCodeSize);
|
||||||
|
sourceCode[sourceCodeChunkSize - 2] = '\n';
|
||||||
|
|
||||||
// Encrypt source code
|
// Encrypt source code
|
||||||
Encryption::EncryptBytes(sourceCode, sourceCodeSize);
|
Encryption::EncryptBytes(sourceCode, sourceCodeChunkSize - 1);
|
||||||
sourceCode[sourceCodeSize] = 0;
|
sourceCode[sourceCodeChunkSize - 1] = 0;
|
||||||
|
|
||||||
// Set Custom Data with Header
|
// Set Custom Data with Header
|
||||||
ShaderStorage::Header20 shaderHeader;
|
ShaderStorage::Header20 shaderHeader;
|
||||||
|
|||||||
@@ -102,9 +102,6 @@ int32 Engine::Main(const Char* cmdLine)
|
|||||||
|
|
||||||
Platform::SetHighDpiAwarenessEnabled(!CommandLine::Options.LowDPI.IsTrue());
|
Platform::SetHighDpiAwarenessEnabled(!CommandLine::Options.LowDPI.IsTrue());
|
||||||
Time::StartupTime = DateTime::Now();
|
Time::StartupTime = DateTime::Now();
|
||||||
#if COMPILE_WITH_PROFILER
|
|
||||||
ProfilerCPU::Enabled = true;
|
|
||||||
#endif
|
|
||||||
Globals::StartupFolder = Globals::BinariesFolder = Platform::GetMainDirectory();
|
Globals::StartupFolder = Globals::BinariesFolder = Platform::GetMainDirectory();
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
Globals::StartupFolder /= TEXT("../../../..");
|
Globals::StartupFolder /= TEXT("../../../..");
|
||||||
|
|||||||
@@ -851,39 +851,46 @@ namespace FlaxEngine.Interop
|
|||||||
*assemblyFullName = NativeAllocStringAnsi(flaxEngineAssembly.FullName);
|
*assemblyFullName = NativeAllocStringAnsi(flaxEngineAssembly.FullName);
|
||||||
return GetAssemblyHandle(flaxEngineAssembly);
|
return GetAssemblyHandle(flaxEngineAssembly);
|
||||||
}
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string assemblyPath = Marshal.PtrToStringUni(assemblyPathPtr);
|
||||||
|
|
||||||
string assemblyPath = Marshal.PtrToStringAnsi(assemblyPathPtr);
|
Assembly assembly;
|
||||||
|
|
||||||
Assembly assembly;
|
|
||||||
#if FLAX_EDITOR
|
#if FLAX_EDITOR
|
||||||
// Load assembly from loaded bytes to prevent file locking in Editor
|
// Load assembly from loaded bytes to prevent file locking in Editor
|
||||||
var assemblyBytes = File.ReadAllBytes(assemblyPath);
|
var assemblyBytes = File.ReadAllBytes(assemblyPath);
|
||||||
using MemoryStream stream = new MemoryStream(assemblyBytes);
|
using MemoryStream stream = new MemoryStream(assemblyBytes);
|
||||||
var pdbPath = Path.ChangeExtension(assemblyPath, "pdb");
|
var pdbPath = Path.ChangeExtension(assemblyPath, "pdb");
|
||||||
if (File.Exists(pdbPath))
|
if (File.Exists(pdbPath))
|
||||||
{
|
{
|
||||||
// Load including debug symbols
|
// 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);
|
||||||
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream, pdbStream);
|
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream, pdbStream);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream);
|
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// Load assembly from file
|
// Load assembly from file
|
||||||
assembly = scriptingAssemblyLoadContext.LoadFromAssemblyPath(assemblyPath);
|
assembly = scriptingAssemblyLoadContext.LoadFromAssemblyPath(assemblyPath);
|
||||||
#endif
|
#endif
|
||||||
if (assembly == null)
|
if (assembly == null)
|
||||||
return new ManagedHandle();
|
return new ManagedHandle();
|
||||||
NativeLibrary.SetDllImportResolver(assembly, NativeLibraryImportResolver);
|
NativeLibrary.SetDllImportResolver(assembly, NativeLibraryImportResolver);
|
||||||
|
|
||||||
// Assemblies loaded via streams have no Location: https://github.com/dotnet/runtime/issues/12822
|
// Assemblies loaded via streams have no Location: https://github.com/dotnet/runtime/issues/12822
|
||||||
AssemblyLocations.Add(assembly.FullName, assemblyPath);
|
AssemblyLocations.Add(assembly.FullName, assemblyPath);
|
||||||
|
|
||||||
*assemblyName = NativeAllocStringAnsi(assembly.GetName().Name);
|
*assemblyName = NativeAllocStringAnsi(assembly.GetName().Name);
|
||||||
*assemblyFullName = NativeAllocStringAnsi(assembly.FullName);
|
*assemblyFullName = NativeAllocStringAnsi(assembly.FullName);
|
||||||
return GetAssemblyHandle(assembly);
|
return GetAssemblyHandle(assembly);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogException(ex);
|
||||||
|
}
|
||||||
|
return new ManagedHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
|||||||
@@ -81,5 +81,6 @@ public class Main : EngineModule
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void GetFilesToDeploy(List<string> files)
|
public override void GetFilesToDeploy(List<string> files)
|
||||||
{
|
{
|
||||||
|
files.Add(Path.Combine(FolderPath, "Android/android_native_app_glue.h"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
#if COMPILE_WITH_PROFILER
|
||||||
|
#include "Engine/Core/Collections/Dictionary.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
enum class NetworkMessageIDs : uint8
|
enum class NetworkMessageIDs : uint8
|
||||||
{
|
{
|
||||||
@@ -35,4 +38,22 @@ public:
|
|||||||
static void OnNetworkMessageObjectDespawn(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
static void OnNetworkMessageObjectDespawn(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||||
static void OnNetworkMessageObjectRole(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
static void OnNetworkMessageObjectRole(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||||
static void OnNetworkMessageObjectRpc(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
static void OnNetworkMessageObjectRpc(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||||
|
|
||||||
|
#if COMPILE_WITH_PROFILER
|
||||||
|
|
||||||
|
struct ProfilerEvent
|
||||||
|
{
|
||||||
|
uint16 Count = 0;
|
||||||
|
uint16 DataSize = 0;
|
||||||
|
uint16 MessageSize = 0;
|
||||||
|
uint16 Receivers = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables network usage profiling tools. Captures network objects replication and RPCs send statistics.
|
||||||
|
/// </summary>
|
||||||
|
static bool EnableProfiling;
|
||||||
|
|
||||||
|
static Dictionary<Pair<ScriptingTypeHandle, StringAnsiView>, ProfilerEvent> ProfilerEvents;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,9 +8,10 @@
|
|||||||
#include "Engine/Platform/CPUInfo.h"
|
#include "Engine/Platform/CPUInfo.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
|
||||||
|
Array<NetworkPeer*> NetworkPeer::Peers;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
Array<NetworkPeer*, HeapAllocation> Peers;
|
|
||||||
uint32 LastHostId = 0;
|
uint32 LastHostId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ API_CLASS(sealed, NoSpawn, Namespace = "FlaxEngine.Networking") class FLAXENGINE
|
|||||||
{
|
{
|
||||||
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(NetworkPeer, ScriptingObject);
|
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(NetworkPeer, ScriptingObject);
|
||||||
|
|
||||||
|
// List with all active peers.
|
||||||
|
API_FIELD(ReadOnly) static Array<NetworkPeer*> Peers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int HostId = -1;
|
int HostId = -1;
|
||||||
NetworkConfig Config;
|
NetworkConfig Config;
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ bool NetworkReplicator::EnableLog = false;
|
|||||||
#define NETWORK_REPLICATOR_LOG(messageType, format, ...)
|
#define NETWORK_REPLICATOR_LOG(messageType, format, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if COMPILE_WITH_PROFILER
|
||||||
|
bool NetworkInternal::EnableProfiling = false;
|
||||||
|
Dictionary<Pair<ScriptingTypeHandle, StringAnsiView>, NetworkInternal::ProfilerEvent> NetworkInternal::ProfilerEvents;
|
||||||
|
#endif
|
||||||
|
|
||||||
PACK_STRUCT(struct NetworkMessageObjectReplicate
|
PACK_STRUCT(struct NetworkMessageObjectReplicate
|
||||||
{
|
{
|
||||||
NetworkMessageIDs ID = NetworkMessageIDs::ObjectReplicate;
|
NetworkMessageIDs ID = NetworkMessageIDs::ObjectReplicate;
|
||||||
@@ -1806,6 +1811,7 @@ void NetworkInternal::NetworkReplicatorUpdate()
|
|||||||
NetworkMessage msg = peer->BeginSendMessage();
|
NetworkMessage msg = peer->BeginSendMessage();
|
||||||
msg.WriteStructure(msgData);
|
msg.WriteStructure(msgData);
|
||||||
msg.WriteBytes(stream->GetBuffer(), msgDataSize);
|
msg.WriteBytes(stream->GetBuffer(), msgDataSize);
|
||||||
|
uint32 dataSize = msgDataSize, messageSize = msg.Length;
|
||||||
if (isClient)
|
if (isClient)
|
||||||
peer->EndSendMessage(NetworkChannelType::Unreliable, msg);
|
peer->EndSendMessage(NetworkChannelType::Unreliable, msg);
|
||||||
else
|
else
|
||||||
@@ -1824,6 +1830,8 @@ void NetworkInternal::NetworkReplicatorUpdate()
|
|||||||
msg = peer->BeginSendMessage();
|
msg = peer->BeginSendMessage();
|
||||||
msg.WriteStructure(msgDataPart);
|
msg.WriteStructure(msgDataPart);
|
||||||
msg.WriteBytes(stream->GetBuffer() + msgDataPart.PartStart, msgDataPart.PartSize);
|
msg.WriteBytes(stream->GetBuffer() + msgDataPart.PartStart, msgDataPart.PartSize);
|
||||||
|
messageSize += msg.Length;
|
||||||
|
dataSize += msgDataPart.PartSize;
|
||||||
dataStart += msgDataPart.PartSize;
|
dataStart += msgDataPart.PartSize;
|
||||||
if (isClient)
|
if (isClient)
|
||||||
peer->EndSendMessage(NetworkChannelType::Unreliable, msg);
|
peer->EndSendMessage(NetworkChannelType::Unreliable, msg);
|
||||||
@@ -1832,7 +1840,18 @@ void NetworkInternal::NetworkReplicatorUpdate()
|
|||||||
}
|
}
|
||||||
ASSERT_LOW_LAYER(dataStart == size);
|
ASSERT_LOW_LAYER(dataStart == size);
|
||||||
|
|
||||||
// TODO: stats for bytes send per object type
|
#if COMPILE_WITH_PROFILER
|
||||||
|
// Network stats recording
|
||||||
|
if (EnableProfiling)
|
||||||
|
{
|
||||||
|
const Pair<ScriptingTypeHandle, StringAnsiView> name(obj->GetTypeHandle(), StringAnsiView::Empty);
|
||||||
|
auto& profileEvent = ProfilerEvents[name];
|
||||||
|
profileEvent.Count++;
|
||||||
|
profileEvent.DataSize += dataSize;
|
||||||
|
profileEvent.MessageSize += messageSize;
|
||||||
|
profileEvent.Receivers += isClient ? 1 : CachedTargets.Count();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1873,6 +1892,7 @@ void NetworkInternal::NetworkReplicatorUpdate()
|
|||||||
NetworkMessage msg = peer->BeginSendMessage();
|
NetworkMessage msg = peer->BeginSendMessage();
|
||||||
msg.WriteStructure(msgData);
|
msg.WriteStructure(msgData);
|
||||||
msg.WriteBytes(e.ArgsData.Get(), e.ArgsData.Length());
|
msg.WriteBytes(e.ArgsData.Get(), e.ArgsData.Length());
|
||||||
|
uint32 dataSize = e.ArgsData.Length(), messageSize = msg.Length, receivers = 0;
|
||||||
NetworkChannelType channel = (NetworkChannelType)e.Info.Channel;
|
NetworkChannelType channel = (NetworkChannelType)e.Info.Channel;
|
||||||
if (e.Info.Server && isClient)
|
if (e.Info.Server && isClient)
|
||||||
{
|
{
|
||||||
@@ -1882,13 +1902,27 @@ void NetworkInternal::NetworkReplicatorUpdate()
|
|||||||
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Server RPC '{}::{}' called with non-empty list of targets is not supported (only server will receive it)", e.Name.First.ToString(), e.Name.Second.ToString());
|
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Server RPC '{}::{}' called with non-empty list of targets is not supported (only server will receive it)", e.Name.First.ToString(), e.Name.Second.ToString());
|
||||||
#endif
|
#endif
|
||||||
peer->EndSendMessage(channel, msg);
|
peer->EndSendMessage(channel, msg);
|
||||||
|
receivers = 1;
|
||||||
}
|
}
|
||||||
else if (e.Info.Client && (isServer || isHost))
|
else if (e.Info.Client && (isServer || isHost))
|
||||||
{
|
{
|
||||||
// Server -> Client(s)
|
// Server -> Client(s)
|
||||||
BuildCachedTargets(NetworkManager::Clients, item.TargetClientIds, e.Targets, NetworkManager::LocalClientId);
|
BuildCachedTargets(NetworkManager::Clients, item.TargetClientIds, e.Targets, NetworkManager::LocalClientId);
|
||||||
peer->EndSendMessage(channel, msg, CachedTargets);
|
peer->EndSendMessage(channel, msg, CachedTargets);
|
||||||
|
receivers = CachedTargets.Count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if COMPILE_WITH_PROFILER
|
||||||
|
// Network stats recording
|
||||||
|
if (EnableProfiling && receivers)
|
||||||
|
{
|
||||||
|
auto& profileEvent = ProfilerEvents[e.Name];
|
||||||
|
profileEvent.Count++;
|
||||||
|
profileEvent.DataSize += dataSize;
|
||||||
|
profileEvent.MessageSize += messageSize;
|
||||||
|
profileEvent.Receivers += receivers;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
RpcQueue.Clear();
|
RpcQueue.Clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The network transport driver statistics container. Contains information about INetworkDriver usage and performance.
|
/// The network transport driver statistics container. Contains information about INetworkDriver usage and performance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_STRUCT(Namespace="FlaxEngine.Networking") struct FLAXENGINE_API NetworkDriverStats
|
API_STRUCT(Namespace="FlaxEngine.Networking", NoDefault) struct FLAXENGINE_API NetworkDriverStats
|
||||||
{
|
{
|
||||||
DECLARE_SCRIPTING_TYPE_MINIMAL(NetworkDriverStats);
|
DECLARE_SCRIPTING_TYPE_MINIMAL(NetworkDriverStats);
|
||||||
|
|
||||||
|
|||||||
@@ -402,7 +402,7 @@ SceneRenderTask* ParticleEffect::GetRenderTask() const
|
|||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
|
||||||
Array<ParticleEffect::ParameterOverride> ParticleEffect::GetParametersOverrides()
|
Array<ParticleEffect::ParameterOverride>& ParticleEffect::GetParametersOverrides()
|
||||||
{
|
{
|
||||||
CacheModifiedParameters();
|
CacheModifiedParameters();
|
||||||
return _parametersOverrides;
|
return _parametersOverrides;
|
||||||
@@ -461,7 +461,6 @@ void ParticleEffect::CacheModifiedParameters()
|
|||||||
{
|
{
|
||||||
if (_parameters.IsEmpty())
|
if (_parameters.IsEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_parametersOverrides.Clear();
|
_parametersOverrides.Clear();
|
||||||
auto& parameters = GetParameters();
|
auto& parameters = GetParameters();
|
||||||
for (auto& param : parameters)
|
for (auto& param : parameters)
|
||||||
|
|||||||
@@ -382,7 +382,7 @@ public:
|
|||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
protected:
|
protected:
|
||||||
// Exposed parameters overrides for Editor Undo.
|
// Exposed parameters overrides for Editor Undo.
|
||||||
API_PROPERTY(Attributes="HideInEditor, Serialize") Array<ParticleEffect::ParameterOverride> GetParametersOverrides();
|
API_PROPERTY(Attributes="HideInEditor, Serialize") Array<ParticleEffect::ParameterOverride>& GetParametersOverrides();
|
||||||
API_PROPERTY() void SetParametersOverrides(const Array<ParticleEffect::ParameterOverride>& value);
|
API_PROPERTY() void SetParametersOverrides(const Array<ParticleEffect::ParameterOverride>& value);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ int32 ProfilerCPU::BeginEvent(const char* name)
|
|||||||
|
|
||||||
void ProfilerCPU::EndEvent(int32 index)
|
void ProfilerCPU::EndEvent(int32 index)
|
||||||
{
|
{
|
||||||
if (Enabled && Thread::Current)
|
if (index != -1 && Thread::Current)
|
||||||
Thread::Current->EndEvent(index);
|
Thread::Current->EndEvent(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ RenderStatsData RenderStatsData::Counter;
|
|||||||
int32 ProfilerGPU::_depth = 0;
|
int32 ProfilerGPU::_depth = 0;
|
||||||
Array<GPUTimerQuery*> ProfilerGPU::_timerQueriesPool;
|
Array<GPUTimerQuery*> ProfilerGPU::_timerQueriesPool;
|
||||||
Array<GPUTimerQuery*> ProfilerGPU::_timerQueriesFree;
|
Array<GPUTimerQuery*> ProfilerGPU::_timerQueriesFree;
|
||||||
bool ProfilerGPU::Enabled = true;
|
bool ProfilerGPU::Enabled = false;
|
||||||
int32 ProfilerGPU::CurrentBuffer = 0;
|
int32 ProfilerGPU::CurrentBuffer = 0;
|
||||||
ProfilerGPU::EventBuffer ProfilerGPU::Buffers[PROFILER_GPU_EVENTS_FRAMES];
|
ProfilerGPU::EventBuffer ProfilerGPU::Buffers[PROFILER_GPU_EVENTS_FRAMES];
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,17 @@
|
|||||||
#if COMPILE_WITH_PROFILER
|
#if COMPILE_WITH_PROFILER
|
||||||
|
|
||||||
#include "ProfilingTools.h"
|
#include "ProfilingTools.h"
|
||||||
|
#include "Engine/Core/Types/Pair.h"
|
||||||
#include "Engine/Engine/Engine.h"
|
#include "Engine/Engine/Engine.h"
|
||||||
#include "Engine/Engine/Time.h"
|
#include "Engine/Engine/Time.h"
|
||||||
#include "Engine/Engine/EngineService.h"
|
#include "Engine/Engine/EngineService.h"
|
||||||
#include "Engine/Graphics/GPUDevice.h"
|
#include "Engine/Graphics/GPUDevice.h"
|
||||||
|
#include "Engine/Networking/NetworkInternal.h"
|
||||||
|
|
||||||
ProfilingTools::MainStats ProfilingTools::Stats;
|
ProfilingTools::MainStats ProfilingTools::Stats;
|
||||||
Array<ProfilingTools::ThreadStats, InlinedAllocation<64>> ProfilingTools::EventsCPU;
|
Array<ProfilingTools::ThreadStats, InlinedAllocation<64>> ProfilingTools::EventsCPU;
|
||||||
Array<ProfilerGPU::Event> ProfilingTools::EventsGPU;
|
Array<ProfilerGPU::Event> ProfilingTools::EventsGPU;
|
||||||
|
Array<ProfilingTools::NetworkEventStat> ProfilingTools::EventsNetwork;
|
||||||
|
|
||||||
class ProfilingToolsService : public EngineService
|
class ProfilingToolsService : public EngineService
|
||||||
{
|
{
|
||||||
@@ -120,6 +123,40 @@ void ProfilingToolsService::Update()
|
|||||||
frame.Extract(ProfilingTools::EventsGPU);
|
frame.Extract(ProfilingTools::EventsGPU);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the last events from networking runtime
|
||||||
|
{
|
||||||
|
auto& networkEvents = ProfilingTools::EventsNetwork;
|
||||||
|
networkEvents.Resize(NetworkInternal::ProfilerEvents.Count());
|
||||||
|
int32 i = 0;
|
||||||
|
for (const auto& e : NetworkInternal::ProfilerEvents)
|
||||||
|
{
|
||||||
|
const auto& src = e.Value;
|
||||||
|
auto& dst = networkEvents[i++];
|
||||||
|
dst.Count = src.Count;
|
||||||
|
dst.DataSize = src.DataSize;
|
||||||
|
dst.MessageSize = src.MessageSize;
|
||||||
|
dst.Receivers = src.Receivers;
|
||||||
|
const StringAnsiView& typeName = e.Key.First.GetType().Fullname;
|
||||||
|
uint64 len = Math::Min<uint64>(typeName.Length(), ARRAY_COUNT(dst.Name) - 10);
|
||||||
|
Platform::MemoryCopy(dst.Name, typeName.Get(), len);
|
||||||
|
const StringAnsiView& name = e.Key.Second;
|
||||||
|
if (name.HasChars())
|
||||||
|
{
|
||||||
|
uint64 pos = len;
|
||||||
|
dst.Name[pos++] = ':';
|
||||||
|
dst.Name[pos++] = ':';
|
||||||
|
len = Math::Min<uint64>(name.Length(), ARRAY_COUNT(dst.Name) - pos - 1);
|
||||||
|
Platform::MemoryCopy(dst.Name + pos, name.Get(), len);
|
||||||
|
dst.Name[pos + len] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dst.Name[len] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NetworkInternal::ProfilerEvents.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// Print CPU events to the log
|
// Print CPU events to the log
|
||||||
{
|
{
|
||||||
@@ -173,6 +210,19 @@ void ProfilingToolsService::Dispose()
|
|||||||
ProfilingTools::EventsCPU.Clear();
|
ProfilingTools::EventsCPU.Clear();
|
||||||
ProfilingTools::EventsCPU.SetCapacity(0);
|
ProfilingTools::EventsCPU.SetCapacity(0);
|
||||||
ProfilingTools::EventsGPU.SetCapacity(0);
|
ProfilingTools::EventsGPU.SetCapacity(0);
|
||||||
|
ProfilingTools::EventsNetwork.SetCapacity(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProfilingTools::GetEnabled()
|
||||||
|
{
|
||||||
|
return ProfilerCPU::Enabled && ProfilerGPU::Enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfilingTools::SetEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
ProfilerCPU::Enabled = enabled;
|
||||||
|
ProfilerGPU::Enabled = enabled;
|
||||||
|
NetworkInternal::EnableProfiling = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -105,7 +105,35 @@ public:
|
|||||||
API_FIELD() Array<ProfilerCPU::Event> Events;
|
API_FIELD() Array<ProfilerCPU::Event> Events;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The network stat.
|
||||||
|
/// </summary>
|
||||||
|
API_STRUCT(NoDefault) struct NetworkEventStat
|
||||||
|
{
|
||||||
|
DECLARE_SCRIPTING_TYPE_MINIMAL(NetworkEventStat);
|
||||||
|
|
||||||
|
// Amount of occurrences.
|
||||||
|
API_FIELD() uint16 Count;
|
||||||
|
// Transferred data size (in bytes).
|
||||||
|
API_FIELD() uint16 DataSize;
|
||||||
|
// Transferred message (data+header) size (in bytes).
|
||||||
|
API_FIELD() uint16 MessageSize;
|
||||||
|
// Amount of peers that will receive this message.
|
||||||
|
API_FIELD() uint16 Receivers;
|
||||||
|
API_FIELD(Private, NoArray) byte Name[120];
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Controls the engine profiler (CPU, GPU, etc.) usage.
|
||||||
|
/// </summary>
|
||||||
|
API_PROPERTY() static bool GetEnabled();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controls the engine profiler (CPU, GPU, etc.) usage.
|
||||||
|
/// </summary>
|
||||||
|
API_PROPERTY() static void SetEnabled(bool enabled);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current collected main stats by the profiler from the local session. Updated every frame.
|
/// The current collected main stats by the profiler from the local session. Updated every frame.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -120,6 +148,11 @@ public:
|
|||||||
/// The GPU rendering profiler events.
|
/// The GPU rendering profiler events.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(ReadOnly) static Array<ProfilerGPU::Event> EventsGPU;
|
API_FIELD(ReadOnly) static Array<ProfilerGPU::Event> EventsGPU;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The networking profiler events.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(ReadOnly) static Array<NetworkEventStat> EventsNetwork;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ using System;
|
|||||||
namespace FlaxEngine
|
namespace FlaxEngine
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates that a field or a property of a serializable class should be serialized. This class cannot be inherited.
|
/// Indicates that a field or a property of a serializable class should be serialized.
|
||||||
|
/// The <see cref="FlaxEngine.ShowInEditorAttribute"/> attribute is required to show hidden fields in the editor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||||
public sealed class SerializeAttribute : Attribute
|
public sealed class SerializeAttribute : Attribute
|
||||||
|
|||||||
@@ -703,13 +703,12 @@ bool MAssembly::LoadImage(const String& assemblyPath, const StringView& nativePa
|
|||||||
{
|
{
|
||||||
// TODO: Use new hostfxr delegate load_assembly_bytes? (.NET 8+)
|
// TODO: Use new hostfxr delegate load_assembly_bytes? (.NET 8+)
|
||||||
// Open .Net assembly
|
// Open .Net assembly
|
||||||
const StringAnsi assemblyPathAnsi = assemblyPath.ToStringAnsi();
|
const char* name = nullptr;
|
||||||
const char* name;
|
const char* fullname = nullptr;
|
||||||
const char* fullname;
|
|
||||||
static void* LoadAssemblyImagePtr = GetStaticMethodPointer(TEXT("LoadAssemblyImage"));
|
static void* LoadAssemblyImagePtr = GetStaticMethodPointer(TEXT("LoadAssemblyImage"));
|
||||||
_handle = CallStaticMethod<void*, const char*, const char**, const char**>(LoadAssemblyImagePtr, assemblyPathAnsi.Get(), &name, &fullname);
|
_handle = CallStaticMethod<void*, const Char*, const char**, const char**>(LoadAssemblyImagePtr, assemblyPath.Get(), &name, &fullname);
|
||||||
_name = name;
|
_name = StringAnsi(name);
|
||||||
_fullname = fullname;
|
_fullname = StringAnsi(fullname);
|
||||||
MCore::GC::FreeMemory((void*)name);
|
MCore::GC::FreeMemory((void*)name);
|
||||||
MCore::GC::FreeMemory((void*)fullname);
|
MCore::GC::FreeMemory((void*)fullname);
|
||||||
if (_handle == nullptr)
|
if (_handle == nullptr)
|
||||||
|
|||||||
@@ -84,17 +84,23 @@ namespace FlaxEngine.GUI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Border Style"), EditorOrder(2010), ExpandGroups]
|
[EditorDisplay("Border Style"), EditorOrder(2010), ExpandGroups]
|
||||||
public bool HasBorder { get; set; } = true;
|
public bool HasBorder { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the border thickness.
|
||||||
|
/// </summary>
|
||||||
|
[EditorDisplay("Border Style"), EditorOrder(2011), Limit(0)]
|
||||||
|
public float BorderThickness { get; set; } = 1.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the color of the border.
|
/// Gets or sets the color of the border.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Border Style"), EditorOrder(2011), ExpandGroups]
|
[EditorDisplay("Border Style"), EditorOrder(2012)]
|
||||||
public Color BorderColor { get; set; }
|
public Color BorderColor { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the border color when button is highlighted.
|
/// Gets or sets the border color when button is highlighted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Border Style"), EditorOrder(2012)]
|
[EditorDisplay("Border Style"), EditorOrder(2013)]
|
||||||
public Color BorderColorHighlighted { get; set; }
|
public Color BorderColorHighlighted { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -252,7 +258,7 @@ namespace FlaxEngine.GUI
|
|||||||
else
|
else
|
||||||
Render2D.FillRectangle(clientRect, backgroundColor);
|
Render2D.FillRectangle(clientRect, backgroundColor);
|
||||||
if (HasBorder)
|
if (HasBorder)
|
||||||
Render2D.DrawRectangle(clientRect, borderColor);
|
Render2D.DrawRectangle(clientRect, borderColor, BorderThickness);
|
||||||
|
|
||||||
// Draw text
|
// Draw text
|
||||||
Render2D.DrawText(_font?.GetFont(), TextMaterial, _text, clientRect, textColor, TextAlignment.Center, TextAlignment.Center);
|
Render2D.DrawText(_font?.GetFont(), TextMaterial, _text, clientRect, textColor, TextAlignment.Center, TextAlignment.Center);
|
||||||
|
|||||||
@@ -107,17 +107,29 @@ namespace FlaxEngine.GUI
|
|||||||
CacheBox();
|
CacheBox();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether to have a border.
|
||||||
|
/// </summary>
|
||||||
|
[EditorDisplay("Border Style"), EditorOrder(2010), Tooltip("Whether to have a border."), ExpandGroups]
|
||||||
|
public bool HasBorder { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the border thickness.
|
||||||
|
/// </summary>
|
||||||
|
[EditorDisplay("Border Style"), EditorOrder(2011), Tooltip("The thickness of the border."), Limit(0)]
|
||||||
|
public float BorderThickness { get; set; } = 1.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the color of the border.
|
/// Gets or sets the color of the border.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Border Style"), EditorOrder(2010), ExpandGroups]
|
[EditorDisplay("Border Style"), EditorOrder(2012)]
|
||||||
public Color BorderColor { get; set; }
|
public Color BorderColor { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the border color when checkbox is hovered.
|
/// Gets or sets the border color when checkbox is hovered.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Border Style"), EditorOrder(2011)]
|
[EditorDisplay("Border Style"), EditorOrder(2013)]
|
||||||
public Color BorderColorHighlighted { get; set; }
|
public Color BorderColorHighlighted { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -221,12 +233,15 @@ namespace FlaxEngine.GUI
|
|||||||
bool enabled = EnabledInHierarchy;
|
bool enabled = EnabledInHierarchy;
|
||||||
|
|
||||||
// Border
|
// Border
|
||||||
Color borderColor = BorderColor;
|
if (HasBorder)
|
||||||
if (!enabled)
|
{
|
||||||
borderColor *= 0.5f;
|
Color borderColor = BorderColor;
|
||||||
else if (_isPressed || _mouseOverBox || IsNavFocused)
|
if (!enabled)
|
||||||
borderColor = BorderColorHighlighted;
|
borderColor *= 0.5f;
|
||||||
Render2D.DrawRectangle(_box.MakeExpanded(-2.0f), borderColor);
|
else if (_isPressed || _mouseOverBox || IsNavFocused)
|
||||||
|
borderColor = BorderColorHighlighted;
|
||||||
|
Render2D.DrawRectangle(_box.MakeExpanded(-2.0f), borderColor, BorderThickness);
|
||||||
|
}
|
||||||
|
|
||||||
// Icon
|
// Icon
|
||||||
if (_state != CheckBoxState.Default)
|
if (_state != CheckBoxState.Default)
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ public class Slider : ContainerControl
|
|||||||
// Draw track fill
|
// Draw track fill
|
||||||
if (FillTrack)
|
if (FillTrack)
|
||||||
{
|
{
|
||||||
var fillLineRect = new Rectangle(_thumbSize.X / 2, (Height - TrackHeight - 2) / 2, Width - (Width - _thumbCenter) - _thumbSize.X / 2, TrackHeight + 2);
|
var fillLineRect = new Rectangle(_thumbSize.X / 2 - 1, (Height - TrackHeight - 2) / 2, Width - (Width - _thumbCenter) - _thumbSize.X / 2, TrackHeight + 2);
|
||||||
Render2D.PushClip(ref fillLineRect);
|
Render2D.PushClip(ref fillLineRect);
|
||||||
if (FillTrackBrush != null)
|
if (FillTrackBrush != null)
|
||||||
FillTrackBrush.Draw(lineRect, TrackFillLineColor);
|
FillTrackBrush.Draw(lineRect, TrackFillLineColor);
|
||||||
|
|||||||
@@ -155,7 +155,8 @@ namespace FlaxEngine.GUI
|
|||||||
if (IsMouseOver || IsNavFocused)
|
if (IsMouseOver || IsNavFocused)
|
||||||
backColor = BackgroundSelectedColor;
|
backColor = BackgroundSelectedColor;
|
||||||
Render2D.FillRectangle(rect, backColor);
|
Render2D.FillRectangle(rect, backColor);
|
||||||
Render2D.DrawRectangle(rect, IsFocused ? BorderSelectedColor : BorderColor);
|
if (HasBorder)
|
||||||
|
Render2D.DrawRectangle(rect, IsFocused ? BorderSelectedColor : BorderColor, BorderThickness);
|
||||||
|
|
||||||
// Apply view offset and clip mask
|
// Apply view offset and clip mask
|
||||||
if (ClipText)
|
if (ClipText)
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ namespace FlaxEngine.GUI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class TextBoxBase : ContainerControl
|
public abstract class TextBoxBase : ContainerControl
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The delete control character (used for text filtering).
|
||||||
|
/// </summary>
|
||||||
|
protected const char DelChar = (char)0x7F;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The text separators (used for words skipping).
|
/// The text separators (used for words skipping).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -270,16 +275,28 @@ namespace FlaxEngine.GUI
|
|||||||
[EditorDisplay("Background Style"), EditorOrder(2002), Tooltip("The speed of the selection background flashing animation.")]
|
[EditorDisplay("Background Style"), EditorOrder(2002), Tooltip("The speed of the selection background flashing animation.")]
|
||||||
public float BackgroundSelectedFlashSpeed { get; set; } = 6.0f;
|
public float BackgroundSelectedFlashSpeed { get; set; } = 6.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether to have a border.
|
||||||
|
/// </summary>
|
||||||
|
[EditorDisplay("Border Style"), EditorOrder(2010), Tooltip("Whether to have a border."), ExpandGroups]
|
||||||
|
public bool HasBorder { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the border thickness.
|
||||||
|
/// </summary>
|
||||||
|
[EditorDisplay("Border Style"), EditorOrder(2011), Tooltip("The thickness of the border."), Limit(0)]
|
||||||
|
public float BorderThickness { get; set; } = 1.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the color of the border (Transparent if not used).
|
/// Gets or sets the color of the border (Transparent if not used).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Border Style"), EditorOrder(2010), Tooltip("The color of the border (Transparent if not used)."), ExpandGroups]
|
[EditorDisplay("Border Style"), EditorOrder(2012), Tooltip("The color of the border (Transparent if not used).")]
|
||||||
public Color BorderColor { get; set; }
|
public Color BorderColor { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the color of the border when control is focused (Transparent if not used).
|
/// Gets or sets the color of the border when control is focused (Transparent if not used).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Border Style"), EditorOrder(2011), Tooltip("The color of the border when control is focused (Transparent if not used)")]
|
[EditorDisplay("Border Style"), EditorOrder(2013), Tooltip("The color of the border when control is focused (Transparent if not used)")]
|
||||||
public Color BorderSelectedColor { get; set; }
|
public Color BorderSelectedColor { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -351,6 +368,10 @@ namespace FlaxEngine.GUI
|
|||||||
if (value.IndexOf('\r') != -1)
|
if (value.IndexOf('\r') != -1)
|
||||||
value = value.Replace("\r", "");
|
value = value.Replace("\r", "");
|
||||||
|
|
||||||
|
// Filter text (handle backspace control character)
|
||||||
|
if (value.IndexOf(DelChar) != -1)
|
||||||
|
value = value.Replace(DelChar.ToString(), "");
|
||||||
|
|
||||||
// Clamp length
|
// Clamp length
|
||||||
if (value.Length > MaxLength)
|
if (value.Length > MaxLength)
|
||||||
value = value.Substring(0, MaxLength);
|
value = value.Substring(0, MaxLength);
|
||||||
@@ -673,6 +694,8 @@ namespace FlaxEngine.GUI
|
|||||||
// Filter text
|
// Filter text
|
||||||
if (str.IndexOf('\r') != -1)
|
if (str.IndexOf('\r') != -1)
|
||||||
str = str.Replace("\r", "");
|
str = str.Replace("\r", "");
|
||||||
|
if (str.IndexOf(DelChar) != -1)
|
||||||
|
str = str.Replace(DelChar.ToString(), "");
|
||||||
if (!IsMultiline && str.IndexOf('\n') != -1)
|
if (!IsMultiline && str.IndexOf('\n') != -1)
|
||||||
str = str.Replace("\n", "");
|
str = str.Replace("\n", "");
|
||||||
|
|
||||||
@@ -1327,6 +1350,15 @@ namespace FlaxEngine.GUI
|
|||||||
if (IsReadOnly)
|
if (IsReadOnly)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (ctrDown)
|
||||||
|
{
|
||||||
|
int prevWordBegin = FindPrevWordBegin();
|
||||||
|
_text = _text.Remove(prevWordBegin, CaretPosition - prevWordBegin);
|
||||||
|
SetSelection(prevWordBegin);
|
||||||
|
OnTextChanged();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int left = SelectionLeft;
|
int left = SelectionLeft;
|
||||||
if (HasSelection)
|
if (HasSelection)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
var containerControl = child as ContainerControl;
|
var containerControl = child as ContainerControl;
|
||||||
var childAtRecursive = containerControl?.GetChildAtRecursive(childLocation);
|
var childAtRecursive = containerControl?.GetChildAtRecursive(childLocation);
|
||||||
if (childAtRecursive != null)
|
if (childAtRecursive != null && childAtRecursive.Visible)
|
||||||
{
|
{
|
||||||
child = childAtRecursive;
|
child = childAtRecursive;
|
||||||
}
|
}
|
||||||
@@ -507,15 +507,19 @@ namespace FlaxEngine.GUI
|
|||||||
|
|
||||||
// Perform automatic navigation based on the layout
|
// Perform automatic navigation based on the layout
|
||||||
var result = NavigationRaycast(direction, location, visited);
|
var result = NavigationRaycast(direction, location, visited);
|
||||||
if (result == null && direction == NavDirection.Next)
|
var rightMostLocation = location;
|
||||||
|
if (result == null && (direction == NavDirection.Next || direction == NavDirection.Previous))
|
||||||
{
|
{
|
||||||
// Try wrap the navigation over the layout based on the direction
|
// Try wrap the navigation over the layout based on the direction
|
||||||
var visitedWrap = new List<Control>(visited);
|
var visitedWrap = new List<Control>(visited);
|
||||||
result = NavigationWrap(direction, location, visitedWrap);
|
result = NavigationWrap(direction, location, visitedWrap, out rightMostLocation);
|
||||||
}
|
}
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
result = result.OnNavigate(direction, result.PointFromParent(location), this, visited);
|
// HACK: only the 'previous' direction needs the rightMostLocation so i used a ternary conditional operator.
|
||||||
|
// The rightMostLocation can probably become a 'desired raycast origin' that gets calculated correctly in the NavigationWrap method.
|
||||||
|
var useLocation = direction == NavDirection.Previous ? rightMostLocation : location;
|
||||||
|
result = result.OnNavigate(direction, result.PointFromParent(useLocation), this, visited);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -551,8 +555,9 @@ namespace FlaxEngine.GUI
|
|||||||
/// <param name="direction">The navigation direction.</param>
|
/// <param name="direction">The navigation direction.</param>
|
||||||
/// <param name="location">The navigation start location (in the control-space).</param>
|
/// <param name="location">The navigation start location (in the control-space).</param>
|
||||||
/// <param name="visited">The list with visited controls. Used to skip recursive navigation calls when doing traversal across the UI hierarchy.</param>
|
/// <param name="visited">The list with visited controls. Used to skip recursive navigation calls when doing traversal across the UI hierarchy.</param>
|
||||||
|
/// <param name="rightMostLocation">Returns the rightmost location of the parent container for the raycast used by the child container</param>
|
||||||
/// <returns>The target navigation control or null if didn't performed any navigation.</returns>
|
/// <returns>The target navigation control or null if didn't performed any navigation.</returns>
|
||||||
protected virtual Control NavigationWrap(NavDirection direction, Float2 location, List<Control> visited)
|
protected virtual Control NavigationWrap(NavDirection direction, Float2 location, List<Control> visited, out Float2 rightMostLocation)
|
||||||
{
|
{
|
||||||
// This searches form a child that calls this navigation event (see Control.OnNavigate) to determinate the layout wrapping size based on that child size
|
// This searches form a child that calls this navigation event (see Control.OnNavigate) to determinate the layout wrapping size based on that child size
|
||||||
var currentChild = RootWindow?.FocusedControl;
|
var currentChild = RootWindow?.FocusedControl;
|
||||||
@@ -566,15 +571,22 @@ namespace FlaxEngine.GUI
|
|||||||
case NavDirection.Next:
|
case NavDirection.Next:
|
||||||
predictedLocation = new Float2(0, location.Y + layoutSize.Y);
|
predictedLocation = new Float2(0, location.Y + layoutSize.Y);
|
||||||
break;
|
break;
|
||||||
|
case NavDirection.Previous:
|
||||||
|
predictedLocation = new Float2(Size.X, location.Y - layoutSize.Y);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (new Rectangle(Float2.Zero, Size).Contains(ref predictedLocation))
|
if (new Rectangle(Float2.Zero, Size).Contains(ref predictedLocation))
|
||||||
{
|
{
|
||||||
var result = NavigationRaycast(direction, predictedLocation, visited);
|
var result = NavigationRaycast(direction, predictedLocation, visited);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
return result;
|
{
|
||||||
|
rightMostLocation = predictedLocation;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Parent?.NavigationWrap(direction, PointToParent(ref location), visited);
|
rightMostLocation = location;
|
||||||
|
return Parent?.NavigationWrap(direction, PointToParent(ref location), visited, out rightMostLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CanGetAutoFocus(Control c)
|
private static bool CanGetAutoFocus(Control c)
|
||||||
@@ -613,6 +625,10 @@ namespace FlaxEngine.GUI
|
|||||||
uiDir1 = new Float2(1, 0);
|
uiDir1 = new Float2(1, 0);
|
||||||
uiDir2 = new Float2(0, 1);
|
uiDir2 = new Float2(0, 1);
|
||||||
break;
|
break;
|
||||||
|
case NavDirection.Previous:
|
||||||
|
uiDir1 = new Float2(-1, 0);
|
||||||
|
uiDir2 = new Float2(0, -1);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
Control result = null;
|
Control result = null;
|
||||||
var minDistance = float.MaxValue;
|
var minDistance = float.MaxValue;
|
||||||
|
|||||||
@@ -634,6 +634,7 @@ namespace FlaxEngine.GUI
|
|||||||
case NavDirection.Left: return new Float2(0, size.Y * 0.5f);
|
case NavDirection.Left: return new Float2(0, size.Y * 0.5f);
|
||||||
case NavDirection.Right: return new Float2(size.X, size.Y * 0.5f);
|
case NavDirection.Right: return new Float2(size.X, size.Y * 0.5f);
|
||||||
case NavDirection.Next: return Float2.Zero;
|
case NavDirection.Next: return Float2.Zero;
|
||||||
|
case NavDirection.Previous: return size;
|
||||||
default: return size * 0.5f;
|
default: return size * 0.5f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,5 +202,10 @@ namespace FlaxEngine.GUI
|
|||||||
/// The next item (right with layout wrapping).
|
/// The next item (right with layout wrapping).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Next,
|
Next,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The previous item (left with layout wrapping).
|
||||||
|
/// </summary>
|
||||||
|
Previous,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -968,7 +968,7 @@ namespace Flax.Build.Bindings
|
|||||||
CppParamsWrappersCache[i] = result;
|
CppParamsWrappersCache[i] = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
string eventSignature;
|
string eventType;
|
||||||
if (useCustomDelegateSignature)
|
if (useCustomDelegateSignature)
|
||||||
{
|
{
|
||||||
contents.Append(indent).Append($"/// <summary>The delegate for event {eventInfo.Name}.</summary>").AppendLine();
|
contents.Append(indent).Append($"/// <summary>The delegate for event {eventInfo.Name}.</summary>").AppendLine();
|
||||||
@@ -983,24 +983,25 @@ namespace Flax.Build.Bindings
|
|||||||
contents.Append(CppParamsWrappersCache[i]).Append(" arg").Append(i);
|
contents.Append(CppParamsWrappersCache[i]).Append(" arg").Append(i);
|
||||||
}
|
}
|
||||||
contents.Append(");").AppendLine().AppendLine();
|
contents.Append(");").AppendLine().AppendLine();
|
||||||
eventSignature = "event " + eventInfo.Name + "Delegate";
|
eventType = eventInfo.Name + "Delegate";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
eventSignature = "event Action";
|
eventType = "Action";
|
||||||
if (paramsCount != 0)
|
if (paramsCount != 0)
|
||||||
{
|
{
|
||||||
eventSignature += '<';
|
eventType += '<';
|
||||||
for (var i = 0; i < paramsCount; i++)
|
for (var i = 0; i < paramsCount; i++)
|
||||||
{
|
{
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
eventSignature += ", ";
|
eventType += ", ";
|
||||||
CppParamsWrappersCache[i] = GenerateCSharpNativeToManaged(buildData, eventInfo.Type.GenericArgs[i], classInfo);
|
CppParamsWrappersCache[i] = GenerateCSharpNativeToManaged(buildData, eventInfo.Type.GenericArgs[i], classInfo);
|
||||||
eventSignature += CppParamsWrappersCache[i];
|
eventType += CppParamsWrappersCache[i];
|
||||||
}
|
}
|
||||||
eventSignature += '>';
|
eventType += '>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
string eventSignature = "event " + eventType;
|
||||||
|
|
||||||
GenerateCSharpComment(contents, indent, eventInfo.Comment, true);
|
GenerateCSharpComment(contents, indent, eventInfo.Comment, true);
|
||||||
GenerateCSharpAttributes(buildData, contents, indent, classInfo, eventInfo, useUnmanaged);
|
GenerateCSharpAttributes(buildData, contents, indent, classInfo, eventInfo, useUnmanaged);
|
||||||
@@ -1013,11 +1014,7 @@ namespace Flax.Build.Bindings
|
|||||||
indent += " ";
|
indent += " ";
|
||||||
var eventInstance = eventInfo.IsStatic ? string.Empty : "__unmanagedPtr, ";
|
var eventInstance = eventInfo.IsStatic ? string.Empty : "__unmanagedPtr, ";
|
||||||
contents.Append(indent).Append($"add {{ Internal_{eventInfo.Name} += value; if (Internal_{eventInfo.Name}_Count++ == 0) Internal_{eventInfo.Name}_Bind({eventInstance}true); }}").AppendLine();
|
contents.Append(indent).Append($"add {{ Internal_{eventInfo.Name} += value; if (Internal_{eventInfo.Name}_Count++ == 0) Internal_{eventInfo.Name}_Bind({eventInstance}true); }}").AppendLine();
|
||||||
contents.Append(indent).Append("remove { ").AppendLine();
|
contents.Append(indent).Append($"remove {{ var __delegate = ({eventType})Delegate.Remove(Internal_{eventInfo.Name}, value); if (__delegate != Internal_{eventInfo.Name}) {{ Internal_{eventInfo.Name} = __delegate; if (--Internal_{eventInfo.Name}_Count == 0) Internal_{eventInfo.Name}_Bind({eventInstance}false); }} }}").AppendLine();
|
||||||
contents.Append("#if FLAX_EDITOR || BUILD_DEBUG").AppendLine();
|
|
||||||
contents.Append(indent).Append($"if (Internal_{eventInfo.Name} != null) {{ bool invalid = true; foreach (Delegate e in Internal_{eventInfo.Name}.GetInvocationList()) {{ if (e == (Delegate)value) {{ invalid = false; break; }} }} if (invalid) throw new Exception(\"Cannot unregister from event if not registered before.\"); }}").AppendLine();
|
|
||||||
contents.Append("#endif").AppendLine();
|
|
||||||
contents.Append(indent).Append($"Internal_{eventInfo.Name} -= value; if (--Internal_{eventInfo.Name}_Count == 0) Internal_{eventInfo.Name}_Bind({eventInstance}false); }}").AppendLine();
|
|
||||||
indent = indent.Substring(0, indent.Length - 4);
|
indent = indent.Substring(0, indent.Length - 4);
|
||||||
contents.Append(indent).Append('}').AppendLine();
|
contents.Append(indent).Append('}').AppendLine();
|
||||||
|
|
||||||
@@ -1034,6 +1031,7 @@ namespace Flax.Build.Bindings
|
|||||||
contents.Append("static ");
|
contents.Append("static ");
|
||||||
contents.Append($"{eventSignature} Internal_{eventInfo.Name};");
|
contents.Append($"{eventSignature} Internal_{eventInfo.Name};");
|
||||||
contents.AppendLine();
|
contents.AppendLine();
|
||||||
|
contents.Append("#pragma warning restore 67").AppendLine();
|
||||||
|
|
||||||
contents.AppendLine();
|
contents.AppendLine();
|
||||||
contents.Append(indent).Append("internal ");
|
contents.Append(indent).Append("internal ");
|
||||||
@@ -1515,8 +1513,8 @@ namespace Flax.Build.Bindings
|
|||||||
type = "IntPtr";
|
type = "IntPtr";
|
||||||
else if (type == "bool")
|
else if (type == "bool")
|
||||||
type = "byte";
|
type = "byte";
|
||||||
else if (type == "object")
|
else if (fieldInfo.Type.Type == "Variant")
|
||||||
type = "NativeVariant";
|
type = "IntPtr";
|
||||||
else if (internalType)
|
else if (internalType)
|
||||||
{
|
{
|
||||||
internalTypeMarshaller = type + "Marshaller";
|
internalTypeMarshaller = type + "Marshaller";
|
||||||
@@ -1533,9 +1531,6 @@ namespace Flax.Build.Bindings
|
|||||||
if (fieldInfo.NoArray && fieldInfo.Type.IsArray)
|
if (fieldInfo.NoArray && fieldInfo.Type.IsArray)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (type == "NativeVariant")
|
|
||||||
continue; // TODO: FIXME
|
|
||||||
|
|
||||||
if (useSeparator)
|
if (useSeparator)
|
||||||
{
|
{
|
||||||
toManagedContent.Append(", ");
|
toManagedContent.Append(", ");
|
||||||
@@ -1637,6 +1632,12 @@ namespace Flax.Build.Bindings
|
|||||||
toManagedContent.Append($"managed.{fieldInfo.Name} != 0");
|
toManagedContent.Append($"managed.{fieldInfo.Name} != 0");
|
||||||
toNativeContent.Append($"managed.{fieldInfo.Name} ? (byte)1 : (byte)0");
|
toNativeContent.Append($"managed.{fieldInfo.Name} ? (byte)1 : (byte)0");
|
||||||
}
|
}
|
||||||
|
else if (fieldInfo.Type.Type == "Variant")
|
||||||
|
{
|
||||||
|
// Variant passed as boxed object handle
|
||||||
|
toManagedContent.Append($"ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(managed.{fieldInfo.Name})");
|
||||||
|
toNativeContent.Append($"ManagedHandleMarshaller.NativeToManaged.ConvertToUnmanaged(managed.{fieldInfo.Name})");
|
||||||
|
}
|
||||||
else if (internalType)
|
else if (internalType)
|
||||||
{
|
{
|
||||||
toManagedContent.Append($"{internalTypeMarshaller}.ToManaged(managed.{fieldInfo.Name})");
|
toManagedContent.Append($"{internalTypeMarshaller}.ToManaged(managed.{fieldInfo.Name})");
|
||||||
@@ -1770,6 +1771,10 @@ namespace Flax.Build.Bindings
|
|||||||
// char's are not blittable, store as short instead
|
// char's are not blittable, store as short instead
|
||||||
contents.Append($"fixed short {fieldInfo.Name}0[{fieldInfo.Type.ArraySize}]; // {managedType}*").AppendLine();
|
contents.Append($"fixed short {fieldInfo.Name}0[{fieldInfo.Type.ArraySize}]; // {managedType}*").AppendLine();
|
||||||
}
|
}
|
||||||
|
else if (managedType == "byte")
|
||||||
|
{
|
||||||
|
contents.Append($"fixed byte {fieldInfo.Name}0[{fieldInfo.Type.ArraySize}]; // {managedType}*").AppendLine();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user