From ec3b921a4f494c9b2a11da9709d72bb7accce5eb Mon Sep 17 00:00:00 2001 From: Wiktor Kocielski Date: Wed, 2 Aug 2023 05:17:49 +0300 Subject: [PATCH 01/17] Fix navigation rebuilding --- Source/Engine/Navigation/NavMeshBoundsVolume.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Navigation/NavMeshBoundsVolume.cpp b/Source/Engine/Navigation/NavMeshBoundsVolume.cpp index 85a022c82..89e76a9bc 100644 --- a/Source/Engine/Navigation/NavMeshBoundsVolume.cpp +++ b/Source/Engine/Navigation/NavMeshBoundsVolume.cpp @@ -34,10 +34,10 @@ void NavMeshBoundsVolume::Deserialize(DeserializeStream& stream, ISerializeModif void NavMeshBoundsVolume::OnEnable() { + GetScene()->Navigation.Volumes.Add(this); + // Base Actor::OnEnable(); - - GetScene()->Navigation.Volumes.Add(this); } void NavMeshBoundsVolume::OnDisable() From b9ffb950f37b4ede8e2497b71fad0bfc35562615 Mon Sep 17 00:00:00 2001 From: envision3d Date: Sun, 6 Aug 2023 13:11:45 -0500 Subject: [PATCH 02/17] Refactor and more appropriately organize logic - move play logic to simulation module - update play hotkey to call play game/scene delegate function - link hotkey tooltip text to inputOptions --- Source/Editor/Editor.cs | 2 +- Source/Editor/Modules/SimulationModule.cs | 76 ++++++++++++++++++- Source/Editor/Modules/UIModule.cs | 86 ++++------------------ Source/Editor/Windows/GameWindow.cs | 2 +- Source/Editor/Windows/SceneEditorWindow.cs | 2 +- 5 files changed, 88 insertions(+), 80 deletions(-) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 1a1fd3b2d..7f0359331 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -1579,7 +1579,7 @@ namespace FlaxEditor private static void RequestStartPlayOnEditMode() { if (Instance.StateMachine.IsEditMode) - Instance.Simulation.RequestStartPlay(); + Instance.Simulation.RequestStartPlayScenes(); if (Instance.StateMachine.IsPlayMode) Instance.StateMachine.StateChanged -= RequestStartPlayOnEditMode; } diff --git a/Source/Editor/Modules/SimulationModule.cs b/Source/Editor/Modules/SimulationModule.cs index cc081c23c..97676c2eb 100644 --- a/Source/Editor/Modules/SimulationModule.cs +++ b/Source/Editor/Modules/SimulationModule.cs @@ -20,6 +20,7 @@ namespace FlaxEditor.Modules private bool _updateOrFixedUpdateWasCalled; private long _breakpointHangFlag; private EditorWindow _enterPlayFocusedWindow; + private Scene[] _scenesToReload; internal SimulationModule(Editor editor) : base(editor) @@ -68,6 +69,22 @@ namespace FlaxEditor.Modules BreakpointHangEnd?.Invoke(); } + /// + /// Delegates between playing game and playing scenes in editor based on the user's editor preference. + /// + public void DelegatePlayOrStopPlayInEditor() + { + switch (Editor.Options.Options.Interface.PlayButtonAction) + { + case Options.InterfaceOptions.PlayAction.PlayGame: + Editor.Simulation.RequestPlayGameOrStopPlay(); + return; + case Options.InterfaceOptions.PlayAction.PlayScenes: + Editor.Simulation.RequestPlayScenesOrStopPlay(); + return; + } + } + /// /// Returns true if play mode has been requested. /// @@ -76,7 +93,7 @@ namespace FlaxEditor.Modules /// /// Requests start playing in editor. /// - public void RequestStartPlay() + public void RequestStartPlayScenes() { if (Editor.StateMachine.IsEditMode) { @@ -89,6 +106,57 @@ namespace FlaxEditor.Modules } } + /// + /// Requests playing game start or stop in editor from the project's configured FirstScene. + /// + public void RequestPlayGameOrStopPlay() + { + if (Editor.StateMachine.IsPlayMode) + { + RequestStopPlay(); + } + else + { + RequestStartPlayGame(); + } + } + + /// + /// Requests start playing in editor from the project's configured FirstScene. + /// + public void RequestStartPlayGame() + { + if (!Editor.StateMachine.IsEditMode) + { + return; + } + + var firstScene = Content.Settings.GameSettings.Load().FirstScene; + if (firstScene == Guid.Empty) + { + if (Level.IsAnySceneLoaded) + Editor.Simulation.RequestStartPlayScenes(); + return; + } + + _scenesToReload = Level.Scenes; + Level.UnloadAllScenes(); + Level.LoadScene(firstScene); + + Editor.PlayModeEnd += OnPlayGameEnd; + RequestPlayScenesOrStopPlay(); + } + + private void OnPlayGameEnd() + { + Editor.PlayModeEnd -= OnPlayGameEnd; + + Level.UnloadAllScenes(); + + foreach (var scene in _scenesToReload) + Level.LoadScene(scene.ID); + } + /// /// Requests stop playing in editor. /// @@ -106,14 +174,14 @@ namespace FlaxEditor.Modules } /// - /// Requests the playing start or stop in editor. + /// Requests the playing scenes start or stop in editor. /// - public void RequestPlayOrStopPlay() + public void RequestPlayScenesOrStopPlay() { if (Editor.StateMachine.IsPlayMode) RequestStopPlay(); else - RequestStartPlay(); + RequestStartPlayScenes(); } /// diff --git a/Source/Editor/Modules/UIModule.cs b/Source/Editor/Modules/UIModule.cs index 38c61942a..08ec09de8 100644 --- a/Source/Editor/Modules/UIModule.cs +++ b/Source/Editor/Modules/UIModule.cs @@ -39,7 +39,6 @@ namespace FlaxEditor.Modules private bool _progressFailed; ContextMenuSingleSelectGroup _numberOfClientsGroup = new ContextMenuSingleSelectGroup(); - private Scene[] _scenesToReload; private ContextMenuButton _menuFileSaveScenes; private ContextMenuButton _menuFileCloseScenes; @@ -556,8 +555,8 @@ namespace FlaxEditor.Modules cm = MenuGame.ContextMenu; cm.VisibleChanged += OnMenuGameShowHide; - _menuGamePlayGame = cm.AddButton("Play Game", PlayGame); - _menuGamePlayCurrentScenes = cm.AddButton("Play Current Scenes", inputOptions.Play.ToString(), PlayScenes); + _menuGamePlayGame = cm.AddButton("Play Game", Editor.Simulation.RequestPlayGameOrStopPlay); + _menuGamePlayCurrentScenes = cm.AddButton("Play Current Scenes", Editor.Simulation.RequestPlayScenesOrStopPlay); _menuGameStop = cm.AddButton("Stop Game", Editor.Simulation.RequestStopPlay); _menuGamePause = cm.AddButton("Pause", inputOptions.Pause.ToString(), Editor.Simulation.RequestPausePlay); @@ -566,8 +565,8 @@ namespace FlaxEditor.Modules _numberOfClientsGroup.AddItemsToContextMenu(numberOfClientsMenu.ContextMenu); cm.AddSeparator(); - cm.AddButton("Cook & Run", CookAndRun).LinkTooltip("Runs Game Cooker to build the game for this platform and runs the game after."); - cm.AddButton("Run cooked game", RunCookedGame).LinkTooltip("Runs the game build from the last cooking output. Use Cook&Play or Game Cooker first."); + cm.AddButton("Cook & Run", Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip("Runs Game Cooker to build the game for this platform and runs the game after."); + cm.AddButton("Run cooked game", Editor.Windows.GameCookerWin.RunCooked).LinkTooltip("Runs the game build from the last cooking output. Use Cook&Play or Game Cooker first."); // Tools MenuTools = MainMenu.AddButton("Tools"); @@ -658,23 +657,23 @@ namespace FlaxEditor.Modules Parent = mainWindow, }; - _toolStripSaveAll = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Save64, Editor.SaveAll).LinkTooltip("Save all (Ctrl+S)"); + _toolStripSaveAll = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Save64, Editor.SaveAll).LinkTooltip($"Save all ({inputOptions.Save})"); ToolStrip.AddSeparator(); - _toolStripUndo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Undo64, Editor.PerformUndo).LinkTooltip("Undo (Ctrl+Z)"); - _toolStripRedo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Redo64, Editor.PerformRedo).LinkTooltip("Redo (Ctrl+Y)"); + _toolStripUndo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Undo64, Editor.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})"); + _toolStripRedo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Redo64, Editor.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})"); ToolStrip.AddSeparator(); - _toolStripTranslate = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Translate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate).LinkTooltip("Change Gizmo tool mode to Translate (1)"); - _toolStripRotate = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Rotate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate).LinkTooltip("Change Gizmo tool mode to Rotate (2)"); - _toolStripScale = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Scale32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale).LinkTooltip("Change Gizmo tool mode to Scale (3)"); + _toolStripTranslate = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Translate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate).LinkTooltip($"Change Gizmo tool mode to Translate ({inputOptions.TranslateMode})"); + _toolStripRotate = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Rotate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate).LinkTooltip($"Change Gizmo tool mode to Rotate ({inputOptions.RotateMode})"); + _toolStripScale = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Scale32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale).LinkTooltip($"Change Gizmo tool mode to Scale ({inputOptions.ScaleMode})"); ToolStrip.AddSeparator(); // Cook scenes _toolStripBuildScenes = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Build64, Editor.BuildScenesOrCancel).LinkTooltip("Build scenes data - CSG, navmesh, static lighting, env probes - configurable via Build Actions in editor options (Ctrl+F10)"); // Cook and run - _toolStripCook = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.ShipIt64, CookAndRun).LinkTooltip("Cook & Run - build game for the current platform and run it locally"); + _toolStripCook = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.ShipIt64, Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip("Cook & Run - build game for the current platform and run it locally"); _toolStripCook.ContextMenu = new ContextMenu(); - _toolStripCook.ContextMenu.AddButton("Run cooked game", RunCookedGame); + _toolStripCook.ContextMenu.AddButton("Run cooked game", Editor.Windows.GameCookerWin.RunCooked); _toolStripCook.ContextMenu.AddSeparator(); var numberOfClientsMenu = _toolStripCook.ContextMenu.AddChildMenu("Number of game clients"); _numberOfClientsGroup.AddItemsToContextMenu(numberOfClientsMenu.ContextMenu); @@ -682,7 +681,7 @@ namespace FlaxEditor.Modules ToolStrip.AddSeparator(); // Play - _toolStripPlay = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Play64, OnPlayPressed).LinkTooltip("Play Game"); + _toolStripPlay = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Play64, Editor.Simulation.DelegatePlayOrStopPlayInEditor).LinkTooltip($"Play In Editor ({inputOptions.Play})"); _toolStripPlay.ContextMenu = new ContextMenu(); var playSubMenu = _toolStripPlay.ContextMenu.AddChildMenu("Play button action"); var playActionGroup = new ContextMenuSingleSelectGroup(); @@ -1039,65 +1038,6 @@ namespace FlaxEditor.Modules Editor.Options.Apply(options); } - private void OnPlayPressed() - { - switch (Editor.Options.Options.Interface.PlayButtonAction) - { - case InterfaceOptions.PlayAction.PlayGame: - if (Editor.IsPlayMode) - Editor.Simulation.RequestStopPlay(); - else - PlayGame(); - return; - case InterfaceOptions.PlayAction.PlayScenes: - PlayScenes(); - return; - } - } - - private void PlayGame() - { - var firstScene = GameSettings.Load().FirstScene; - if (firstScene == Guid.Empty) - { - if (Level.IsAnySceneLoaded) - Editor.Simulation.RequestStartPlay(); - return; - } - - _scenesToReload = Level.Scenes; - Level.UnloadAllScenes(); - Level.LoadScene(firstScene); - - Editor.PlayModeEnd += OnPlayGameSceneEnding; - Editor.Simulation.RequestPlayOrStopPlay(); - } - - private void OnPlayGameSceneEnding() - { - Editor.PlayModeEnd -= OnPlayGameSceneEnding; - - Level.UnloadAllScenes(); - - foreach (var scene in _scenesToReload) - Level.LoadScene(scene.ID); - } - - private void PlayScenes() - { - Editor.Simulation.RequestPlayOrStopPlay(); - } - - private void CookAndRun() - { - Editor.Windows.GameCookerWin.BuildAndRun(); - } - - private void RunCookedGame() - { - Editor.Windows.GameCookerWin.RunCooked(); - } - private void OnMainWindowClosing() { // Clear UI references (GUI cannot be used after window closing) diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs index 46c0f33f4..513542fdc 100644 --- a/Source/Editor/Windows/GameWindow.cs +++ b/Source/Editor/Windows/GameWindow.cs @@ -303,7 +303,7 @@ namespace FlaxEditor.Windows Editor.Options.OptionsChanged += OnOptionsChanged; OnOptionsChanged(Editor.Options.Options); - InputActions.Add(options => options.Play, Editor.Simulation.RequestPlayOrStopPlay); + InputActions.Add(options => options.Play, Editor.Simulation.DelegatePlayOrStopPlayInEditor); InputActions.Add(options => options.Pause, Editor.Simulation.RequestResumeOrPause); InputActions.Add(options => options.StepFrame, Editor.Simulation.RequestPlayOneFrame); } diff --git a/Source/Editor/Windows/SceneEditorWindow.cs b/Source/Editor/Windows/SceneEditorWindow.cs index f55ff4ee4..72ff3be33 100644 --- a/Source/Editor/Windows/SceneEditorWindow.cs +++ b/Source/Editor/Windows/SceneEditorWindow.cs @@ -38,7 +38,7 @@ namespace FlaxEditor.Windows InputActions.Add(options => options.SelectAll, Editor.SceneEditing.SelectAllScenes); InputActions.Add(options => options.Delete, Editor.SceneEditing.Delete); InputActions.Add(options => options.Search, () => Editor.Windows.SceneWin.Search()); - InputActions.Add(options => options.Play, Editor.Simulation.RequestPlayOrStopPlay); + InputActions.Add(options => options.Play, Editor.Simulation.DelegatePlayOrStopPlayInEditor); InputActions.Add(options => options.Pause, Editor.Simulation.RequestResumeOrPause); InputActions.Add(options => options.StepFrame, Editor.Simulation.RequestPlayOneFrame); } From aa3dd14bfcdcdd1e1f698d0cbcd345b95872aae6 Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Thu, 10 Aug 2023 22:24:55 -0400 Subject: [PATCH 03/17] add locked focus --- Source/Editor/Options/InputOptions.cs | 4 ++ .../Viewport/MainEditorGizmoViewport.cs | 46 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs index 4f2b40514..225f79b83 100644 --- a/Source/Editor/Options/InputOptions.cs +++ b/Source/Editor/Options/InputOptions.cs @@ -60,6 +60,10 @@ namespace FlaxEditor.Options [EditorDisplay("Common"), EditorOrder(200)] public InputBinding FocusSelection = new InputBinding(KeyboardKeys.F); + [DefaultValue(typeof(InputBinding), "F")] + [EditorDisplay("Common"), EditorOrder(200)] + public InputBinding LockFocusSelection = new InputBinding(KeyboardKeys.F, KeyboardKeys.Shift); + [DefaultValue(typeof(InputBinding), "Ctrl+F")] [EditorDisplay("Common"), EditorOrder(210)] public InputBinding Search = new InputBinding(KeyboardKeys.F, KeyboardKeys.Control); diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index 48cd4fd98..78e5cbf56 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -133,6 +133,7 @@ namespace FlaxEditor.Viewport } } + private bool _lockedFocus; private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32); private StaticModel _previewStaticModel; private int _previewModelEntryIndex; @@ -386,11 +387,40 @@ namespace FlaxEditor.Viewport InputActions.Add(options => options.TranslateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate); InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate); InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale); + + InputActions.Add(options => options.LockFocusSelection, LockFocusSelection); InputActions.Add(options => options.FocusSelection, FocusSelection); InputActions.Add(options => options.RotateSelection, RotateSelection); InputActions.Add(options => options.Delete, _editor.SceneEditing.Delete); } + public override void Update(float deltaTime) + { + base.Update(deltaTime); + + var hasSelections = TransformGizmo.SelectedParents.Count != 0; + var requestUnlockFocus = FlaxEngine.Input.Mouse.GetButtonDown(MouseButton.Right) || FlaxEngine.Input.Mouse.GetButtonDown(MouseButton.Left); + + if ((IsFocused && requestUnlockFocus) || !hasSelections) + { + UnlockFocusSelection(); + } + + if (_lockedFocus) + { + BoundingSphere selectionBounds = BoundingSphere.Empty; + for (int i = 0; i < TransformGizmo.SelectedParents.Count; i++) + { + TransformGizmo.SelectedParents[i].GetEditorSphere(out var sphere); + BoundingSphere.Merge(ref selectionBounds, ref sphere, out selectionBounds); + } + + var focusDistance = Mathf.Max(selectionBounds.Radius * 2f, 100f); + var viewportPosition = selectionBounds.Center + (-ViewDirection * focusDistance); + ViewPosition = viewportPosition; + } + } + /// /// Overrides the selection outline effect or restored the default one. /// @@ -753,6 +783,22 @@ namespace FlaxEditor.Viewport FocusSelection(ref orientation); } + /// + /// Lock focus on the current selection gizmo. + /// + public void LockFocusSelection() + { + _lockedFocus = true; + } + + /// + /// Unlock focus on the current selection. + /// + public void UnlockFocusSelection() + { + _lockedFocus = false; + } + /// /// Focuses the viewport on the current selection of the gizmo. /// From f2072028d4e5a488296784f14d1ca7dee6d8775e Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Thu, 10 Aug 2023 22:31:03 -0400 Subject: [PATCH 04/17] change default key --- Source/Editor/Options/InputOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs index 225f79b83..e0a51622b 100644 --- a/Source/Editor/Options/InputOptions.cs +++ b/Source/Editor/Options/InputOptions.cs @@ -60,7 +60,7 @@ namespace FlaxEditor.Options [EditorDisplay("Common"), EditorOrder(200)] public InputBinding FocusSelection = new InputBinding(KeyboardKeys.F); - [DefaultValue(typeof(InputBinding), "F")] + [DefaultValue(typeof(InputBinding), "Shift+F")] [EditorDisplay("Common"), EditorOrder(200)] public InputBinding LockFocusSelection = new InputBinding(KeyboardKeys.F, KeyboardKeys.Shift); From 645977f14824623b409601cfd6d96c127e4bc339 Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Thu, 10 Aug 2023 22:41:48 -0400 Subject: [PATCH 05/17] add scroll to focus --- Source/Editor/Viewport/MainEditorGizmoViewport.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index 78e5cbf56..90a5b8f22 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -134,6 +134,7 @@ namespace FlaxEditor.Viewport } private bool _lockedFocus; + private float _lockedFocusOffset; private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32); private StaticModel _previewStaticModel; private int _previewModelEntryIndex; @@ -408,7 +409,7 @@ namespace FlaxEditor.Viewport if (_lockedFocus) { - BoundingSphere selectionBounds = BoundingSphere.Empty; + var selectionBounds = BoundingSphere.Empty; for (int i = 0; i < TransformGizmo.SelectedParents.Count; i++) { TransformGizmo.SelectedParents[i].GetEditorSphere(out var sphere); @@ -416,7 +417,14 @@ namespace FlaxEditor.Viewport } var focusDistance = Mathf.Max(selectionBounds.Radius * 2f, 100f); - var viewportPosition = selectionBounds.Center + (-ViewDirection * focusDistance); + + if (IsFocused) + { + _lockedFocusOffset += -FlaxEngine.Input.Mouse.ScrollDelta * focusDistance; + } + + var viewportPosition = selectionBounds.Center + (-ViewDirection * (focusDistance + _lockedFocusOffset)); + ViewPosition = viewportPosition; } } @@ -797,6 +805,7 @@ namespace FlaxEditor.Viewport public void UnlockFocusSelection() { _lockedFocus = false; + _lockedFocusOffset = 0f; } /// From db806ad500a9c07cdd318654d0f76b26f58b4c76 Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Fri, 11 Aug 2023 08:28:28 -0400 Subject: [PATCH 06/17] fix for large worlds --- Source/Editor/Viewport/MainEditorGizmoViewport.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index 90a5b8f22..a40ff5369 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -134,7 +134,7 @@ namespace FlaxEditor.Viewport } private bool _lockedFocus; - private float _lockedFocusOffset; + private double _lockedFocusOffset; private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32); private StaticModel _previewStaticModel; private int _previewModelEntryIndex; @@ -416,7 +416,7 @@ namespace FlaxEditor.Viewport BoundingSphere.Merge(ref selectionBounds, ref sphere, out selectionBounds); } - var focusDistance = Mathf.Max(selectionBounds.Radius * 2f, 100f); + var focusDistance = Mathf.Max(selectionBounds.Radius * 2d, 100d); if (IsFocused) { From be33fc6018fb4241f7848b876e3bed8efff2c173 Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Fri, 11 Aug 2023 22:31:12 -0400 Subject: [PATCH 07/17] improv scroll locked focus --- Source/Editor/Viewport/MainEditorGizmoViewport.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index a40ff5369..3132faf39 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -420,7 +420,8 @@ namespace FlaxEditor.Viewport if (IsFocused) { - _lockedFocusOffset += -FlaxEngine.Input.Mouse.ScrollDelta * focusDistance; + var viewportFocusDistance = Vector3.Distance(ViewPosition, selectionBounds.Center) / 10f; + _lockedFocusOffset -= FlaxEngine.Input.Mouse.ScrollDelta * viewportFocusDistance; } var viewportPosition = selectionBounds.Center + (-ViewDirection * (focusDistance + _lockedFocusOffset)); From 1413da189ea391ba386dd70c6ead668121cbe3d1 Mon Sep 17 00:00:00 2001 From: Wiktor Kocielski Date: Sun, 13 Aug 2023 06:39:35 +0300 Subject: [PATCH 08/17] NetworkReplicator::ResolveForeignObject --- Source/Engine/Networking/NetworkReplicator.cpp | 7 +++++++ Source/Engine/Networking/NetworkReplicator.h | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index 279391e31..f63543126 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -941,6 +941,13 @@ bool NetworkReplicator::HasObject(const ScriptingObject* obj) return false; } +ScriptingObject* NetworkReplicator::ResolveForeignObject(Guid objectId) +{ + if (const auto& object = ResolveObject(objectId)) + return object->Object.Get(); + return nullptr; +} + uint32 NetworkReplicator::GetObjectOwnerClientId(const ScriptingObject* obj) { uint32 id = NetworkManager::ServerClientId; diff --git a/Source/Engine/Networking/NetworkReplicator.h b/Source/Engine/Networking/NetworkReplicator.h index ecccc52cd..3806f8c9d 100644 --- a/Source/Engine/Networking/NetworkReplicator.h +++ b/Source/Engine/Networking/NetworkReplicator.h @@ -116,6 +116,13 @@ public: /// The network object. /// True if object exists in networking, otherwise false. API_FUNCTION() static bool HasObject(const ScriptingObject* obj); + + /// + /// Resolves foreign Guid into a local ScriptingObject + /// + /// The Guid of a foreign object. + /// Object if managed to resolve, otherwise null. + API_FUNCTION() static ScriptingObject* ResolveForeignObject(Guid objectId); /// /// Gets the Client Id of the network object owner. From 0008123e7638b7a7bc3bcba60ad6383be418546f Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Fri, 4 Aug 2023 21:37:38 +0300 Subject: [PATCH 09/17] Cache ManagedDictionary types and helper method thunks --- .../Scripting/Internal/ManagedDictionary.cpp | 14 ++ .../Scripting/Internal/ManagedDictionary.h | 140 +++++++++++++++--- 2 files changed, 130 insertions(+), 24 deletions(-) create mode 100644 Source/Engine/Scripting/Internal/ManagedDictionary.cpp diff --git a/Source/Engine/Scripting/Internal/ManagedDictionary.cpp b/Source/Engine/Scripting/Internal/ManagedDictionary.cpp new file mode 100644 index 000000000..7cb4d1cfb --- /dev/null +++ b/Source/Engine/Scripting/Internal/ManagedDictionary.cpp @@ -0,0 +1,14 @@ +#include "ManagedDictionary.h" + +Dictionary ManagedDictionary::CachedDictionaryTypes; +#if !USE_MONO_AOT +ManagedDictionary::MakeGenericTypeThunk ManagedDictionary::MakeGenericType; +ManagedDictionary::CreateInstanceThunk ManagedDictionary::CreateInstance; +ManagedDictionary::AddDictionaryItemThunk ManagedDictionary::AddDictionaryItem; +ManagedDictionary::GetDictionaryKeysThunk ManagedDictionary::GetDictionaryKeys; +#else +MMethod* ManagedDictionary::MakeGenericType; +MMethod* ManagedDictionary::CreateInstance; +MMethod* ManagedDictionary::AddDictionaryItem; +MMethod* ManagedDictionary::GetDictionaryKeys; +#endif diff --git a/Source/Engine/Scripting/Internal/ManagedDictionary.h b/Source/Engine/Scripting/Internal/ManagedDictionary.h index c42eb1d27..f957dfcec 100644 --- a/Source/Engine/Scripting/Internal/ManagedDictionary.h +++ b/Source/Engine/Scripting/Internal/ManagedDictionary.h @@ -12,17 +12,96 @@ #include "Engine/Scripting/ManagedCLR/MAssembly.h" #include "Engine/Scripting/ManagedCLR/MException.h" #include "Engine/Scripting/Internal/StdTypesContainer.h" +#include "Engine/Core/Collections/Dictionary.h" /// /// Utility interop between C++ and C# for Dictionary collection. /// struct FLAXENGINE_API ManagedDictionary { +public: + struct KeyValueType + { + MType* keyType; + MType* valueType; + + bool operator==(const KeyValueType& other) const + { + return keyType == other.keyType && valueType == other.valueType; + } + }; + +private: + static Dictionary CachedDictionaryTypes; + +#if !USE_MONO_AOT + typedef MTypeObject* (*MakeGenericTypeThunk)(MObject* instance, MTypeObject* genericType, MArray* genericArgs, MObject** exception); + static MakeGenericTypeThunk MakeGenericType; + + typedef MObject* (*CreateInstanceThunk)(MObject* instance, MTypeObject* type, void* arr, MObject** exception); + static CreateInstanceThunk CreateInstance; + + typedef void (*AddDictionaryItemThunk)(MObject* instance, MObject* dictionary, MObject* key, MObject* value, MObject** exception); + static AddDictionaryItemThunk AddDictionaryItem; + + typedef MArray* (*GetDictionaryKeysThunk)(MObject* instance, MObject* dictionary, MObject** exception); + static GetDictionaryKeysThunk GetDictionaryKeys; +#else + static MMethod* MakeGenericType; + static MMethod* CreateInstance; + static MMethod* AddDictionaryItem; + static MMethod* GetDictionaryKeys; +#endif + +public: MObject* Instance; ManagedDictionary(MObject* instance = nullptr) { Instance = instance; + +#if !USE_MONO_AOT + // Cache the thunks of the dictionary helper methods + if (MakeGenericType == nullptr) + { + MClass* scriptingClass = Scripting::GetStaticClass(); + CHECK(scriptingClass); + + MMethod* makeGenericTypeMethod = scriptingClass->GetMethod("MakeGenericType", 2); + CHECK(makeGenericTypeMethod); + MakeGenericType = (MakeGenericTypeThunk)makeGenericTypeMethod->GetThunk(); + + MMethod* createInstanceMethod = StdTypesContainer::Instance()->ActivatorClass->GetMethod("CreateInstance", 2); + CHECK(createInstanceMethod); + CreateInstance = (CreateInstanceThunk)createInstanceMethod->GetThunk(); + + MMethod* addDictionaryItemMethod = scriptingClass->GetMethod("AddDictionaryItem", 3); + CHECK(addDictionaryItemMethod); + AddDictionaryItem = (AddDictionaryItemThunk)addDictionaryItemMethod->GetThunk(); + + MMethod* getDictionaryKeysItemMethod = scriptingClass->GetMethod("GetDictionaryKeys", 1); + CHECK(getDictionaryKeysItemMethod); + GetDictionaryKeys = (GetDictionaryKeysThunk)getDictionaryKeysItemMethod->GetThunk(); + } +#else + if (MakeGenericType == nullptr) + { + MClass* scriptingClass = Scripting::GetStaticClass(); + CHECK(scriptingClass); + + MakeGenericType = scriptingClass->GetMethod("MakeGenericType", 2); + CHECK(MakeGenericType); + + CreateInstance = StdTypesContainer::Instance()->ActivatorClass->GetMethod("CreateInstance", 2); + CHECK(CreateInstance); + + AddDictionaryItem = scriptingClass->GetMethod("AddDictionaryItem", 3); + CHECK(AddDictionaryItem); + + GetDictionaryKeys = scriptingClass->GetMethod("GetDictionaryKeys", 1); + CHECK(GetDictionaryKeys); + } +#endif } template @@ -76,10 +155,11 @@ struct FLAXENGINE_API ManagedDictionary static MTypeObject* GetClass(MType* keyType, MType* valueType) { - MClass* scriptingClass = Scripting::GetStaticClass(); - CHECK_RETURN(scriptingClass, nullptr); - MMethod* makeGenericMethod = scriptingClass->GetMethod("MakeGenericType", 2); - CHECK_RETURN(makeGenericMethod, nullptr); + // Check if the generic type was generated earlier + KeyValueType cacheKey = { keyType, valueType }; + MTypeObject* dictionaryType; + if (CachedDictionaryTypes.TryGet(cacheKey, dictionaryType)) + return dictionaryType; MTypeObject* genericType = MUtils::GetType(StdTypesContainer::Instance()->DictionaryClass); #if USE_NETCORE @@ -91,18 +171,23 @@ struct FLAXENGINE_API ManagedDictionary genericArgsPtr[0] = INTERNAL_TYPE_GET_OBJECT(keyType); genericArgsPtr[1] = INTERNAL_TYPE_GET_OBJECT(valueType); + MObject* exception = nullptr; +#if !USE_MONO_AOT + dictionaryType = MakeGenericType(nullptr, genericType, genericArgs, &exception); +#else void* params[2]; params[0] = genericType; params[1] = genericArgs; - MObject* exception = nullptr; - MObject* dictionaryType = makeGenericMethod->Invoke(nullptr, params, &exception); + dictionaryType = (MTypeObject*)MakeGenericType->Invoke(nullptr, params, &exception); +#endif if (exception) { MException ex(exception); ex.Log(LogType::Error, TEXT("")); return nullptr; } - return (MTypeObject*)dictionaryType; + CachedDictionaryTypes.Add(cacheKey, dictionaryType); + return dictionaryType; } static ManagedDictionary New(MType* keyType, MType* valueType) @@ -112,16 +197,15 @@ struct FLAXENGINE_API ManagedDictionary if (!dictionaryType) return result; - MClass* scriptingClass = Scripting::GetStaticClass(); - CHECK_RETURN(scriptingClass, result); - MMethod* createMethod = StdTypesContainer::Instance()->ActivatorClass->GetMethod("CreateInstance", 2); - CHECK_RETURN(createMethod, result); - MObject* exception = nullptr; +#if !USE_MONO_AOT + MObject* instance = CreateInstance(nullptr, dictionaryType, nullptr, &exception); +#else void* params[2]; params[0] = dictionaryType; params[1] = nullptr; - MObject* instance = createMethod->Invoke(nullptr, params, &exception); + MObject* instance = CreateInstance->Invoke(nullptr, params, &exception); +#endif if (exception) { MException ex(exception); @@ -136,16 +220,17 @@ struct FLAXENGINE_API ManagedDictionary void Add(MObject* key, MObject* value) { CHECK(Instance); - MClass* scriptingClass = Scripting::GetStaticClass(); - CHECK(scriptingClass); - MMethod* addDictionaryItemMethod = scriptingClass->GetMethod("AddDictionaryItem", 3); - CHECK(addDictionaryItemMethod); + + MObject* exception = nullptr; +#if !USE_MONO_AOT + AddDictionaryItem(nullptr, Instance, key, value, &exception); +#else void* params[3]; params[0] = Instance; params[1] = key; params[2] = value; - MObject* exception = nullptr; - addDictionaryItemMethod->Invoke(Instance, params, &exception); + AddDictionaryItem->Invoke(Instance, params, &exception); +#endif if (exception) { MException ex(exception); @@ -156,13 +241,13 @@ struct FLAXENGINE_API ManagedDictionary MArray* GetKeys() const { CHECK_RETURN(Instance, nullptr); - MClass* scriptingClass = Scripting::GetStaticClass(); - CHECK_RETURN(scriptingClass, nullptr); - MMethod* getDictionaryKeysMethod = scriptingClass->GetMethod("GetDictionaryKeys", 1); - CHECK_RETURN(getDictionaryKeysMethod, nullptr); +#if !USE_MONO_AOT + return GetDictionaryKeys(nullptr, Instance, nullptr); +#else void* params[1]; params[0] = Instance; - return (MArray*)getDictionaryKeysMethod->Invoke( nullptr, params, nullptr); + return (MArray*)GetDictionaryKeys->Invoke(nullptr, params, nullptr); +#endif } MObject* GetValue(MObject* key) const @@ -177,4 +262,11 @@ struct FLAXENGINE_API ManagedDictionary } }; +inline uint32 GetHash(const ManagedDictionary::KeyValueType& other) +{ + uint32 hash = ::GetHash((void*)other.keyType); + CombineHash(hash, ::GetHash((void*)other.valueType)); + return hash; +} + #endif From 1948a84301099ba73c910e03434f5e3149dff6e8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 14 Aug 2023 18:40:03 +0200 Subject: [PATCH 10/17] Add crash to soft-return if managed event bind target object native instance is gone #1278 --- Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index d69b8dcbf..da94a0056 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -1116,7 +1116,7 @@ namespace Flax.Build.Bindings var signatureEnd = contents.Length; if (useSeparateImpl) { - // Write declarion only, function definition wil be put in the end of the file + // Write declaration only, function definition wil be put in the end of the file CppContentsEnd.AppendFormat("{0} {2}::{1}(", returnValueType, functionInfo.UniqueName, callerName); CppContentsEnd.Append(contents.ToString(signatureStart, signatureEnd - signatureStart)); contents.Append(';').AppendLine(); @@ -2016,7 +2016,7 @@ namespace Flax.Build.Bindings var indent = " "; if (useSeparateImpl) { - // Write declarion only, function definition wil be put in the end of the file + // Write declaration only, function definition wil be put in the end of the file CppContentsEnd.AppendFormat("void {1}::{0}_ManagedBind(", eventInfo.Name, internalTypeName); var sig = contents.ToString(signatureStart, contents.Length - signatureStart); CppContentsEnd.Append(contents.ToString(signatureStart, contents.Length - signatureStart)); @@ -2027,6 +2027,8 @@ namespace Flax.Build.Bindings contents.AppendLine().Append(indent).Append('{').AppendLine(); if (buildData.Toolchain?.Compiler == TargetCompiler.MSVC) contents.Append(indent).AppendLine($" MSVC_FUNC_EXPORT(\"{classTypeNameManaged}::Internal_{eventInfo.Name}_Bind\")"); // Export generated function binding under the C# name + if (!eventInfo.IsStatic) + contents.Append(indent).Append(" if (__obj == nullptr) return;").AppendLine(); contents.Append(indent).Append(" Function Date: Mon, 14 Aug 2023 18:44:21 +0200 Subject: [PATCH 11/17] Codestyle fix --- Source/Editor/Modules/SimulationModule.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Editor/Modules/SimulationModule.cs b/Source/Editor/Modules/SimulationModule.cs index 97676c2eb..72b197123 100644 --- a/Source/Editor/Modules/SimulationModule.cs +++ b/Source/Editor/Modules/SimulationModule.cs @@ -76,12 +76,12 @@ namespace FlaxEditor.Modules { switch (Editor.Options.Options.Interface.PlayButtonAction) { - case Options.InterfaceOptions.PlayAction.PlayGame: - Editor.Simulation.RequestPlayGameOrStopPlay(); - return; - case Options.InterfaceOptions.PlayAction.PlayScenes: - Editor.Simulation.RequestPlayScenesOrStopPlay(); - return; + case Options.InterfaceOptions.PlayAction.PlayGame: + Editor.Simulation.RequestPlayGameOrStopPlay(); + return; + case Options.InterfaceOptions.PlayAction.PlayScenes: + Editor.Simulation.RequestPlayScenesOrStopPlay(); + return; } } From 95fdcf01bea08b91eed198c22f396576ed58ece1 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 14 Aug 2023 18:53:11 +0200 Subject: [PATCH 12/17] Codestyle fix --- .../Viewport/MainEditorGizmoViewport.cs | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index 3132faf39..8d7039dc6 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -388,45 +388,40 @@ namespace FlaxEditor.Viewport InputActions.Add(options => options.TranslateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate); InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate); InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale); - InputActions.Add(options => options.LockFocusSelection, LockFocusSelection); InputActions.Add(options => options.FocusSelection, FocusSelection); InputActions.Add(options => options.RotateSelection, RotateSelection); InputActions.Add(options => options.Delete, _editor.SceneEditing.Delete); } + /// public override void Update(float deltaTime) { base.Update(deltaTime); - var hasSelections = TransformGizmo.SelectedParents.Count != 0; + var selection = TransformGizmo.SelectedParents; var requestUnlockFocus = FlaxEngine.Input.Mouse.GetButtonDown(MouseButton.Right) || FlaxEngine.Input.Mouse.GetButtonDown(MouseButton.Left); - - if ((IsFocused && requestUnlockFocus) || !hasSelections) + if (TransformGizmo.SelectedParents.Count == 0 || (requestUnlockFocus && ContainsFocus)) { UnlockFocusSelection(); } - - if (_lockedFocus) + else if (_lockedFocus) { var selectionBounds = BoundingSphere.Empty; - for (int i = 0; i < TransformGizmo.SelectedParents.Count; i++) + for (int i = 0; i < selection.Count; i++) { - TransformGizmo.SelectedParents[i].GetEditorSphere(out var sphere); + selection[i].GetEditorSphere(out var sphere); BoundingSphere.Merge(ref selectionBounds, ref sphere, out selectionBounds); } - var focusDistance = Mathf.Max(selectionBounds.Radius * 2d, 100d); - - if (IsFocused) + if (ContainsFocus) { var viewportFocusDistance = Vector3.Distance(ViewPosition, selectionBounds.Center) / 10f; _lockedFocusOffset -= FlaxEngine.Input.Mouse.ScrollDelta * viewportFocusDistance; } - var viewportPosition = selectionBounds.Center + (-ViewDirection * (focusDistance + _lockedFocusOffset)); - - ViewPosition = viewportPosition; + var focusDistance = Mathf.Max(selectionBounds.Radius * 2d, 100d); + ViewPosition = selectionBounds.Center + (-ViewDirection * (focusDistance + _lockedFocusOffset)); } } From 3e33c63957dfadf614d8f0e9e2a709e474cf3800 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Wed, 16 Aug 2023 20:23:08 +0300 Subject: [PATCH 13/17] Optimize actor pasting performance with huge amount of actors - Name lookups are cached to avoid checking the name from same Actor multiple times - Avoid getting actor children multiple times for same parent --- .../Editor/Undo/Actions/PasteActorsAction.cs | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/Source/Editor/Undo/Actions/PasteActorsAction.cs b/Source/Editor/Undo/Actions/PasteActorsAction.cs index c90e94189..8b0d040d8 100644 --- a/Source/Editor/Undo/Actions/PasteActorsAction.cs +++ b/Source/Editor/Undo/Actions/PasteActorsAction.cs @@ -138,6 +138,8 @@ namespace FlaxEditor.Actions } } + // Store previously looked up names and the results + Dictionary foundNamesResults = new(); for (int i = 0; i < nodeParents.Count; i++) { var node = nodeParents[i]; @@ -145,15 +147,28 @@ namespace FlaxEditor.Actions var parent = actor?.Parent; if (parent != null) { + bool IsNameValid(string name) + { + if (!foundNamesResults.TryGetValue(name, out bool found)) + { + found = parent.GetChild(name) != null; + foundNamesResults.Add(name, found); + } + return !found; + } + // Fix name collisions var name = actor.Name; - for (int j = 0; j < parent.ChildrenCount; j++) + var children = parent.Children; + for (int j = 0; j < children.Length; j++) { - var child = parent.Children[j]; - if (child != actor && child.Name == actor.Name) + var child = children[j]; + if (child != actor && child.Name == name) { - var children = parent.Children; - actor.Name = Utilities.Utils.IncrementNameNumber(name, x => children.All(y => y.Name != x)); + string newName = Utilities.Utils.IncrementNameNumber(name, x => IsNameValid(x)); + foundNamesResults[newName] = true; + actor.Name = newName; + // Multiple actors may have the same name, continue } } } @@ -162,10 +177,7 @@ namespace FlaxEditor.Actions } for (int i = 0; i < nodeParents.Count; i++) - { - var node = nodeParents[i]; - node.PostPaste(); - } + nodeParents[i].PostPaste(); } /// From b78db755ec1b807abaeafad1a5ca394dc722e040 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 17 Aug 2023 21:40:36 +0200 Subject: [PATCH 14/17] Fix crash regression d9ee8f46654767809e03c332e1fd4c300e538c73 #1318 --- Source/Engine/Engine/NativeInterop.Marshallers.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.Marshallers.cs b/Source/Engine/Engine/NativeInterop.Marshallers.cs index 0f7d238bc..3ea8a5faa 100644 --- a/Source/Engine/Engine/NativeInterop.Marshallers.cs +++ b/Source/Engine/Engine/NativeInterop.Marshallers.cs @@ -395,18 +395,17 @@ namespace FlaxEngine.Interop { if (managed is null) return; - sourceArray = managed; (managedHandle, managedArray) = ManagedArray.AllocatePooledArray(managed.Length); } public ReadOnlySpan GetManagedValuesSource() => sourceArray; - public Span GetUnmanagedValuesDestination() => managedArray.ToSpan(); + public Span GetUnmanagedValuesDestination() => managedArray != null ? managedArray.ToSpan() : Span.Empty; public TUnmanagedElement* ToUnmanaged() => (TUnmanagedElement*)ManagedHandle.ToIntPtr(managedHandle); - public void Free() => managedArray.FreePooled(); + public void Free() => managedArray?.FreePooled(); } #if FLAX_EDITOR From 925b5abb78695b4587f8b1a030a23ff301809152 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 17 Aug 2023 21:47:02 +0200 Subject: [PATCH 15/17] Fix crash on Linux when using unmapped keyboard Keyboard #1321 --- Source/Engine/Input/Input.cpp | 4 ++++ Source/Engine/Platform/Linux/LinuxPlatform.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Source/Engine/Input/Input.cpp b/Source/Engine/Input/Input.cpp index 22969c752..81411ed76 100644 --- a/Source/Engine/Input/Input.cpp +++ b/Source/Engine/Input/Input.cpp @@ -333,6 +333,8 @@ void Keyboard::OnCharInput(Char c, Window* target) void Keyboard::OnKeyUp(KeyboardKeys key, Window* target) { + if (key >= KeyboardKeys::MAX) + return; Event& e = _queue.AddOne(); e.Type = EventType::KeyUp; e.Target = target; @@ -341,6 +343,8 @@ void Keyboard::OnKeyUp(KeyboardKeys key, Window* target) void Keyboard::OnKeyDown(KeyboardKeys key, Window* target) { + if (key >= KeyboardKeys::MAX) + return; Event& e = _queue.AddOne(); e.Type = EventType::KeyDown; e.Target = target; diff --git a/Source/Engine/Platform/Linux/LinuxPlatform.cpp b/Source/Engine/Platform/Linux/LinuxPlatform.cpp index 0434d8414..5a74d8f68 100644 --- a/Source/Engine/Platform/Linux/LinuxPlatform.cpp +++ b/Source/Engine/Platform/Linux/LinuxPlatform.cpp @@ -2206,6 +2206,10 @@ bool LinuxPlatform::Init() KeyCodeMap[keyCode] = key; } } + else + { + KeyCodeMap[keyCode] = KeyboardKeys::None; + } } Input::Mouse = Impl::Mouse = New(); From 595bb2b7fa55525658b8b5251c88baf061c2d34a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 18 Aug 2023 00:17:27 +0200 Subject: [PATCH 16/17] Fix nested animation playrate when the framerate is different #1258 --- Source/Engine/Animations/Graph/AnimGroup.Animation.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index 82842376e..73ddbc41c 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -233,11 +233,10 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode* // Get nested animation time position float nestedAnimPrevPos = animPrevPos - nestedAnim.Time; const float nestedAnimLength = nestedAnim.Anim->GetLength(); - const float nestedAnimDuration = nestedAnim.Anim->GetDuration(); const float nestedAnimSpeed = nestedAnim.Speed * speed; - const float frameRateMatchScale = (float)nestedAnim.Anim->Data.FramesPerSecond / (float)anim->Data.FramesPerSecond; - nestedAnimPos = nestedAnimPos / nestedAnimDuration * nestedAnimSpeed * frameRateMatchScale; - nestedAnimPrevPos = nestedAnimPrevPos / nestedAnimDuration * nestedAnimSpeed * frameRateMatchScale; + const float frameRateMatchScale = nestedAnimSpeed / (float)anim->Data.FramesPerSecond; + nestedAnimPos = nestedAnimPos * frameRateMatchScale; + nestedAnimPrevPos = nestedAnimPrevPos * frameRateMatchScale; GetAnimSamplePos(nestedAnim.Loop, nestedAnimLength, nestedAnim.StartTime, nestedAnimPrevPos, nestedAnimPos, nestedAnimPos, nestedAnimPrevPos); ProcessAnimation(nodes, node, true, nestedAnimLength, nestedAnimPos, nestedAnimPrevPos, nestedAnim.Anim, 1.0f, weight, mode); From 122524bd1965345c3421aea42c3c2131dc790256 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 18 Aug 2023 09:12:10 +0200 Subject: [PATCH 17/17] Fix linux build --- Source/Engine/Platform/Linux/LinuxPlatform.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Source/Engine/Platform/Linux/LinuxPlatform.cpp b/Source/Engine/Platform/Linux/LinuxPlatform.cpp index 5a74d8f68..ab314ab72 100644 --- a/Source/Engine/Platform/Linux/LinuxPlatform.cpp +++ b/Source/Engine/Platform/Linux/LinuxPlatform.cpp @@ -2191,6 +2191,7 @@ bool LinuxPlatform::Init() // Initialize "X11 keycode" -> "Flax KeyboardKeys" map KeyCodeMap.Resize(desc->max_key_code + 1); + Platform::MemoryClear(KeyCodeMap.Get(), KeyCodeMap.Count() * sizeof(KeyboardKeys)); XkbFreeNames(desc, XkbKeyNamesMask, 1); X11::XkbFreeKeyboard(desc, 0, 1); for (int32 keyIdx = (int32)KeyboardKeys::None; keyIdx < MAX_uint8; keyIdx++) @@ -2206,10 +2207,6 @@ bool LinuxPlatform::Init() KeyCodeMap[keyCode] = key; } } - else - { - KeyCodeMap[keyCode] = KeyboardKeys::None; - } } Input::Mouse = Impl::Mouse = New();