diff --git a/Development/Scripts/Windows/CallBuildTool.bat b/Development/Scripts/Windows/CallBuildTool.bat
index 9f60368c5..22c2d1dd7 100644
--- a/Development/Scripts/Windows/CallBuildTool.bat
+++ b/Development/Scripts/Windows/CallBuildTool.bat
@@ -11,16 +11,6 @@ for %%I in (Source\Logo.png) do if %%~zI LSS 2000 (
call "Development\Scripts\Windows\GetMSBuildPath.bat"
if errorlevel 1 goto Error_NoVisualStudioEnvironment
-if not exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" goto Compile
-for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath') do (
- for %%j in (15.0, Current) do (
- if exist "%%i\MSBuild\%%j\Bin\MSBuild.exe" (
- set MSBUILD_PATH="%%i\MSBuild\%%j\Bin\MSBuild.exe"
- goto Compile
- )
- )
-)
-
:Compile
md Cache\Intermediate >nul 2>nul
dir /s /b Source\Tools\Flax.Build\*.cs >Cache\Intermediate\Flax.Build.Files.txt
@@ -44,7 +34,7 @@ goto Exit
echo CallBuildTool ERROR: The script is in invalid directory.
goto Exit
:Error_NoVisualStudioEnvironment
-echo CallBuildTool ERROR: Missing Visual Studio 2015 or newer.
+echo CallBuildTool ERROR: Missing Visual Studio 2022 or newer.
goto Exit
:Error_CompilationFailed
echo CallBuildTool ERROR: Failed to compile Flax.Build project.
diff --git a/Development/Scripts/Windows/GetMSBuildPath.bat b/Development/Scripts/Windows/GetMSBuildPath.bat
index b20230118..f44155272 100644
--- a/Development/Scripts/Windows/GetMSBuildPath.bat
+++ b/Development/Scripts/Windows/GetMSBuildPath.bat
@@ -4,66 +4,26 @@ rem Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
set MSBUILD_PATH=
+rem Look for MSBuild version 17.0 or later
if not exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" goto VsWhereNotFound
-for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath') do (
- if exist "%%i\MSBuild\15.0\Bin\MSBuild.exe" (
- set MSBUILD_PATH="%%i\MSBuild\15.0\Bin\MSBuild.exe"
- goto End
- )
-)
-for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath') do (
- if exist "%%i\MSBuild\15.0\Bin\MSBuild.exe" (
- set MSBUILD_PATH="%%i\MSBuild\15.0\Bin\MSBuild.exe"
- goto End
- )
+for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -version 17.0 -latest -products * -requires Microsoft.Component.MSBuild -property installationPath') do (
if exist "%%i\MSBuild\Current\Bin\MSBuild.exe" (
set MSBUILD_PATH="%%i\MSBuild\Current\Bin\MSBuild.exe"
goto End
)
)
-:VsWhereNotFound
-if exist "%ProgramFiles(x86)%\MSBuild\14.0\bin\MSBuild.exe" (
- set MSBUILD_PATH="%ProgramFiles(x86)%\MSBuild\14.0\bin\MSBuild.exe"
- goto End
+rem Look for MSBuild version 17.0 or later in pre-release versions
+for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -version 17.0 -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath') do (
+ if exist "%%i\MSBuild\Current\Bin\MSBuild.exe" (
+ set MSBUILD_PATH="%%i\MSBuild\Current\Bin\MSBuild.exe"
+ goto End
+ )
)
-
-call :GetInstallPath Microsoft\VisualStudio\SxS\VS7 15.0 MSBuild\15.0\bin\MSBuild.exe
-if not errorlevel 1 goto End
-call :GetInstallPath Microsoft\MSBuild\ToolsVersions\14.0 MSBuildToolsPath MSBuild.exe
-if not errorlevel 1 goto End
-call :GetInstallPath Microsoft\MSBuild\ToolsVersions\12.0 MSBuildToolsPath MSBuild.exe
-if not errorlevel 1 goto End
-call :GetInstallPath Microsoft\MSBuild\ToolsVersions\4.0 MSBuildToolsPath MSBuild.exe
-if not errorlevel 1 goto End
-
+echo GetMSBuildPath ERROR: Could not find MSBuild version 17.0 or later.
+exit /B 1
+:VsWhereNotFound
+echo GetMSBuildPath ERROR: vswhere.exe was not found.
exit /B 1
:End
-exit /B 0
-
-:GetInstallPath
-for /f "tokens=2,*" %%A in ('REG.exe query HKCU\SOFTWARE\%1 /v %2 2^>Nul') do (
- if exist "%%B%%3" (
- set MSBUILD_PATH="%%B%3"
- exit /B 0
- )
-)
-for /f "tokens=2,*" %%A in ('REG.exe query HKLM\SOFTWARE\%1 /v %2 2^>Nul') do (
- if exist "%%B%3" (
- set MSBUILD_PATH="%%B%3"
- exit /B 0
- )
-)
-for /f "tokens=2,*" %%A in ('REG.exe query HKCU\SOFTWARE\Wow6432Node\%1 /v %2 2^>Nul') do (
- if exist "%%B%%3" (
- set MSBUILD_PATH="%%B%3"
- exit /B 0
- )
-)
-for /f "tokens=2,*" %%A in ('REG.exe query HKLM\SOFTWARE\Wow6432Node\%1 /v %2 2^>Nul') do (
- if exist "%%B%3" (
- set MSBUILD_PATH="%%B%3"
- exit /B 0
- )
-)
-exit /B 1
+exit /B 0
\ No newline at end of file
diff --git a/Flax.flaxproj b/Flax.flaxproj
index 50fcaeda3..fbf48cc2b 100644
--- a/Flax.flaxproj
+++ b/Flax.flaxproj
@@ -3,7 +3,7 @@
"Version": {
"Major": 1,
"Minor": 6,
- "Build": 6344
+ "Build": 6345
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.",
diff --git a/README.md b/README.md
index dc5abb84f..fac631a6a 100644
--- a/README.md
+++ b/README.md
@@ -31,19 +31,20 @@ Follow the instructions below to compile and run the engine from source.
* Install Visual Studio 2022 or newer
* Install Windows 8.1 SDK or newer (via Visual Studio Installer)
* Install Microsoft Visual C++ 2015 v140 toolset or newer (via Visual Studio Installer)
-* Install .Net 7 SDK (via Visual Studio Installer or [from web](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
+* Install .NET 7 SDK for **Windows x64** (via Visual Studio Installer or [from web](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
* Install Git with LFS
* Clone repo (with LFS)
* Run **GenerateProjectFiles.bat**
* Open `Flax.sln` and set solution configuration to **Editor.Development** and solution platform to **Win64**
* Set Flax (C++) or FlaxEngine (C#) as startup project
* Compile Flax project (hit F7 or CTRL+Shift+B)
+* Optionally set Debug Type to **Managed Only (.NET Core)** to debug C#-only, or **Mixed (.NET Core)** to debug both C++ and C#
* Run Flax (hit F5 key)
## Linux
* Install Visual Studio Code
-* Install .Net 7 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
+* Install .NET 7 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
* Ubuntu: `sudo apt install dotnet-sdk-7.0`
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
* Ubuntu: `sudo apt install vulkan-sdk`
@@ -66,7 +67,7 @@ Follow the instructions below to compile and run the engine from source.
## Mac
* Install XCode
-* Install .Net 7 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
+* Install .NET 7 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
* Clone repo (with LFS)
* Run `GenerateProjectFiles.command`
diff --git a/Source/Editor/Cooker/Platform/Mac/MacPlatformTools.cpp b/Source/Editor/Cooker/Platform/Mac/MacPlatformTools.cpp
index c059acba9..b66a96a9b 100644
--- a/Source/Editor/Cooker/Platform/Mac/MacPlatformTools.cpp
+++ b/Source/Editor/Cooker/Platform/Mac/MacPlatformTools.cpp
@@ -5,6 +5,7 @@
#include "MacPlatformTools.h"
#include "Engine/Platform/File.h"
#include "Engine/Platform/FileSystem.h"
+#include "Engine/Platform/CreateProcessSettings.h"
#include "Engine/Platform/Mac/MacPlatformSettings.h"
#include "Engine/Core/Config/GameSettings.h"
#include "Engine/Core/Config/BuildSettings.h"
@@ -124,17 +125,35 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
LOG(Error, "Failed to export application icon.");
return true;
}
- bool failed = Platform::RunProcess(TEXT("sips -z 16 16 icon_1024x1024.png --out icon_16x16.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 32 32 icon_1024x1024.png --out icon_16x16@2x.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 32 32 icon_1024x1024.png --out icon_32x32.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 64 64 icon_1024x1024.png --out icon_32x32@2x.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 128 128 icon_1024x1024.png --out icon_128x128.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 256 256 icon_1024x1024.png --out icon_128x128@2x.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 256 256 icon_1024x1024.png --out icon_256x256.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 512 512 icon_1024x1024.png --out icon_256x256@2x.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 512 512 icon_1024x1024.png --out icon_512x512.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 1024 1024 icon_1024x1024.png --out icon_512x512@2x.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("iconutil -c icns icon.iconset"), iconFolderPath);
+ CreateProcessSettings procSettings;
+ procSettings.HiddenWindow = true;
+ procSettings.FileName = TEXT("/usr/bin/sips");
+ procSettings.WorkingDirectory = tmpFolderPath;
+ procSettings.Arguments = TEXT("-z 16 16 icon_1024x1024.png --out icon_16x16.png");
+ bool failed = false;
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 32 32 icon_1024x1024.png --out icon_16x16@2x.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 32 32 icon_1024x1024.png --out icon_32x32.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 64 64 icon_1024x1024.png --out icon_32x32@2x.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 128 128 icon_1024x1024.png --out icon_128x128.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 256 256 icon_1024x1024.png --out icon_128x128@2x.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 256 256 icon_1024x1024.png --out icon_256x256.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 512 512 icon_1024x1024.png --out icon_256x256@2x.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 512 512 icon_1024x1024.png --out icon_512x512.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 1024 1024 icon_1024x1024.png --out icon_512x512@2x.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.FileName = TEXT("/usr/bin/iconutil");
+ procSettings.Arguments = TEXT("-c icns icon.iconset");
+ procSettings.WorkingDirectory = iconFolderPath;
+ failed |= Platform::CreateProcess(procSettings);
if (failed)
{
LOG(Error, "Failed to export application icon.");
@@ -210,16 +229,22 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
return false;
GameCooker::PackageFiles();
LOG(Info, "Building app package...");
- const String dmgPath = data.OriginalOutputPath / appName + TEXT(".dmg");
- const String dmgCommand = String::Format(TEXT("hdiutil create {0}.dmg -volname {0} -fs HFS+ -srcfolder {0}.app"), appName);
- const int32 result = Platform::RunProcess(dmgCommand, data.OriginalOutputPath);
- if (result != 0)
{
- data.Error(String::Format(TEXT("Failed to package app (result code: {0}). See log for more info."), result));
- return true;
+ const String dmgPath = data.OriginalOutputPath / appName + TEXT(".dmg");
+ CreateProcessSettings procSettings;
+ procSettings.HiddenWindow = true;
+ procSettings.WorkingDirectory = data.OriginalOutputPath;
+ procSettings.FileName = TEXT("/usr/bin/hdiutil");
+ procSettings.Arguments = String::Format(TEXT("create {0}.dmg -volname {0} -fs HFS+ -srcfolder {0}.app"), appName);
+ const int32 result = Platform::CreateProcess(procSettings);
+ if (result != 0)
+ {
+ data.Error(String::Format(TEXT("Failed to package app (result code: {0}). See log for more info."), result));
+ return true;
+ }
+ // TODO: sign dmg
+ LOG(Info, "Output application package: {0} (size: {1} MB)", dmgPath, FileSystem::GetFileSize(dmgPath) / 1024 / 1024);
}
- // TODO: sign dmg
- LOG(Info, "Output application package: {0} (size: {1} MB)", dmgPath, FileSystem::GetFileSize(dmgPath) / 1024 / 1024);
return false;
}
diff --git a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp
index 8b0cf06a8..85a7f99fa 100644
--- a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp
+++ b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp
@@ -260,15 +260,20 @@ bool iOSPlatformTools::OnPostProcess(CookingData& data)
{
LOG(Info, "Building app package...");
const Char* configuration = data.Configuration == BuildConfiguration::Release ? TEXT("Release") : TEXT("Debug");
- String command = String::Format(TEXT("xcodebuild -project FlaxGame.xcodeproj -configuration {} -scheme FlaxGame -archivePath FlaxGame.xcarchive archive"), configuration);
- int32 result = Platform::RunProcess(command, data.OriginalOutputPath);
+ CreateProcessSettings procSettings;
+ procSettings.HiddenWindow = true;
+ procSettings.WorkingDirectory = data.OriginalOutputPath;
+ procSettings.FileName = TEXT("/usr/bin/xcodebuild");
+ procSettings.Arguments = String::Format(TEXT("-project FlaxGame.xcodeproj -configuration {} -scheme FlaxGame -archivePath FlaxGame.xcarchive archive"), configuration);
+ int32 result = Platform::CreateProcess(procSettings);
if (result != 0)
{
data.Error(String::Format(TEXT("Failed to package app (result code: {0}). See log for more info."), result));
return true;
}
- command = TEXT("xcodebuild -exportArchive -archivePath FlaxGame.xcarchive -allowProvisioningUpdates -exportPath . -exportOptionsPlist ExportOptions.plist");
- result = Platform::RunProcess(command, data.OriginalOutputPath);
+ procSettings.FileName = TEXT("/usr/bin/xcodebuild");
+ procSettings.Arguments = TEXT("-exportArchive -archivePath FlaxGame.xcarchive -allowProvisioningUpdates -exportPath . -exportOptionsPlist ExportOptions.plist");
+ result = Platform::CreateProcess(procSettings);
if (result != 0)
{
data.Error(String::Format(TEXT("Failed to package app (result code: {0}). See log for more info."), result));
diff --git a/Source/Editor/CustomEditors/Editors/InputEditor.cs b/Source/Editor/CustomEditors/Editors/InputEditor.cs
index 416626e81..7b2682a84 100644
--- a/Source/Editor/CustomEditors/Editors/InputEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/InputEditor.cs
@@ -1,8 +1,10 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System.Collections.Generic;
+using FlaxEditor.CustomEditors.GUI;
+using FlaxEditor.GUI;
+using FlaxEditor.GUI.ContextMenu;
using FlaxEngine;
-using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Editors
{
@@ -12,7 +14,7 @@ namespace FlaxEditor.CustomEditors.Editors
[CustomEditor(typeof(InputEvent)), DefaultEditor]
public class InputEventEditor : CustomEditor
{
- private Dropdown _dropdown;
+ private ComboBox _comboBox;
///
public override DisplayStyle Style => DisplayStyle.Inline;
@@ -20,23 +22,30 @@ namespace FlaxEditor.CustomEditors.Editors
///
public override void Initialize(LayoutElementsContainer layout)
{
- var dropdownElement = layout.Custom();
- _dropdown = dropdownElement.CustomControl;
- var names = new List();
+ LinkedLabel.SetupContextMenu += OnSetupContextMenu;
+ var comboBoxElement = layout.ComboBox();
+ _comboBox = comboBoxElement.ComboBox;
+ var names = new List();
foreach (var mapping in Input.ActionMappings)
{
if (!names.Contains(mapping.Name))
names.Add(mapping.Name);
}
- _dropdown.Items = names;
+ _comboBox.Items = names;
if (Values[0] is InputEvent inputEvent && names.Contains(inputEvent.Name))
- _dropdown.SelectedItem = inputEvent.Name;
- _dropdown.SelectedIndexChanged += OnSelectedIndexChanged;
+ _comboBox.SelectedItem = inputEvent.Name;
+ _comboBox.SelectedIndexChanged += OnSelectedIndexChanged;
}
- private void OnSelectedIndexChanged(Dropdown dropdown)
+ private void OnSetupContextMenu(PropertyNameLabel label, ContextMenu menu, CustomEditor linkededitor)
{
- SetValue(new InputEvent(dropdown.SelectedItem));
+ var button = menu.AddButton("Set to null");
+ button.Clicked += () => _comboBox.SelectedItem = null;
+ }
+
+ private void OnSelectedIndexChanged(ComboBox comboBox)
+ {
+ SetValue(comboBox.SelectedItem == null ? null : new InputEvent(comboBox.SelectedItem));
}
///
@@ -49,17 +58,21 @@ namespace FlaxEditor.CustomEditors.Editors
}
else
{
- if (Values[0] is InputEvent inputEvent && _dropdown.Items.Contains(inputEvent.Name))
- _dropdown.SelectedItem = inputEvent.Name;
+ if (Values[0] is InputEvent inputEvent && _comboBox.Items.Contains(inputEvent.Name))
+ _comboBox.SelectedItem = inputEvent.Name;
+ else
+ _comboBox.SelectedItem = null;
}
}
///
protected override void Deinitialize()
{
- if (_dropdown != null)
- _dropdown.SelectedIndexChanged -= OnSelectedIndexChanged;
- _dropdown = null;
+ if (LinkedLabel != null)
+ LinkedLabel.SetupContextMenu -= OnSetupContextMenu;
+ if (_comboBox != null)
+ _comboBox.SelectedIndexChanged -= OnSelectedIndexChanged;
+ _comboBox = null;
}
}
@@ -69,7 +82,7 @@ namespace FlaxEditor.CustomEditors.Editors
[CustomEditor(typeof(InputAxis)), DefaultEditor]
public class InputAxisEditor : CustomEditor
{
- private Dropdown _dropdown;
+ private ComboBox _comboBox;
///
public override DisplayStyle Style => DisplayStyle.Inline;
@@ -77,23 +90,30 @@ namespace FlaxEditor.CustomEditors.Editors
///
public override void Initialize(LayoutElementsContainer layout)
{
- var dropdownElement = layout.Custom();
- _dropdown = dropdownElement.CustomControl;
- var names = new List();
+ LinkedLabel.SetupContextMenu += OnSetupContextMenu;
+ var comboBoxElement = layout.ComboBox();
+ _comboBox = comboBoxElement.ComboBox;
+ var names = new List();
foreach (var mapping in Input.AxisMappings)
{
if (!names.Contains(mapping.Name))
names.Add(mapping.Name);
}
- _dropdown.Items = names;
+ _comboBox.Items = names;
if (Values[0] is InputAxis inputAxis && names.Contains(inputAxis.Name))
- _dropdown.SelectedItem = inputAxis.Name;
- _dropdown.SelectedIndexChanged += OnSelectedIndexChanged;
+ _comboBox.SelectedItem = inputAxis.Name;
+ _comboBox.SelectedIndexChanged += OnSelectedIndexChanged;
}
- private void OnSelectedIndexChanged(Dropdown dropdown)
+ private void OnSetupContextMenu(PropertyNameLabel label, ContextMenu menu, CustomEditor linkededitor)
{
- SetValue(new InputAxis(dropdown.SelectedItem));
+ var button = menu.AddButton("Set to null");
+ button.Clicked += () => _comboBox.SelectedItem = null;
+ }
+
+ private void OnSelectedIndexChanged(ComboBox comboBox)
+ {
+ SetValue(comboBox.SelectedItem == null ? null : new InputAxis(comboBox.SelectedItem));
}
///
@@ -106,17 +126,21 @@ namespace FlaxEditor.CustomEditors.Editors
}
else
{
- if (Values[0] is InputAxis inputAxis && _dropdown.Items.Contains(inputAxis.Name))
- _dropdown.SelectedItem = inputAxis.Name;
+ if (Values[0] is InputAxis inputAxis && _comboBox.Items.Contains(inputAxis.Name))
+ _comboBox.SelectedItem = inputAxis.Name;
+ else
+ _comboBox.SelectedItem = null;
}
}
///
protected override void Deinitialize()
{
- if (_dropdown != null)
- _dropdown.SelectedIndexChanged -= OnSelectedIndexChanged;
- _dropdown = null;
+ if (LinkedLabel != null)
+ LinkedLabel.SetupContextMenu -= OnSetupContextMenu;
+ if (_comboBox != null)
+ _comboBox.SelectedIndexChanged -= OnSelectedIndexChanged;
+ _comboBox = null;
}
}
}
diff --git a/Source/Editor/GUI/ComboBox.cs b/Source/Editor/GUI/ComboBox.cs
index da2106450..0417cc7e3 100644
--- a/Source/Editor/GUI/ComboBox.cs
+++ b/Source/Editor/GUI/ComboBox.cs
@@ -545,7 +545,7 @@ namespace FlaxEditor.GUI
Render2D.DrawRectangle(clientRect.MakeExpanded(-2.0f), borderColor);
// Check if has selected item
- if (_selectedIndices.Count > 0)
+ if (_selectedIndices != null && _selectedIndices.Count > 0)
{
string text = _selectedIndices.Count == 1 ? _items[_selectedIndices[0]] : "Multiple Values";
diff --git a/Source/Editor/GUI/Dialogs/Dialog.cs b/Source/Editor/GUI/Dialogs/Dialog.cs
index 8910cfe49..07fc3ff0d 100644
--- a/Source/Editor/GUI/Dialogs/Dialog.cs
+++ b/Source/Editor/GUI/Dialogs/Dialog.cs
@@ -290,7 +290,11 @@ namespace FlaxEditor.GUI.Dialogs
OnCancel();
return true;
case KeyboardKeys.Tab:
- Root?.Navigate(NavDirection.Next);
+ if (Root != null)
+ {
+ bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
+ Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next);
+ }
return true;
}
return false;
diff --git a/Source/Editor/GUI/Docking/DockHintWindow.cs b/Source/Editor/GUI/Docking/DockHintWindow.cs
index 6dc700731..52c5dcd3c 100644
--- a/Source/Editor/GUI/Docking/DockHintWindow.cs
+++ b/Source/Editor/GUI/Docking/DockHintWindow.cs
@@ -476,6 +476,7 @@ namespace FlaxEditor.GUI.Docking
settings.ShowInTaskbar = false;
settings.ActivateWhenFirstShown = false;
settings.IsTopmost = true;
+ settings.ShowAfterFirstPaint = false;
win = Platform.CreateWindow(ref settings);
diff --git a/Source/Editor/GUI/MainMenu.cs b/Source/Editor/GUI/MainMenu.cs
index 370ad056b..b313fed9f 100644
--- a/Source/Editor/GUI/MainMenu.cs
+++ b/Source/Editor/GUI/MainMenu.cs
@@ -292,7 +292,8 @@ namespace FlaxEditor.GUI
return true;
#if PLATFORM_WINDOWS
- if (_useCustomWindowSystem)
+ var child = GetChildAtRecursive(location);
+ if (_useCustomWindowSystem && child is not Button && child is not MainMenuButton)
{
if (_window.IsMaximized)
_window.Restore();
diff --git a/Source/Editor/Modules/ContentDatabaseModule.cs b/Source/Editor/Modules/ContentDatabaseModule.cs
index 29d6b2c00..143352421 100644
--- a/Source/Editor/Modules/ContentDatabaseModule.cs
+++ b/Source/Editor/Modules/ContentDatabaseModule.cs
@@ -643,7 +643,8 @@ namespace FlaxEditor.Modules
/// Deletes the specified item.
///
/// The item.
- public void Delete(ContentItem item)
+ /// If the file was deleted by the user and not outside the editor.
+ public void Delete(ContentItem item, bool deletedByUser = false)
{
if (item == null)
throw new ArgumentNullException();
@@ -667,12 +668,12 @@ namespace FlaxEditor.Modules
var children = folder.Children.ToArray();
for (int i = 0; i < children.Length; i++)
{
- Delete(children[i]);
+ Delete(children[i], deletedByUser);
}
}
// Remove directory
- if (Directory.Exists(path))
+ if (deletedByUser && Directory.Exists(path))
{
try
{
@@ -701,7 +702,7 @@ namespace FlaxEditor.Modules
// Delete asset by using content pool
FlaxEngine.Content.DeleteAsset(path);
}
- else
+ else if (deletedByUser)
{
// Delete file
if (File.Exists(path))
@@ -847,7 +848,7 @@ namespace FlaxEditor.Modules
Editor.Log(string.Format($"Content item \'{child.Path}\' has been removed"));
// Destroy it
- Delete(child);
+ Delete(child, false);
i--;
}
diff --git a/Source/Editor/Modules/ContentEditingModule.cs b/Source/Editor/Modules/ContentEditingModule.cs
index 3db27af40..a6d8132f0 100644
--- a/Source/Editor/Modules/ContentEditingModule.cs
+++ b/Source/Editor/Modules/ContentEditingModule.cs
@@ -90,6 +90,12 @@ namespace FlaxEditor.Modules
hint = "Too long name.";
return false;
}
+
+ if (item.IsFolder && shortName.EndsWith("."))
+ {
+ hint = "Name cannot end with '.'";
+ return false;
+ }
// Find invalid characters
if (Utilities.Utils.HasInvalidPathChar(shortName))
@@ -120,7 +126,7 @@ namespace FlaxEditor.Modules
// Cache data
string sourcePath = item.Path;
string sourceFolder = System.IO.Path.GetDirectoryName(sourcePath);
- string extension = System.IO.Path.GetExtension(sourcePath);
+ string extension = item.IsFolder ? "" : System.IO.Path.GetExtension(sourcePath);
string destinationPath = StringUtils.CombinePaths(sourceFolder, shortName + extension);
if (item.IsFolder)
diff --git a/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp b/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp
index e28d1e381..7f5ca6f17 100644
--- a/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp
+++ b/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp
@@ -24,7 +24,8 @@ namespace
String version;
RiderInstallation(const String& path_, const String& version_)
- : path(path_), version(version_)
+ : path(path_)
+ , version(version_)
{
}
};
@@ -44,6 +45,10 @@ namespace
if (document.HasParseError())
return;
+ // Check if this is actually rider and not another jetbrains product
+ if (document.FindMember("name")->value != "JetBrains Rider")
+ return;
+
// Find version
auto versionMember = document.FindMember("version");
if (versionMember == document.MemberEnd())
@@ -141,14 +146,14 @@ bool sortInstallations(RiderInstallation* const& i1, RiderInstallation* const& i
int32 version2[3] = { 0 };
StringUtils::Parse(values1[0].Get(), &version1[0]);
StringUtils::Parse(values1[1].Get(), &version1[1]);
-
- if(values1.Count() > 2)
+
+ if (values1.Count() > 2)
StringUtils::Parse(values1[2].Get(), &version1[2]);
-
+
StringUtils::Parse(values2[0].Get(), &version2[0]);
StringUtils::Parse(values2[1].Get(), &version2[1]);
-
- if(values2.Count() > 2)
+
+ if (values2.Count() > 2)
StringUtils::Parse(values2[2].Get(), &version2[2]);
// Compare by MAJOR.MINOR.BUILD
@@ -174,7 +179,7 @@ void RiderCodeEditor::FindEditors(Array* output)
String localAppDataPath;
FileSystem::GetSpecialFolderPath(SpecialFolder::LocalAppData, localAppDataPath);
-
+
#if PLATFORM_WINDOWS
// Lookup from all known registry locations
SearchRegistry(&installations, HKEY_CURRENT_USER, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\Rider for Unreal Engine"));
@@ -187,6 +192,7 @@ void RiderCodeEditor::FindEditors(Array* output)
SearchRegistry(&installations, HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\JetBrains Rider"));
// Versions installed via JetBrains Toolbox
+ FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT("Programs"));
FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT("JetBrains\\Toolbox\\apps\\Rider\\ch-0\\"));
FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT("JetBrains\\Toolbox\\apps\\Rider\\ch-1\\")); // Beta versions
#endif
@@ -201,6 +207,7 @@ void RiderCodeEditor::FindEditors(Array* output)
FileSystem::GetChildDirectories(subDirectories, TEXT("/opt/"));
// Versions installed via JetBrains Toolbox
+ SearchDirectory(&installations, localAppDataPath / TEXT(".local/share/JetBrains/Toolbox/apps/rider/"));
FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT(".local/share/JetBrains/Toolbox/apps/Rider/ch-0"));
FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT(".local/share/JetBrains/Toolbox/apps/Rider/ch-1")); // Beta versions
@@ -210,7 +217,24 @@ void RiderCodeEditor::FindEditors(Array* output)
TEXT("flatpak run com.jetbrains.Rider"));
#endif
- for (auto directory : subDirectories)
+#if PLATFORM_MAC
+ String applicationSupportFolder;
+ FileSystem::GetSpecialFolderPath(SpecialFolder::ProgramData, applicationSupportFolder);
+
+ Array subMacDirectories;
+ FileSystem::GetChildDirectories(subMacDirectories, applicationSupportFolder / TEXT("JetBrains/Toolbox/apps/Rider/ch-0/"));
+ FileSystem::GetChildDirectories(subMacDirectories, applicationSupportFolder / TEXT("JetBrains/Toolbox/apps/Rider/ch-1/"));
+ for (const String& directory : subMacDirectories)
+ {
+ String riderAppDirectory = directory / TEXT("Rider.app/Contents/Resources");
+ SearchDirectory(&installations, riderAppDirectory);
+ }
+
+ // Check the local installer version
+ SearchDirectory(&installations, TEXT("/Applications/Rider.app/Contents/Resources"));
+#endif
+
+ for (const String& directory : subDirectories)
SearchDirectory(&installations, directory);
// Sort found installations by version number
@@ -244,8 +268,16 @@ void RiderCodeEditor::OpenFile(const String& path, int32 line)
// Open file
line = line > 0 ? line : 1;
CreateProcessSettings procSettings;
+
+#if !PLATFORM_MAC
procSettings.FileName = _execPath;
procSettings.Arguments = String::Format(TEXT("\"{0}\" --line {2} \"{1}\""), _solutionPath, path, line);
+#else
+ // This follows pretty much how all the other engines open rider which deals with cross architecture issues
+ procSettings.FileName = "/usr/bin/open";
+ procSettings.Arguments = String::Format(TEXT("-n -a \"{0}\" --args \"{1}\" --line {3} \"{2}\""), _execPath, _solutionPath, path, line);
+#endif
+
procSettings.HiddenWindow = false;
procSettings.WaitForEnd = false;
procSettings.LogOutput = false;
@@ -263,8 +295,14 @@ void RiderCodeEditor::OpenSolution()
// Open solution
CreateProcessSettings procSettings;
+#if !PLATFORM_MAC
procSettings.FileName = _execPath;
procSettings.Arguments = String::Format(TEXT("\"{0}\""), _solutionPath);
+#else
+ // This follows pretty much how all the other engines open rider which deals with cross architecture issues
+ procSettings.FileName = "/usr/bin/open";
+ procSettings.Arguments = String::Format(TEXT("-n -a \"{0}\" \"{1}\""), _execPath, _solutionPath);
+#endif
procSettings.HiddenWindow = false;
procSettings.WaitForEnd = false;
procSettings.LogOutput = false;
diff --git a/Source/Editor/Scripting/ScriptsBuilder.cpp b/Source/Editor/Scripting/ScriptsBuilder.cpp
index 3082a531e..8807379cf 100644
--- a/Source/Editor/Scripting/ScriptsBuilder.cpp
+++ b/Source/Editor/Scripting/ScriptsBuilder.cpp
@@ -246,20 +246,17 @@ bool ScriptsBuilder::RunBuildTool(const StringView& args, const StringView& work
Log::FileNotFoundException(monoPath).SetLevel(LogType::Fatal);
return true;
}
- //const String monoPath = TEXT("mono");
- cmdLine.Append(TEXT("\""));
+ const String monoPath = TEXT("mono");
cmdLine.Append(monoPath);
- cmdLine.Append(TEXT("\" "));
+ cmdLine.Append(TEXT(" "));
// TODO: Set env var for the mono MONO_GC_PARAMS=nursery-size64m to boost build performance -> profile it
#endif
- cmdLine.Append(TEXT("\""));
cmdLine.Append(buildToolPath);
- cmdLine.Append(TEXT("\" "));
- cmdLine.Append(args.Get(), args.Length());
// Call build tool
CreateProcessSettings procSettings;
procSettings.FileName = StringView(*cmdLine, cmdLine.Length());
+ procSettings.Arguments = args.Get();
procSettings.WorkingDirectory = workingDir;
const int32 result = Platform::CreateProcess(procSettings);
if (result != 0)
diff --git a/Source/Editor/States/LoadingState.cs b/Source/Editor/States/LoadingState.cs
index 746c8d92b..698dc192f 100644
--- a/Source/Editor/States/LoadingState.cs
+++ b/Source/Editor/States/LoadingState.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
+using System.IO;
using FlaxEngine;
using FlaxEngine.Utilities;
@@ -54,6 +55,13 @@ namespace FlaxEditor.States
}
else if (Editor.Options.Options.General.ForceScriptCompilationOnStartup && !skipCompile)
{
+ // Generate project files when Cache is missing or was cleared previously
+ if (!Directory.Exists(Path.Combine(Editor.GameProject?.ProjectFolderPath, "Cache", "Intermediate")) ||
+ !Directory.Exists(Path.Combine(Editor.GameProject?.ProjectFolderPath, "Cache", "Projects")))
+ {
+ var customArgs = Editor.Instance.CodeEditing.SelectedEditor.GenerateProjectCustomArgs;
+ ScriptsBuilder.GenerateProject(customArgs);
+ }
// Compile scripts before loading any scenes, then we load them and can open scenes
ScriptsBuilder.Compile();
}
diff --git a/Source/Editor/Surface/Archetypes/Math.cs b/Source/Editor/Surface/Archetypes/Math.cs
index 1b8f62e62..fe2f1e044 100644
--- a/Source/Editor/Surface/Archetypes/Math.cs
+++ b/Source/Editor/Surface/Archetypes/Math.cs
@@ -126,7 +126,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Clamp",
Description = "Clamps value to the specified range",
Flags = NodeFlags.AllGraphs,
- Size = new Float2(110, 60),
+ Size = new Float2(140, 60),
ConnectionsHints = ConnectionsHint.Numeric,
IndependentBoxes = new[] { 0 },
DependentBoxes = new[] { 1, 2, 3 },
diff --git a/Source/Editor/Surface/VisjectSurface.Input.cs b/Source/Editor/Surface/VisjectSurface.Input.cs
index 7264321c3..5e30ff110 100644
--- a/Source/Editor/Surface/VisjectSurface.Input.cs
+++ b/Source/Editor/Surface/VisjectSurface.Input.cs
@@ -213,6 +213,23 @@ namespace FlaxEditor.Surface
return;
}
+ if (_middleMouseDown)
+ {
+ // Calculate delta
+ var delta = location - _middleMouseDownPos;
+ if (delta.LengthSquared > 0.01f)
+ {
+ // Move view
+ _mouseMoveAmount += delta.Length;
+ _rootControl.Location += delta;
+ _middleMouseDownPos = location;
+ Cursor = CursorType.SizeAll;
+ }
+
+ // Handled
+ return;
+ }
+
// Check if user is selecting or moving node(s)
if (_leftMouseDown)
{
@@ -269,6 +286,11 @@ namespace FlaxEditor.Surface
_rightMouseDown = false;
Cursor = CursorType.Default;
}
+ if (_middleMouseDown)
+ {
+ _middleMouseDown = false;
+ Cursor = CursorType.Default;
+ }
_isMovingSelection = false;
ConnectingEnd(null);
@@ -291,7 +313,7 @@ namespace FlaxEditor.Surface
if (IsMouseOver && !_leftMouseDown && !IsPrimaryMenuOpened)
{
var nextViewScale = ViewScale + delta * 0.1f;
-
+
if (delta > 0 && !_rightMouseDown)
{
// Scale towards mouse when zooming in
@@ -306,7 +328,7 @@ namespace FlaxEditor.Surface
ViewScale = nextViewScale;
ViewCenterPosition = viewCenter;
}
-
+
return true;
}
@@ -380,6 +402,7 @@ namespace FlaxEditor.Surface
_isMovingSelection = false;
_rightMouseDown = false;
_leftMouseDown = false;
+ _middleMouseDown = false;
return true;
}
@@ -399,6 +422,11 @@ namespace FlaxEditor.Surface
_rightMouseDown = true;
_rightMouseDownPos = location;
}
+ if (button == MouseButton.Middle)
+ {
+ _middleMouseDown = true;
+ _middleMouseDownPos = location;
+ }
// Check if any node is under the mouse
SurfaceControl controlUnderMouse = GetControlUnderMouse();
@@ -444,7 +472,7 @@ namespace FlaxEditor.Surface
Focus();
return true;
}
- if (_rightMouseDown)
+ if (_rightMouseDown || _middleMouseDown)
{
// Start navigating
StartMouseCapture();
@@ -513,6 +541,13 @@ namespace FlaxEditor.Surface
}
_mouseMoveAmount = 0;
}
+ if (_middleMouseDown && button == MouseButton.Middle)
+ {
+ _middleMouseDown = false;
+ EndMouseCapture();
+ Cursor = CursorType.Default;
+ _mouseMoveAmount = 0;
+ }
// Base
bool handled = base.OnMouseUp(location, button);
@@ -523,6 +558,7 @@ namespace FlaxEditor.Surface
// Clear flags
_rightMouseDown = false;
_leftMouseDown = false;
+ _middleMouseDown = false;
return true;
}
@@ -706,6 +742,8 @@ namespace FlaxEditor.Surface
{
if (_inputBrackets.Count == 0)
{
+ if (currentInputText.StartsWith(' '))
+ currentInputText = "";
ResetInput();
ShowPrimaryMenu(_mousePos, false, currentInputText);
}
diff --git a/Source/Editor/Surface/VisjectSurface.cs b/Source/Editor/Surface/VisjectSurface.cs
index 22aba4855..6aed7cf68 100644
--- a/Source/Editor/Surface/VisjectSurface.cs
+++ b/Source/Editor/Surface/VisjectSurface.cs
@@ -59,6 +59,11 @@ namespace FlaxEditor.Surface
///
protected bool _rightMouseDown;
+ ///
+ /// The middle mouse down flag.
+ ///
+ protected bool _middleMouseDown;
+
///
/// The left mouse down position.
///
@@ -69,6 +74,11 @@ namespace FlaxEditor.Surface
///
protected Float2 _rightMouseDownPos = Float2.Minimum;
+ ///
+ /// The middle mouse down position.
+ ///
+ protected Float2 _middleMouseDownPos = Float2.Minimum;
+
///
/// The mouse position.
///
@@ -902,7 +912,7 @@ namespace FlaxEditor.Surface
{
return _context.FindNode(id);
}
-
+
///
/// Adds the undo action to be batched (eg. if multiple undo actions is performed in a sequence during single update).
///
diff --git a/Source/Editor/Windows/ContentWindow.ContextMenu.cs b/Source/Editor/Windows/ContentWindow.ContextMenu.cs
index 283133688..6923d634d 100644
--- a/Source/Editor/Windows/ContentWindow.ContextMenu.cs
+++ b/Source/Editor/Windows/ContentWindow.ContextMenu.cs
@@ -145,10 +145,9 @@ namespace FlaxEditor.Windows
cm.AddButton("Refresh all thumbnails", RefreshViewItemsThumbnails);
}
- cm.AddSeparator();
-
- if (!isRootFolder)
+ if (!isRootFolder && !(item is ContentFolder projectFolder && projectFolder.Node is ProjectTreeNode))
{
+ cm.AddSeparator();
cm.AddButton("New folder", NewFolder);
}
diff --git a/Source/Editor/Windows/ContentWindow.cs b/Source/Editor/Windows/ContentWindow.cs
index 0f3c12286..c65735c4c 100644
--- a/Source/Editor/Windows/ContentWindow.cs
+++ b/Source/Editor/Windows/ContentWindow.cs
@@ -46,7 +46,7 @@ namespace FlaxEditor.Windows
private TextBox _itemsSearchBox;
private ViewDropdown _viewDropdown;
private SortType _sortType;
- private bool _showEngineFiles = true, _showPluginsFiles = true, _showAllFiles = true;
+ private bool _showEngineFiles = true, _showPluginsFiles = true, _showAllFiles = true, _showGeneratedFiles = false;
private RootContentTreeNode _root;
@@ -106,6 +106,19 @@ namespace FlaxEditor.Windows
}
}
+ internal bool ShowGeneratedFiles
+ {
+ get => _showGeneratedFiles;
+ set
+ {
+ if (_showGeneratedFiles != value)
+ {
+ _showGeneratedFiles = value;
+ RefreshView();
+ }
+ }
+ }
+
internal bool ShowAllFiles
{
get => _showAllFiles;
@@ -314,6 +327,12 @@ namespace FlaxEditor.Windows
b.Checked = ShowPluginsFiles;
b.CloseMenuOnClick = false;
b.AutoCheck = true;
+
+ b = show.ContextMenu.AddButton("Generated files", () => ShowGeneratedFiles = !ShowGeneratedFiles);
+ b.TooltipText = "Shows generated files";
+ b.Checked = ShowGeneratedFiles;
+ b.CloseMenuOnClick = false;
+ b.AutoCheck = true;
b = show.ContextMenu.AddButton("All files", () => ShowAllFiles = !ShowAllFiles);
b.TooltipText = "Shows all files including other than assets and source code";
@@ -520,7 +539,7 @@ namespace FlaxEditor.Windows
}
// Cache data
- string extension = Path.GetExtension(item.Path);
+ string extension = item.IsFolder ? "" : Path.GetExtension(item.Path);
var newPath = StringUtils.CombinePaths(item.ParentFolder.Path, newShortName + extension);
// Check if was renaming mock element
@@ -626,7 +645,7 @@ namespace FlaxEditor.Windows
// Delete items
for (int i = 0; i < toDelete.Count; i++)
- Editor.ContentDatabase.Delete(toDelete[i]);
+ Editor.ContentDatabase.Delete(toDelete[i], true);
RefreshView();
}
@@ -722,7 +741,12 @@ namespace FlaxEditor.Windows
{
var item = Editor.ContentDatabase.Find(sourcePath);
if (item != null)
- Editor.ContentDatabase.Copy(item, Path.Combine(CurrentViewFolder.Path, item.FileName));
+ {
+ var newPath = StringUtils.NormalizePath(Path.Combine(CurrentViewFolder.Path, item.FileName));
+ if (sourcePath.Equals(newPath))
+ newPath = GetClonedAssetPath(item);
+ Editor.ContentDatabase.Copy(item, newPath);
+ }
else
importFiles.Add(sourcePath);
}
@@ -969,6 +993,8 @@ namespace FlaxEditor.Windows
var items = target.Folder.Children;
if (!_showAllFiles)
items = items.Where(x => !(x is FileItem)).ToList();
+ if (!_showGeneratedFiles)
+ items = items.Where(x => !(x.Path.EndsWith(".Gen.cs", StringComparison.Ordinal) || x.Path.EndsWith(".Gen.h", StringComparison.Ordinal) || x.Path.EndsWith(".Gen.cpp", StringComparison.Ordinal) || x.Path.EndsWith(".csproj", StringComparison.Ordinal) || x.Path.Contains(".CSharp"))).ToList();
_view.ShowItems(items, _sortType, false, true);
}
}
@@ -1145,6 +1171,7 @@ namespace FlaxEditor.Windows
writer.WriteAttributeString("ShowEngineFiles", ShowEngineFiles.ToString());
writer.WriteAttributeString("ShowPluginsFiles", ShowPluginsFiles.ToString());
writer.WriteAttributeString("ShowAllFiles", ShowAllFiles.ToString());
+ writer.WriteAttributeString("ShowGeneratedFiles", ShowGeneratedFiles.ToString());
writer.WriteAttributeString("ViewType", _view.ViewType.ToString());
}
@@ -1162,6 +1189,8 @@ namespace FlaxEditor.Windows
ShowPluginsFiles = value2;
if (bool.TryParse(node.GetAttribute("ShowAllFiles"), out value2))
ShowAllFiles = value2;
+ if (bool.TryParse(node.GetAttribute("ShowGeneratedFiles"), out value2))
+ ShowGeneratedFiles = value2;
if (Enum.TryParse(node.GetAttribute("ViewType"), out ContentViewType viewType))
_view.ViewType = viewType;
}
diff --git a/Source/Editor/Windows/DebugLogWindow.cs b/Source/Editor/Windows/DebugLogWindow.cs
index 49b03ede1..24e38d9af 100644
--- a/Source/Editor/Windows/DebugLogWindow.cs
+++ b/Source/Editor/Windows/DebugLogWindow.cs
@@ -544,7 +544,7 @@ namespace FlaxEditor.Windows
if (noLocation)
{
desc.LocationFile = match.Groups[2].Value;
- int.TryParse(match.Groups[5].Value, out desc.LocationLine);
+ int.TryParse(match.Groups[4].Value, out desc.LocationLine);
noLocation = false;
}
fineStackTrace.AppendLine(match.Groups[0].Value);
@@ -573,7 +573,7 @@ namespace FlaxEditor.Windows
if (match.Success)
{
desc.LocationFile = match.Groups[2].Value;
- int.TryParse(match.Groups[3].Value, out desc.LocationLine);
+ int.TryParse(match.Groups[4].Value, out desc.LocationLine);
}
}
diff --git a/Source/Editor/Windows/EditorWindow.cs b/Source/Editor/Windows/EditorWindow.cs
index 1ff0363f1..60817a51b 100644
--- a/Source/Editor/Windows/EditorWindow.cs
+++ b/Source/Editor/Windows/EditorWindow.cs
@@ -207,7 +207,8 @@ namespace FlaxEditor.Windows
case KeyboardKeys.Tab:
if (CanUseNavigation && Root != null)
{
- Root.Navigate(NavDirection.Next);
+ bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
+ Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next);
return true;
}
break;
diff --git a/Source/Engine/Content/Assets/MaterialInstance.cpp b/Source/Engine/Content/Assets/MaterialInstance.cpp
index 7581692e1..3bf0c54cd 100644
--- a/Source/Engine/Content/Assets/MaterialInstance.cpp
+++ b/Source/Engine/Content/Assets/MaterialInstance.cpp
@@ -205,8 +205,6 @@ void MaterialInstance::Bind(BindParameters& params)
Asset::LoadResult MaterialInstance::load()
{
- ASSERT(_baseMaterial == nullptr);
-
// Get main chunk
auto chunk0 = GetChunk(0);
if (chunk0 == nullptr || chunk0->IsMissing())
@@ -229,6 +227,7 @@ Asset::LoadResult MaterialInstance::load()
else
{
// Clear parameters if has no material loaded
+ _baseMaterial = nullptr;
Params.Dispose();
ParamsChanged();
}
diff --git a/Source/Engine/ContentImporters/ImportShader.cpp b/Source/Engine/ContentImporters/ImportShader.cpp
index 9cfb1242c..bf5b5581d 100644
--- a/Source/Engine/ContentImporters/ImportShader.cpp
+++ b/Source/Engine/ContentImporters/ImportShader.cpp
@@ -32,14 +32,21 @@ CreateAssetResult ImportShader::Import(CreateAssetContext& context)
LOG(Warning, "Empty shader source file.");
return CreateAssetResult::Error;
}
+
+ // Ensure the source code has an empty line at the end (expected by glslang)
+ auto sourceCodeChunkSize = sourceCodeSize + 1;
+ if (sourceCodeText[sourceCodeSize - 1] != '\n')
+ sourceCodeChunkSize++;
+
const auto& sourceCodeChunk = context.Data.Header.Chunks[SourceCodeChunk];
- sourceCodeChunk->Data.Allocate(sourceCodeSize + 1);
+ sourceCodeChunk->Data.Allocate(sourceCodeChunkSize);
const auto sourceCode = sourceCodeChunk->Get();
Platform::MemoryCopy(sourceCode, sourceCodeText.Get(), sourceCodeSize);
+ sourceCode[sourceCodeChunkSize - 2] = '\n';
// Encrypt source code
- Encryption::EncryptBytes(sourceCode, sourceCodeSize);
- sourceCode[sourceCodeSize] = 0;
+ Encryption::EncryptBytes(sourceCode, sourceCodeChunkSize - 1);
+ sourceCode[sourceCodeChunkSize - 1] = 0;
// Set Custom Data with Header
ShaderStorage::Header20 shaderHeader;
diff --git a/Source/Engine/Core/Log.cpp b/Source/Engine/Core/Log.cpp
index fea72bfe8..1147c4ff1 100644
--- a/Source/Engine/Core/Log.cpp
+++ b/Source/Engine/Core/Log.cpp
@@ -223,10 +223,10 @@ void Log::Logger::ProcessLogMessage(LogType type, const StringView& msg, fmt_fla
else
{
//w.append(msg.Get(), msg.Get() + msg.Length());
- fmt_flax::format(w, TEXT("{}"), (const Char*)msg.Get());
+ fmt_flax::format(w, TEXT("{}"), msg);
}
#else
- fmt_flax::format(w, TEXT("{}"), (const Char*)msg.Get());
+ fmt_flax::format(w, TEXT("{}"), msg);
#endif
}
diff --git a/Source/Engine/Core/Types/String.cpp b/Source/Engine/Core/Types/String.cpp
index e53f04af7..dab000873 100644
--- a/Source/Engine/Core/Types/String.cpp
+++ b/Source/Engine/Core/Types/String.cpp
@@ -72,7 +72,7 @@ void String::Set(const char* chars, int32 length)
}
_length = length;
}
- if (chars)
+ if (chars && length)
StringUtils::ConvertANSI2UTF16(chars, _data, length, _length);
}
@@ -298,8 +298,10 @@ String String::TrimTrailing() const
end--;
}
- ASSERT_LOW_LAYER(end >= start);
- return Substring(start, end - start + 1);
+ const int32 count = end - start + 1;
+ if (start >= 0 && start + count <= Length() && count >= 0)
+ return String(_data + start, count);
+ return Empty;
}
String& String::operator/=(const Char* str)
diff --git a/Source/Engine/Engine/NativeInterop.Marshallers.cs b/Source/Engine/Engine/NativeInterop.Marshallers.cs
index 74d6e6bad..a74299670 100644
--- a/Source/Engine/Engine/NativeInterop.Marshallers.cs
+++ b/Source/Engine/Engine/NativeInterop.Marshallers.cs
@@ -32,6 +32,7 @@ namespace FlaxEngine.Interop
public static class NativeToManaged
{
public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(unmanaged).Target;
+ public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero;
public static void Free(IntPtr unmanaged)
{
@@ -44,6 +45,7 @@ namespace FlaxEngine.Interop
#endif
public static class ManagedToNative
{
+ public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(unmanaged).Target;
public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero;
public static void Free(IntPtr unmanaged)
@@ -147,29 +149,16 @@ namespace FlaxEngine.Interop
#if FLAX_EDITOR
[HideInEditor]
#endif
- [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedIn, typeof(ObjectMarshaller.ManagedToNative))]
- [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedOut, typeof(ObjectMarshaller.ManagedToNative))]
- [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementIn, typeof(ObjectMarshaller.ManagedToNative))]
- [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedOut, typeof(ObjectMarshaller.NativeToManaged))]
- [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedIn, typeof(ObjectMarshaller.NativeToManaged))]
- [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementOut, typeof(ObjectMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedIn, typeof(ObjectMarshaller))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedOut, typeof(ObjectMarshaller))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementIn, typeof(ObjectMarshaller))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedOut, typeof(ObjectMarshaller))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedIn, typeof(ObjectMarshaller))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementOut, typeof(ObjectMarshaller))]
public static class ObjectMarshaller
{
-#if FLAX_EDITOR
- [HideInEditor]
-#endif
- public static class NativeToManaged
- {
- public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As(ManagedHandle.FromIntPtr(unmanaged).Target) : null;
- }
-
-#if FLAX_EDITOR
- [HideInEditor]
-#endif
- public static class ManagedToNative
- {
- public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => Unsafe.As