From 8f76fe40498c014318d22f45c3ce644544eeeaa6 Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Fri, 9 Jun 2023 22:14:33 -0400 Subject: [PATCH 01/65] don't let rename source/content folders --- Source/Editor/Content/Items/ContentFolder.cs | 11 ++++++++++- Source/Editor/ProjectInfo.cs | 12 ++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Content/Items/ContentFolder.cs b/Source/Editor/Content/Items/ContentFolder.cs index 86c374fee..f3c698782 100644 --- a/Source/Editor/Content/Items/ContentFolder.cs +++ b/Source/Editor/Content/Items/ContentFolder.cs @@ -113,7 +113,16 @@ namespace FlaxEditor.Content public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other; /// - public override bool CanRename => ParentFolder != null; // Deny rename action for root folders + public override bool CanRename + { + get + { + var hasParentFolder = ParentFolder != null; + var isContentFolder = IsFolder && Path == Editor.Instance.GameProject.ContentFolderPath; + var isSourceFolder = IsFolder && Path == Editor.Instance.GameProject.SourceFolderPath; + return hasParentFolder && !isContentFolder && !isSourceFolder; + } + } /// public override bool CanDrag => ParentFolder != null; // Deny rename action for root folders diff --git a/Source/Editor/ProjectInfo.cs b/Source/Editor/ProjectInfo.cs index bc55a9c05..62402b0d8 100644 --- a/Source/Editor/ProjectInfo.cs +++ b/Source/Editor/ProjectInfo.cs @@ -55,6 +55,16 @@ namespace FlaxEditor [NonSerialized] public string ProjectFolderPath; + /// + /// The content assets folder + /// + public string ContentFolderPath; + + /// + /// The source files folder path + /// + public string SourceFolderPath; + /// /// The project version. /// @@ -157,6 +167,8 @@ namespace FlaxEditor var project = JsonConvert.DeserializeObject(contents); project.ProjectPath = path; project.ProjectFolderPath = StringUtils.NormalizePath(Path.GetDirectoryName(path)); + project.ContentFolderPath = StringUtils.NormalizePath(project.ProjectFolderPath + "/Content"); + project.SourceFolderPath = StringUtils.NormalizePath(project.ProjectFolderPath + "/Source"); // Process project data if (string.IsNullOrEmpty(project.Name)) From 164670cceb4b7bdc654b928e1da771a286e312d1 Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Mon, 12 Jun 2023 20:04:32 -0400 Subject: [PATCH 02/65] change content folder detection mode on "CanRename" --- Source/Editor/Content/Items/ContentFolder.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Source/Editor/Content/Items/ContentFolder.cs b/Source/Editor/Content/Items/ContentFolder.cs index f3c698782..57e55d3fe 100644 --- a/Source/Editor/Content/Items/ContentFolder.cs +++ b/Source/Editor/Content/Items/ContentFolder.cs @@ -118,9 +118,8 @@ namespace FlaxEditor.Content get { var hasParentFolder = ParentFolder != null; - var isContentFolder = IsFolder && Path == Editor.Instance.GameProject.ContentFolderPath; - var isSourceFolder = IsFolder && Path == Editor.Instance.GameProject.SourceFolderPath; - return hasParentFolder && !isContentFolder && !isSourceFolder; + var isContentFolder = Node is MainContentTreeNode; + return hasParentFolder && !isContentFolder; } } From 2190031ccf42e954cffdc8931d0e0a7ef5857053 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 18 Jun 2023 20:10:56 +0300 Subject: [PATCH 03/65] Support decimal values in Font sizes --- Source/Editor/Windows/SplashScreen.cpp | 4 ++-- Source/Engine/Render2D/Font.cpp | 4 ++-- Source/Engine/Render2D/Font.h | 6 +++--- Source/Engine/Render2D/FontAsset.cpp | 2 +- Source/Engine/Render2D/FontAsset.h | 2 +- Source/Engine/Render2D/FontReference.cs | 8 ++++---- Source/Engine/UI/TextRender.cpp | 6 +++--- Source/Engine/UI/TextRender.h | 6 +++--- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Source/Editor/Windows/SplashScreen.cpp b/Source/Editor/Windows/SplashScreen.cpp index 3e36d3618..7cf7a7f78 100644 --- a/Source/Editor/Windows/SplashScreen.cpp +++ b/Source/Editor/Windows/SplashScreen.cpp @@ -304,6 +304,6 @@ void SplashScreen::OnFontLoaded(Asset* asset) // Create fonts const float s = _dpiScale; - _titleFont = font->CreateFont((uint32)(35 * s)); - _subtitleFont = font->CreateFont((uint32)(9 * s)); + _titleFont = font->CreateFont(35 * s); + _subtitleFont = font->CreateFont(9 * s); } diff --git a/Source/Engine/Render2D/Font.cpp b/Source/Engine/Render2D/Font.cpp index f12a9ce1c..90423f5ce 100644 --- a/Source/Engine/Render2D/Font.cpp +++ b/Source/Engine/Render2D/Font.cpp @@ -7,7 +7,7 @@ #include "Engine/Threading/Threading.h" #include "IncludeFreeType.h" -Font::Font(FontAsset* parentAsset, int32 size) +Font::Font(FontAsset* parentAsset, float size) : ManagedScriptingObject(SpawnParams(Guid::New(), Font::TypeInitializer)) , _asset(parentAsset) , _size(size) @@ -436,7 +436,7 @@ void Font::FlushFaceSize() const { // Set the character size const FT_Face face = _asset->GetFTFace(); - const FT_Error error = FT_Set_Char_Size(face, 0, ConvertPixelTo26Dot6((float)_size * FontManager::FontScale), DefaultDPI, DefaultDPI); + const FT_Error error = FT_Set_Char_Size(face, 0, ConvertPixelTo26Dot6(_size * FontManager::FontScale), DefaultDPI, DefaultDPI); if (error) { LOG_FT_ERROR(error); diff --git a/Source/Engine/Render2D/Font.h b/Source/Engine/Render2D/Font.h index d68f497d6..90f723cd8 100644 --- a/Source/Engine/Render2D/Font.h +++ b/Source/Engine/Render2D/Font.h @@ -228,7 +228,7 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Font); private: FontAsset* _asset; - int32 _size; + float _size; int32 _height; int32 _ascender; int32 _descender; @@ -244,7 +244,7 @@ public: /// /// The parent asset. /// The size. - Font(FontAsset* parentAsset, int32 size); + Font(FontAsset* parentAsset, float size); /// /// Finalizes an instance of the class. @@ -264,7 +264,7 @@ public: /// /// Gets font size. /// - API_PROPERTY() FORCE_INLINE int32 GetSize() const + API_PROPERTY() FORCE_INLINE float GetSize() const { return _size; } diff --git a/Source/Engine/Render2D/FontAsset.cpp b/Source/Engine/Render2D/FontAsset.cpp index 5fa07771f..f000eb3c6 100644 --- a/Source/Engine/Render2D/FontAsset.cpp +++ b/Source/Engine/Render2D/FontAsset.cpp @@ -92,7 +92,7 @@ void FontAsset::SetOptions(const FontOptions& value) _options = value; } -Font* FontAsset::CreateFont(int32 size) +Font* FontAsset::CreateFont(float size) { PROFILE_CPU(); diff --git a/Source/Engine/Render2D/FontAsset.h b/Source/Engine/Render2D/FontAsset.h index abc601f45..60dbee01d 100644 --- a/Source/Engine/Render2D/FontAsset.h +++ b/Source/Engine/Render2D/FontAsset.h @@ -139,7 +139,7 @@ public: /// /// The font characters size. /// The created font object. - API_FUNCTION() Font* CreateFont(int32 size); + API_FUNCTION() Font* CreateFont(float size); /// /// Gets the font with bold style. Returns itself or creates a new virtual font asset using this font but with bold option enabled. diff --git a/Source/Engine/Render2D/FontReference.cs b/Source/Engine/Render2D/FontReference.cs index 290e10312..cc32bcd9a 100644 --- a/Source/Engine/Render2D/FontReference.cs +++ b/Source/Engine/Render2D/FontReference.cs @@ -13,7 +13,7 @@ namespace FlaxEngine private FontAsset _font; [NoSerialize] - private int _size; + private float _size; [NoSerialize] private Font _cachedFont; @@ -33,7 +33,7 @@ namespace FlaxEngine /// /// The font. /// The font size. - public FontReference(FontAsset font, int size) + public FontReference(FontAsset font, float size) { _font = font; _size = size; @@ -91,7 +91,7 @@ namespace FlaxEngine /// The size of the font characters. /// [EditorOrder(10), Limit(1, 500, 0.1f), Tooltip("The size of the font characters.")] - public int Size + public float Size { get => _size; set @@ -187,7 +187,7 @@ namespace FlaxEngine unchecked { int hashCode = _font ? _font.GetHashCode() : 0; - hashCode = (hashCode * 397) ^ _size; + hashCode = (hashCode * 397) ^ _size.GetHashCode(); return hashCode; } } diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp index d4db794eb..cd60abddf 100644 --- a/Source/Engine/UI/TextRender.cpp +++ b/Source/Engine/UI/TextRender.cpp @@ -73,14 +73,14 @@ void TextRender::SetColor(const Color& value) } } -int32 TextRender::GetFontSize() const +float TextRender::GetFontSize() const { return _size; } -void TextRender::SetFontSize(int32 value) +void TextRender::SetFontSize(float value) { - value = Math::Clamp(value, 1, 1024); + value = Math::Clamp(value, 1.0f, 1024.0f); if (_size != value) { _size = value; diff --git a/Source/Engine/UI/TextRender.h b/Source/Engine/UI/TextRender.h index d69b5427b..816ad8aa4 100644 --- a/Source/Engine/UI/TextRender.h +++ b/Source/Engine/UI/TextRender.h @@ -38,7 +38,7 @@ private: LocalizedString _text; Color _color; TextLayoutOptions _layoutOptions; - int32 _size; + float _size; int32 _sceneRenderingKey = -1; BoundingBox _localBox; @@ -91,12 +91,12 @@ public: /// Gets the font characters size. /// API_PROPERTY(Attributes="EditorOrder(40), DefaultValue(32), Limit(1, 1000), EditorDisplay(\"Text\")") - int32 GetFontSize() const; + float GetFontSize() const; /// /// Sets the font characters size. /// - API_PROPERTY() void SetFontSize(int32 value); + API_PROPERTY() void SetFontSize(float value); /// /// The draw passes to use for rendering this object. From 6a1552505ec226794f793b43557a7a3cc543cbe4 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 18 Jun 2023 21:22:24 +0300 Subject: [PATCH 04/65] Fix sluggish EditorViewport camera movement with high DPI Flooring the mouse delta values seems to drop slight movements in viewport when screen DPI is high. --- Source/Editor/Viewport/EditorViewport.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index f56370352..b4fb8f8f1 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -1168,14 +1168,15 @@ namespace FlaxEditor.Viewport { offset = Float2.Zero; } - offset.X = offset.X > 0 ? Mathf.Floor(offset.X) : Mathf.Ceil(offset.X); - offset.Y = offset.Y > 0 ? Mathf.Floor(offset.Y) : Mathf.Ceil(offset.Y); - _mouseDelta = offset / size; - _mouseDelta.Y *= size.Y / size.X; var mouseDelta = Float2.Zero; if (_useMouseFiltering) { + offset.X = offset.X > 0 ? Mathf.Floor(offset.X) : Mathf.Ceil(offset.X); + offset.Y = offset.Y > 0 ? Mathf.Floor(offset.Y) : Mathf.Ceil(offset.Y); + _mouseDelta = offset / size; + _mouseDelta.Y *= size.Y / size.X; + // Update delta filtering buffer _deltaFilteringBuffer[_deltaFilteringStep] = _mouseDelta; _deltaFilteringStep++; @@ -1192,6 +1193,8 @@ namespace FlaxEditor.Viewport } else { + _mouseDelta = offset / size; + _mouseDelta.Y *= size.Y / size.X; mouseDelta = _mouseDelta; } From 46c406cc9e97e5e8e7bcdcb3897a825d97934c0f Mon Sep 17 00:00:00 2001 From: Wiktor Kocielski Date: Mon, 19 Jun 2023 15:54:03 +0300 Subject: [PATCH 05/65] Implement optional object replication --- Source/Engine/Networking/NetworkReplicationHierarchy.cpp | 6 +++++- Source/Engine/Networking/NetworkReplicationHierarchy.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp index d86acfc7f..3935229a9 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp @@ -80,7 +80,11 @@ void NetworkReplicationNode::Update(NetworkReplicationHierarchyUpdateResult* res const float networkFPS = NetworkManager::NetworkFPS / result->ReplicationScale; for (NetworkReplicationHierarchyObject& obj : Objects) { - if (obj.ReplicationFPS <= 0.0f) + if (obj.ReplicationFPS < 0.0f) + { + continue; + } + else if (obj.ReplicationFPS == 0.0f) { // Always relevant result->AddObject(obj.Object); diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.h b/Source/Engine/Networking/NetworkReplicationHierarchy.h index 55cd6b7b1..f052a3b93 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.h +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.h @@ -20,7 +20,7 @@ API_STRUCT(NoDefault, Namespace = "FlaxEngine.Networking") struct FLAXENGINE_API // The object to replicate. API_FIELD() ScriptingObjectReference Object; - // The target amount of the replication updates per second (frequency of the replication). Constrained by NetworkManager::NetworkFPS. Use 0 for 'always relevant' object. + // The target amount of the replication updates per second (frequency of the replication). Constrained by NetworkManager::NetworkFPS. Use 0 for 'always relevant' object and < 0 for 'never relevant' objects that would only get synched on client join once. API_FIELD() float ReplicationFPS = 60; // The minimum distance from the player to the object at which it can process replication. For example, players further away won't receive object data. Use 0 if unused. API_FIELD() float CullDistance = 15000; From e17eed7029ffd63c46e7be1d4227769adc603dbc Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 19 Jun 2023 17:49:34 +0200 Subject: [PATCH 06/65] Fix regression in script values creation in Editor #1184 #1183 --- Source/Editor/Scripting/ScriptType.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Source/Editor/Scripting/ScriptType.cs b/Source/Editor/Scripting/ScriptType.cs index d174b7dff..454c3a5d2 100644 --- a/Source/Editor/Scripting/ScriptType.cs +++ b/Source/Editor/Scripting/ScriptType.cs @@ -832,7 +832,7 @@ namespace FlaxEditor.Scripting get { if (_managed != null) - return _managed.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null) != null; + return _managed.IsValueType || _managed.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null) != null; return _custom?.CanCreateInstance ?? false; } } @@ -893,9 +893,16 @@ namespace FlaxEditor.Scripting { if (_managed != null) { - var ctor = _managed.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null); object value = RuntimeHelpers.GetUninitializedObject(_managed); - ctor.Invoke(value, null); + if (!_managed.IsValueType) + { + var ctor = _managed.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null); +#if !BUILD_RELEASE + if (ctor == null) + throw new Exception($"Missing empty constructor for type {_managed.FullName}."); +#endif + ctor.Invoke(value, null); + } return value; } return _custom.CreateInstance(); From f7e3480d79525e2e3692c95b865b0afdd19de084 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 19 Jun 2023 18:01:25 +0200 Subject: [PATCH 07/65] Fix floating point comparison #1188 --- Source/Engine/Networking/NetworkReplicationHierarchy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp index 3935229a9..99a43a34a 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp @@ -80,11 +80,11 @@ void NetworkReplicationNode::Update(NetworkReplicationHierarchyUpdateResult* res const float networkFPS = NetworkManager::NetworkFPS / result->ReplicationScale; for (NetworkReplicationHierarchyObject& obj : Objects) { - if (obj.ReplicationFPS < 0.0f) + if (obj.ReplicationFPS < -ZeroTolerance) // < 0 { continue; } - else if (obj.ReplicationFPS == 0.0f) + else if (obj.ReplicationFPS < ZeroTolerance) // == 0 { // Always relevant result->AddObject(obj.Object); From 6f487bcab5bb77364ee44543efa008ba0f497534 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 19 Jun 2023 18:05:00 +0200 Subject: [PATCH 08/65] Fix doc comment warning #1188 --- Source/Engine/Networking/NetworkReplicationHierarchy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.h b/Source/Engine/Networking/NetworkReplicationHierarchy.h index f052a3b93..36701c15d 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.h +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.h @@ -20,7 +20,7 @@ API_STRUCT(NoDefault, Namespace = "FlaxEngine.Networking") struct FLAXENGINE_API // The object to replicate. API_FIELD() ScriptingObjectReference Object; - // The target amount of the replication updates per second (frequency of the replication). Constrained by NetworkManager::NetworkFPS. Use 0 for 'always relevant' object and < 0 for 'never relevant' objects that would only get synched on client join once. + // The target amount of the replication updates per second (frequency of the replication). Constrained by NetworkManager::NetworkFPS. Use 0 for 'always relevant' object and less than 0 (eg. -1) for 'never relevant' objects that would only get synched on client join once. API_FIELD() float ReplicationFPS = 60; // The minimum distance from the player to the object at which it can process replication. For example, players further away won't receive object data. Use 0 if unused. API_FIELD() float CullDistance = 15000; From b82f19a0dfbd87d5ae449c18bcc5c095b7f007e2 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Mon, 19 Jun 2023 19:32:38 +0300 Subject: [PATCH 09/65] Support changing C# nullable references context build option --- .../Flax.Build/Build/DotNet/Builder.DotNet.cs | 5 ++- .../Build/NativeCpp/BuildOptions.cs | 35 +++++++++++++++++++ .../VisualStudio/CSSDKProjectGenerator.cs | 2 +- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs index 921a1e43f..e6a250eb5 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using Flax.Build.Graph; +using Flax.Build.NativeCpp; using Flax.Deploy; namespace Flax.Build @@ -242,7 +243,9 @@ namespace Flax.Build args.Add("/filealign:512"); #if USE_NETCORE args.Add("/langversion:11.0"); - args.Add("-nowarn:8632"); // Nullable + args.Add(string.Format("/nullable:{0}", buildOptions.ScriptingAPI.CSharpNullableReferences.ToString().ToLowerInvariant())); + if (buildOptions.ScriptingAPI.CSharpNullableReferences == CSharpNullableReferences.Disable) + args.Add("-nowarn:8632"); // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. #else args.Add("/langversion:7.3"); #endif diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs b/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs index 8a5a55873..c2ea81372 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs @@ -23,6 +23,32 @@ namespace Flax.Build.NativeCpp GenerateProject = 1, } + /// + /// The nullable context type used with reference types (C#). + /// + public enum CSharpNullableReferences + { + /// + /// The code is nullable oblivious, nullable warnings and language analysis features are disabled. + /// + Disable, + + /// + /// The compiler enables all null reference analysis and all language features. + /// + Enable, + + /// + /// The compiler performs all null analysis and emits warnings when code might dereference null. + /// + Warnings, + + /// + /// The compiler doesn't perform null analysis or emit warnings when code might dereference null. + /// + Annotations, + } + /// /// The native C++ module build settings container. /// @@ -188,6 +214,15 @@ namespace Flax.Build.NativeCpp /// public bool IgnoreMissingDocumentationWarnings; + /// + /// The nullable context used in C# project. + /// + public CSharpNullableReferences CSharpNullableReferences = CSharpNullableReferences.Disable; + + public ScriptingAPIOptions() + { + } + /// /// Adds the other options into this. /// diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/CSSDKProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/CSSDKProjectGenerator.cs index ed8222fb7..efce04776 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/CSSDKProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/CSSDKProjectGenerator.cs @@ -88,7 +88,7 @@ namespace Flax.Build.Projects.VisualStudio csProjectFileContent.AppendLine(" net7.0"); csProjectFileContent.AppendLine(" disable"); - csProjectFileContent.AppendLine(" annotations"); + csProjectFileContent.AppendLine(string.Format(" {0}", baseConfiguration.TargetBuildOptions.ScriptingAPI.CSharpNullableReferences.ToString().ToLowerInvariant())); csProjectFileContent.AppendLine(" false"); csProjectFileContent.AppendLine(" false"); csProjectFileContent.AppendLine(" false"); From c0ba3b0edbf4e26b1efc34fce9a08e044e66e859 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Mon, 19 Jun 2023 22:18:06 +0300 Subject: [PATCH 10/65] Expose Content importers and exporters for scripting API --- Source/Engine/ContentExporters/AssetsExportingManager.h | 2 +- Source/Engine/ContentExporters/Types.h | 2 +- Source/Engine/ContentImporters/AssetsImportingManager.h | 2 +- Source/Engine/ContentImporters/Types.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Engine/ContentExporters/AssetsExportingManager.h b/Source/Engine/ContentExporters/AssetsExportingManager.h index f9f50075e..7e3b11b6d 100644 --- a/Source/Engine/ContentExporters/AssetsExportingManager.h +++ b/Source/Engine/ContentExporters/AssetsExportingManager.h @@ -10,7 +10,7 @@ /// /// Assets Importing service allows to import or create new assets /// -class AssetsExportingManager +class FLAXENGINE_API AssetsExportingManager { public: /// diff --git a/Source/Engine/ContentExporters/Types.h b/Source/Engine/ContentExporters/Types.h index cfc341f37..a2095934f 100644 --- a/Source/Engine/ContentExporters/Types.h +++ b/Source/Engine/ContentExporters/Types.h @@ -26,7 +26,7 @@ typedef Function ExportAssetFunction; /// /// Exporting asset context structure /// -class ExportAssetContext : public NonCopyable +class FLAXENGINE_API ExportAssetContext : public NonCopyable { public: /// diff --git a/Source/Engine/ContentImporters/AssetsImportingManager.h b/Source/Engine/ContentImporters/AssetsImportingManager.h index 2f8369a41..2930f8979 100644 --- a/Source/Engine/ContentImporters/AssetsImportingManager.h +++ b/Source/Engine/ContentImporters/AssetsImportingManager.h @@ -9,7 +9,7 @@ /// /// Assets Importing service allows to import or create new assets /// -class AssetsImportingManager +class FLAXENGINE_API AssetsImportingManager { public: /// diff --git a/Source/Engine/ContentImporters/Types.h b/Source/Engine/ContentImporters/Types.h index 05d1fc116..4ebf55583 100644 --- a/Source/Engine/ContentImporters/Types.h +++ b/Source/Engine/ContentImporters/Types.h @@ -28,7 +28,7 @@ typedef Function CreateAssetFunction; /// /// Importing/creating asset context structure /// -class CreateAssetContext : public NonCopyable +class FLAXENGINE_API CreateAssetContext : public NonCopyable { private: CreateAssetResult _applyChangesResult; From cd7ad4e5f855c66d261eeedc57770ff6cbca672c Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 20 Jun 2023 15:17:46 +0200 Subject: [PATCH 11/65] Fix crash in particle effect #1194 --- Source/Engine/Particles/ParticleEffect.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Source/Engine/Particles/ParticleEffect.cpp b/Source/Engine/Particles/ParticleEffect.cpp index 18bcbdd54..1d7fa18a1 100644 --- a/Source/Engine/Particles/ParticleEffect.cpp +++ b/Source/Engine/Particles/ParticleEffect.cpp @@ -299,17 +299,19 @@ void ParticleEffect::Stop() void ParticleEffect::UpdateBounds() { BoundingBox bounds = BoundingBox::Empty; - if (ParticleSystem && Instance.LastUpdateTime >= 0) + const auto particleSystem = ParticleSystem.Get(); + if (particleSystem && Instance.LastUpdateTime >= 0) { - for (int32 j = 0; j < ParticleSystem->Tracks.Count(); j++) + for (int32 j = 0; j < particleSystem->Tracks.Count(); j++) { - const auto& track = ParticleSystem->Tracks[j]; + const auto& track = particleSystem->Tracks[j]; if (track.Type != ParticleSystem::Track::Types::Emitter || track.Disabled) continue; - auto& emitter = ParticleSystem->Emitters[track.AsEmitter.Index]; - auto& data = Instance.Emitters[track.AsEmitter.Index]; - if (!emitter || emitter->Capacity == 0 || emitter->Graph.Layout.Size == 0) + const int32 emitterIndex = track.AsEmitter.Index; + ParticleEmitter* emitter = particleSystem->Emitters[emitterIndex].Get(); + if (!emitter || emitter->Capacity == 0 || emitter->Graph.Layout.Size == 0 || Instance.Emitters.Count() <= emitterIndex) continue; + auto& data = Instance.Emitters[emitterIndex]; BoundingBox emitterBounds; if (emitter->GraphExecutorCPU.ComputeBounds(emitter, this, data, emitterBounds)) From 87e96a901758c6d1ba3a49813d28e3fa3d82f5f4 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Tue, 20 Jun 2023 16:28:37 +0300 Subject: [PATCH 12/65] Fix native library lookup after hot reload --- Source/Engine/Engine/NativeInterop.cs | 11 ----------- Source/Engine/Scripting/Runtime/DotNet.cpp | 3 ++- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index b33e4bcb6..faa19d060 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -58,19 +58,8 @@ namespace FlaxEngine.Interop if (!loadedNativeLibraries.TryGetValue(libraryName, out IntPtr nativeLibrary)) { if (!nativeLibraryPaths.TryGetValue(libraryName, out var nativeLibraryPath)) - { nativeLibraryPath = libraryName; - // Check if any of the loaded assemblies has matching native module filename - foreach (var e in nativeLibraryPaths) - { - if (string.Equals(Path.GetFileNameWithoutExtension(e.Value), libraryName, StringComparison.Ordinal)) - { - nativeLibraryPath = e.Value; - break; - } - } - } nativeLibrary = NativeLibrary.Load(nativeLibraryPath, assembly, dllImportSearchPath); loadedNativeLibraries.Add(libraryName, nativeLibrary); assemblyOwnedNativeLibraries.Add(assembly, libraryName); diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index f2c5ee376..1736cc106 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -712,7 +712,8 @@ bool MAssembly::LoadImage(const String& assemblyPath, const StringView& nativePa // Provide new path of hot-reloaded native library path for managed DllImport if (nativePath.HasChars()) { - RegisterNativeLibrary(assemblyPathAnsi.Get(), StringAnsi(nativePath).Get()); + StringAnsi nativeName = _name.EndsWith(".CSharp") ? StringAnsi(_name.Get(), _name.Length() - 7) : StringAnsi(_name); + RegisterNativeLibrary(nativeName.Get(), StringAnsi(nativePath).Get()); } _hasCachedClasses = false; From d3073f52518f6d6dbd3c2e2616977904c320dd61 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Tue, 20 Jun 2023 21:47:05 +0300 Subject: [PATCH 13/65] Release custom assets before scripting hot reload --- Source/Engine/Scripting/Scripting.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index 9bddc333e..bbd109cd1 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -640,9 +640,9 @@ void Scripting::Reload(bool canTriggerSceneReload) MCore::GC::WaitForPendingFinalizers(); // Destroy objects from game assemblies (eg. not released objects that might crash if persist in memory after reload) + const auto flaxModule = GetBinaryModuleFlaxEngine(); _objectsLocker.Lock(); { - const auto flaxModule = GetBinaryModuleFlaxEngine(); for (auto i = _objectsDictionary.Begin(); i.IsNotEnd(); ++i) { auto obj = i->Value; @@ -657,6 +657,15 @@ void Scripting::Reload(bool canTriggerSceneReload) } _objectsLocker.Unlock(); + // Release assets sourced from game assemblies + for (auto asset : Content::GetAssets()) + { + if (asset->GetTypeHandle().Module == flaxModule) + continue; + + asset->DeleteObjectNow(); + } + // Unload all game modules LOG(Info, "Unloading game binary modules"); auto modules = BinaryModule::GetModules(); From 64a7985376109c646fd9b38d6d01a7df4364b278 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 20 Jun 2023 21:59:36 +0200 Subject: [PATCH 14/65] Fix `GridGizmo` to render before transparency in Editor viewport #1196 --- Source/Editor/Gizmo/GridGizmo.cs | 137 +++++++++++++++++++----------- Source/Engine/Debug/DebugDraw.cpp | 8 +- 2 files changed, 91 insertions(+), 54 deletions(-) diff --git a/Source/Editor/Gizmo/GridGizmo.cs b/Source/Editor/Gizmo/GridGizmo.cs index a36bb8da1..4b8dec2de 100644 --- a/Source/Editor/Gizmo/GridGizmo.cs +++ b/Source/Editor/Gizmo/GridGizmo.cs @@ -12,19 +12,98 @@ namespace FlaxEditor.Gizmo [HideInEditor] public class GridGizmo : GizmoBase { - private bool _enabled = true; + [HideInEditor] + private sealed class Renderer : PostProcessEffect + { + private IntPtr _debugDrawContext; + + public Renderer() + { + Order = -100; + UseSingleTarget = true; + Location = PostProcessEffectLocation.BeforeForwardPass; + } + + ~Renderer() + { + if (_debugDrawContext != IntPtr.Zero) + { + DebugDraw.FreeContext(_debugDrawContext); + _debugDrawContext = IntPtr.Zero; + } + } + + public override void Render(GPUContext context, ref RenderContext renderContext, GPUTexture input, GPUTexture output) + { + Profiler.BeginEventGPU("Editor Grid"); + + if (_debugDrawContext == IntPtr.Zero) + _debugDrawContext = DebugDraw.AllocateContext(); + DebugDraw.SetContext(_debugDrawContext); + DebugDraw.UpdateContext(_debugDrawContext, 1.0f / Mathf.Max(Engine.FramesPerSecond, 1)); + + var viewPos = (Vector3)renderContext.View.Position; + var plane = new Plane(Vector3.Zero, Vector3.UnitY); + var dst = CollisionsHelper.DistancePlanePoint(ref plane, ref viewPos); + + float space, size; + if (dst <= 500.0f) + { + space = 50; + size = 8000; + } + else if (dst <= 2000.0f) + { + space = 100; + size = 8000; + } + else + { + space = 1000; + size = 100000; + } + + Color color = Color.Gray * 0.7f; + int count = (int)(size / space); + + Vector3 start = new Vector3(0, 0, size * -0.5f); + Vector3 end = new Vector3(0, 0, size * 0.5f); + + for (int i = 0; i <= count; i++) + { + start.X = end.X = i * space + start.Z; + DebugDraw.DrawLine(start, end, color); + } + + start = new Vector3(size * -0.5f, 0, 0); + end = new Vector3(size * 0.5f, 0, 0); + + for (int i = 0; i <= count; i++) + { + start.Z = end.Z = i * space + start.X; + DebugDraw.DrawLine(start, end, color); + } + + DebugDraw.Draw(ref renderContext, input.View(), null, true); + DebugDraw.SetContext(IntPtr.Zero); + + Profiler.EndEventGPU(); + } + } + + private Renderer _renderer; /// /// Gets or sets a value indicating whether this is enabled. /// public bool Enabled { - get => _enabled; + get => _renderer.Enabled; set { - if (_enabled != value) + if (_renderer.Enabled != value) { - _enabled = value; + _renderer.Enabled = value; EnabledChanged?.Invoke(this); } } @@ -42,55 +121,13 @@ namespace FlaxEditor.Gizmo public GridGizmo(IGizmoOwner owner) : base(owner) { + _renderer = new Renderer(); + owner.RenderTask.AddCustomPostFx(_renderer); } - /// - public override void Draw(ref RenderContext renderContext) + ~GridGizmo() { - if (!Enabled) - return; - - var viewPos = Owner.ViewPosition; - var plane = new Plane(Vector3.Zero, Vector3.UnitY); - var dst = CollisionsHelper.DistancePlanePoint(ref plane, ref viewPos); - - float space, size; - if (dst <= 500.0f) - { - space = 50; - size = 8000; - } - else if (dst <= 2000.0f) - { - space = 100; - size = 8000; - } - else - { - space = 1000; - size = 100000; - } - - Color color = Color.Gray * 0.7f; - int count = (int)(size / space); - - Vector3 start = new Vector3(0, 0, size * -0.5f); - Vector3 end = new Vector3(0, 0, size * 0.5f); - - for (int i = 0; i <= count; i++) - { - start.X = end.X = i * space + start.Z; - DebugDraw.DrawLine(start, end, color); - } - - start = new Vector3(size * -0.5f, 0, 0); - end = new Vector3(size * 0.5f, 0, 0); - - for (int i = 0; i <= count; i++) - { - start.Z = end.Z = i * space + start.X; - DebugDraw.DrawLine(start, end, color); - } + FlaxEngine.Object.Destroy(ref _renderer); } } } diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp index 891792d79..97422b9e2 100644 --- a/Source/Engine/Debug/DebugDraw.cpp +++ b/Source/Engine/Debug/DebugDraw.cpp @@ -466,7 +466,7 @@ inline void DrawText3D(const DebugText3D& t, const RenderContext& renderContext, Matrix::Multiply(fw, vp, m); Render2D::Begin(context, target, depthBuffer, viewport, m); const StringView text(t.Text.Get(), t.Text.Count() - 1); - Render2D::DrawText(DebugDrawFont->CreateFont(t.Size), text, t.Color, Vector2::Zero); + Render2D::DrawText(DebugDrawFont->CreateFont((float)t.Size), text, t.Color, Vector2::Zero); Render2D::End(); } @@ -777,7 +777,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe context->BindSR(0, renderContext.Buffers->DepthBuffer); const bool enableDepthWrite = data.EnableDepthTest; - context->SetRenderTarget(depthBuffer ? depthBuffer : *renderContext.Buffers->DepthBuffer, target); + context->SetRenderTarget(depthBuffer ? depthBuffer : (data.EnableDepthTest ? nullptr : renderContext.Buffers->DepthBuffer->View()), target); // Lines if (depthTestLines.VertexCount) @@ -859,12 +859,12 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe for (auto& t : Context->DebugDrawDefault.DefaultText2D) { const StringView text(t.Text.Get(), t.Text.Count() - 1); - Render2D::DrawText(DebugDrawFont->CreateFont(t.Size), text, t.Color, t.Position); + Render2D::DrawText(DebugDrawFont->CreateFont((float)t.Size), text, t.Color, t.Position); } for (auto& t : Context->DebugDrawDefault.OneFrameText2D) { const StringView text(t.Text.Get(), t.Text.Count() - 1); - Render2D::DrawText(DebugDrawFont->CreateFont(t.Size), text, t.Color, t.Position); + Render2D::DrawText(DebugDrawFont->CreateFont((float)t.Size), text, t.Color, t.Position); } Render2D::End(); } From 74760a76614345b3c1c172e1ffd4108e047473ca Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Wed, 21 Jun 2023 13:14:27 +0300 Subject: [PATCH 15/65] Add support for writing UTF-8 files in FileBase::WriteAllText --- Source/Engine/Core/Encoding.h | 2 +- Source/Engine/Platform/Base/FileBase.cpp | 39 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Core/Encoding.h b/Source/Engine/Core/Encoding.h index 6ac716ba8..3e74144e2 100644 --- a/Source/Engine/Core/Encoding.h +++ b/Source/Engine/Core/Encoding.h @@ -4,4 +4,4 @@ #include "Enums.h" -DECLARE_ENUM_3(Encoding, ANSI, Unicode, UnicodeBigEndian); +DECLARE_ENUM_4(Encoding, ANSI, Unicode, UnicodeBigEndian, UTF8); diff --git a/Source/Engine/Platform/Base/FileBase.cpp b/Source/Engine/Platform/Base/FileBase.cpp index f45685c7f..4794e2452 100644 --- a/Source/Engine/Platform/Base/FileBase.cpp +++ b/Source/Engine/Platform/Base/FileBase.cpp @@ -309,6 +309,45 @@ bool FileBase::WriteAllText(const StringView& path, const Char* data, int32 leng return WriteAllBytes(path, tmp.Get(), tmp.Count()); } + case Encoding::UTF8: + { + Array tmp; + tmp.SetCapacity(length); + + for (int i=0; i> 6)); + tmp.Add(0x80 | (c & 0x3F)); + } + else if (c < 0xD800 || c >= 0xE000) + { + tmp.Add(0xE0 | (c >> 12)); + tmp.Add(0x80 | ((c >> 6) & 0x3F)); + tmp.Add(0x80 | (c & 0x3F)); + } + else // Surrogate pair + { + ++i; + if (i >= length) + return true; + + uint32 p = 0x10000 + (((c & 0x3FF) << 10) | (data[i] & 0x3FF)); + tmp.Add(0xF0 | (p >> 18)); + tmp.Add(0x80 | ((p >> 12) & 0x3F)); + tmp.Add(0x80 | ((p >> 6) & 0x3F)); + tmp.Add(0x80 | (p & 0x3F)); + } + } + + return WriteAllBytes(path, tmp.Get(), tmp.Count()); + } default: return true; } From 83485d2f528cfeb52c12ef7193a22d0dbcffa3c8 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Wed, 21 Jun 2023 13:16:49 +0300 Subject: [PATCH 16/65] Write generated build configuration files in UTF-8 Git seems to have issues with handling UTF-16 encoded files, so it would be more appropriate to write the generated files with more common UTF-8 encoding instead. --- Source/Editor/Editor.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Source/Editor/Editor.cpp b/Source/Editor/Editor.cpp index 8a92d11f4..527bfeb6d 100644 --- a/Source/Editor/Editor.cpp +++ b/Source/Editor/Editor.cpp @@ -184,7 +184,7 @@ bool Editor::CheckProjectUpgrade() " BuildNativeCode = false;\n" " }}\n" "}}\n" - ), codeName), Encoding::Unicode); + ), codeName), Encoding::UTF8); if (useEditorModule) { File::WriteAllText(gameEditorModuleFolder / String::Format(TEXT("{0}Editor.Build.cs"), codeName), String::Format(TEXT( @@ -211,7 +211,7 @@ bool Editor::CheckProjectUpgrade() " BuildNativeCode = false;\n" " }}\n" "}}\n" - ), codeName), Encoding::Unicode); + ), codeName), Encoding::UTF8); } // Generate target files @@ -229,7 +229,7 @@ bool Editor::CheckProjectUpgrade() " Modules.Add(\"{0}\");\n" " }}\n" "}}\n" - ), codeName), Encoding::Unicode); + ), codeName), Encoding::UTF8); const String editorTargetGameEditorModule = useEditorModule ? String::Format(TEXT(" Modules.Add(\"{0}Editor\");\n"), codeName) : String::Empty; File::WriteAllText(sourceFolder / String::Format(TEXT("{0}EditorTarget.Build.cs"), codeName), String::Format(TEXT( "using Flax.Build;\n" @@ -246,7 +246,7 @@ bool Editor::CheckProjectUpgrade() "{1}" " }}\n" "}}\n" - ), codeName, editorTargetGameEditorModule), Encoding::Unicode); + ), codeName, editorTargetGameEditorModule), Encoding::UTF8); // Generate new project file Project->ProjectPath = root / String::Format(TEXT("{0}.flaxproj"), codeName); @@ -454,7 +454,7 @@ int32 Editor::LoadProduct() " // Reference the modules for game\n" " Modules.Add(\"Game\");\n" " }\n" - "}\n"), Encoding::Unicode); + "}\n"), Encoding::UTF8); failed |= File::WriteAllText(projectPath / TEXT("Source/GameEditorTarget.Build.cs"),TEXT( "using Flax.Build;\n" "\n" @@ -468,7 +468,7 @@ int32 Editor::LoadProduct() " // Reference the modules for editor\n" " Modules.Add(\"Game\");\n" " }\n" - "}\n"), Encoding::Unicode); + "}\n"), Encoding::UTF8); failed |= File::WriteAllText(projectPath / TEXT("Source/Game/Game.Build.cs"),TEXT( "using Flax.Build;\n" "using Flax.Build.NativeCpp;\n" @@ -496,7 +496,7 @@ int32 Editor::LoadProduct() " // To add C++ define use: options.PublicDefinitions.Add(\"COMPILE_WITH_FLAX\");\n" " // To learn more see scripting documentation.\n" " }\n" - "}\n"), Encoding::Unicode); + "}\n"), Encoding::UTF8); if (failed) return 12; } From 9c2a04aa213ac231782df126e1dc3f91c529789c Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Wed, 21 Jun 2023 07:24:37 -0500 Subject: [PATCH 17/65] Add eol=lf to gitattribute --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index f84404f19..df7d89342 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,5 @@ # Set the default behavior, in case people don't have core.autocrlf set. -* text=auto +* text=auto eol=lf # Explicitly declare text files you want to always be normalized and converted to native line endings on checkout. *.c text diff=cpp From 875dd30d57dd064498032da1d1b1a2ab7f8a5faf Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Wed, 21 Jun 2023 21:27:38 -0400 Subject: [PATCH 18/65] add optional parameter to find only active actors on Level.FinActors(tag) --- Source/Engine/Level/Level.cpp | 12 +++++++----- Source/Engine/Level/Level.h | 3 ++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp index ae617b980..7b6a3844f 100644 --- a/Source/Engine/Level/Level.cpp +++ b/Source/Engine/Level/Level.cpp @@ -740,12 +740,14 @@ Actor* FindActorRecursive(Actor* node, const Tag& tag) return result; } -void FindActorsRecursive(Actor* node, const Tag& tag, Array& result) +void FindActorsRecursive(Actor* node, const Tag& tag, const bool activeOnly, Array& result) { + if (activeOnly && !node->GetIsActive()) + return; if (node->HasTag(tag)) result.Add(node); for (Actor* child : node->Children) - FindActorsRecursive(child, tag, result); + FindActorsRecursive(child, tag, activeOnly, result); } void FindActorsRecursiveByParentTags(Actor* node, const Array& tags, Array& result) @@ -785,19 +787,19 @@ void FindActorRecursive(Actor* node, const Tag& tag, Array& result) FindActorRecursive(child, tag, result); } -Array Level::FindActors(const Tag& tag, Actor* root) +Array Level::FindActors(const Tag& tag, const bool activeOnly, Actor* root) { PROFILE_CPU(); Array result; if (root) { - FindActorsRecursive(root, tag, result); + FindActorsRecursive(root, tag, activeOnly, result); } else { ScopeLock lock(ScenesLock); for (Scene* scene : Scenes) - FindActorsRecursive(scene, tag, result); + FindActorsRecursive(scene, tag, activeOnly, result); } return result; } diff --git a/Source/Engine/Level/Level.h b/Source/Engine/Level/Level.h index e27b81bb9..a7524b40a 100644 --- a/Source/Engine/Level/Level.h +++ b/Source/Engine/Level/Level.h @@ -494,9 +494,10 @@ public: /// Tries to find the actors with the given tag (returns all found). /// /// The tag of the actor to search for. + /// Find only active actors. /// The custom root actor to start searching from (hierarchical), otherwise null to search all loaded scenes. /// Found actors or empty if none. - API_FUNCTION() static Array FindActors(const Tag& tag, Actor* root = nullptr); + API_FUNCTION() static Array FindActors(const Tag& tag, const bool activeOnly = false, Actor* root = nullptr); /// /// Search actors using a parent parentTag. From 072d70722c640b563270c91070f37584c151ffb7 Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Wed, 21 Jun 2023 21:38:22 -0400 Subject: [PATCH 19/65] add optional parameter to find only active actors on Level.FindActorsByParentTag --- Source/Engine/Level/Level.cpp | 14 ++++++++------ Source/Engine/Level/Level.h | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp index 7b6a3844f..ab8a9bbfe 100644 --- a/Source/Engine/Level/Level.cpp +++ b/Source/Engine/Level/Level.cpp @@ -750,8 +750,10 @@ void FindActorsRecursive(Actor* node, const Tag& tag, const bool activeOnly, Arr FindActorsRecursive(child, tag, activeOnly, result); } -void FindActorsRecursiveByParentTags(Actor* node, const Array& tags, Array& result) +void FindActorsRecursiveByParentTags(Actor* node, const Array& tags, const bool activeOnly, Array& result) { + if (activeOnly && !node->GetIsActive()) + return; for (Tag tag : tags) { if (node->HasTag(tag)) @@ -761,7 +763,7 @@ void FindActorsRecursiveByParentTags(Actor* node, const Array& tags, Array< } } for (Actor* child : node->Children) - FindActorsRecursiveByParentTags(child, tags, result); + FindActorsRecursiveByParentTags(child, tags, activeOnly, result); } Actor* Level::FindActor(const Tag& tag, Actor* root) @@ -804,7 +806,7 @@ Array Level::FindActors(const Tag& tag, const bool activeOnly, Actor* ro return result; } -Array Level::FindActorsByParentTag(const Tag& parentTag, Actor* root) +Array Level::FindActorsByParentTag(const Tag& parentTag, const bool activeOnly, Actor* root) { PROFILE_CPU(); Array result; @@ -816,19 +818,19 @@ Array Level::FindActorsByParentTag(const Tag& parentTag, Actor* root) } if (subTags.Count() == 1) { - result = FindActors(subTags[0], root); + result = FindActors(subTags[0], activeOnly, root); return result; } if (root) { - FindActorsRecursiveByParentTags(root, subTags, result); + FindActorsRecursiveByParentTags(root, subTags, activeOnly, result); } else { ScopeLock lock(ScenesLock); for (Scene* scene : Scenes) - FindActorsRecursiveByParentTags(scene, subTags, result); + FindActorsRecursiveByParentTags(scene, subTags, activeOnly, result); } return result; diff --git a/Source/Engine/Level/Level.h b/Source/Engine/Level/Level.h index a7524b40a..9a041bda9 100644 --- a/Source/Engine/Level/Level.h +++ b/Source/Engine/Level/Level.h @@ -503,9 +503,10 @@ public: /// Search actors using a parent parentTag. /// /// The tag to search actors with subtags belonging to this tag + /// Find only active actors. /// The custom root actor to start searching from (hierarchical), otherwise null to search all loaded scenes. /// Returns all actors that have subtags belonging to the given parent parentTag - API_FUNCTION() static Array FindActorsByParentTag(const Tag& parentTag, Actor* root = nullptr); + API_FUNCTION() static Array FindActorsByParentTag(const Tag& parentTag, const bool activeOnly = false, Actor* root = nullptr); private: // Actor API From 028ccfca2e3b435e8da331750c8707cedc1b4cc8 Mon Sep 17 00:00:00 2001 From: Wiktor Kocielski <118038102+Withaust@users.noreply.github.com> Date: Fri, 23 Jun 2023 13:14:59 +0300 Subject: [PATCH 20/65] Update NetworkReplicationNode::AddObject --- Source/Engine/Networking/NetworkReplicationHierarchy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp index 99a43a34a..32b7978d0 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp @@ -49,7 +49,7 @@ bool NetworkReplicationHierarchyUpdateResult::GetClientLocation(int32 clientInde void NetworkReplicationNode::AddObject(NetworkReplicationHierarchyObject obj) { - if (obj.ReplicationFPS > 0.0f) + if (obj.ReplicationFPS > ZeroTolerance) // > 0 { // Randomize initial replication update to spread rep rates more evenly for large scenes that register all objects within the same frame obj.ReplicationUpdatesLeft = NetworkReplicationNodeObjectCounter++ % Math::Clamp(Math::RoundToInt(NetworkManager::NetworkFPS / obj.ReplicationFPS), 1, 60); From 9b570a46d2b1b894f6c019f3aea57f687a2dbea7 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 23 Jun 2023 21:28:16 +0200 Subject: [PATCH 21/65] Codestyle tweak --- Source/Editor/Gizmo/GridGizmo.cs | 3 +++ Source/Engine/Platform/Base/FileBase.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Gizmo/GridGizmo.cs b/Source/Editor/Gizmo/GridGizmo.cs index 4b8dec2de..8b4f49986 100644 --- a/Source/Editor/Gizmo/GridGizmo.cs +++ b/Source/Editor/Gizmo/GridGizmo.cs @@ -125,6 +125,9 @@ namespace FlaxEditor.Gizmo owner.RenderTask.AddCustomPostFx(_renderer); } + /// + /// Destructor. + /// ~GridGizmo() { FlaxEngine.Object.Destroy(ref _renderer); diff --git a/Source/Engine/Platform/Base/FileBase.cpp b/Source/Engine/Platform/Base/FileBase.cpp index 4794e2452..eb11292b0 100644 --- a/Source/Engine/Platform/Base/FileBase.cpp +++ b/Source/Engine/Platform/Base/FileBase.cpp @@ -314,7 +314,7 @@ bool FileBase::WriteAllText(const StringView& path, const Char* data, int32 leng Array tmp; tmp.SetCapacity(length); - for (int i=0; i Date: Fri, 23 Jun 2023 22:22:50 +0200 Subject: [PATCH 22/65] Fix missing collision events generated during `CharacterController::Move` #1200 --- .../Physics/PhysX/PhysicsBackendPhysX.cpp | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp index 41430fb4d..69dfeaa27 100644 --- a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp @@ -203,6 +203,60 @@ class CharacterControllerFilterPhysX : public PxControllerFilterCallback } }; +class CharacterControllerHitReportPhysX : public PxUserControllerHitReport +{ + void onHit(const PxControllerHit& hit, Collision& c) + { + ASSERT_LOW_LAYER(c.ThisActor && c.OtherActor); + c.Impulse = Vector3::Zero; + c.ThisVelocity = P2C(hit.dir) * hit.length; + c.OtherVelocity = Vector3::Zero; + c.ContactsCount = 1; + ContactPoint& contact = c.Contacts[0]; + contact.Point = P2C(hit.worldPos); + contact.Normal = P2C(hit.worldNormal); + contact.Separation = 0.0f; + + //auto simulationEventCallback = static_cast(hit.controller->getScene()->getSimulationEventCallback()); + //simulationEventCallback->Collisions[SimulationEventCallback::CollidersPair(c.ThisActor, c.OtherActor)] = c; + // TODO: build additional list for hit-only events to properly send enter/exit pairs instead of spamming every frame whether controller executes move + + // Single-hit collision + c.ThisActor->OnCollisionEnter(c); + c.SwapObjects(); + c.ThisActor->OnCollisionEnter(c); + c.SwapObjects(); + c.ThisActor->OnCollisionExit(c); + c.SwapObjects(); + c.ThisActor->OnCollisionExit(c); + } + + void onShapeHit(const PxControllerShapeHit& hit) override + { + Collision c; + PxShape* controllerShape; + hit.controller->getActor()->getShapes(&controllerShape, 1); + c.ThisActor = static_cast(controllerShape->userData); + c.OtherActor = static_cast(hit.shape->userData); + onHit(hit, c); + } + + void onControllerHit(const PxControllersHit& hit) override + { + Collision c; + PxShape* controllerShape; + hit.controller->getActor()->getShapes(&controllerShape, 1); + c.ThisActor = static_cast(controllerShape->userData); + hit.other->getActor()->getShapes(&controllerShape, 1); + c.OtherActor = static_cast(controllerShape->userData); + onHit(hit, c); + } + + void onObstacleHit(const PxControllerObstacleHit& hit) override + { + } +}; + #if WITH_VEHICLE class WheelFilterPhysX : public PxQueryFilterCallback @@ -383,6 +437,7 @@ namespace QueryFilterPhysX QueryFilter; CharacterQueryFilterPhysX CharacterQueryFilter; CharacterControllerFilterPhysX CharacterControllerFilter; + CharacterControllerHitReportPhysX CharacterControllerHitReport; Dictionary> SceneOrigins; CriticalSection FlushLocker; @@ -2475,6 +2530,7 @@ void* PhysicsBackend::CreateController(void* scene, IPhysicsActor* actor, Physic const Vector3 sceneOrigin = SceneOrigins[scenePhysX->Scene]; PxCapsuleControllerDesc desc; desc.userData = actor; + desc.reportCallback = &CharacterControllerHitReport; desc.contactOffset = Math::Max(contactOffset, ZeroTolerance); desc.position = PxExtendedVec3(position.X - sceneOrigin.X, position.Y - sceneOrigin.Y, position.Z - sceneOrigin.Z); desc.slopeLimit = Math::Cos(slopeLimit * DegreesToRadians); From 1d8ae580b71eb3db23d55135f2f634014cd78c12 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 24 Jun 2023 12:05:51 -0500 Subject: [PATCH 23/65] Add Realloc with alignment. --- Source/Engine/Core/Memory/Memory.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Source/Engine/Core/Memory/Memory.h b/Source/Engine/Core/Memory/Memory.h index 770fd2c22..a35929ed2 100644 --- a/Source/Engine/Core/Memory/Memory.h +++ b/Source/Engine/Core/Memory/Memory.h @@ -36,6 +36,32 @@ namespace AllocatorExt return result; } + /// + /// Reallocates block of the memory. + /// + /// + /// A pointer to the memory block to reallocate. + /// The size of the new allocation (in bytes). + /// The memory alignment (in bytes). Must be an integer power of 2. + /// The pointer to the allocated chunk of the memory. The pointer is a multiple of alignment. + inline void* ReallocWithAlignment(void* ptr, uint64 newSize, uint64 alignment) + { + if (newSize == 0) + { + Allocator::Free(ptr); + return nullptr; + } + if (!ptr) + return Allocator::Allocate(newSize, alignment); + void* result = Allocator::Allocate(newSize, alignment); + if (result) + { + Platform::MemoryCopy(result, ptr, newSize); + Allocator::Free(ptr); + } + return result; + } + /// /// Reallocates block of the memory. /// From 9282bcfbbfaca4ed83bb2355f1292f40053df305 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 25 Jun 2023 21:24:30 +0200 Subject: [PATCH 24/65] Fix crash due to invalid RPC codegen for enum value type variable --- Source/Tools/Flax.Build/Utilities/MonoCecil.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Tools/Flax.Build/Utilities/MonoCecil.cs b/Source/Tools/Flax.Build/Utilities/MonoCecil.cs index 0301e33d2..188327931 100644 --- a/Source/Tools/Flax.Build/Utilities/MonoCecil.cs +++ b/Source/Tools/Flax.Build/Utilities/MonoCecil.cs @@ -249,7 +249,7 @@ namespace Flax.Build public static void GetType(this ModuleDefinition module, string fullName, out TypeReference type) { - if (!module.TryGetTypeReference(fullName, out type)) + //if (!module.TryGetTypeReference(fullName, out type)) // TODO: this seams to return 'FlaxEngine.Networking.NetworkManagerMode' as a Class instead of Enum { // Do manual search foreach (var a in module.AssemblyReferences) From cbd1e5c837c0c28a81ddf2e7dc2e2a82bf9a30cc Mon Sep 17 00:00:00 2001 From: Wiktor Kocielski Date: Sun, 25 Jun 2023 23:39:59 +0300 Subject: [PATCH 25/65] Add NetworkReplicationNode::GetObject --- .../Engine/Networking/NetworkReplicationHierarchy.cpp | 11 +++++++++++ .../Engine/Networking/NetworkReplicationHierarchy.h | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp index 32b7978d0..364e4f7dd 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp @@ -63,6 +63,17 @@ bool NetworkReplicationNode::RemoveObject(ScriptingObject* obj) return !Objects.Remove(obj); } +bool NetworkReplicationNode::GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result) +{ + const int32 index = Objects.Find(obj); + if (index != -1) + { + result = Objects[index]; + return true; + } + return false; +} + bool NetworkReplicationNode::DirtyObject(ScriptingObject* obj) { const int32 index = Objects.Find(obj); diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.h b/Source/Engine/Networking/NetworkReplicationHierarchy.h index 36701c15d..1260859a5 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.h +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.h @@ -200,6 +200,14 @@ API_CLASS(Abstract, Namespace = "FlaxEngine.Networking") class FLAXENGINE_API Ne /// True on successful removal, otherwise false. API_FUNCTION() virtual bool RemoveObject(ScriptingObject* obj); + /// + /// Gets object from the hierarchy. + /// + /// The object to get. + /// The hierarchy object to retrieve. + /// True on successful retrieval, otherwise false. + API_FUNCTION() bool GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result); + /// /// Force replicates the object during the next update. Resets any internal tracking state to force the synchronization. /// From 65397621e90138ce9e2b6992cbb1fcd409954321 Mon Sep 17 00:00:00 2001 From: Wiktor Kocielski Date: Mon, 26 Jun 2023 17:12:48 +0300 Subject: [PATCH 26/65] Make GetObject virtual and implement for Grid --- .../Networking/NetworkReplicationHierarchy.cpp | 12 ++++++++++++ .../Engine/Networking/NetworkReplicationHierarchy.h | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp index 364e4f7dd..e95a06423 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp @@ -186,6 +186,18 @@ bool NetworkReplicationGridNode::RemoveObject(ScriptingObject* obj) return false; } +bool NetworkReplicationGridNode::GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result) +{ + for (const auto& e : _children) + { + if (e.Value.Node->GetObject(obj, result)) + { + return true; + } + } + return false; +} + void NetworkReplicationGridNode::Update(NetworkReplicationHierarchyUpdateResult* result) { CHECK(result); diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.h b/Source/Engine/Networking/NetworkReplicationHierarchy.h index 1260859a5..ae482dfa6 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.h +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.h @@ -206,7 +206,7 @@ API_CLASS(Abstract, Namespace = "FlaxEngine.Networking") class FLAXENGINE_API Ne /// The object to get. /// The hierarchy object to retrieve. /// True on successful retrieval, otherwise false. - API_FUNCTION() bool GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result); + API_FUNCTION() virtual bool GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result); /// /// Force replicates the object during the next update. Resets any internal tracking state to force the synchronization. @@ -255,6 +255,7 @@ public: void AddObject(NetworkReplicationHierarchyObject obj) override; bool RemoveObject(ScriptingObject* obj) override; + bool GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result) override; void Update(NetworkReplicationHierarchyUpdateResult* result) override; }; From 60137059889fa164c3897288ee3a3fffe5824e8d Mon Sep 17 00:00:00 2001 From: Wiktor Kocielski Date: Mon, 26 Jun 2023 17:32:19 +0300 Subject: [PATCH 27/65] Implement object to cell caching for the grid --- .../NetworkReplicationHierarchy.cpp | 34 ++++++++++++------- .../Networking/NetworkReplicationHierarchy.h | 1 + 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp index e95a06423..5097b6a26 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp @@ -167,6 +167,7 @@ void NetworkReplicationGridNode::AddObject(NetworkReplicationHierarchyObject obj cell->MinCullDistance = obj.CullDistance; } cell->Node->AddObject(obj); + _objectToCell[obj.Object] = coord; // Cache minimum culling distance for a whole cell to skip it at once cell->MinCullDistance = Math::Min(cell->MinCullDistance, obj.CullDistance); @@ -174,26 +175,35 @@ void NetworkReplicationGridNode::AddObject(NetworkReplicationHierarchyObject obj bool NetworkReplicationGridNode::RemoveObject(ScriptingObject* obj) { - for (const auto& e : _children) + Int3 coord; + + if (!_objectToCell.TryGet(obj, coord)) { - if (e.Value.Node->RemoveObject(obj)) - { - // TODO: remove empty cells? - // TODO: update MinCullDistance for cell? - return true; - } + return false; + } + + if (_children[coord].Node->RemoveObject(obj)) + { + _objectToCell.Remove(obj); + // TODO: remove empty cells? + // TODO: update MinCullDistance for cell? + return true; } return false; } bool NetworkReplicationGridNode::GetObject(ScriptingObject* obj, NetworkReplicationHierarchyObject& result) { - for (const auto& e : _children) + Int3 coord; + + if (!_objectToCell.TryGet(obj, coord)) { - if (e.Value.Node->GetObject(obj, result)) - { - return true; - } + return false; + } + + if (_children[coord].Node->GetObject(obj, result)) + { + return true; } return false; } diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.h b/Source/Engine/Networking/NetworkReplicationHierarchy.h index ae482dfa6..b054de453 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.h +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.h @@ -246,6 +246,7 @@ private: }; Dictionary _children; + Dictionary _objectToCell; public: /// From 020b0a90d76a58dce1d3dbceedff6fe5b7c1addf Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Tue, 27 Jun 2023 00:22:12 -0400 Subject: [PATCH 28/65] remove unecessary code --- Source/Editor/ProjectInfo.cs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Source/Editor/ProjectInfo.cs b/Source/Editor/ProjectInfo.cs index 62402b0d8..bc55a9c05 100644 --- a/Source/Editor/ProjectInfo.cs +++ b/Source/Editor/ProjectInfo.cs @@ -55,16 +55,6 @@ namespace FlaxEditor [NonSerialized] public string ProjectFolderPath; - /// - /// The content assets folder - /// - public string ContentFolderPath; - - /// - /// The source files folder path - /// - public string SourceFolderPath; - /// /// The project version. /// @@ -167,8 +157,6 @@ namespace FlaxEditor var project = JsonConvert.DeserializeObject(contents); project.ProjectPath = path; project.ProjectFolderPath = StringUtils.NormalizePath(Path.GetDirectoryName(path)); - project.ContentFolderPath = StringUtils.NormalizePath(project.ProjectFolderPath + "/Content"); - project.SourceFolderPath = StringUtils.NormalizePath(project.ProjectFolderPath + "/Source"); // Process project data if (string.IsNullOrEmpty(project.Name)) From 75d5023354f8c6f3cdf046845b4b1bc8cb96fff1 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 27 Jun 2023 23:24:02 +0200 Subject: [PATCH 29/65] Fix tooltip for project folder --- Source/Editor/Utilities/Utils.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs index d980b0c4a..fe801bbaf 100644 --- a/Source/Editor/Utilities/Utils.cs +++ b/Source/Editor/Utilities/Utils.cs @@ -1125,7 +1125,9 @@ namespace FlaxEditor.Utilities public static string GetAssetNamePathWithExt(string path) { var projectFolder = Globals.ProjectFolder; - if (path.StartsWith(projectFolder)) + if (path == projectFolder) + path = string.Empty; + else if (path.StartsWith(projectFolder)) path = path.Substring(projectFolder.Length + 1); return path; } From 90f9754781105f2d29e898aa820bb0c57f54de59 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Wed, 28 Jun 2023 00:35:06 +0300 Subject: [PATCH 30/65] Release custom assets before binary modules on scripting release --- Source/Engine/Scripting/Scripting.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index bbd109cd1..e2d709653 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -559,6 +559,16 @@ void Scripting::Release() } _objectsLocker.Unlock(); + // Release assets sourced from game assemblies + const auto flaxModule = GetBinaryModuleFlaxEngine(); + for (auto asset : Content::GetAssets()) + { + if (asset->GetTypeHandle().Module == flaxModule) + continue; + + asset->DeleteObjectNow(); + } + // Unload assemblies (from back to front) { LOG(Info, "Unloading binary modules"); From fe8260fe140a2b0c7285611726852f87b05c6fd3 Mon Sep 17 00:00:00 2001 From: PhyresiCompany Date: Tue, 27 Jun 2023 19:58:37 -0300 Subject: [PATCH 31/65] Window improvements with a new approach --- .../Viewport/Previews/AnimatedModelPreview.cs | 116 ++--------- .../Viewport/Previews/MaterialPreview.cs | 50 +++-- .../Viewport/Previews/ModelBasePreview.cs | 27 +-- .../Editor/Viewport/Previews/ModelPreview.cs | 84 ++++++-- .../Viewport/Previews/SkinnedModelPreview.cs | 188 ++++++++++++++++++ .../Windows/Assets/CollisionDataWindow.cs | 3 + Source/Editor/Windows/Assets/ModelWindow.cs | 9 + .../Windows/Assets/SkinnedModelWindow.cs | 11 +- 8 files changed, 342 insertions(+), 146 deletions(-) create mode 100644 Source/Editor/Viewport/Previews/SkinnedModelPreview.cs diff --git a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs index 2310668b6..aae48fe11 100644 --- a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs @@ -15,11 +15,13 @@ namespace FlaxEditor.Viewport.Previews /// public class AnimatedModelPreview : AssetPreview { + /// + public AnimatedModel _previewModel; + private ContextMenuButton _showNodesButton, _showBoundsButton, _showFloorButton, _showNodesNamesButton; - private bool _showNodes, _showBounds, _showFloor, _showCurrentLOD, _showNodesNames; - private AnimatedModel _previewModel; + private bool _showNodes, _showBounds, _showFloor, _showNodesNames; private StaticModel _floorModel; - private ContextMenuButton _showCurrentLODButton; + private bool _playAnimation, _playAnimationOnce; private float _playSpeed = 1.0f; @@ -207,26 +209,6 @@ namespace FlaxEditor.Viewport.Previews // Show Floor _showFloorButton = ViewWidgetShowMenu.AddButton("Floor", button => ShowFloor = !ShowFloor); _showFloorButton.IndexInParent = 1; - - // Show Current LOD - _showCurrentLODButton = ViewWidgetShowMenu.AddButton("Current LOD", button => - { - _showCurrentLOD = !_showCurrentLOD; - _showCurrentLODButton.Icon = _showCurrentLOD ? Style.Current.CheckBoxTick : SpriteHandle.Invalid; - }); - _showCurrentLODButton.IndexInParent = 2; - - // Preview LOD - { - var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD"); - previewLOD.CloseMenuOnClick = false; - var previewLODValue = new IntValueBox(-1, 90, 2, 70.0f, -1, 10, 0.02f) - { - Parent = previewLOD - }; - previewLODValue.ValueChanged += () => _previewModel.ForcedLOD = previewLODValue.Value; - ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = _previewModel.ForcedLOD; - } } // Enable shadows @@ -339,44 +321,6 @@ namespace FlaxEditor.Viewport.Previews _previewModel.ResetAnimation(); } - private int ComputeLODIndex(SkinnedModel model) - { - if (PreviewActor.ForcedLOD != -1) - return PreviewActor.ForcedLOD; - - // Based on RenderTools::ComputeModelLOD - CreateProjectionMatrix(out var projectionMatrix); - float screenMultiple = 0.5f * Mathf.Max(projectionMatrix.M11, projectionMatrix.M22); - var sphere = PreviewActor.Sphere; - var viewOrigin = ViewPosition; - var distSqr = Vector3.DistanceSquared(ref sphere.Center, ref viewOrigin); - var screenRadiusSquared = Mathf.Square(screenMultiple * sphere.Radius) / Mathf.Max(1.0f, distSqr); - - // Check if model is being culled - if (Mathf.Square(model.MinScreenSize * 0.5f) > screenRadiusSquared) - return -1; - - // Skip if no need to calculate LOD - if (model.LoadedLODs == 0) - return -1; - var lods = model.LODs; - if (lods.Length == 0) - return -1; - if (lods.Length == 1) - return 0; - - // Iterate backwards and return the first matching LOD - for (int lodIndex = lods.Length - 1; lodIndex >= 0; lodIndex--) - { - if (Mathf.Square(lods[lodIndex].ScreenSize * 0.5f) >= screenRadiusSquared) - { - return lodIndex + PreviewActor.LODBias; - } - } - - return 0; - } - /// protected override void OnDebugDraw(GPUContext context, ref RenderContext renderContext) { @@ -440,45 +384,6 @@ namespace FlaxEditor.Viewport.Previews } } - /// - public override void Draw() - { - base.Draw(); - - var skinnedModel = _previewModel.SkinnedModel; - if (skinnedModel == null || !skinnedModel.IsLoaded) - return; - var lods = skinnedModel.LODs; - if (lods.Length == 0) - { - // Force show skeleton for models without geometry - ShowNodes = true; - return; - } - if (_showCurrentLOD) - { - var lodIndex = ComputeLODIndex(skinnedModel); - string text = string.Format("Current LOD: {0}", lodIndex); - if (lodIndex != -1) - { - lodIndex = Mathf.Clamp(lodIndex + PreviewActor.LODBias, 0, lods.Length - 1); - var lod = lods[lodIndex]; - int triangleCount = 0, vertexCount = 0; - for (int meshIndex = 0; meshIndex < lod.Meshes.Length; meshIndex++) - { - var mesh = lod.Meshes[meshIndex]; - triangleCount += mesh.TriangleCount; - vertexCount += mesh.VertexCount; - } - text += string.Format("\nTriangles: {0:N0}\nVertices: {1:N0}", triangleCount, vertexCount); - } - var font = Style.Current.FontMedium; - var pos = new Float2(10, 50); - Render2D.DrawText(font, text, new Rectangle(pos + Float2.One, Size), Color.Black); - Render2D.DrawText(font, text, new Rectangle(pos, Size), Color.White); - } - } - /// public override void Update(float deltaTime) { @@ -498,6 +403,14 @@ namespace FlaxEditor.Viewport.Previews } } + /// + /// Calls SetArcBallView from ViewportCamera + /// + public void CallSetArcBallView() + { + ViewportCamera.SetArcBallView(_previewModel.Box); + } + /// public override bool OnKeyDown(KeyboardKeys key) { @@ -505,7 +418,7 @@ namespace FlaxEditor.Viewport.Previews { case KeyboardKeys.F: // Pay respect.. - ViewportCamera.SetArcBallView(_previewModel.Box); + CallSetArcBallView(); return true; case KeyboardKeys.Spacebar: PlayAnimation = !PlayAnimation; @@ -525,7 +438,6 @@ namespace FlaxEditor.Viewport.Previews _showNodesButton = null; _showBoundsButton = null; _showFloorButton = null; - _showCurrentLODButton = null; _showNodesNamesButton = null; base.OnDestroy(); diff --git a/Source/Editor/Viewport/Previews/MaterialPreview.cs b/Source/Editor/Viewport/Previews/MaterialPreview.cs index 632ec199e..3dfab1cff 100644 --- a/Source/Editor/Viewport/Previews/MaterialPreview.cs +++ b/Source/Editor/Viewport/Previews/MaterialPreview.cs @@ -4,6 +4,8 @@ using System; using FlaxEditor.Surface; using FlaxEngine; using FlaxEngine.GUI; +using FlaxEditor.Viewport.Widgets; +using FlaxEditor.GUI.ContextMenu; using Object = FlaxEngine.Object; namespace FlaxEditor.Viewport.Previews @@ -63,6 +65,11 @@ namespace FlaxEditor.Viewport.Previews } } + /// + /// The "Model" widget button context menu. + /// + private ContextMenu modelWidgetButtonMenu; + /// /// Gets or sets the selected preview model index. /// @@ -80,6 +87,27 @@ namespace FlaxEditor.Viewport.Previews } } + /// + /// Fill out all models + /// + /// + private void ModelWidgetMenuOnVisibleChanged(Control control) + { + if (!control.Visible) return; + + modelWidgetButtonMenu.ItemsContainer.DisposeChildren(); + + // Fill out all models + for (int i = 0; i < Models.Length; i++) + { + var index = i; + var button = modelWidgetButtonMenu.AddButton(Models[index]); + button.ButtonClicked += (button) => SelectedModelIndex = index; + button.Checked = SelectedModelIndex == index; + button.Tag = index; + } + } + /// /// Initializes a new instance of the class. /// @@ -95,20 +123,18 @@ namespace FlaxEditor.Viewport.Previews Task.AddCustomActor(_previewModel); // Create context menu for primitive switching - if (useWidgets && ViewWidgetButtonMenu != null) + if (useWidgets) { - ViewWidgetButtonMenu.AddSeparator(); - var modelSelect = ViewWidgetButtonMenu.AddChildMenu("Model").ContextMenu; - - // Fill out all models - for (int i = 0; i < Models.Length; i++) + // Model mode widget + var modelMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); + modelWidgetButtonMenu = new ContextMenu(); + modelWidgetButtonMenu.VisibleChanged += ModelWidgetMenuOnVisibleChanged; + var previewLODSModeButton = new ViewportWidgetButton("Model", SpriteHandle.Invalid, modelWidgetButtonMenu) { - var button = modelSelect.AddButton(Models[i]); - button.Tag = i; - } - - // Link the action - modelSelect.ButtonClicked += (button) => SelectedModelIndex = (int)button.Tag; + TooltipText = "Change material model", + Parent = modelMode, + }; + modelMode.Parent = this; } } diff --git a/Source/Editor/Viewport/Previews/ModelBasePreview.cs b/Source/Editor/Viewport/Previews/ModelBasePreview.cs index ffba23094..e5834edc9 100644 --- a/Source/Editor/Viewport/Previews/ModelBasePreview.cs +++ b/Source/Editor/Viewport/Previews/ModelBasePreview.cs @@ -56,25 +56,14 @@ namespace FlaxEditor.Viewport.Previews // Link actors for rendering Task.AddCustomActor(StaticModel); Task.AddCustomActor(AnimatedModel); + } - if (useWidgets) - { - // Preview LOD - { - var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD"); - previewLOD.CloseMenuOnClick = false; - var previewLODValue = new IntValueBox(-1, 90, 2, 70.0f, -1, 10, 0.02f) - { - Parent = previewLOD - }; - previewLODValue.ValueChanged += () => - { - StaticModel.ForcedLOD = previewLODValue.Value; - AnimatedModel.ForcedLOD = previewLODValue.Value; - }; - ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = StaticModel.ForcedLOD; - } - } + /// + /// Calls SetArcBallView from ViewportCamera + /// + public void CallSetArcBallView() + { + ViewportCamera.SetArcBallView(StaticModel.Model != null ? StaticModel.Box : AnimatedModel.Box); } private void OnBegin(RenderTask task, GPUContext context) @@ -104,7 +93,7 @@ namespace FlaxEditor.Viewport.Previews { case KeyboardKeys.F: // Pay respect.. - ViewportCamera.SetArcBallView(StaticModel.Model != null ? StaticModel.Box : AnimatedModel.Box); + CallSetArcBallView(); break; } return base.OnKeyDown(key); diff --git a/Source/Editor/Viewport/Previews/ModelPreview.cs b/Source/Editor/Viewport/Previews/ModelPreview.cs index 9193b6d40..dc0de37da 100644 --- a/Source/Editor/Viewport/Previews/ModelPreview.cs +++ b/Source/Editor/Viewport/Previews/ModelPreview.cs @@ -5,6 +5,7 @@ using FlaxEditor.GUI.Input; using FlaxEngine; using FlaxEngine.GUI; using FlaxEngine.Utilities; +using FlaxEditor.Viewport.Widgets; using Object = FlaxEngine.Object; namespace FlaxEditor.Viewport.Previews @@ -20,6 +21,29 @@ namespace FlaxEditor.Viewport.Previews private bool _showBounds, _showCurrentLOD, _showNormals, _showTangents, _showBitangents, _showFloor; private MeshDataCache _meshDatas; + /// + /// The "PreviewLODS" widget button context menu. + /// + private ContextMenu previewLODSWidgetButtonMenu; + + /// + /// Gets or sets a value that shows LOD statistics + /// + public bool ShowCurrentLOD + { + get => _showCurrentLOD; + set + { + if (_showCurrentLOD == value) + return; + _showCurrentLOD = value; + if (value) + ShowDebugDraw = true; + if (_showCurrentLODButton != null) + _showCurrentLODButton.Checked = value; + } + } + /// /// Gets or sets the model asset to preview. /// @@ -198,16 +222,41 @@ namespace FlaxEditor.Viewport.Previews }); _showCurrentLODButton.IndexInParent = 2; - // Preview LOD + // PreviewLODS mode widget + var PreviewLODSMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); + previewLODSWidgetButtonMenu = new ContextMenu(); + previewLODSWidgetButtonMenu.VisibleChanged += PreviewLODSWidgetMenuOnVisibleChanged; + var previewLODSModeButton = new ViewportWidgetButton("Preview LOD", SpriteHandle.Invalid, previewLODSWidgetButtonMenu) { - var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD"); - previewLOD.CloseMenuOnClick = false; - var previewLODValue = new IntValueBox(-1, 90, 2, 70.0f, -1, 10, 0.02f) - { - Parent = previewLOD - }; - previewLODValue.ValueChanged += () => _previewModel.ForcedLOD = previewLODValue.Value; - ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = _previewModel.ForcedLOD; + TooltipText = "Preview LOD properties", + Parent = PreviewLODSMode, + }; + PreviewLODSMode.Parent = this; + } + } + + /// + /// Fill out all Model LODS + /// + /// + private void PreviewLODSWidgetMenuOnVisibleChanged(Control control) + { + if (!control.Visible) + return; + + var model = _previewModel.Model; + if (model && !model.WaitForLoaded() && model.IsLoaded) + { + previewLODSWidgetButtonMenu.ItemsContainer.DisposeChildren(); + var lods = model.LODs.Length; + for (int i = -1; i < lods; i++) + { + var index = i; + var button = previewLODSWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); + button.ButtonClicked += (button) => _previewModel.ForcedLOD = index; + button.Checked = _previewModel.ForcedLOD == index; + button.Tag = index; + if (lods <= 1) return; } } } @@ -346,8 +395,11 @@ namespace FlaxEditor.Viewport.Previews if (_showCurrentLOD) { var asset = Model; - var lodIndex = ComputeLODIndex(asset, out var screenSize); - string text = string.Format("Current LOD: {0}\nScreen Size: {1:F2}", lodIndex, screenSize); + var lodIndex = ComputeLODIndex(asset, out var screenSize); + var auto = _previewModel.ForcedLOD == -1; + string text = auto ? "LOD Automatic" : ""; + text += auto ? string.Format("\nScreen Size: {0:F2}", screenSize) : ""; + text += string.Format("\nCurrent LOD: {0}", lodIndex); if (lodIndex != -1) { var lods = asset.LODs; @@ -369,6 +421,14 @@ namespace FlaxEditor.Viewport.Previews } } + /// + /// Calls SetArcBallView from ViewportCamera + /// + public void CallSetArcBallView() + { + ViewportCamera.SetArcBallView(_previewModel.Box); + } + /// public override bool OnKeyDown(KeyboardKeys key) { @@ -376,7 +436,7 @@ namespace FlaxEditor.Viewport.Previews { case KeyboardKeys.F: // Pay respect.. - ViewportCamera.SetArcBallView(_previewModel.Box); + CallSetArcBallView(); break; } return base.OnKeyDown(key); diff --git a/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs b/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs new file mode 100644 index 000000000..a8b98b423 --- /dev/null +++ b/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs @@ -0,0 +1,188 @@ +using System; +using FlaxEditor.GUI.ContextMenu; +using FlaxEngine; +using FlaxEngine.GUI; +using FlaxEditor.Viewport.Widgets; + +namespace FlaxEditor.Viewport.Previews +{ + /// + /// Animation asset preview editor viewport. + /// + /// + public class SkinnedModelPreview : AnimatedModelPreview + { + private bool _showCurrentLOD; + private ContextMenuButton _showCurrentLODButton; + + /// + /// The "PreviewLODS" widget button context menu. + /// + private ContextMenu previewLODSWidgetButtonMenu; + + /// + /// Gets or sets a value that shows LOD statistics + /// + public bool ShowCurrentLOD + { + get => _showCurrentLOD; + set + { + if (_showCurrentLOD == value) + return; + _showCurrentLOD = value; + if (value) + ShowDebugDraw = true; + if (_showCurrentLODButton != null) + _showCurrentLODButton.Checked = value; + } + } + + /// + /// Initializes a new instance of the class. + /// + /// if set to true use widgets. + public SkinnedModelPreview(bool useWidgets) + : base(useWidgets) + { + if (useWidgets) + { + // Show Current LOD + _showCurrentLODButton = ViewWidgetShowMenu.AddButton("Current LOD", button => + { + _showCurrentLOD = !_showCurrentLOD; + _showCurrentLODButton.Icon = _showCurrentLOD ? Style.Current.CheckBoxTick : SpriteHandle.Invalid; + }); + _showCurrentLODButton.IndexInParent = 2; + + // PreviewLODS mode widget + var PreviewLODSMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); + previewLODSWidgetButtonMenu = new ContextMenu(); + previewLODSWidgetButtonMenu.VisibleChanged += PreviewLODSWidgetMenuOnVisibleChanged; + var previewLODSModeButton = new ViewportWidgetButton("Preview LOD", SpriteHandle.Invalid, previewLODSWidgetButtonMenu) + { + TooltipText = "Preview LOD properties", + Parent = PreviewLODSMode, + }; + PreviewLODSMode.Parent = this; + } + } + + /// + /// Fill out all SkinnedModel LODS + /// + /// + private void PreviewLODSWidgetMenuOnVisibleChanged(Control control) + { + if (!control.Visible) + return; + + var skinned = _previewModel.SkinnedModel; + if (skinned && !skinned.WaitForLoaded() && skinned.IsLoaded) + { + previewLODSWidgetButtonMenu.ItemsContainer.DisposeChildren(); + var lods = skinned.LODs.Length; + for (int i = -1; i < lods; i++) + { + var index = i; + var button = previewLODSWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); + button.ButtonClicked += (button) => _previewModel.ForcedLOD = index; + button.Checked = _previewModel.ForcedLOD == index; + button.Tag = index; + if (lods <= 1) return; + } + } + } + + /// + private int ComputeLODIndex(SkinnedModel model, out float screenSize) + { + screenSize = 1.0f; + if (PreviewActor.ForcedLOD != -1) + return PreviewActor.ForcedLOD; + + // Based on RenderTools::ComputeModelLOD + CreateProjectionMatrix(out var projectionMatrix); + float screenMultiple = 0.5f * Mathf.Max(projectionMatrix.M11, projectionMatrix.M22); + var sphere = PreviewActor.Sphere; + var viewOrigin = ViewPosition; + var distSqr = Vector3.DistanceSquared(ref sphere.Center, ref viewOrigin); + var screenRadiusSquared = Mathf.Square(screenMultiple * sphere.Radius) / Mathf.Max(1.0f, distSqr); + screenSize = Mathf.Sqrt((float)screenRadiusSquared) * 2.0f; + + // Check if model is being culled + if (Mathf.Square(model.MinScreenSize * 0.5f) > screenRadiusSquared) + return -1; + + // Skip if no need to calculate LOD + if (model.LoadedLODs == 0) + return -1; + var lods = model.LODs; + if (lods.Length == 0) + return -1; + if (lods.Length == 1) + return 0; + + // Iterate backwards and return the first matching LOD + for (int lodIndex = lods.Length - 1; lodIndex >= 0; lodIndex--) + { + if (Mathf.Square(lods[lodIndex].ScreenSize * 0.5f) >= screenRadiusSquared) + { + return lodIndex + PreviewActor.LODBias; + } + } + + return 0; + } + + /// + public override void Draw() + { + base.Draw(); + + var skinnedModel = _previewModel.SkinnedModel; + if (skinnedModel == null || !skinnedModel.IsLoaded) + return; + var lods = skinnedModel.LODs; + if (lods.Length == 0) + { + // Force show skeleton for models without geometry + ShowNodes = true; + return; + } + if (_showCurrentLOD) + { + var lodIndex = ComputeLODIndex(skinnedModel, out var screenSize); + var auto = _previewModel.ForcedLOD == -1; + string text = auto ? "LOD Automatic" : ""; + text += auto ? string.Format("\nScreen Size: {0:F2}", screenSize) : ""; + text += string.Format("\nCurrent LOD: {0}", lodIndex); + if (lodIndex != -1) + { + lodIndex = Mathf.Clamp(lodIndex + PreviewActor.LODBias, 0, lods.Length - 1); + var lod = lods[lodIndex]; + int triangleCount = 0, vertexCount = 0; + for (int meshIndex = 0; meshIndex < lod.Meshes.Length; meshIndex++) + { + var mesh = lod.Meshes[meshIndex]; + triangleCount += mesh.TriangleCount; + vertexCount += mesh.VertexCount; + } + text += string.Format("\nTriangles: {0:N0}\nVertices: {1:N0}", triangleCount, vertexCount); + } + var font = Style.Current.FontMedium; + var pos = new Float2(10, 50); + Render2D.DrawText(font, text, new Rectangle(pos + Float2.One, Size), Color.Black); + Render2D.DrawText(font, text, new Rectangle(pos, Size), Color.White); + } + } + + /// + public override void OnDestroy() + { + _showCurrentLODButton = null; + + base.OnDestroy(); + } + } +} diff --git a/Source/Editor/Windows/Assets/CollisionDataWindow.cs b/Source/Editor/Windows/Assets/CollisionDataWindow.cs index 9ce4c8765..82e0681fa 100644 --- a/Source/Editor/Windows/Assets/CollisionDataWindow.cs +++ b/Source/Editor/Windows/Assets/CollisionDataWindow.cs @@ -182,6 +182,9 @@ namespace FlaxEditor.Windows.Assets { // Toolstrip _toolstrip.AddSeparator(); + + _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.CallSetArcBallView()).LinkTooltip("Show whole collision"); + _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/physics/colliders/collision-data.html")).LinkTooltip("See documentation to learn more"); // Split Panel diff --git a/Source/Editor/Windows/Assets/ModelWindow.cs b/Source/Editor/Windows/Assets/ModelWindow.cs index e44882b73..cc7657fc7 100644 --- a/Source/Editor/Windows/Assets/ModelWindow.cs +++ b/Source/Editor/Windows/Assets/ModelWindow.cs @@ -779,12 +779,18 @@ namespace FlaxEditor.Windows.Assets private MeshDataCache _meshData; private ModelImportSettings _importSettings = new ModelImportSettings(); private float _backfacesThreshold = 0.6f; + private ToolStripButton _showCurrentLODButton; /// public ModelWindow(Editor editor, AssetItem item) : base(editor, item) { // Toolstrip + _toolstrip.AddSeparator(); + _showCurrentLODButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Info64, () => _preview.ShowCurrentLOD = !_preview.ShowCurrentLOD).LinkTooltip("Show LOD statistics"); + + _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.CallSetArcBallView()).LinkTooltip("Show whole model"); + _toolstrip.AddSeparator(); _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/models/index.html")).LinkTooltip("See documentation to learn more"); @@ -869,6 +875,8 @@ namespace FlaxEditor.Windows.Assets } } + _showCurrentLODButton.Checked = _preview.ShowCurrentLOD; + base.Update(deltaTime); } @@ -946,6 +954,7 @@ namespace FlaxEditor.Windows.Assets base.OnDestroy(); Object.Destroy(ref _highlightActor); + _showCurrentLODButton = null; } } } diff --git a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs index d18593549..367fc3a1a 100644 --- a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs +++ b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs @@ -31,7 +31,7 @@ namespace FlaxEditor.Windows.Assets /// public sealed class SkinnedModelWindow : ModelBaseWindow { - private sealed class Preview : AnimatedModelPreview + private sealed class Preview : SkinnedModelPreview { private readonly SkinnedModelWindow _window; @@ -1105,6 +1105,7 @@ namespace FlaxEditor.Windows.Assets private Preview _preview; private AnimatedModel _highlightActor; private ToolStripButton _showNodesButton; + private ToolStripButton _showCurrentLODButton; private MeshData[][] _meshDatas; private bool _meshDatasInProgress; @@ -1116,7 +1117,13 @@ namespace FlaxEditor.Windows.Assets { // Toolstrip _toolstrip.AddSeparator(); + + _showCurrentLODButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Info64, () => _preview.ShowCurrentLOD = !_preview.ShowCurrentLOD).LinkTooltip("Show LOD statistics"); + _showNodesButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Bone64, () => _preview.ShowNodes = !_preview.ShowNodes).LinkTooltip("Show animated model nodes debug view"); + + _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.CallSetArcBallView()).LinkTooltip("Show whole model"); + _toolstrip.AddSeparator(); _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/skinned-model/index.html")).LinkTooltip("See documentation to learn more"); @@ -1265,6 +1272,7 @@ namespace FlaxEditor.Windows.Assets } } + _showCurrentLODButton.Checked = _preview.ShowCurrentLOD; _showNodesButton.Checked = _preview.ShowNodes; base.Update(deltaTime); @@ -1349,6 +1357,7 @@ namespace FlaxEditor.Windows.Assets Object.Destroy(ref _highlightActor); _preview = null; _showNodesButton = null; + _showCurrentLODButton = null; } } } From 76e4e1b8d49e6a71ae9f6c3c5df7555507a568bc Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Tue, 27 Jun 2023 21:08:12 -0400 Subject: [PATCH 32/65] fix debug vehicle wheel orientation --- Source/Engine/Physics/Actors/WheeledVehicle.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.cpp b/Source/Engine/Physics/Actors/WheeledVehicle.cpp index 2ed59c8f6..995150bdc 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.cpp +++ b/Source/Engine/Physics/Actors/WheeledVehicle.cpp @@ -230,10 +230,11 @@ void WheeledVehicle::DrawPhysicsDebug(RenderView& view) { const Vector3 currentPos = wheel.Collider->GetPosition(); const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0); + const Quaternion wheelDebugOrientation = wheel.Collider->GetOrientation() * Quaternion::Euler(90, 0, 90); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(basePos, wheel.Radius * 0.07f), Color::Blue * 0.3f, 0, true); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(currentPos, wheel.Radius * 0.08f), Color::Blue * 0.8f, 0, true); DEBUG_DRAW_LINE(basePos, currentPos, Color::Blue, 0, true); - DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheel.Collider->GetOrientation(), wheel.Radius, wheel.Width, Color::Red * 0.8f, 0, true); + DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheelDebugOrientation, wheel.Radius, wheel.Width, Color::Red * 0.8f, 0, true); if (!data.State.IsInAir) { DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(data.State.TireContactPoint, 5.0f), Color::Green, 0, true); @@ -260,6 +261,7 @@ void WheeledVehicle::OnDebugDrawSelected() { const Vector3 currentPos = wheel.Collider->GetPosition(); const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0); + const Quaternion wheelDebugOrientation = wheel.Collider->GetOrientation() * Quaternion::Euler(90, 0, 90); Transform actorPose = Transform::Identity, shapePose = Transform::Identity; PhysicsBackend::GetRigidActorPose(_actor, actorPose.Translation, actorPose.Orientation); PhysicsBackend::GetShapeLocalPose(wheel.Collider->GetPhysicsShape(), shapePose.Translation, shapePose.Orientation); @@ -267,7 +269,7 @@ void WheeledVehicle::OnDebugDrawSelected() DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(currentPos, wheel.Radius * 0.08f), Color::Blue * 0.8f, 0, false); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(actorPose.LocalToWorld(shapePose.Translation), wheel.Radius * 0.11f), Color::OrangeRed * 0.8f, 0, false); DEBUG_DRAW_LINE(basePos, currentPos, Color::Blue, 0, false); - DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheel.Collider->GetOrientation(), wheel.Radius, wheel.Width, Color::Red * 0.4f, 0, false); + DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheelDebugOrientation, wheel.Radius, wheel.Width, Color::Red * 0.4f, 0, false); if (!data.State.SuspensionTraceStart.IsZero()) { DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(data.State.SuspensionTraceStart, 5.0f), Color::AliceBlue, 0, false); From 17aa4ea60dc4b48243c225612995ad515211e932 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 12:21:58 +0200 Subject: [PATCH 33/65] Optimize `CollisionsHelper::FrustumContainsBox` --- Source/Engine/Core/Math/BoundingFrustum.h | 1 + Source/Engine/Core/Math/CollisionsHelper.cpp | 19 +++++-------------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/Source/Engine/Core/Math/BoundingFrustum.h b/Source/Engine/Core/Math/BoundingFrustum.h index 61c5d122f..287d33c2f 100644 --- a/Source/Engine/Core/Math/BoundingFrustum.h +++ b/Source/Engine/Core/Math/BoundingFrustum.h @@ -12,6 +12,7 @@ /// API_STRUCT(InBuild) struct FLAXENGINE_API BoundingFrustum { + friend CollisionsHelper; private: Matrix _matrix; diff --git a/Source/Engine/Core/Math/CollisionsHelper.cpp b/Source/Engine/Core/Math/CollisionsHelper.cpp index 60ba61f28..8ad5b7673 100644 --- a/Source/Engine/Core/Math/CollisionsHelper.cpp +++ b/Source/Engine/Core/Math/CollisionsHelper.cpp @@ -939,7 +939,6 @@ bool CollisionsHelper::RayIntersectsSphere(const Ray& ray, const BoundingSphere& normal = Vector3::Up; return false; } - const Vector3 point = ray.Position + ray.Direction * distance; normal = Vector3::Normalize(point - sphere.Center); return true; @@ -953,22 +952,17 @@ bool CollisionsHelper::RayIntersectsSphere(const Ray& ray, const BoundingSphere& point = Vector3::Zero; return false; } - point = ray.Position + ray.Direction * distance; return true; } PlaneIntersectionType CollisionsHelper::PlaneIntersectsPoint(const Plane& plane, const Vector3& point) { - Real distance = Vector3::Dot(plane.Normal, point); - distance += plane.D; - + const Real distance = Vector3::Dot(plane.Normal, point) + plane.D; if (distance > Plane::DistanceEpsilon) return PlaneIntersectionType::Front; - if (distance < Plane::DistanceEpsilon) return PlaneIntersectionType::Back; - return PlaneIntersectionType::Intersecting; } @@ -1169,7 +1163,6 @@ ContainmentType CollisionsHelper::SphereContainsPoint(const BoundingSphere& sphe { if (Vector3::DistanceSquared(point, sphere.Center) <= sphere.Radius * sphere.Radius) return ContainmentType::Contains; - return ContainmentType::Disjoint; } @@ -1254,13 +1247,10 @@ ContainmentType CollisionsHelper::SphereContainsBox(const BoundingSphere& sphere ContainmentType CollisionsHelper::SphereContainsSphere(const BoundingSphere& sphere1, const BoundingSphere& sphere2) { const Real distance = Vector3::Distance(sphere1.Center, sphere2.Center); - if (sphere1.Radius + sphere2.Radius < distance) return ContainmentType::Disjoint; - if (sphere1.Radius - sphere2.Radius < distance) return ContainmentType::Intersects; - return ContainmentType::Contains; } @@ -1274,7 +1264,8 @@ ContainmentType CollisionsHelper::FrustumContainsBox(const BoundingFrustum& frus auto result = ContainmentType::Contains; for (int32 i = 0; i < 6; i++) { - Plane plane = frustum.GetPlane(i); + Plane plane = frustum._planes[i]; + Vector3 p = box.Minimum; if (plane.Normal.X >= 0) p.X = box.Maximum.X; @@ -1282,7 +1273,7 @@ ContainmentType CollisionsHelper::FrustumContainsBox(const BoundingFrustum& frus p.Y = box.Maximum.Y; if (plane.Normal.Z >= 0) p.Z = box.Maximum.Z; - if (PlaneIntersectsPoint(plane, p) == PlaneIntersectionType::Back) + if (Vector3::Dot(plane.Normal, p) + plane.D < Plane::DistanceEpsilon) return ContainmentType::Disjoint; p = box.Maximum; @@ -1292,7 +1283,7 @@ ContainmentType CollisionsHelper::FrustumContainsBox(const BoundingFrustum& frus p.Y = box.Minimum.Y; if (plane.Normal.Z >= 0) p.Z = box.Minimum.Z; - if (PlaneIntersectsPoint(plane, p) == PlaneIntersectionType::Back) + if (Vector3::Dot(plane.Normal, p) + plane.D < Plane::DistanceEpsilon) result = ContainmentType::Intersects; } return result; From fb6bc75e3a4cc2fae13ee7416b4c8ada25076e54 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 13:42:18 +0200 Subject: [PATCH 34/65] Fix `launchSettings.json` generation bug --- .../Projects/VisualStudio/VisualStudioProjectGenerator.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs index fb5c90872..1955a57ba 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs @@ -547,6 +547,7 @@ namespace Flax.Build.Projects.VisualStudio if (project.Type == TargetType.DotNetCore) { var path = Path.Combine(Path.GetDirectoryName(project.Path), "Properties/launchSettings.json"); + path = Utilities.NormalizePath(path); if (profiles.ContainsKey(path)) profile.AppendLine(","); profile.AppendLine($" \"{project.BaseName}\": {{"); @@ -568,6 +569,7 @@ namespace Flax.Build.Projects.VisualStudio var folder = Path.GetDirectoryName(e.Key); if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); + profile.Clear(); profile.AppendLine("{"); profile.AppendLine(" \"profiles\": {"); profile.AppendLine(e.Value); From d3b96742e73b6a1bfa2a1356bb90ebb42a2fb379 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Wed, 28 Jun 2023 14:42:06 +0300 Subject: [PATCH 35/65] Fix compile-time error in HashSet::ClearDelete --- Source/Engine/Core/Collections/HashSet.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Core/Collections/HashSet.h b/Source/Engine/Core/Collections/HashSet.h index 698788869..ad6f8ffc6 100644 --- a/Source/Engine/Core/Collections/HashSet.h +++ b/Source/Engine/Core/Collections/HashSet.h @@ -357,8 +357,8 @@ public: { for (Iterator i = Begin(); i.IsNotEnd(); ++i) { - if (i->Value) - ::Delete(i->Value); + if (i->Item) + ::Delete(i->Item); } Clear(); } From 093928f2f96059489f4c47463463a6a2671b0ece Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Wed, 28 Jun 2023 06:42:54 -0500 Subject: [PATCH 36/65] Change name to `ReallocAligned` --- Source/Engine/Core/Memory/Memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Core/Memory/Memory.h b/Source/Engine/Core/Memory/Memory.h index a35929ed2..96acc0746 100644 --- a/Source/Engine/Core/Memory/Memory.h +++ b/Source/Engine/Core/Memory/Memory.h @@ -44,7 +44,7 @@ namespace AllocatorExt /// The size of the new allocation (in bytes). /// The memory alignment (in bytes). Must be an integer power of 2. /// The pointer to the allocated chunk of the memory. The pointer is a multiple of alignment. - inline void* ReallocWithAlignment(void* ptr, uint64 newSize, uint64 alignment) + inline void* ReallocAligned(void* ptr, uint64 newSize, uint64 alignment) { if (newSize == 0) { From b16a6199d0b26c9aa1e0437bd8e2fa581704d53a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 14:52:58 +0200 Subject: [PATCH 37/65] Fix invoking Client RPC on Host client when it's not included in `targetIds` list --- Source/Engine/Core/Types/Span.h | 11 ++++++ .../Engine/Networking/NetworkReplicator.cpp | 18 +++++++-- Source/Engine/Networking/NetworkReplicator.cs | 5 ++- Source/Engine/Networking/NetworkReplicator.h | 5 ++- Source/Engine/Networking/NetworkRpc.h | 7 +--- .../Build/Plugins/NetworkingPlugin.cs | 39 ++++--------------- 6 files changed, 41 insertions(+), 44 deletions(-) diff --git a/Source/Engine/Core/Types/Span.h b/Source/Engine/Core/Types/Span.h index 678550e85..e7bea5fbd 100644 --- a/Source/Engine/Core/Types/Span.h +++ b/Source/Engine/Core/Types/Span.h @@ -114,3 +114,14 @@ inline Span ToSpan(const T* ptr, int32 length) { return Span(ptr, length); } + +template +inline bool SpanContains(const Span span, const T& value) +{ + for (int32 i = 0; i < span.Length(); i++) + { + if (span.Get()[i] == value) + return true; + } + return false; +} diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index c41e104ef..ae7549a50 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -700,9 +700,9 @@ void NetworkReplicator::AddRPC(const ScriptingTypeHandle& typeHandle, const Stri NetworkRpcInfo::RPCsTable[rpcName] = rpcInfo; } -void NetworkReplicator::CSharpEndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, MArray* targetIds) +bool NetworkReplicator::CSharpEndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, MArray* targetIds) { - EndInvokeRPC(obj, type, GetCSharpCachedName(name), argsStream, MUtils::ToSpan(targetIds)); + return EndInvokeRPC(obj, type, GetCSharpCachedName(name), argsStream, MUtils::ToSpan(targetIds)); } StringAnsiView NetworkReplicator::GetCSharpCachedName(const StringAnsiView& name) @@ -1113,12 +1113,12 @@ NetworkStream* NetworkReplicator::BeginInvokeRPC() return CachedWriteStream; } -void NetworkReplicator::EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, Span targetIds) +bool NetworkReplicator::EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, Span targetIds) { Scripting::ObjectsLookupIdMapping.Set(nullptr); const NetworkRpcInfo* info = NetworkRpcInfo::RPCsTable.TryGet(NetworkRpcName(type, name)); if (!info || !obj || NetworkManager::IsOffline()) - return; + return false; ObjectsLock.Lock(); auto& rpc = RpcQueue.AddOne(); rpc.Object = obj; @@ -1135,6 +1135,16 @@ void NetworkReplicator::EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHa } #endif ObjectsLock.Unlock(); + + // Check if skip local execution (eg. server rpc called from client or client rpc with specific targets) + const NetworkManagerMode networkMode = NetworkManager::Mode; + if (info->Server && networkMode == NetworkManagerMode::Client) + return true; + if (info->Client && networkMode == NetworkManagerMode::Server) + return true; + if (info->Client && networkMode == NetworkManagerMode::Host && targetIds.IsValid() && !SpanContains(targetIds, NetworkManager::LocalClientId)) + return true; + return false; } void NetworkInternal::NetworkReplicatorClientConnected(NetworkClient* client) diff --git a/Source/Engine/Networking/NetworkReplicator.cs b/Source/Engine/Networking/NetworkReplicator.cs index 1ca251f75..bc437b82e 100644 --- a/Source/Engine/Networking/NetworkReplicator.cs +++ b/Source/Engine/Networking/NetworkReplicator.cs @@ -120,10 +120,11 @@ namespace FlaxEngine.Networking /// The RPC name. /// The RPC serialized arguments stream returned from BeginInvokeRPC. /// Optional list with network client IDs that should receive RPC. Empty to send on all clients. Ignored by Server RPCs. + /// True if RPC cannot be executed locally, false if execute it locally too (checks RPC mode and target client ids). [Unmanaged] - public static void EndInvokeRPC(Object obj, Type type, string name, NetworkStream argsStream, uint[] targetIds = null) + public static bool EndInvokeRPC(Object obj, Type type, string name, NetworkStream argsStream, uint[] targetIds = null) { - Internal_CSharpEndInvokeRPC(FlaxEngine.Object.GetUnmanagedPtr(obj), type, name, FlaxEngine.Object.GetUnmanagedPtr(argsStream), targetIds); + return Internal_CSharpEndInvokeRPC(FlaxEngine.Object.GetUnmanagedPtr(obj), type, name, FlaxEngine.Object.GetUnmanagedPtr(argsStream), targetIds); } /// diff --git a/Source/Engine/Networking/NetworkReplicator.h b/Source/Engine/Networking/NetworkReplicator.h index 156e7eeea..ecccc52cd 100644 --- a/Source/Engine/Networking/NetworkReplicator.h +++ b/Source/Engine/Networking/NetworkReplicator.h @@ -195,13 +195,14 @@ public: /// The RPC name. /// The RPC serialized arguments stream returned from BeginInvokeRPC. /// Optional list with network client IDs that should receive RPC. Empty to send on all clients. Ignored by Server RPCs. - static void EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, Span targetIds = Span()); + /// True if RPC cannot be executed locally, false if execute it locally too (checks RPC mode and target client ids). + static bool EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, Span targetIds = Span()); private: #if !COMPILE_WITHOUT_CSHARP API_FUNCTION(NoProxy) static void AddSerializer(const ScriptingTypeHandle& typeHandle, const Function& serialize, const Function& deserialize); API_FUNCTION(NoProxy) static void AddRPC(const ScriptingTypeHandle& typeHandle, const StringAnsiView& name, const Function& execute, bool isServer, bool isClient, NetworkChannelType channel); - API_FUNCTION(NoProxy) static void CSharpEndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, MArray* targetIds); + API_FUNCTION(NoProxy) static bool CSharpEndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, MArray* targetIds); static StringAnsiView GetCSharpCachedName(const StringAnsiView& name); #endif }; diff --git a/Source/Engine/Networking/NetworkRpc.h b/Source/Engine/Networking/NetworkRpc.h index c0c8a558e..6e8d26752 100644 --- a/Source/Engine/Networking/NetworkRpc.h +++ b/Source/Engine/Networking/NetworkRpc.h @@ -41,7 +41,7 @@ struct FLAXENGINE_API NetworkRpcInfo uint8 Client : 1; uint8 Channel : 4; void (*Execute)(ScriptingObject* obj, NetworkStream* stream, void* tag); - void (*Invoke)(ScriptingObject* obj, void** args); + bool (*Invoke)(ScriptingObject* obj, void** args); void* Tag; /// @@ -83,10 +83,7 @@ FORCE_INLINE void NetworkRpcInitArg(Array>& args, con { \ Array> args; \ NetworkRpcInitArg(args, __VA_ARGS__); \ - rpcInfo.Invoke(this, args.Get()); \ - if (rpcInfo.Server && networkMode == NetworkManagerMode::Client) \ - return; \ - if (rpcInfo.Client && networkMode == NetworkManagerMode::Server) \ + if (rpcInfo.Invoke(this, args.Get())) \ return; \ } \ } diff --git a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs index 21464ab55..b24b887b3 100644 --- a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs +++ b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs @@ -254,7 +254,7 @@ namespace Flax.Build.Plugins // Generated method thunk to invoke RPC to network { - contents.Append(" static void ").Append(functionInfo.Name).AppendLine("_Invoke(ScriptingObject* obj, void** args)"); + contents.Append(" static bool ").Append(functionInfo.Name).AppendLine("_Invoke(ScriptingObject* obj, void** args)"); contents.AppendLine(" {"); contents.AppendLine(" NetworkStream* stream = NetworkReplicator::BeginInvokeRPC();"); contents.AppendLine(" Span targetIds;"); @@ -274,7 +274,7 @@ namespace Flax.Build.Plugins } // Invoke RPC - contents.AppendLine($" NetworkReplicator::EndInvokeRPC(obj, {typeInfo.NativeName}::TypeInitializer, StringAnsiView(\"{functionInfo.Name}\", {functionInfo.Name.Length}), stream, targetIds);"); + contents.AppendLine($" return NetworkReplicator::EndInvokeRPC(obj, {typeInfo.NativeName}::TypeInitializer, StringAnsiView(\"{functionInfo.Name}\", {functionInfo.Name.Length}), stream, targetIds);"); contents.AppendLine(" }"); } contents.AppendLine(); @@ -1753,10 +1753,10 @@ namespace Flax.Build.Plugins if (jumpBodyEnd == null) throw new Exception("Missing IL Return op code in method " + method.Name); il.Emit(OpCodes.Ldloc, varsStart + 0); - il.Emit(OpCodes.Brfalse_S, jumpIf2Start); + il.Emit(OpCodes.Brfalse, jumpIf2Start); il.Emit(OpCodes.Ldloc, varsStart + 2); il.Emit(OpCodes.Ldc_I4_2); - il.Emit(OpCodes.Beq_S, jumpIfBodyStart); + il.Emit(OpCodes.Beq, jumpIfBodyStart); // || il.Emit(jumpIf2Start); il.Emit(OpCodes.Ldloc, varsStart + 1); @@ -1812,35 +1812,12 @@ namespace Flax.Build.Plugins else il.Emit(OpCodes.Ldnull); var endInvokeRPC = networkReplicatorType.Resolve().GetMethod("EndInvokeRPC", 5); + if (endInvokeRPC.ReturnType.FullName != boolType.FullName) + throw new Exception("Invalid EndInvokeRPC return type. Remove any 'Binaries' folders to force project recompile."); il.Emit(OpCodes.Call, module.ImportReference(endInvokeRPC)); - // if (server && networkMode == NetworkManagerMode.Client) return; - if (methodRPC.IsServer) - { - il.Emit(OpCodes.Nop); - il.Emit(OpCodes.Ldloc, varsStart + 2); - il.Emit(OpCodes.Ldc_I4_2); - var tmp = ilp.Create(OpCodes.Nop); - il.Emit(OpCodes.Beq_S, tmp); - il.Emit(OpCodes.Br, jumpBodyStart); - il.Emit(tmp); - //il.Emit(OpCodes.Ret); - il.Emit(OpCodes.Br, jumpBodyEnd); - } - - // if (client && networkMode == NetworkManagerMode.Server) return; - if (methodRPC.IsClient) - { - il.Emit(OpCodes.Nop); - il.Emit(OpCodes.Ldloc, varsStart + 2); - il.Emit(OpCodes.Ldc_I4_1); - var tmp = ilp.Create(OpCodes.Nop); - il.Emit(OpCodes.Beq_S, tmp); - il.Emit(OpCodes.Br, jumpBodyStart); - il.Emit(tmp); - //il.Emit(OpCodes.Ret); - il.Emit(OpCodes.Br, jumpBodyEnd); - } + // if (EndInvokeRPC) return + il.Emit(OpCodes.Brtrue, jumpBodyEnd); // Continue to original method body il.Emit(jumpBodyStart); From 864f5f77f5024ab6e038fd1dfd82b7027cf2d520 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 14:53:23 +0200 Subject: [PATCH 38/65] Add output binaries folder cleanp to build clear command --- Source/Tools/Flax.Build/Build/Builder.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Source/Tools/Flax.Build/Build/Builder.cs b/Source/Tools/Flax.Build/Build/Builder.cs index 0765a94ab..aa0f7c879 100644 --- a/Source/Tools/Flax.Build/Build/Builder.cs +++ b/Source/Tools/Flax.Build/Build/Builder.cs @@ -143,6 +143,16 @@ namespace Flax.Build { Log.Info("Removing: " + targetBuildOptions.IntermediateFolder); CleanDirectory(intermediateFolder); + intermediateFolder.Create(); + } + + // Delete all output files + var outputFolder = new DirectoryInfo(targetBuildOptions.OutputFolder); + if (outputFolder.Exists) + { + Log.Info("Removing: " + targetBuildOptions.OutputFolder); + CleanDirectory(outputFolder); + outputFolder.Create(); } } } From bf6daed6d20957f2831ea8cc63399b5dd00fd325 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Wed, 28 Jun 2023 15:56:42 +0300 Subject: [PATCH 39/65] Fix Intellisense errors with referenced binary module structures --- Source/Tools/Flax.Build/Build/Builder.Projects.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Tools/Flax.Build/Build/Builder.Projects.cs b/Source/Tools/Flax.Build/Build/Builder.Projects.cs index 2860148de..4fbabe986 100644 --- a/Source/Tools/Flax.Build/Build/Builder.Projects.cs +++ b/Source/Tools/Flax.Build/Build/Builder.Projects.cs @@ -330,7 +330,7 @@ namespace Flax.Build var referenceBuildOptions = GetBuildOptions(referenceTarget, configurationData.TargetBuildOptions.Platform, configurationData.TargetBuildOptions.Toolchain, configurationData.Architecture, configurationData.Configuration, reference.Project.ProjectFolderPath); referenceBuildOptions.Flags |= BuildFlags.GenerateProject; var referenceModules = CollectModules(rules, referenceBuildOptions.Platform, referenceTarget, referenceBuildOptions, referenceBuildOptions.Toolchain, referenceBuildOptions.Architecture, referenceBuildOptions.Configuration); - var referenceBinaryModules = GetBinaryModules(projectInfo, referenceTarget, referenceModules); + var referenceBinaryModules = referenceModules.Keys.GroupBy(x => x.BinaryModuleName).ToArray(); foreach (var binaryModule in referenceBinaryModules) { project.Defines.Add(binaryModule.Key.ToUpperInvariant() + "_API="); From 9536c376234f8097a8d8154f9049ac97a5face34 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 15:12:58 +0200 Subject: [PATCH 40/65] Add ability to unset type reference with `null` item --- Source/Editor/GUI/Popups/TypeSearchPopup.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Source/Editor/GUI/Popups/TypeSearchPopup.cs b/Source/Editor/GUI/Popups/TypeSearchPopup.cs index 9d9ee2040..73c5baab7 100644 --- a/Source/Editor/GUI/Popups/TypeSearchPopup.cs +++ b/Source/Editor/GUI/Popups/TypeSearchPopup.cs @@ -27,6 +27,17 @@ namespace FlaxEditor.GUI /// public ScriptType Type => _type; + /// + /// Initializes a new instance of the class. + /// + public TypeItemView() + { + _type = ScriptType.Null; + Name = ""; + TooltipText = "Unset value."; + Tag = _type; + } + /// /// Initializes a new instance of the class. /// @@ -83,6 +94,7 @@ namespace FlaxEditor.GUI // TODO: use async thread to search types without UI stall var allTypes = Editor.Instance.CodeEditing.All.Get(); + AddItem(new TypeItemView()); for (int i = 0; i < allTypes.Count; i++) { var type = allTypes[i]; From 890248edf218e81466f07c2dbf69a41f53f22230 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 15:13:33 +0200 Subject: [PATCH 41/65] Fix `MClass::HasInterface` in .NET 7 --- Source/Engine/Scripting/Runtime/DotNet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 1736cc106..246c1620f 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -846,7 +846,7 @@ bool MClass::IsSubClassOf(const MClass* klass, bool checkInterfaces) const bool MClass::HasInterface(const MClass* klass) const { static void* TypeIsAssignableFrom = GetStaticMethodPointer(TEXT("TypeIsAssignableFrom")); - return klass && CallStaticMethod(TypeIsAssignableFrom, _handle, klass->_handle); + return klass && CallStaticMethod(TypeIsAssignableFrom, klass->_handle, _handle); } bool MClass::IsInstanceOfType(MObject* object) const From c44e97c8bc8ea413056412e5a0e747a295e94835 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 15:22:48 +0200 Subject: [PATCH 42/65] Bump build number --- Flax.flaxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flax.flaxproj b/Flax.flaxproj index d8e86b1ed..7cebe1714 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -3,7 +3,7 @@ "Version": { "Major": 1, "Minor": 6, - "Build": 6342 + "Build": 6343 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.", From bb3cefbe54d14182c971bced908d1ff4f1bec4ee Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 15:48:32 +0200 Subject: [PATCH 43/65] Add check for `NetworkClientsMask` to ensure it has capacity --- Source/Engine/Networking/NetworkReplicator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index ae7549a50..daf2537f4 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -1151,6 +1151,7 @@ void NetworkInternal::NetworkReplicatorClientConnected(NetworkClient* client) { ScopeLock lock(ObjectsLock); NewClients.Add(client); + ASSERT(sizeof(NetworkClientsMask) * 8 >= (uint32)NetworkManager::Clients.Count()); // Ensure that clients mask can hold all of clients } void NetworkInternal::NetworkReplicatorClientDisconnected(NetworkClient* client) From 45a1d336899fb689d3ec8856719c881ec7a91069 Mon Sep 17 00:00:00 2001 From: Ruan Lucas <79365912+RuanLucasGD@users.noreply.github.com> Date: Wed, 28 Jun 2023 09:56:15 -0400 Subject: [PATCH 44/65] fix orientation --- Source/Engine/Physics/Actors/WheeledVehicle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.cpp b/Source/Engine/Physics/Actors/WheeledVehicle.cpp index 995150bdc..f5f729d39 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.cpp +++ b/Source/Engine/Physics/Actors/WheeledVehicle.cpp @@ -230,7 +230,7 @@ void WheeledVehicle::DrawPhysicsDebug(RenderView& view) { const Vector3 currentPos = wheel.Collider->GetPosition(); const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0); - const Quaternion wheelDebugOrientation = wheel.Collider->GetOrientation() * Quaternion::Euler(90, 0, 90); + const Quaternion wheelDebugOrientation = GetOrientation() * Quaternion::Euler(-data.State.RotationAngle, data.State.SteerAngle, 0) * Quaternion::Euler(90, 0, 90); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(basePos, wheel.Radius * 0.07f), Color::Blue * 0.3f, 0, true); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(currentPos, wheel.Radius * 0.08f), Color::Blue * 0.8f, 0, true); DEBUG_DRAW_LINE(basePos, currentPos, Color::Blue, 0, true); @@ -261,7 +261,7 @@ void WheeledVehicle::OnDebugDrawSelected() { const Vector3 currentPos = wheel.Collider->GetPosition(); const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0); - const Quaternion wheelDebugOrientation = wheel.Collider->GetOrientation() * Quaternion::Euler(90, 0, 90); + const Quaternion wheelDebugOrientation = GetOrientation() * Quaternion::Euler(-data.State.RotationAngle, data.State.SteerAngle, 0) * Quaternion::Euler(90, 0, 90); Transform actorPose = Transform::Identity, shapePose = Transform::Identity; PhysicsBackend::GetRigidActorPose(_actor, actorPose.Translation, actorPose.Orientation); PhysicsBackend::GetShapeLocalPose(wheel.Collider->GetPhysicsShape(), shapePose.Translation, shapePose.Orientation); From bb9711277ae8094323f255c514bd66e222542c67 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 16:27:42 +0200 Subject: [PATCH 45/65] Cleanup code from #1213 --- .../Viewport/Previews/AnimatedModelPreview.cs | 12 +-- .../Viewport/Previews/MaterialPreview.cs | 48 +++++------ .../Viewport/Previews/ModelBasePreview.cs | 8 +- .../Editor/Viewport/Previews/ModelPreview.cs | 79 ++++++++----------- .../Viewport/Previews/SkinnedModelPreview.cs | 65 +++++++-------- .../Windows/Assets/CollisionDataWindow.cs | 4 +- Source/Editor/Windows/Assets/ModelWindow.cs | 4 +- .../Windows/Assets/SkinnedModelWindow.cs | 6 +- 8 files changed, 88 insertions(+), 138 deletions(-) diff --git a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs index aae48fe11..4a1c57757 100644 --- a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs @@ -3,8 +3,6 @@ using System; using FlaxEditor.GUI.ContextMenu; using FlaxEngine; -using FlaxEditor.GUI.Input; -using FlaxEngine.GUI; using Object = FlaxEngine.Object; namespace FlaxEditor.Viewport.Previews @@ -15,13 +13,10 @@ namespace FlaxEditor.Viewport.Previews /// public class AnimatedModelPreview : AssetPreview { - /// public AnimatedModel _previewModel; - private ContextMenuButton _showNodesButton, _showBoundsButton, _showFloorButton, _showNodesNamesButton; private bool _showNodes, _showBounds, _showFloor, _showNodesNames; private StaticModel _floorModel; - private bool _playAnimation, _playAnimationOnce; private float _playSpeed = 1.0f; @@ -404,9 +399,9 @@ namespace FlaxEditor.Viewport.Previews } /// - /// Calls SetArcBallView from ViewportCamera + /// Resets the camera to focus on a object. /// - public void CallSetArcBallView() + public void ResetCamera() { ViewportCamera.SetArcBallView(_previewModel.Box); } @@ -417,8 +412,7 @@ namespace FlaxEditor.Viewport.Previews switch (key) { case KeyboardKeys.F: - // Pay respect.. - CallSetArcBallView(); + ResetCamera(); return true; case KeyboardKeys.Spacebar: PlayAnimation = !PlayAnimation; diff --git a/Source/Editor/Viewport/Previews/MaterialPreview.cs b/Source/Editor/Viewport/Previews/MaterialPreview.cs index 3dfab1cff..5520d6c4c 100644 --- a/Source/Editor/Viewport/Previews/MaterialPreview.cs +++ b/Source/Editor/Viewport/Previews/MaterialPreview.cs @@ -48,6 +48,7 @@ namespace FlaxEditor.Viewport.Previews private int _selectedModelIndex; private Image _guiMaterialControl; private readonly MaterialBase[] _postFxMaterialsCache = new MaterialBase[1]; + private ContextMenu _modelWidgetButtonMenu; /// /// Gets or sets the material asset to preview. It can be or . @@ -65,11 +66,6 @@ namespace FlaxEditor.Viewport.Previews } } - /// - /// The "Model" widget button context menu. - /// - private ContextMenu modelWidgetButtonMenu; - /// /// Gets or sets the selected preview model index. /// @@ -87,27 +83,6 @@ namespace FlaxEditor.Viewport.Previews } } - /// - /// Fill out all models - /// - /// - private void ModelWidgetMenuOnVisibleChanged(Control control) - { - if (!control.Visible) return; - - modelWidgetButtonMenu.ItemsContainer.DisposeChildren(); - - // Fill out all models - for (int i = 0; i < Models.Length; i++) - { - var index = i; - var button = modelWidgetButtonMenu.AddButton(Models[index]); - button.ButtonClicked += (button) => SelectedModelIndex = index; - button.Checked = SelectedModelIndex == index; - button.Tag = index; - } - } - /// /// Initializes a new instance of the class. /// @@ -127,9 +102,24 @@ namespace FlaxEditor.Viewport.Previews { // Model mode widget var modelMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); - modelWidgetButtonMenu = new ContextMenu(); - modelWidgetButtonMenu.VisibleChanged += ModelWidgetMenuOnVisibleChanged; - var previewLODSModeButton = new ViewportWidgetButton("Model", SpriteHandle.Invalid, modelWidgetButtonMenu) + _modelWidgetButtonMenu = new ContextMenu(); + _modelWidgetButtonMenu.VisibleChanged += control => + { + if (!control.Visible) + return; + _modelWidgetButtonMenu.ItemsContainer.DisposeChildren(); + + // Fill out all models + for (int i = 0; i < Models.Length; i++) + { + var index = i; + var button = _modelWidgetButtonMenu.AddButton(Models[index]); + button.ButtonClicked += _ => SelectedModelIndex = index; + button.Checked = SelectedModelIndex == index; + button.Tag = index; + } + }; + new ViewportWidgetButton("Model", SpriteHandle.Invalid, _modelWidgetButtonMenu) { TooltipText = "Change material model", Parent = modelMode, diff --git a/Source/Editor/Viewport/Previews/ModelBasePreview.cs b/Source/Editor/Viewport/Previews/ModelBasePreview.cs index e5834edc9..e4f1109d4 100644 --- a/Source/Editor/Viewport/Previews/ModelBasePreview.cs +++ b/Source/Editor/Viewport/Previews/ModelBasePreview.cs @@ -1,6 +1,5 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. -using FlaxEditor.GUI.Input; using FlaxEngine; using Object = FlaxEngine.Object; @@ -59,9 +58,9 @@ namespace FlaxEditor.Viewport.Previews } /// - /// Calls SetArcBallView from ViewportCamera + /// Resets the camera to focus on a object. /// - public void CallSetArcBallView() + public void ResetCamera() { ViewportCamera.SetArcBallView(StaticModel.Model != null ? StaticModel.Box : AnimatedModel.Box); } @@ -92,8 +91,7 @@ namespace FlaxEditor.Viewport.Previews switch (key) { case KeyboardKeys.F: - // Pay respect.. - CallSetArcBallView(); + ResetCamera(); break; } return base.OnKeyDown(key); diff --git a/Source/Editor/Viewport/Previews/ModelPreview.cs b/Source/Editor/Viewport/Previews/ModelPreview.cs index dc0de37da..a0b6d0ca0 100644 --- a/Source/Editor/Viewport/Previews/ModelPreview.cs +++ b/Source/Editor/Viewport/Previews/ModelPreview.cs @@ -1,7 +1,6 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using FlaxEditor.GUI.ContextMenu; -using FlaxEditor.GUI.Input; using FlaxEngine; using FlaxEngine.GUI; using FlaxEngine.Utilities; @@ -17,15 +16,11 @@ namespace FlaxEditor.Viewport.Previews public class ModelPreview : AssetPreview { private ContextMenuButton _showBoundsButton, _showCurrentLODButton, _showNormalsButton, _showTangentsButton, _showBitangentsButton, _showFloorButton; + private ContextMenu _previewLODsWidgetButtonMenu; private StaticModel _previewModel, _floorModel; private bool _showBounds, _showCurrentLOD, _showNormals, _showTangents, _showBitangents, _showFloor; private MeshDataCache _meshDatas; - /// - /// The "PreviewLODS" widget button context menu. - /// - private ContextMenu previewLODSWidgetButtonMenu; - /// /// Gets or sets a value that shows LOD statistics /// @@ -37,8 +32,6 @@ namespace FlaxEditor.Viewport.Previews if (_showCurrentLOD == value) return; _showCurrentLOD = value; - if (value) - ShowDebugDraw = true; if (_showCurrentLODButton != null) _showCurrentLODButton.Checked = value; } @@ -222,42 +215,36 @@ namespace FlaxEditor.Viewport.Previews }); _showCurrentLODButton.IndexInParent = 2; - // PreviewLODS mode widget - var PreviewLODSMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); - previewLODSWidgetButtonMenu = new ContextMenu(); - previewLODSWidgetButtonMenu.VisibleChanged += PreviewLODSWidgetMenuOnVisibleChanged; - var previewLODSModeButton = new ViewportWidgetButton("Preview LOD", SpriteHandle.Invalid, previewLODSWidgetButtonMenu) + // Preview LODs mode widget + var PreviewLODsMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); + _previewLODsWidgetButtonMenu = new ContextMenu(); + _previewLODsWidgetButtonMenu.VisibleChanged += control => + { + if (!control.Visible) + return; + var model = _previewModel.Model; + if (model && !model.WaitForLoaded()) + { + _previewLODsWidgetButtonMenu.ItemsContainer.DisposeChildren(); + var lods = model.LODs.Length; + for (int i = -1; i < lods; i++) + { + var index = i; + var button = _previewLODsWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); + button.ButtonClicked += _ => _previewModel.ForcedLOD = index; + button.Checked = _previewModel.ForcedLOD == index; + button.Tag = index; + if (lods <= 1) + break; + } + } + }; + new ViewportWidgetButton("Preview LOD", SpriteHandle.Invalid, _previewLODsWidgetButtonMenu) { TooltipText = "Preview LOD properties", - Parent = PreviewLODSMode, + Parent = PreviewLODsMode, }; - PreviewLODSMode.Parent = this; - } - } - - /// - /// Fill out all Model LODS - /// - /// - private void PreviewLODSWidgetMenuOnVisibleChanged(Control control) - { - if (!control.Visible) - return; - - var model = _previewModel.Model; - if (model && !model.WaitForLoaded() && model.IsLoaded) - { - previewLODSWidgetButtonMenu.ItemsContainer.DisposeChildren(); - var lods = model.LODs.Length; - for (int i = -1; i < lods; i++) - { - var index = i; - var button = previewLODSWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); - button.ButtonClicked += (button) => _previewModel.ForcedLOD = index; - button.Checked = _previewModel.ForcedLOD == index; - button.Tag = index; - if (lods <= 1) return; - } + PreviewLODsMode.Parent = this; } } @@ -361,7 +348,7 @@ namespace FlaxEditor.Viewport.Previews var distSqr = Vector3.DistanceSquared(ref sphere.Center, ref viewOrigin); var screenRadiusSquared = Mathf.Square(screenMultiple * sphere.Radius) / Mathf.Max(1.0f, distSqr); screenSize = Mathf.Sqrt((float)screenRadiusSquared) * 2.0f; - + // Check if model is being culled if (Mathf.Square(model.MinScreenSize * 0.5f) > screenRadiusSquared) return -1; @@ -422,9 +409,9 @@ namespace FlaxEditor.Viewport.Previews } /// - /// Calls SetArcBallView from ViewportCamera + /// Resets the camera to focus on a object. /// - public void CallSetArcBallView() + public void ResetCamera() { ViewportCamera.SetArcBallView(_previewModel.Box); } @@ -435,8 +422,7 @@ namespace FlaxEditor.Viewport.Previews switch (key) { case KeyboardKeys.F: - // Pay respect.. - CallSetArcBallView(); + ResetCamera(); break; } return base.OnKeyDown(key); @@ -449,6 +435,7 @@ namespace FlaxEditor.Viewport.Previews Object.Destroy(ref _previewModel); _showBoundsButton = null; _showCurrentLODButton = null; + _previewLODsWidgetButtonMenu = null; _showNormalsButton = null; _showTangentsButton = null; _showBitangentsButton = null; diff --git a/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs b/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs index a8b98b423..c11ea9ea4 100644 --- a/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs @@ -1,4 +1,5 @@ -using System; +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + using FlaxEditor.GUI.ContextMenu; using FlaxEngine; using FlaxEngine.GUI; @@ -14,11 +15,7 @@ namespace FlaxEditor.Viewport.Previews { private bool _showCurrentLOD; private ContextMenuButton _showCurrentLODButton; - - /// - /// The "PreviewLODS" widget button context menu. - /// - private ContextMenu previewLODSWidgetButtonMenu; + private ContextMenu _previewLODsWidgetButtonMenu; /// /// Gets or sets a value that shows LOD statistics @@ -31,8 +28,6 @@ namespace FlaxEditor.Viewport.Previews if (_showCurrentLOD == value) return; _showCurrentLOD = value; - if (value) - ShowDebugDraw = true; if (_showCurrentLODButton != null) _showCurrentLODButton.Checked = value; } @@ -57,9 +52,29 @@ namespace FlaxEditor.Viewport.Previews // PreviewLODS mode widget var PreviewLODSMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); - previewLODSWidgetButtonMenu = new ContextMenu(); - previewLODSWidgetButtonMenu.VisibleChanged += PreviewLODSWidgetMenuOnVisibleChanged; - var previewLODSModeButton = new ViewportWidgetButton("Preview LOD", SpriteHandle.Invalid, previewLODSWidgetButtonMenu) + _previewLODsWidgetButtonMenu = new ContextMenu(); + _previewLODsWidgetButtonMenu.VisibleChanged += control => + { + if (!control.Visible) + return; + var skinned = _previewModel.SkinnedModel; + if (skinned && !skinned.WaitForLoaded()) + { + _previewLODsWidgetButtonMenu.ItemsContainer.DisposeChildren(); + var lods = skinned.LODs.Length; + for (int i = -1; i < lods; i++) + { + var index = i; + var button = _previewLODsWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); + button.ButtonClicked += (button) => _previewModel.ForcedLOD = index; + button.Checked = _previewModel.ForcedLOD == index; + button.Tag = index; + if (lods <= 1) + break; + } + } + }; + new ViewportWidgetButton("Preview LOD", SpriteHandle.Invalid, _previewLODsWidgetButtonMenu) { TooltipText = "Preview LOD properties", Parent = PreviewLODSMode, @@ -68,33 +83,6 @@ namespace FlaxEditor.Viewport.Previews } } - /// - /// Fill out all SkinnedModel LODS - /// - /// - private void PreviewLODSWidgetMenuOnVisibleChanged(Control control) - { - if (!control.Visible) - return; - - var skinned = _previewModel.SkinnedModel; - if (skinned && !skinned.WaitForLoaded() && skinned.IsLoaded) - { - previewLODSWidgetButtonMenu.ItemsContainer.DisposeChildren(); - var lods = skinned.LODs.Length; - for (int i = -1; i < lods; i++) - { - var index = i; - var button = previewLODSWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); - button.ButtonClicked += (button) => _previewModel.ForcedLOD = index; - button.Checked = _previewModel.ForcedLOD == index; - button.Tag = index; - if (lods <= 1) return; - } - } - } - - /// private int ComputeLODIndex(SkinnedModel model, out float screenSize) { screenSize = 1.0f; @@ -181,6 +169,7 @@ namespace FlaxEditor.Viewport.Previews public override void OnDestroy() { _showCurrentLODButton = null; + _previewLODsWidgetButtonMenu = null; base.OnDestroy(); } diff --git a/Source/Editor/Windows/Assets/CollisionDataWindow.cs b/Source/Editor/Windows/Assets/CollisionDataWindow.cs index 82e0681fa..cc1daa45b 100644 --- a/Source/Editor/Windows/Assets/CollisionDataWindow.cs +++ b/Source/Editor/Windows/Assets/CollisionDataWindow.cs @@ -182,9 +182,7 @@ namespace FlaxEditor.Windows.Assets { // Toolstrip _toolstrip.AddSeparator(); - - _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.CallSetArcBallView()).LinkTooltip("Show whole collision"); - + _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.ResetCamera()).LinkTooltip("Show whole collision"); _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/physics/colliders/collision-data.html")).LinkTooltip("See documentation to learn more"); // Split Panel diff --git a/Source/Editor/Windows/Assets/ModelWindow.cs b/Source/Editor/Windows/Assets/ModelWindow.cs index cc7657fc7..f70f6a3b5 100644 --- a/Source/Editor/Windows/Assets/ModelWindow.cs +++ b/Source/Editor/Windows/Assets/ModelWindow.cs @@ -788,9 +788,7 @@ namespace FlaxEditor.Windows.Assets // Toolstrip _toolstrip.AddSeparator(); _showCurrentLODButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Info64, () => _preview.ShowCurrentLOD = !_preview.ShowCurrentLOD).LinkTooltip("Show LOD statistics"); - - _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.CallSetArcBallView()).LinkTooltip("Show whole model"); - + _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.ResetCamera()).LinkTooltip("Show whole model"); _toolstrip.AddSeparator(); _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/models/index.html")).LinkTooltip("See documentation to learn more"); diff --git a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs index 367fc3a1a..a7ee6e767 100644 --- a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs +++ b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs @@ -1117,13 +1117,9 @@ namespace FlaxEditor.Windows.Assets { // Toolstrip _toolstrip.AddSeparator(); - _showCurrentLODButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Info64, () => _preview.ShowCurrentLOD = !_preview.ShowCurrentLOD).LinkTooltip("Show LOD statistics"); - _showNodesButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Bone64, () => _preview.ShowNodes = !_preview.ShowNodes).LinkTooltip("Show animated model nodes debug view"); - - _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.CallSetArcBallView()).LinkTooltip("Show whole model"); - + _toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.ResetCamera()).LinkTooltip("Show whole model"); _toolstrip.AddSeparator(); _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/skinned-model/index.html")).LinkTooltip("See documentation to learn more"); From ac54838eea13d6caafb2c3dda75317d0f9becf69 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 18:46:46 +0200 Subject: [PATCH 46/65] Fix custom editor window restore after hot-reload #1208 --- Source/Editor/CustomEditorWindow.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/Editor/CustomEditorWindow.cs b/Source/Editor/CustomEditorWindow.cs index 2d5293f30..242b4d28d 100644 --- a/Source/Editor/CustomEditorWindow.cs +++ b/Source/Editor/CustomEditorWindow.cs @@ -3,7 +3,6 @@ using FlaxEditor.CustomEditors; using FlaxEditor.Windows; using FlaxEngine.GUI; -using FlaxEngine; using DockState = FlaxEditor.GUI.Docking.DockState; namespace FlaxEditor @@ -86,8 +85,12 @@ namespace FlaxEditor if (!FlaxEngine.Scripting.IsTypeFromGameScripts(type)) return; - Editor.Instance.Windows.AddToRestore(this); + if (!Window.IsHidden) + { + Editor.Instance.Windows.AddToRestore(this); + } Window.Close(); + Window.Dispose(); } /// From 70ab159dd4bc518d41ff5811bdb30840a537ec8f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 19:55:10 +0200 Subject: [PATCH 47/65] Fix empty clients mask for `NetworkReplicationHierarchy` on client to properly replicate client-owned objects #1205 --- Source/Engine/Networking/NetworkReplicationHierarchy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp index 5097b6a26..6ec5e52c2 100644 --- a/Source/Engine/Networking/NetworkReplicationHierarchy.cpp +++ b/Source/Engine/Networking/NetworkReplicationHierarchy.cpp @@ -23,7 +23,7 @@ void NetworkReplicationHierarchyUpdateResult::Init() { _clientsHaveLocation = false; _clients.Resize(NetworkManager::Clients.Count()); - _clientsMask = NetworkClientsMask(); + _clientsMask = NetworkManager::Mode == NetworkManagerMode::Client ? NetworkClientsMask::All : NetworkClientsMask(); for (int32 i = 0; i < _clients.Count(); i++) _clientsMask.SetBit(i); _entries.Clear(); From 04c1cf469d12d86a6f69ce7d70f667adf07cde98 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 20:08:35 +0200 Subject: [PATCH 48/65] Fix codegen for C++ RPS with Array ParameterDefinition #1209 --- Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs | 2 +- Source/Tools/Flax.Build/Bindings/TypeInfo.cs | 6 +++--- Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index 0cb8982a2..d69b8dcbf 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -1204,7 +1204,7 @@ namespace Flax.Build.Bindings if (apiType != null) { if (parameterInfo.IsOut) - contents.Append(indent).AppendFormat("{1} {0}Temp;", parameterInfo.Name, new TypeInfo(parameterInfo.Type) { IsRef = false }.GetFullNameNative(buildData, caller)).AppendLine(); + contents.Append(indent).AppendFormat("{1} {0}Temp;", parameterInfo.Name, parameterInfo.Type.GetFullNameNative(buildData, caller, false)).AppendLine(); else contents.Append(indent).AppendFormat("auto {0}Temp = {1};", parameterInfo.Name, param).AppendLine(); if (parameterInfo.Type.IsPtr && !parameterInfo.Type.IsRef) diff --git a/Source/Tools/Flax.Build/Bindings/TypeInfo.cs b/Source/Tools/Flax.Build/Bindings/TypeInfo.cs index 7b2326527..df47c85e4 100644 --- a/Source/Tools/Flax.Build/Bindings/TypeInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/TypeInfo.cs @@ -144,7 +144,7 @@ namespace Flax.Build.Bindings GenericArgs = BindingsGenerator.Read(reader, GenericArgs); } - public string GetFullNameNative(Builder.BuildData buildData, ApiTypeInfo caller) + public string GetFullNameNative(Builder.BuildData buildData, ApiTypeInfo caller, bool canRef = true, bool canConst = true) { var type = BindingsGenerator.FindApiTypeInfo(buildData, this, caller); if (type == null) @@ -155,7 +155,7 @@ namespace Flax.Build.Bindings return type.FullNameNative; var sb = new StringBuilder(64); - if (IsConst) + if (IsConst && canConst) sb.Append("const "); sb.Append(type.FullNameNative); if (GenericArgs != null) @@ -171,7 +171,7 @@ namespace Flax.Build.Bindings } if (IsPtr) sb.Append('*'); - if (IsRef) + if (IsRef && canRef) sb.Append('&'); return sb.ToString(); } diff --git a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs index b24b887b3..d76fc43cc 100644 --- a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs +++ b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs @@ -241,7 +241,7 @@ namespace Flax.Build.Plugins // Deserialize arguments argNames += arg.Name; - contents.AppendLine($" {arg.Type.Type} {arg.Name};"); + contents.AppendLine($" {arg.Type.GetFullNameNative(buildData, typeInfo, false, false)} {arg.Name};"); contents.AppendLine($" stream->Read({arg.Name});"); } @@ -270,7 +270,7 @@ namespace Flax.Build.Plugins } // Serialize arguments - contents.AppendLine($" stream->Write(*({arg.Type.Type}*)args[{i}]);"); + contents.AppendLine($" stream->Write(*(const {arg.Type.GetFullNameNative(buildData, typeInfo, false, false)}*)args[{i}]);"); } // Invoke RPC From 3119c507899961b7ad141479f7d20b6d07e7d677 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 20:09:01 +0200 Subject: [PATCH 49/65] Fix nullable warnings --- Source/Editor/ProjectInfo.cs | 4 ++-- .../Engine/Engine/NativeInterop.Marshallers.cs | 18 +++++++++--------- Source/Engine/Engine/NativeInterop.cs | 2 +- Source/Engine/Utilities/Utils.cs | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Source/Editor/ProjectInfo.cs b/Source/Editor/ProjectInfo.cs index ed9470c35..b00c4e042 100644 --- a/Source/Editor/ProjectInfo.cs +++ b/Source/Editor/ProjectInfo.cs @@ -20,7 +20,7 @@ namespace FlaxEditor /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value == null) { @@ -44,7 +44,7 @@ namespace FlaxEditor /// The existing property value of the JSON that is being converted. /// The calling serializer. /// The object value. - public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { diff --git a/Source/Engine/Engine/NativeInterop.Marshallers.cs b/Source/Engine/Engine/NativeInterop.Marshallers.cs index a3531d11d..0a23bfcbd 100644 --- a/Source/Engine/Engine/NativeInterop.Marshallers.cs +++ b/Source/Engine/Engine/NativeInterop.Marshallers.cs @@ -350,14 +350,14 @@ namespace FlaxEngine.Interop #endif public static class NativeToManaged { - public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) + public static T[] AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) { if (unmanaged is null) return null; return new T[numElements]; } - public static Span GetManagedValuesDestination(T[]? managed) => managed; + public static Span GetManagedValuesDestination(T[] managed) => managed; public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements) { @@ -390,7 +390,7 @@ namespace FlaxEngine.Interop #endif public static class ManagedToNative { - public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[] managed, out int numElements) { if (managed is null) { @@ -402,7 +402,7 @@ namespace FlaxEngine.Interop return (TUnmanagedElement*)ManagedHandle.ToIntPtr(managedArray, GCHandleType.Weak); } - public static ReadOnlySpan GetManagedValuesSource(T[]? managed) => managed; + public static ReadOnlySpan GetManagedValuesSource(T[] managed) => managed; public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { @@ -431,7 +431,7 @@ namespace FlaxEngine.Interop ManagedArray unmanagedArray; ManagedHandle handle; - public void FromManaged(T[]? managed) + public void FromManaged(T[] managed) { if (managed == null) return; @@ -476,7 +476,7 @@ namespace FlaxEngine.Interop } } - public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[] managed, out int numElements) { if (managed is null) { @@ -489,7 +489,7 @@ namespace FlaxEngine.Interop return (TUnmanagedElement*)handle; } - public static ReadOnlySpan GetManagedValuesSource(T[]? managed) => managed; + public static ReadOnlySpan GetManagedValuesSource(T[] managed) => managed; public static Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) { @@ -499,9 +499,9 @@ namespace FlaxEngine.Interop return unmanagedArray.ToSpan(); } - public static T[]? AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) => unmanaged is null ? null : new T[numElements]; + public static T[] AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) => unmanaged is null ? null : new T[numElements]; - public static Span GetManagedValuesDestination(T[]? managed) => managed; + public static Span GetManagedValuesDestination(T[] managed) => managed; public static ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements) { diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index faa19d060..4aedbe171 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -96,7 +96,7 @@ namespace FlaxEngine.Interop } #if FLAX_EDITOR - private static Assembly? OnScriptingAssemblyLoadContextResolving(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) + private static Assembly OnScriptingAssemblyLoadContextResolving(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) { // FIXME: There should be a better way to resolve the path to EditorTargetPath where the dependencies are stored string editorTargetPath = Path.GetDirectoryName(nativeLibraryPaths.Keys.First(x => x != "FlaxEngine")); diff --git a/Source/Engine/Utilities/Utils.cs b/Source/Engine/Utilities/Utils.cs index 5ac43ecd9..cb385efcf 100644 --- a/Source/Engine/Utilities/Utils.cs +++ b/Source/Engine/Utilities/Utils.cs @@ -255,7 +255,7 @@ namespace FlaxEngine #else private class ExtractArrayFromListContext { - public static FieldInfo? itemsField; + public static FieldInfo itemsField; } internal static T[] ExtractArrayFromList(List list) { From 96589557b32f417423a1ea6729dd0aa6586f9e05 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 28 Jun 2023 20:09:18 +0200 Subject: [PATCH 50/65] Fix access level 96a1f20bee63c2096c435e75d3a7dd48622aa05e --- .../Editor/Viewport/Previews/AnimatedModelPreview.cs | 2 +- Source/Editor/Viewport/Previews/SkinnedModelPreview.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs index 4a1c57757..9a7ec6800 100644 --- a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs @@ -13,7 +13,7 @@ namespace FlaxEditor.Viewport.Previews /// public class AnimatedModelPreview : AssetPreview { - public AnimatedModel _previewModel; + private AnimatedModel _previewModel; private ContextMenuButton _showNodesButton, _showBoundsButton, _showFloorButton, _showNodesNamesButton; private bool _showNodes, _showBounds, _showFloor, _showNodesNames; private StaticModel _floorModel; diff --git a/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs b/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs index c11ea9ea4..08f8d8509 100644 --- a/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/SkinnedModelPreview.cs @@ -57,7 +57,7 @@ namespace FlaxEditor.Viewport.Previews { if (!control.Visible) return; - var skinned = _previewModel.SkinnedModel; + var skinned = PreviewActor.SkinnedModel; if (skinned && !skinned.WaitForLoaded()) { _previewLODsWidgetButtonMenu.ItemsContainer.DisposeChildren(); @@ -66,8 +66,8 @@ namespace FlaxEditor.Viewport.Previews { var index = i; var button = _previewLODsWidgetButtonMenu.AddButton("LOD " + (index == -1 ? "Auto" : index)); - button.ButtonClicked += (button) => _previewModel.ForcedLOD = index; - button.Checked = _previewModel.ForcedLOD == index; + button.ButtonClicked += (button) => PreviewActor.ForcedLOD = index; + button.Checked = PreviewActor.ForcedLOD == index; button.Tag = index; if (lods <= 1) break; @@ -128,7 +128,7 @@ namespace FlaxEditor.Viewport.Previews { base.Draw(); - var skinnedModel = _previewModel.SkinnedModel; + var skinnedModel = PreviewActor.SkinnedModel; if (skinnedModel == null || !skinnedModel.IsLoaded) return; var lods = skinnedModel.LODs; @@ -141,7 +141,7 @@ namespace FlaxEditor.Viewport.Previews if (_showCurrentLOD) { var lodIndex = ComputeLODIndex(skinnedModel, out var screenSize); - var auto = _previewModel.ForcedLOD == -1; + var auto = PreviewActor.ForcedLOD == -1; string text = auto ? "LOD Automatic" : ""; text += auto ? string.Format("\nScreen Size: {0:F2}", screenSize) : ""; text += string.Format("\nCurrent LOD: {0}", lodIndex); From 0498f1488ebd052110dc3a28b6d094c82ec98e71 Mon Sep 17 00:00:00 2001 From: ExMatics HydrogenC <33123710+HydrogenC@users.noreply.github.com> Date: Fri, 30 Jun 2023 12:25:58 +0800 Subject: [PATCH 51/65] Fix space conversion issue --- Source/Engine/Level/Actors/AnimatedModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 882026db7..2db3b6fae 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -127,7 +127,7 @@ void AnimatedModel::GetCurrentPose(Array& nodesTransformation, bool worl Matrix world; _transform.GetWorld(world); for (auto& m : nodesTransformation) - m = m * world; + m = world * m; } } From 804826fbc793dbc6bafa931e9789c26150937cfa Mon Sep 17 00:00:00 2001 From: ExMatics HydrogenC <33123710+HydrogenC@users.noreply.github.com> Date: Fri, 30 Jun 2023 14:06:52 +0800 Subject: [PATCH 52/65] Fix multiplication mistake --- Source/Engine/Level/Actors/AnimatedModel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 2db3b6fae..b33878a50 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -127,7 +127,7 @@ void AnimatedModel::GetCurrentPose(Array& nodesTransformation, bool worl Matrix world; _transform.GetWorld(world); for (auto& m : nodesTransformation) - m = world * m; + m = m * world; } } @@ -144,7 +144,7 @@ void AnimatedModel::SetCurrentPose(const Array& nodesTransformation, boo Matrix invWorld; Matrix::Invert(world, invWorld); for (auto& m : GraphInstance.NodesPose) - m = invWorld * m; + m = m * invWorld; } OnAnimationUpdated(); } From 8c006f6e113401ce0aeabb90c5c9e22c87b22064 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 Jun 2023 10:00:12 +0200 Subject: [PATCH 53/65] Fix crash due to replicated objects leak upon system destruction --- Source/Engine/Networking/NetworkReplicator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index daf2537f4..279391e31 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -1204,6 +1204,7 @@ void NetworkInternal::NetworkReplicatorClear() Objects.Remove(it); } } + Objects.Clear(); RpcQueue.Clear(); SpawnQueue.Clear(); DespawnQueue.Clear(); From d5100373be5ad999626b4f26130b067f9773ec4b Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 Jun 2023 10:38:08 +0200 Subject: [PATCH 54/65] Fix bugs in C# codegen for network data serialization --- Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs index d76fc43cc..d646a81cd 100644 --- a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs +++ b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs @@ -780,7 +780,7 @@ namespace Flax.Build.Plugins private static void GenerateCallINetworkSerializable(ref DotnetContext context, TypeDefinition type, string name, MethodDefinition method) { var m = new MethodDefinition(name, MethodAttributes.Public | MethodAttributes.HideBySig, context.VoidType); - m.Parameters.Add(new ParameterDefinition("stream", ParameterAttributes.None, context.NetworkStreamType)); + m.Parameters.Add(new ParameterDefinition("stream", ParameterAttributes.None, type.Module.ImportReference(context.NetworkStreamType))); ILProcessor il = m.Body.GetILProcessor(); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldarg_0); @@ -1304,7 +1304,10 @@ namespace Flax.Build.Plugins il.Emit(jmp4); valueContext.Load(ref il); il.Emit(OpCodes.Ldloc, varStart + 1); // idx - il.Emit(OpCodes.Ldelem_Ref); + if (elementType.IsValueType) + il.Emit(OpCodes.Ldelem_Any, elementType); + else + il.Emit(OpCodes.Ldelem_Ref); il.Emit(OpCodes.Stloc, varStart + 2); // // Serialize item value From 2bd2bd508122a9a8ef76606abc700b5cdbafead8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 30 Jun 2023 11:02:58 +0200 Subject: [PATCH 55/65] Fix crash when modifying animated model skeleton pose from gameplay code during update event --- Source/Engine/Level/Actors/AnimatedModel.cpp | 8 +++++++- Source/Engine/Level/Actors/AnimatedModel.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 882026db7..148b57682 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -603,7 +603,13 @@ void AnimatedModel::OnAnimationUpdated_Sync() // Update synchronous stuff UpdateSockets(); ApplyRootMotion(GraphInstance.RootMotion); - AnimationUpdated(); + if (!_isDuringUpdateEvent) + { + // Prevent stack-overflow when gameplay modifies the pose within the event + _isDuringUpdateEvent = true; + AnimationUpdated(); + _isDuringUpdateEvent = false; + } } void AnimatedModel::OnAnimationUpdated() diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index ccd0ee3b5..33f206580 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -60,6 +60,7 @@ private: AnimationUpdateMode _actualMode; uint32 _counter; Real _lastMinDstSqr; + bool _isDuringUpdateEvent = false; uint64 _lastUpdateFrame; BlendShapesInstance _blendShapes; ScriptingObjectReference _masterPose; From 0ee6aad3ec353b0efe8f50207bb66db6c1758707 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Fri, 30 Jun 2023 13:00:29 +0300 Subject: [PATCH 56/65] Remove old hot-reload files in project references --- Source/Editor/Scripting/ScriptsBuilder.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Source/Editor/Scripting/ScriptsBuilder.cpp b/Source/Editor/Scripting/ScriptsBuilder.cpp index eaffe5691..3082a531e 100644 --- a/Source/Editor/Scripting/ScriptsBuilder.cpp +++ b/Source/Editor/Scripting/ScriptsBuilder.cpp @@ -613,6 +613,28 @@ bool ScriptsBuilderService::Init() const String targetOutput = Globals::ProjectFolder / TEXT("Binaries") / target / platform / architecture / configuration; Array files; FileSystem::DirectoryGetFiles(files, targetOutput, TEXT("*.HotReload.*"), DirectorySearchOption::TopDirectoryOnly); + + for (const auto& reference : Editor::Project->References) + { + if (reference.Project->Name == TEXT("Flax")) + continue; + + String referenceTarget; + if (reference.Project->EditorTarget.HasChars()) + { + referenceTarget = reference.Project->EditorTarget.Get(); + } + else if (reference.Project->GameTarget.HasChars()) + { + referenceTarget = reference.Project->GameTarget.Get(); + } + if (referenceTarget.IsEmpty()) + continue; + + const String referenceTargetOutput = reference.Project->ProjectFolderPath / TEXT("Binaries") / referenceTarget / platform / architecture / configuration; + FileSystem::DirectoryGetFiles(files, referenceTargetOutput, TEXT("*.HotReload.*"), DirectorySearchOption::TopDirectoryOnly); + } + if (files.HasItems()) LOG(Info, "Removing {0} files from previous Editor run hot-reloads", files.Count()); for (auto& file : files) From 58618bd40260a1329847c90839af9f3f34b775f8 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Fri, 30 Jun 2023 14:40:49 +0300 Subject: [PATCH 57/65] Fix garbage DefaultScene value in new projects --- Source/Editor/ProjectInfo.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/ProjectInfo.h b/Source/Editor/ProjectInfo.h index 256269cc9..9f52e414f 100644 --- a/Source/Editor/ProjectInfo.h +++ b/Source/Editor/ProjectInfo.h @@ -112,6 +112,7 @@ public: { Version = ::Version(1, 0); DefaultSceneSpawn = Ray(Vector3::Zero, Vector3::Forward); + DefaultScene = Guid::Empty; } /// From 28335478bd9275078fde606f742b1ed1a57403fc Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 2 Jul 2023 21:55:58 +0300 Subject: [PATCH 58/65] Fix managed library location resolver --- Source/Engine/Engine/NativeInterop.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 4aedbe171..a6eb5368c 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -99,11 +99,14 @@ namespace FlaxEngine.Interop private static Assembly OnScriptingAssemblyLoadContextResolving(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) { // FIXME: There should be a better way to resolve the path to EditorTargetPath where the dependencies are stored - string editorTargetPath = Path.GetDirectoryName(nativeLibraryPaths.Keys.First(x => x != "FlaxEngine")); + foreach (string nativeLibraryPath in nativeLibraryPaths.Values) + { + string editorTargetPath = Path.GetDirectoryName(nativeLibraryPath); - var assemblyPath = Path.Combine(editorTargetPath, assemblyName.Name + ".dll"); - if (File.Exists(assemblyPath)) - return assemblyLoadContext.LoadFromAssemblyPath(assemblyPath); + var assemblyPath = Path.Combine(editorTargetPath, assemblyName.Name + ".dll"); + if (File.Exists(assemblyPath)) + return assemblyLoadContext.LoadFromAssemblyPath(assemblyPath); + } return null; } #endif From 4f78f7920177e068e6606d36427233664563b61f Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 2 Jul 2023 22:12:18 +0300 Subject: [PATCH 59/65] Support line-breaks in API_INJECT_CODE macro --- Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs index b09b0c137..c05ab4e73 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs @@ -1417,6 +1417,9 @@ namespace Flax.Build.Bindings context.Tokenizer.SkipUntil(TokenType.Comma, out desc.Lang); desc.Code = context.Tokenizer.ExpectToken(TokenType.String).Value.Replace("\\\"", "\""); desc.Code = desc.Code.Substring(1, desc.Code.Length - 2); + desc.Code = desc.Code.Replace("\\\n", "\n"); + desc.Code = desc.Code.Replace("\\\r\n", "\n"); + desc.Code = desc.Code.Replace("\t", " "); context.Tokenizer.ExpectToken(TokenType.RightParent); return desc; } From 9a1fd12a8582afc5529a6667c3046f4da36f3584 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 11:42:15 +0200 Subject: [PATCH 60/65] Fix sizeof struct within generic type instance #1219 --- .../CustomEditors/Dedicated/RagdollEditor.cs | 4 ++-- Source/Engine/Engine/NativeInterop.Managed.cs | 8 +++---- .../Engine/Engine/NativeInterop.Unmanaged.cs | 1 + Source/Engine/Engine/NativeInterop.cs | 23 ++++++++++++++++++- Source/Engine/Level/Spline.cs | 4 ++-- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs b/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs index 28c039dc8..5a10b9a52 100644 --- a/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/RagdollEditor.cs @@ -167,7 +167,7 @@ namespace FlaxEditor.CustomEditors.Dedicated Presenter.Undo?.AddAction(new MultiUndoAction(actions)); // Build ragdoll - SceneGraph.Actors.AnimatedModelNode.BuildRagdoll(animatedModel, options, ragdoll); + AnimatedModelNode.BuildRagdoll(animatedModel, options, ragdoll); } private void OnRebuildBone(Button button) @@ -191,7 +191,7 @@ namespace FlaxEditor.CustomEditors.Dedicated } // Build ragdoll - SceneGraph.Actors.AnimatedModelNode.BuildRagdoll(animatedModel, new AnimatedModelNode.RebuildOptions(), ragdoll, name); + AnimatedModelNode.BuildRagdoll(animatedModel, new AnimatedModelNode.RebuildOptions(), ragdoll, name); } private void OnRemoveBone(Button button) diff --git a/Source/Engine/Engine/NativeInterop.Managed.cs b/Source/Engine/Engine/NativeInterop.Managed.cs index 7eda1cdec..797b02d5b 100644 --- a/Source/Engine/Engine/NativeInterop.Managed.cs +++ b/Source/Engine/Engine/NativeInterop.Managed.cs @@ -50,13 +50,13 @@ namespace FlaxEngine.Interop /// The resources must be released by calling FreePooled() instead of Free()-method. public static ManagedArray WrapPooledArray(Array arr, Type arrayType) { - ManagedArray managedArray = ManagedArrayPool.Get(arr.Length * Marshal.SizeOf(arr.GetType().GetElementType())); + ManagedArray managedArray = ManagedArrayPool.Get(arr.Length * NativeInterop.GetTypeSize(arr.GetType().GetElementType())); managedArray.WrapArray(arr, arrayType); return managedArray; } internal static ManagedArray AllocateNewArray(int length, Type arrayType, Type elementType) - => new ManagedArray((IntPtr)NativeInterop.NativeAlloc(length, Marshal.SizeOf(elementType)), length, arrayType, elementType); + => new ManagedArray((IntPtr)NativeInterop.NativeAlloc(length, NativeInterop.GetTypeSize(elementType)), length, arrayType, elementType); internal static ManagedArray AllocateNewArray(IntPtr ptr, int length, Type arrayType, Type elementType) => new ManagedArray(ptr, length, arrayType, elementType); @@ -86,7 +86,7 @@ namespace FlaxEngine.Interop _length = arr.Length; _arrayType = arrayType; _elementType = arr.GetType().GetElementType(); - _elementSize = Marshal.SizeOf(_elementType); + _elementSize = NativeInterop.GetTypeSize(_elementType); } internal void Allocate(int length) where T : unmanaged @@ -117,7 +117,7 @@ namespace FlaxEngine.Interop _length = length; _arrayType = arrayType; _elementType = elementType; - _elementSize = Marshal.SizeOf(elementType); + _elementSize = NativeInterop.GetTypeSize(_elementType); } ~ManagedArray() diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index c079a14e1..d4a8d44f8 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -885,6 +885,7 @@ namespace FlaxEngine.Interop handle.Free(); fieldHandleCacheCollectible.Clear(); #endif + _typeSizeCache.Clear(); foreach (var pair in classAttributesCacheCollectible) pair.Value.Free(); diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index a6eb5368c..e82cb3858 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -46,6 +46,7 @@ namespace FlaxEngine.Interop #endif private static Dictionary classAttributesCacheCollectible = new(); private static Dictionary assemblyHandles = new(); + private static Dictionary _typeSizeCache = new(); private static Dictionary loadedNativeLibraries = new(); internal static Dictionary nativeLibraryPaths = new(); @@ -584,7 +585,7 @@ namespace FlaxEngine.Interop else if (fieldType.IsClass || fieldType.IsPointer) fieldAlignment = IntPtr.Size; else - fieldAlignment = Marshal.SizeOf(fieldType); + fieldAlignment = GetTypeSize(fieldType); } internal static void ToManagedField(FieldInfo field, ref T fieldOwner, IntPtr fieldPtr, out int fieldOffset) @@ -1088,6 +1089,26 @@ namespace FlaxEngine.Interop return handle; } + internal static int GetTypeSize(Type type) + { + if (!_typeSizeCache.TryGetValue(type, out var size)) + { + try + { + size = Marshal.SizeOf(type); + } + catch + { + // Workaround the issue where structure defined within generic type instance (eg. MyType.MyStruct) fails to get size + // https://github.com/dotnet/runtime/issues/46426 + var obj = Activator.CreateInstance(type); + size = Marshal.SizeOf(obj); + } + _typeSizeCache.Add(type, size); + } + return size; + } + private static class DelegateHelpers { #if USE_AOT diff --git a/Source/Engine/Level/Spline.cs b/Source/Engine/Level/Spline.cs index 28a6aff8c..a2c9aecde 100644 --- a/Source/Engine/Level/Spline.cs +++ b/Source/Engine/Level/Spline.cs @@ -23,8 +23,8 @@ namespace FlaxEngine if (_keyframes == null || _keyframes.Length != count) _keyframes = new BezierCurve.Keyframe[count]; #if !BUILD_RELEASE - if (Marshal.SizeOf(typeof(BezierCurve.Keyframe)) != Transform.SizeInBytes * 3 + sizeof(float)) - throw new Exception("Invalid size of BezierCurve keyframe " + Marshal.SizeOf(typeof(BezierCurve.Keyframe)) + " bytes."); + if (System.Runtime.CompilerServices.Unsafe.SizeOf.Keyframe>() != Transform.SizeInBytes * 3 + sizeof(float)) + throw new Exception("Invalid size of BezierCurve keyframe " + System.Runtime.CompilerServices.Unsafe.SizeOf.Keyframe>() + " bytes."); #endif Internal_GetKeyframes(__unmanagedPtr, _keyframes); return _keyframes; From 9d640656e6a2438c5203e1abb96fdb574f4d0be8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 12:10:06 +0200 Subject: [PATCH 61/65] Fix `StringUtils::ConvertANSI2UTF16` to properly handle multi-byte characters Length #1225 --- Source/Engine/Core/Types/String.cpp | 4 ++-- Source/Engine/Core/Types/StringBuilder.h | 3 ++- Source/Engine/Core/Types/Variant.cpp | 6 ++++-- Source/Engine/Graphics/Shaders/GPUShader.cpp | 2 +- Source/Engine/Platform/StringUtils.h | 2 +- Source/Engine/Platform/Unix/UnixStringUtils.cpp | 7 ++++--- Source/Engine/Platform/Win32/Win32StringUtils.cpp | 8 +++++--- Source/Engine/Platform/Windows/WindowsPlatform.cpp | 3 ++- Source/Engine/Utilities/StringConverter.h | 10 +++++----- 9 files changed, 26 insertions(+), 19 deletions(-) diff --git a/Source/Engine/Core/Types/String.cpp b/Source/Engine/Core/Types/String.cpp index cee60c07c..3de255039 100644 --- a/Source/Engine/Core/Types/String.cpp +++ b/Source/Engine/Core/Types/String.cpp @@ -73,7 +73,7 @@ void String::Set(const char* chars, int32 length) _length = length; } if (chars) - StringUtils::ConvertANSI2UTF16(chars, _data, length); + StringUtils::ConvertANSI2UTF16(chars, _data, length, _length); } void String::SetUTF8(const char* chars, int32 length) @@ -112,7 +112,7 @@ void String::Append(const char* chars, int32 count) _data = (Char*)Platform::Allocate((_length + 1) * sizeof(Char), 16); Platform::MemoryCopy(_data, oldData, oldLength * sizeof(Char)); - StringUtils::ConvertANSI2UTF16(chars, _data + oldLength, count * sizeof(Char)); + StringUtils::ConvertANSI2UTF16(chars, _data + oldLength, count, _length); _data[_length] = 0; Platform::Free(oldData); diff --git a/Source/Engine/Core/Types/StringBuilder.h b/Source/Engine/Core/Types/StringBuilder.h index 39c1b3a84..051554a23 100644 --- a/Source/Engine/Core/Types/StringBuilder.h +++ b/Source/Engine/Core/Types/StringBuilder.h @@ -125,7 +125,8 @@ public: const int32 length = str && *str ? StringUtils::Length(str) : 0; const int32 prevCnt = _data.Count(); _data.AddDefault(length); - StringUtils::ConvertANSI2UTF16(str, _data.Get() + prevCnt, length); + int32 tmp; + StringUtils::ConvertANSI2UTF16(str, _data.Get() + prevCnt, length, tmp); return *this; } diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp index 33ffde349..8232d415f 100644 --- a/Source/Engine/Core/Types/Variant.cpp +++ b/Source/Engine/Core/Types/Variant.cpp @@ -660,7 +660,8 @@ Variant::Variant(const StringAnsiView& v) const int32 length = v.Length() * sizeof(Char) + 2; AsBlob.Data = Allocator::Allocate(length); AsBlob.Length = length; - StringUtils::ConvertANSI2UTF16(v.Get(), (Char*)AsBlob.Data, v.Length()); + int32 tmp; + StringUtils::ConvertANSI2UTF16(v.Get(), (Char*)AsBlob.Data, v.Length(), tmp); ((Char*)AsBlob.Data)[v.Length()] = 0; } else @@ -2578,7 +2579,8 @@ void Variant::SetString(const StringAnsiView& str) AsBlob.Data = Allocator::Allocate(length); AsBlob.Length = length; } - StringUtils::ConvertANSI2UTF16(str.Get(), (Char*)AsBlob.Data, str.Length()); + int32 tmp; + StringUtils::ConvertANSI2UTF16(str.Get(), (Char*)AsBlob.Data, str.Length(), tmp); ((Char*)AsBlob.Data)[str.Length()] = 0; } diff --git a/Source/Engine/Graphics/Shaders/GPUShader.cpp b/Source/Engine/Graphics/Shaders/GPUShader.cpp index 2666bf36b..3639e01b1 100644 --- a/Source/Engine/Graphics/Shaders/GPUShader.cpp +++ b/Source/Engine/Graphics/Shaders/GPUShader.cpp @@ -145,7 +145,7 @@ bool GPUShader::Create(MemoryReadStream& stream) // Create CB #if GPU_ENABLE_RESOURCE_NAMING - String name = ToString() + TEXT(".CB") + i; + String name = String::Format(TEXT("{}.CB{}"), ToString(), i); #else String name; #endif diff --git a/Source/Engine/Platform/StringUtils.h b/Source/Engine/Platform/StringUtils.h index 04e644d2e..72b3b5f4b 100644 --- a/Source/Engine/Platform/StringUtils.h +++ b/Source/Engine/Platform/StringUtils.h @@ -179,7 +179,7 @@ public: public: // Converts characters from ANSI to UTF-16 - static void ConvertANSI2UTF16(const char* from, Char* to, int32 len); + static void ConvertANSI2UTF16(const char* from, Char* to, int32 fromLength, int32& toLength); // Converts characters from UTF-16 to ANSI static void ConvertUTF162ANSI(const Char* from, char* to, int32 len); diff --git a/Source/Engine/Platform/Unix/UnixStringUtils.cpp b/Source/Engine/Platform/Unix/UnixStringUtils.cpp index 7e5c34b24..daa705769 100644 --- a/Source/Engine/Platform/Unix/UnixStringUtils.cpp +++ b/Source/Engine/Platform/Unix/UnixStringUtils.cpp @@ -311,14 +311,14 @@ static inline uint32 Utf8ToUtf32Codepoint(const char* src, int32 length) } } -void StringUtils::ConvertANSI2UTF16(const char* from, Char* to, int32 len) +void StringUtils::ConvertANSI2UTF16(const char* from, Char* to, int32 fromLength, int32& toLength) { - const char* const u8end = from + len; + const char* const u8end = from + fromLength; const char* u8cur = from; char16_t* u16cur = to; while (u8cur < u8end) { - len = Utf8CodepointLength(*u8cur); + int32 len = Utf8CodepointLength(*u8cur); uint32 codepoint = Utf8ToUtf32Codepoint(u8cur, len); // Convert the UTF32 codepoint to one or more UTF16 codepoints @@ -336,6 +336,7 @@ void StringUtils::ConvertANSI2UTF16(const char* from, Char* to, int32 len) } u8cur += len; } + toLength = (int32)(u16cur - to); } static const char32_t kByteMask = 0x000000BF; diff --git a/Source/Engine/Platform/Win32/Win32StringUtils.cpp b/Source/Engine/Platform/Win32/Win32StringUtils.cpp index d1634d90d..2a9bcf174 100644 --- a/Source/Engine/Platform/Win32/Win32StringUtils.cpp +++ b/Source/Engine/Platform/Win32/Win32StringUtils.cpp @@ -179,10 +179,12 @@ const char* StringUtils::Find(const char* str, const char* toFind) return strstr(str, toFind); } -void StringUtils::ConvertANSI2UTF16(const char* from, Char* to, int32 len) +void StringUtils::ConvertANSI2UTF16(const char* from, Char* to, int32 fromLength, int32& toLength) { - if (len) - mbstowcs(to, from, len); + if (fromLength) + toLength = mbstowcs(to, from, fromLength); + else + toLength = 0; } void StringUtils::ConvertUTF162ANSI(const Char* from, char* to, int32 len) diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.cpp b/Source/Engine/Platform/Windows/WindowsPlatform.cpp index 8d02312af..4d43272d1 100644 --- a/Source/Engine/Platform/Windows/WindowsPlatform.cpp +++ b/Source/Engine/Platform/Windows/WindowsPlatform.cpp @@ -992,7 +992,8 @@ void ReadPipe(HANDLE pipe, Array& rawData, Array& logData, LogType l // Log contents logData.Clear(); logData.Resize(rawData.Count() + 1); - StringUtils::ConvertANSI2UTF16(rawData.Get(), logData.Get(), rawData.Count()); + int32 tmp; + StringUtils::ConvertANSI2UTF16(rawData.Get(), logData.Get(), rawData.Count(), tmp); logData.Last() = '\0'; if (settings.LogOutput) Log::Logger::Write(logType, StringView(logData.Get(), rawData.Count())); diff --git a/Source/Engine/Utilities/StringConverter.h b/Source/Engine/Utilities/StringConverter.h index 340278c00..e494a8b94 100644 --- a/Source/Engine/Utilities/StringConverter.h +++ b/Source/Engine/Utilities/StringConverter.h @@ -49,7 +49,7 @@ public: { } - StringAsANSI(const Char* text, const int32 length) + StringAsANSI(const Char* text, int32 length) { if (length + 1 < InlinedSize) { @@ -83,7 +83,7 @@ public: { } - StringAsUTF8(const Char* text, const int32 length) + StringAsUTF8(const Char* text, int32 length) { int32 lengthUtf8; if (length + 1 < InlinedSize) @@ -112,17 +112,17 @@ public: { } - StringAsUTF16(const char* text, const int32 length) + StringAsUTF16(const char* text, int32 length) { if (length + 1 < InlinedSize) { - StringUtils::ConvertANSI2UTF16(text, this->_inlined, length); + StringUtils::ConvertANSI2UTF16(text, this->_inlined, length, length); this->_inlined[length] = 0; } else { this->_dynamic = (CharType*)Allocator::Allocate((length + 1) * sizeof(CharType)); - StringUtils::ConvertANSI2UTF16(text, this->_dynamic, length); + StringUtils::ConvertANSI2UTF16(text, this->_dynamic, length, length); this->_dynamic[length] = 0; } } From 544eb03f7e102e99f61b7708230f5967f65b28d0 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 13:06:08 +0200 Subject: [PATCH 62/65] Add network replication support for in-built object/asset reference holders --- Source/Engine/Serialization/ReadStream.h | 28 +++++++++++++++++++++++ Source/Engine/Serialization/Stream.h | 8 +++++++ Source/Engine/Serialization/WriteStream.h | 20 ++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/Source/Engine/Serialization/ReadStream.h b/Source/Engine/Serialization/ReadStream.h index 9d3215442..26b536c6d 100644 --- a/Source/Engine/Serialization/ReadStream.h +++ b/Source/Engine/Serialization/ReadStream.h @@ -159,6 +159,34 @@ public: Read(ptr); v = ptr; } + template + FORCE_INLINE void Read(SoftObjectReference& v) + { + uint32 id[4]; + ReadBytes(id, sizeof(id)); + v.Set(*(Guid*)id); + } + template + FORCE_INLINE void Read(AssetReference& v) + { + uint32 id[4]; + ReadBytes(id, sizeof(id)); + v = (T*)::LoadAsset(*(Guid*)id, T::TypeInitializer); + } + template + FORCE_INLINE void Read(WeakAssetReference& v) + { + uint32 id[4]; + ReadBytes(id, sizeof(id)); + v = (T*)::LoadAsset(*(Guid*)id, T::TypeInitializer); + } + template + FORCE_INLINE void Read(SoftAssetReference& v) + { + uint32 id[4]; + ReadBytes(id, sizeof(id)); + v.Set(*(Guid*)id); + } /// /// Read data array diff --git a/Source/Engine/Serialization/Stream.h b/Source/Engine/Serialization/Stream.h index 83f0eaf21..e477eee95 100644 --- a/Source/Engine/Serialization/Stream.h +++ b/Source/Engine/Serialization/Stream.h @@ -17,6 +17,14 @@ class ISerializable; class ScriptingObject; template class ScriptingObjectReference; +template +class SoftObjectReference; +template +class AssetReference; +template +class WeakAssetReference; +template +class SoftAssetReference; /// /// Base class for all data streams (memory streams, file streams etc.) diff --git a/Source/Engine/Serialization/WriteStream.h b/Source/Engine/Serialization/WriteStream.h index 92ac211ca..95bd87df9 100644 --- a/Source/Engine/Serialization/WriteStream.h +++ b/Source/Engine/Serialization/WriteStream.h @@ -176,6 +176,26 @@ public: { Write(v.Get()); } + template + FORCE_INLINE void Write(const SoftObjectReference& v) + { + Write(v.Get()); + } + template + FORCE_INLINE void Write(const AssetReference& v) + { + Write(v.Get()); + } + template + FORCE_INLINE void Write(const WeakAssetReference& v) + { + Write(v.Get()); + } + template + FORCE_INLINE void Write(const SoftAssetReference& v) + { + Write(v.Get()); + } template void Write(const Array& data) From 9db3439d0d9be39ef76731013a2dd6531ba08e11 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 16:17:46 +0200 Subject: [PATCH 63/65] Fix compilation error --- Source/Engine/Serialization/ReadStream.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Engine/Serialization/ReadStream.h b/Source/Engine/Serialization/ReadStream.h index 26b536c6d..be80e3249 100644 --- a/Source/Engine/Serialization/ReadStream.h +++ b/Source/Engine/Serialization/ReadStream.h @@ -6,6 +6,7 @@ #include "Engine/Core/Templates.h" extern FLAXENGINE_API class ScriptingObject* FindObject(const Guid& id, class MClass* type); +extern FLAXENGINE_API class Asset* LoadAsset(const Guid& id, const struct ScriptingTypeHandle& type); /// /// Base class for all data read streams From 5d9e6b7364846f8229647bbeeea18d490e801a05 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 22:00:23 +0200 Subject: [PATCH 64/65] Fix C# building to properly use reference assemblies for .NET 7 --- Source/Editor/Editor.Build.cs | 3 ++- .../Flax.Build/Build/DotNet/Builder.DotNet.cs | 10 ++++---- .../Build/NativeCpp/BuildOptions.cs | 24 ++++++++++++++----- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Source/Editor/Editor.Build.cs b/Source/Editor/Editor.Build.cs index 64578570c..2e769f431 100644 --- a/Source/Editor/Editor.Build.cs +++ b/Source/Editor/Editor.Build.cs @@ -37,7 +37,8 @@ public class Editor : EditorModule { base.Setup(options); - options.ScriptingAPI.SystemReferences.Add("System.Private.Xml"); + options.ScriptingAPI.SystemReferences.Add("System.Xml"); + options.ScriptingAPI.SystemReferences.Add("System.Xml.ReaderWriter"); options.ScriptingAPI.SystemReferences.Add("System.Text.RegularExpressions"); options.ScriptingAPI.SystemReferences.Add("System.ComponentModel.TypeConverter"); diff --git a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs index e6a250eb5..454376c61 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs @@ -164,6 +164,8 @@ namespace Flax.Build if (!dotnetSdk.IsValid) throw new Exception("Cannot compile C# without .NET SDK"); string dotnetPath = "dotnet", referenceAnalyzers; + string[] runtimeVersionNameParts = dotnetSdk.RuntimeVersionName.Split('.'); + string runtimeVersionShort = runtimeVersionNameParts[0] + '.' + runtimeVersionNameParts[1]; #else string monoRoot, monoPath; #endif @@ -174,7 +176,7 @@ namespace Flax.Build #if USE_NETCORE dotnetPath = Path.Combine(dotnetSdk.RootPath, "dotnet.exe"); cscPath = Path.Combine(dotnetSdk.RootPath, @$"sdk\{dotnetSdk.VersionName}\Roslyn\bincore\csc.dll"); - referenceAssemblies = Path.Combine(dotnetSdk.RootPath, @$"shared\Microsoft.NETCore.App\{dotnetSdk.RuntimeVersionName}\"); + referenceAssemblies = Path.Combine(dotnetSdk.RootPath, @$"packs\Microsoft.NETCore.App.Ref\{dotnetSdk.RuntimeVersionName}\ref\net{runtimeVersionShort}\"); referenceAnalyzers = Path.Combine(dotnetSdk.RootPath, @$"packs\Microsoft.NETCore.App.Ref\{dotnetSdk.RuntimeVersionName}\analyzers\dotnet\cs\"); #else monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Windows", "Mono"); @@ -190,7 +192,7 @@ namespace Flax.Build { #if USE_NETCORE cscPath = Path.Combine(dotnetSdk.RootPath, $"sdk/{dotnetSdk.VersionName}/Roslyn/bincore/csc.dll"); - referenceAssemblies = Path.Combine(dotnetSdk.RootPath, $"shared/Microsoft.NETCore.App/{dotnetSdk.RuntimeVersionName}/"); + referenceAssemblies = Path.Combine(dotnetSdk.RootPath, $"packs/Microsoft.NETCore.App.Ref/{dotnetSdk.RuntimeVersionName}/ref/net{runtimeVersionShort}/"); referenceAnalyzers = Path.Combine(dotnetSdk.RootPath, $"packs/Microsoft.NETCore.App.Ref/{dotnetSdk.RuntimeVersionName}/analyzers/dotnet/cs/"); #else monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Linux", "Mono"); @@ -204,7 +206,7 @@ namespace Flax.Build { #if USE_NETCORE cscPath = Path.Combine(dotnetSdk.RootPath, $"sdk/{dotnetSdk.VersionName}/Roslyn/bincore/csc.dll"); - referenceAssemblies = Path.Combine(dotnetSdk.RootPath, $"shared/Microsoft.NETCore.App/{dotnetSdk.RuntimeVersionName}/"); + referenceAssemblies = Path.Combine(dotnetSdk.RootPath, $"packs/Microsoft.NETCore.App.Ref/{dotnetSdk.RuntimeVersionName}/ref/net{runtimeVersionShort}/"); referenceAnalyzers = Path.Combine(dotnetSdk.RootPath, $"packs/Microsoft.NETCore.App.Ref/{dotnetSdk.RuntimeVersionName}/analyzers/dotnet/cs/"); #else monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Mac", "Mono"); @@ -256,6 +258,7 @@ namespace Flax.Build args.Add(buildData.Configuration == TargetConfiguration.Release ? "/optimize+" : "/optimize-"); #else args.Add(buildData.Configuration == TargetConfiguration.Debug ? "/optimize-" : "/optimize+"); + args.Add(string.Format("/reference:\"{0}mscorlib.dll\"", referenceAssemblies)); #endif args.Add(string.Format("/out:\"{0}\"", outputFile)); args.Add(string.Format("/doc:\"{0}\"", outputDocFile)); @@ -263,7 +266,6 @@ namespace Flax.Build args.Add("/define:" + string.Join(";", buildOptions.ScriptingAPI.Defines)); if (buildData.Configuration == TargetConfiguration.Debug) args.Add("/define:DEBUG"); - args.Add(string.Format("/reference:\"{0}mscorlib.dll\"", referenceAssemblies)); foreach (var reference in buildOptions.ScriptingAPI.SystemReferences) args.Add(string.Format("/reference:\"{0}{1}.dll\"", referenceAssemblies, reference)); foreach (var reference in fileReferences) diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs b/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs index c2ea81372..ef365d3b7 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs @@ -244,6 +244,8 @@ namespace Flax.Build.NativeCpp Defines = new HashSet(), SystemReferences = new HashSet { + "mscorlib", + "netstandard", "Microsoft.CSharp", "System", @@ -258,25 +260,32 @@ namespace Flax.Build.NativeCpp //"System.ComponentModel.TypeConverter", "System.Console", "System.Core", + "System.Diagnostics.StackTrace", "System.Globalization", "System.IO", "System.IO.Compression", "System.IO.FileSystem.Watcher", "System.Linq", "System.Linq.Expressions", + "System.Memory", + "System.Net", "System.Net.Http", "System.Net.Primitives", "System.ObjectModel", - "System.Private.CoreLib", - "System.Private.Uri", - //"System.Private.Xml", + "System.ValueTuple", - "System.Reflection", "System.Runtime", + "System.Runtime.Extensions", + "System.Runtime.Handles", + "System.Runtime.Intrinsics", + "System.Runtime.Numerics", + "System.Runtime.Loader", "System.Runtime.CompilerServices.Unsafe", "System.Runtime.InteropServices", "System.Runtime.InteropServices.RuntimeInformation", - "System.Runtime.Serialization.Formatters", // BinaryFormatter + "System.Runtime.Serialization", + "System.Runtime.Serialization.Formatters", + "System.Security.Cryptography", "System.Security.Cryptography.Algorithms", "System.Security.Cryptography.Primitives", @@ -284,8 +293,11 @@ namespace Flax.Build.NativeCpp "System.Threading.Tasks.Parallel", //"System.Xml", + "System.Threading", + "System.Threading.Thread", + + "System.Reflection", //"System.Reflection.Metadata", - "netstandard", }, SystemAnalyzers = new HashSet { From 5f756a6ceb390a4fd71b7e0d6b1493881a4796c8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Jul 2023 22:00:38 +0200 Subject: [PATCH 65/65] Add `TargetFrameworkAttribute` to compiled C# assembly --- .../Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs index 454376c61..13433f92c 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using Flax.Build.Graph; using Flax.Build.NativeCpp; using Flax.Deploy; @@ -12,7 +13,7 @@ namespace Flax.Build { static partial class Builder { - public static event Action> BuildDotNetAssembly; + public static event Action> BuildDotNetAssembly; private static void BuildTargetDotNet(RulesAssembly rules, TaskGraph graph, Target target, Platform platform, TargetConfiguration configuration) { @@ -151,7 +152,7 @@ namespace Flax.Build } } - private static void BuildDotNet(TaskGraph graph, BuildData buildData, NativeCpp.BuildOptions buildOptions, string name, List sourceFiles, HashSet fileReferences = null, IGrouping binaryModule = null) + private static void BuildDotNet(TaskGraph graph, BuildData buildData, BuildOptions buildOptions, string name, List sourceFiles, HashSet fileReferences = null, IGrouping binaryModule = null) { // Setup build options var buildPlatform = Platform.BuildTargetPlatform; @@ -277,6 +278,13 @@ namespace Flax.Build foreach (var sourceFile in sourceFiles) args.Add("\"" + sourceFile + "\""); +#if USE_NETCORE + // Inject some assembly metadata (similar to msbuild in Visual Studio) + var assemblyAttributesPath = Path.Combine(buildOptions.IntermediateFolder, name + ".AssemblyAttributes.cs"); + File.WriteAllText(assemblyAttributesPath, $"[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(\".NETCoreApp,Version=v{runtimeVersionShort}\", FrameworkDisplayName = \".NET {runtimeVersionShort}\")]\n", Encoding.UTF8); + args.Add("\"" + assemblyAttributesPath + "\""); +#endif + // Generate response file with source files paths and compilation arguments string responseFile = Path.Combine(buildOptions.IntermediateFolder, name + ".response"); Utilities.WriteFileIfChanged(responseFile, string.Join(Environment.NewLine, args));