Merge remote-tracking branch 'origin/1.7' into 1.8

# Conflicts:
#	Flax.flaxproj
This commit is contained in:
2023-11-25 23:36:56 +01:00
60 changed files with 391 additions and 169 deletions
+1 -1
View File
@@ -33,4 +33,4 @@ jobs:
git lfs pull
- name: Build
run: |
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -arch=ARM64 -platform=Android -configuration=Release -buildtargets=FlaxGame
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=7 -arch=ARM64 -platform=Android -configuration=Release -buildtargets=FlaxGame
+1 -1
View File
@@ -33,4 +33,4 @@ jobs:
git lfs pull
- name: Build
run: |
./Development/Scripts/Mac/CallBuildTool.sh -build -log -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame
./Development/Scripts/Mac/CallBuildTool.sh -build -log -dotnet=7 -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame
+2 -2
View File
@@ -36,7 +36,7 @@ jobs:
git lfs pull
- name: Build
run: |
./Development/Scripts/Linux/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxEditor
./Development/Scripts/Linux/CallBuildTool.sh -build -log -printSDKs -dotnet=7 -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxEditor
# Game
game-linux:
@@ -64,4 +64,4 @@ jobs:
git lfs pull
- name: Build
run: |
./Development/Scripts/Linux/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Linux -configuration=Release -buildtargets=FlaxGame
./Development/Scripts/Linux/CallBuildTool.sh -build -log -printSDKs -dotnet=7 -arch=x64 -platform=Linux -configuration=Release -buildtargets=FlaxGame
+2 -2
View File
@@ -30,7 +30,7 @@ jobs:
git lfs pull
- name: Build
run: |
./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Mac -configuration=Development -buildtargets=FlaxEditor
./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -dotnet=7 -arch=x64 -platform=Mac -configuration=Development -buildtargets=FlaxEditor
# Game
game-mac:
@@ -55,4 +55,4 @@ jobs:
git lfs pull
- name: Build
run: |
./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Mac -configuration=Release -buildtargets=FlaxGame
./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -dotnet=7 -arch=x64 -platform=Mac -configuration=Release -buildtargets=FlaxGame
+2 -2
View File
@@ -30,7 +30,7 @@ jobs:
git lfs pull
- name: Build
run: |
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=7 -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor
# Game
game-windows:
@@ -55,4 +55,4 @@ jobs:
git lfs pull
- name: Build
run: |
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -arch=x64 -platform=Windows -configuration=Release -buildtargets=FlaxGame
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=7 -arch=x64 -platform=Windows -configuration=Release -buildtargets=FlaxGame
+5 -5
View File
@@ -34,8 +34,8 @@ jobs:
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
- name: Build
run: |
./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxTestsTarget
./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs -dotnet=7
./Development/Scripts/Linux/CallBuildTool.sh -build -log -dotnet=7 -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxTestsTarget
dotnet msbuild Source/Tools/Flax.Build.Tests/Flax.Build.Tests.csproj /m /t:Restore,Build /p:Configuration=Debug /p:Platform=AnyCPU /nologo
dotnet msbuild Source/Tools/Flax.Build.Tests/Flax.Build.Tests.csproj /m /t:Restore,Build /p:Configuration=Debug /p:Platform=AnyCPU /nologo
- name: Test
@@ -48,7 +48,7 @@ jobs:
dotnet test -f net7.0 Binaries/Tests/FlaxEngine.CSharp.dll
- name: Test UseLargeWorlds
run: |
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxTestsTarget -UseLargeWorlds=true
./Development/Scripts/Linux/CallBuildTool.sh -build -log -dotnet=7 -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxTestsTarget -UseLargeWorlds=true
${GITHUB_WORKSPACE}/Binaries/Editor/Linux/Development/FlaxTests
# Tests on Windows
@@ -72,8 +72,8 @@ jobs:
git lfs pull
- name: Build
run: |
.\GenerateProjectFiles.bat -vs2022 -log -verbose -printSDKs
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxTestsTarget
.\GenerateProjectFiles.bat -vs2022 -log -verbose -printSDKs -dotnet=7
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -dotnet=7 -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxTestsTarget
dotnet msbuild Source\Tools\Flax.Build.Tests\Flax.Build.Tests.csproj /m /t:Restore,Build /p:Configuration=Debug /p:Platform=AnyCPU /nologo
- name: Test
run: |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -4,7 +4,7 @@
"Major": 1,
"Minor": 8,
"Revision": 0,
"Build": 6502
"Build": 6503
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.",
+1 -1
View File
@@ -7,7 +7,7 @@ pushd
echo Performing the full package...
rem Run the build tool.
call "Development\Scripts\Windows\CallBuildTool.bat" -deploy -deployEditor -deployPlatforms -verbose -log -logFile="Cache\Intermediate\PackageLog.txt" %*
call "Development\Scripts\Windows\CallBuildTool.bat" -deploy -deployEditor -deployPlatforms -dotnet=7 -verbose -log -logFile="Cache\Intermediate\PackageLog.txt" %*
if errorlevel 1 goto BuildToolFailed
popd
+1 -1
View File
@@ -7,7 +7,7 @@ pushd
echo Building and packaging Flax Editor...
rem Run the build tool.
call "Development\Scripts\Windows\CallBuildTool.bat" -deploy -deployEditor -verbose -log -logFile="Cache\Intermediate\PackageLog.txt" %*
call "Development\Scripts\Windows\CallBuildTool.bat" -deploy -deployEditor -dotnet=7 -verbose -log -logFile="Cache\Intermediate\PackageLog.txt" %*
if errorlevel 1 goto BuildToolFailed
popd
+1 -1
View File
@@ -9,4 +9,4 @@ echo Building and packaging Flax Editor...
cd "`dirname "$0"`"
# Run Flax.Build (also pass the arguments)
bash ./Development/Scripts/Mac/CallBuildTool.sh --deploy --deployEditor --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
bash ./Development/Scripts/Mac/CallBuildTool.sh --deploy --deployEditor --dotnet=7 --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
+1 -1
View File
@@ -9,4 +9,4 @@ echo Building and packaging Flax Editor...
cd "`dirname "$0"`"
# Run Flax.Build (also pass the arguments)
bash ./Development/Scripts/Linux/CallBuildTool.sh --deploy --deployEditor --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
bash ./Development/Scripts/Linux/CallBuildTool.sh --deploy --deployEditor --dotnet=7 --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
+1 -1
View File
@@ -7,7 +7,7 @@ pushd
echo Building and packaging platforms data...
rem Run the build tool.
call "Development\Scripts\Windows\CallBuildTool.bat" -deploy -deployPlatforms -verbose -log -logFile="Cache\Intermediate\PackageLog.txt" %*
call "Development\Scripts\Windows\CallBuildTool.bat" -deploy -deployPlatforms -dotnet=7 -verbose -log -logFile="Cache\Intermediate\PackageLog.txt" %*
if errorlevel 1 goto BuildToolFailed
popd
+1 -1
View File
@@ -9,4 +9,4 @@ echo Building and packaging platforms data...
cd "`dirname "$0"`"
# Run Flax.Build (also pass the arguments)
bash ./Development/Scripts/Mac/CallBuildTool.sh --deploy --deployPlatforms --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
bash ./Development/Scripts/Mac/CallBuildTool.sh --deploy --deployPlatforms --dotnet=7 --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
+1 -1
View File
@@ -9,4 +9,4 @@ echo Building and packaging platforms data...
cd "`dirname "$0"`"
# Run Flax.Build (also pass the arguments)
bash ./Development/Scripts/Linux/CallBuildTool.sh --deploy --deployPlatforms --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
bash ./Development/Scripts/Linux/CallBuildTool.sh --deploy --deployPlatforms --dotnet=7 --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
+7
View File
@@ -12,6 +12,13 @@
class GameCooker;
class PlatformTools;
#if OFFICIAL_BUILD
// Use the fixed .NET SDK version in packaged builds for compatibility (FlaxGame is precompiled with it)
#define GAME_BUILD_DOTNET_VER TEXT("-dotnet=7")
#else
#define GAME_BUILD_DOTNET_VER TEXT("")
#endif
/// <summary>
/// Game building options. Used as flags.
/// </summary>
@@ -188,8 +188,8 @@ bool CompileScriptsStep::Perform(CookingData& data)
LOG(Info, "Starting scripts compilation for game...");
const String logFile = data.CacheDirectory / TEXT("CompileLog.txt");
auto args = String::Format(
TEXT("-log -logfile=\"{4}\" -build -mutex -buildtargets={0} -platform={1} -arch={2} -configuration={3} -aotMode={5}"),
target, platform, architecture, configuration, logFile, ToString(data.Tools->UseAOT()));
TEXT("-log -logfile=\"{4}\" -build -mutex -buildtargets={0} -platform={1} -arch={2} -configuration={3} -aotMode={5} {6}"),
target, platform, architecture, configuration, logFile, ToString(data.Tools->UseAOT()), GAME_BUILD_DOTNET_VER);
#if PLATFORM_WINDOWS
if (data.Platform == BuildPlatform::LinuxX64)
#elif PLATFORM_LINUX
@@ -87,7 +87,7 @@ bool DeployDataStep::Perform(CookingData& data)
{
// Ask Flax.Build to provide .Net SDK location for the current platform
String sdks;
bool failed = ScriptsBuilder::RunBuildTool(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printSDKs"), data.CacheDirectory);
bool failed = ScriptsBuilder::RunBuildTool(String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printSDKs {}"), GAME_BUILD_DOTNET_VER), data.CacheDirectory);
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
int32 idx = sdks.Find(TEXT("DotNetSdk, "), StringSearchCase::CaseSensitive);
if (idx != -1)
@@ -168,7 +168,7 @@ bool DeployDataStep::Perform(CookingData& data)
String sdks;
const Char *platformName, *archName;
data.GetBuildPlatformName(platformName, archName);
String args = String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printDotNetRuntime -platform={} -arch={}"), platformName, archName);
String args = String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printDotNetRuntime -platform={} -arch={} {}"), platformName, archName, GAME_BUILD_DOTNET_VER);
bool failed = ScriptsBuilder::RunBuildTool(args, data.CacheDirectory);
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
Array<String> parts;
@@ -269,8 +269,8 @@ bool DeployDataStep::Perform(CookingData& data)
LOG(Info, "Optimizing .NET class library size to include only used assemblies");
const String logFile = data.CacheDirectory / TEXT("StripDotnetLibs.txt");
String args = String::Format(
TEXT("-log -logfile=\"{}\" -runDotNetClassLibStripping -mutex -binaries=\"{}\""),
logFile, data.DataOutputPath);
TEXT("-log -logfile=\"{}\" -runDotNetClassLibStripping -mutex -binaries=\"{}\" {}"),
logFile, data.DataOutputPath, GAME_BUILD_DOTNET_VER);
for (const String& define : data.CustomDefines)
{
args += TEXT(" -D");
@@ -67,8 +67,8 @@ bool PrecompileAssembliesStep::Perform(CookingData& data)
data.GetBuildPlatformName(platform, architecture);
const String logFile = data.CacheDirectory / TEXT("AOTLog.txt");
String args = String::Format(
TEXT("-log -logfile=\"{}\" -runDotNetAOT -mutex -platform={} -arch={} -configuration={} -aotMode={} -binaries=\"{}\" -intermediate=\"{}\""),
logFile, platform, architecture, configuration, ToString(aotMode), data.DataOutputPath, data.ManagedCodeOutputPath);
TEXT("-log -logfile=\"{}\" -runDotNetAOT -mutex -platform={} -arch={} -configuration={} -aotMode={} -binaries=\"{}\" -intermediate=\"{}\" {}"),
logFile, platform, architecture, configuration, ToString(aotMode), data.DataOutputPath, data.ManagedCodeOutputPath, GAME_BUILD_DOTNET_VER);
if (!buildSettings.SkipUnusedDotnetLibsPackaging)
args += TEXT(" -skipUnusedDotnetLibs=false"); // Run AOT on whole class library (not just used libs)
for (const String& define : data.CustomDefines)
@@ -171,11 +171,13 @@ namespace FlaxEditor.CustomEditors.Editors
tree.Select(typeNode);
if (addItems)
{
var items = GenericEditor.GetItemsForType(type, type.IsClass, true);
var items = GenericEditor.GetItemsForType(type, type.IsClass, true, true);
foreach (var item in items)
{
if (typed && !typed.IsAssignableFrom(item.Info.ValueType))
continue;
if (item.Info.DeclaringType.Type == typeof(FlaxEngine.Object))
continue; // Skip engine internals
var itemPath = typePath + item.Info.Name;
var node = new TreeNode
{
@@ -247,8 +247,9 @@ namespace FlaxEditor.CustomEditors.Editors
/// <param name="type">The type.</param>
/// <param name="useProperties">True if use type properties.</param>
/// <param name="useFields">True if use type fields.</param>
/// <param name="usePropertiesWithoutSetter">True if use type properties that have only getter method without setter method (aka read-only).</param>
/// <returns>The items.</returns>
public static List<ItemInfo> GetItemsForType(ScriptType type, bool useProperties, bool useFields)
public static List<ItemInfo> GetItemsForType(ScriptType type, bool useProperties, bool useFields, bool usePropertiesWithoutSetter = false)
{
var items = new List<ItemInfo>();
@@ -264,7 +265,7 @@ namespace FlaxEditor.CustomEditors.Editors
var showInEditor = attributes.Any(x => x is ShowInEditorAttribute);
// Skip properties without getter or setter
if (!p.HasGet || (!p.HasSet && !showInEditor))
if (!p.HasGet || (!p.HasSet && !showInEditor && !usePropertiesWithoutSetter))
continue;
// Skip hidden fields, handle special attributes
+2 -1
View File
@@ -111,7 +111,8 @@ namespace FlaxEditor.Gizmo
if (isSelected)
{
GetSelectedObjectsBounds(out var selectionBounds, out _);
ray.Position = ray.GetPoint(selectionBounds.Size.Y * 0.5f);
var offset = Mathf.Max(selectionBounds.Size.Y * 0.5f, 1.0f);
ray.Position = ray.GetPoint(offset);
continue;
}
@@ -288,6 +288,9 @@ namespace FlaxEditor.Surface.Archetypes
}
}
SetValue(2, ids);
// Force refresh UI
ResizeAuto();
}
}
@@ -371,7 +371,10 @@ namespace FlaxEditor.Windows.Assets
private void OnTreeSelectedChanged(List<TreeNode> before, List<TreeNode> after)
{
if (after.Count != 0)
((SkeletonPropertiesProxy)Values[0]).Window._preview.ShowDebugDraw = true;
{
var proxy = (SkeletonPropertiesProxy)Values[0];
proxy.Window._preview.ShowDebugDraw = true;
}
}
private void OnTreeNodeCopyName(ContextMenuButton b)
@@ -1045,6 +1048,7 @@ namespace FlaxEditor.Windows.Assets
{
Proxy = new SkeletonPropertiesProxy();
Presenter.Select(Proxy);
// Draw highlight on selected node
window._preview.CustomDebugDraw += OnDebugDraw;
}
@@ -1146,6 +1150,15 @@ namespace FlaxEditor.Windows.Assets
_tabs.AddTab(new RetargetTab(this));
_tabs.AddTab(new ImportTab(this));
// Automatically show nodes when switching to skeleton page
_tabs.SelectedTabChanged += (tabs) =>
{
if (tabs.SelectedTab is SkeletonTab)
{
_preview.ShowNodes = true;
}
};
// Highlight actor (used to highlight selected material slot, see UpdateEffectsOnAsset)
_highlightActor = new AnimatedModel
{
+1
View File
@@ -386,6 +386,7 @@ namespace FlaxEditor.Windows
{
_viewport.Bounds = new Rectangle(Width * (1 - scaleWidth) / 2, 0, Width * scaleWidth, Height);
}
_viewport.SyncBackbufferSize();
PerformLayout();
}
+19
View File
@@ -391,6 +391,25 @@ namespace FlaxEditor.Windows
}
Editor.Log("Plugin project has been cloned.");
try
{
// Start git submodule clone
var settings = new CreateProcessSettings
{
FileName = "git",
WorkingDirectory = clonePath,
Arguments = "submodule update --init",
ShellExecute = false,
LogOutput = true,
};
Platform.CreateProcess(ref settings);
}
catch (Exception e)
{
Editor.LogError($"Failed Git submodule process. {e}");
return;
}
// Find project config file. Could be different then what the user named the folder.
var files = Directory.GetFiles(clonePath);
+13 -3
View File
@@ -114,14 +114,19 @@ void Behavior::UpdateAsync()
void Behavior::StartLogic()
{
if (_result == BehaviorUpdateResult::Running)
return;
PROFILE_CPU();
// Ensure to have tree loaded on begin play
// Ensure to have tree loaded on play
CHECK(Tree && !Tree->WaitForLoaded());
BehaviorTree* tree = Tree.Get();
CHECK(tree->Graph.Root);
// Setup state
_result = BehaviorUpdateResult::Running;
_accumulatedTime = 0.0f;
_totalTime = 0;
// Init knowledge
_knowledge.InitMemory(tree);
@@ -135,6 +140,7 @@ void Behavior::StopLogic(BehaviorUpdateResult result)
_accumulatedTime = 0.0f;
_totalTime = 0;
_result = result;
_knowledge.FreeMemory();
}
void Behavior::ResetLogic()
@@ -170,7 +176,11 @@ void Behavior::OnDisable()
bool Behavior::GetNodeDebugRelevancy(const BehaviorTreeNode* node, const Behavior* behavior)
{
return node && behavior && node->_executionIndex != -1 && behavior->_knowledge.RelevantNodes.Get(node->_executionIndex);
return node &&
behavior &&
node->_executionIndex >= 0 &&
node->_executionIndex < behavior->_knowledge.RelevantNodes.Count() &&
behavior->_knowledge.RelevantNodes.Get(node->_executionIndex);
}
String Behavior::GetNodeDebugInfo(const BehaviorTreeNode* node, Behavior* behavior)
@@ -179,7 +189,7 @@ String Behavior::GetNodeDebugInfo(const BehaviorTreeNode* node, Behavior* behavi
return String::Empty;
BehaviorUpdateContext context;
Platform::MemoryClear(&context, sizeof(context));
if (behavior && node->_executionIndex != -1 && behavior->_knowledge.RelevantNodes.Get(node->_executionIndex))
if (GetNodeDebugRelevancy(node, behavior))
{
// Pass behavior and knowledge data only for relevant nodes to properly access it
context.Behavior = behavior;
+1 -1
View File
@@ -83,7 +83,7 @@ bool AccessVariant(Variant& instance, const StringAnsiView& member, Variant& val
}
}
#endif
else
else if (typeName.HasChars())
{
LOG(Warning, "Missing scripting type \'{0}\'", String(typeName));
}
@@ -1342,7 +1342,12 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
{
const bool xAxis = Math::IsZero(v0.X) && Math::IsZero(v1.X);
const bool yAxis = Math::IsZero(v0.Y) && Math::IsZero(v1.Y);
if (xAxis || yAxis)
if (xAxis && yAxis)
{
// Single animation
value = SampleAnimation(node, loop, data.Length, startTimePos, bucket.TimePosition, newTimePos, aAnim, aData.W);
}
else if (xAxis || yAxis)
{
if (yAxis)
{
+19 -11
View File
@@ -323,26 +323,29 @@ bool BinaryAsset::SaveToAsset(const StringView& path, AssetInitData& data, bool
{
// Ensure path is in a valid format
String pathNorm(path);
FileSystem::NormalizePath(pathNorm);
ContentStorageManager::FormatPath(pathNorm);
const StringView filePath = pathNorm;
// Find target storage container and the asset
auto storage = ContentStorageManager::TryGetStorage(pathNorm);
auto asset = Content::GetAsset(pathNorm);
auto storage = ContentStorageManager::TryGetStorage(filePath);
auto asset = Content::GetAsset(filePath);
auto binaryAsset = dynamic_cast<BinaryAsset*>(asset);
if (asset && !binaryAsset)
{
LOG(Warning, "Cannot write to the non-binary asset location.");
return true;
}
if (!binaryAsset && !storage && FileSystem::FileExists(filePath))
{
// Force-resolve storage (asset at that path could be not yet loaded into registry)
storage = ContentStorageManager::GetStorage(filePath);
}
// Check if can perform write operation to the asset container
if (storage)
if (storage && !storage->AllowDataModifications())
{
if (!storage->AllowDataModifications())
{
LOG(Warning, "Cannot write to the asset storage container.");
return true;
}
LOG(Warning, "Cannot write to the asset storage container.");
return true;
}
// Initialize data container
@@ -352,6 +355,11 @@ bool BinaryAsset::SaveToAsset(const StringView& path, AssetInitData& data, bool
// Use the same asset ID
data.Header.ID = binaryAsset->GetID();
}
else if (storage && storage->GetEntriesCount())
{
// Use the same file ID
data.Header.ID = storage->GetEntry(0).ID;
}
else
{
// Randomize ID
@@ -373,8 +381,8 @@ bool BinaryAsset::SaveToAsset(const StringView& path, AssetInitData& data, bool
}
else
{
ASSERT(pathNorm.HasChars());
result = FlaxStorage::Create(pathNorm, data, silentMode);
ASSERT(filePath.HasChars());
result = FlaxStorage::Create(filePath, data, silentMode);
}
if (binaryAsset)
binaryAsset->_isSaving = false;
+37 -47
View File
@@ -54,8 +54,7 @@ namespace
// Assets
CriticalSection AssetsLocker;
Dictionary<Guid, Asset*> Assets(2048);
CriticalSection LoadCallAssetsLocker;
Array<Guid> LoadCallAssets(64);
Array<Guid> LoadCallAssets(PLATFORM_THREADS_LIMIT);
CriticalSection LoadedAssetsToInvokeLocker;
Array<Asset*> LoadedAssetsToInvoke(64);
Array<Asset*> ToUnload;
@@ -449,18 +448,19 @@ Asset* Content::LoadAsync(const StringView& path, const ScriptingTypeHandle& typ
{
// Ensure path is in a valid format
String pathNorm(path);
StringUtils::PathRemoveRelativeParts(pathNorm);
ContentStorageManager::FormatPath(pathNorm);
const StringView filePath = pathNorm;
#if USE_EDITOR
if (!FileSystem::FileExists(pathNorm))
if (!FileSystem::FileExists(filePath))
{
LOG(Error, "Missing file \'{0}\'", pathNorm);
LOG(Error, "Missing file \'{0}\'", filePath);
return nullptr;
}
#endif
AssetInfo assetInfo;
if (GetAssetInfo(pathNorm, assetInfo))
if (GetAssetInfo(filePath, assetInfo))
{
return LoadAsync(assetInfo.ID, type);
}
@@ -910,9 +910,13 @@ Asset* Content::LoadAsync(const Guid& id, const ScriptingTypeHandle& type)
return nullptr;
// Check if asset has been already loaded
Asset* result = GetAsset(id);
Asset* result = nullptr;
AssetsLocker.Lock();
Assets.TryGet(id, result);
if (result)
{
AssetsLocker.Unlock();
// Validate type
if (IsAssetTypeIdInvalid(type, result->GetTypeHandle()) && !result->Is(type))
{
@@ -923,57 +927,41 @@ Asset* Content::LoadAsync(const Guid& id, const ScriptingTypeHandle& type)
}
// Check if that asset is during loading
LoadCallAssetsLocker.Lock();
if (LoadCallAssets.Contains(id))
{
LoadCallAssetsLocker.Unlock();
AssetsLocker.Unlock();
// Wait for load end
// TODO: dont use active waiting and prevent deadlocks if running on a main thread
//while (!Engine::ShouldExit())
while (true)
// Wait for loading end by other thread
bool contains = true;
while (contains)
{
LoadCallAssetsLocker.Lock();
const bool contains = LoadCallAssets.Contains(id);
LoadCallAssetsLocker.Unlock();
if (!contains)
return GetAsset(id);
Platform::Sleep(1);
AssetsLocker.Lock();
contains = LoadCallAssets.Contains(id);
AssetsLocker.Unlock();
}
}
else
{
// Mark asset as loading
LoadCallAssets.Add(id);
LoadCallAssetsLocker.Unlock();
Assets.TryGet(id, result);
return result;
}
// Load asset
AssetInfo assetInfo;
result = load(id, type, assetInfo);
// Mark asset as loading and release lock so other threads can load other assets
LoadCallAssets.Add(id);
AssetsLocker.Unlock();
// End loading
LoadCallAssetsLocker.Lock();
LoadCallAssets.Remove(id);
LoadCallAssetsLocker.Unlock();
#define LOAD_FAILED() AssetsLocker.Lock(); LoadCallAssets.Remove(id); AssetsLocker.Unlock(); return nullptr
return result;
}
Asset* Content::load(const Guid& id, const ScriptingTypeHandle& type, AssetInfo& assetInfo)
{
// Get cached asset info (from registry)
AssetInfo assetInfo;
if (!GetAssetInfo(id, assetInfo))
{
LOG(Warning, "Invalid or missing asset ({0}, {1}).", id, type.ToString());
return nullptr;
LOAD_FAILED();
}
#if ASSETS_LOADING_EXTRA_VERIFICATION
if (!FileSystem::FileExists(assetInfo.Path))
{
LOG(Error, "Cannot find file '{0}'", assetInfo.Path);
return nullptr;
LOAD_FAILED();
}
#endif
@@ -982,28 +970,27 @@ Asset* Content::load(const Guid& id, const ScriptingTypeHandle& type, AssetInfo&
if (factory == nullptr)
{
LOG(Error, "Cannot find asset factory. Info: {0}", assetInfo.ToString());
return nullptr;
LOAD_FAILED();
}
// Create asset object
auto result = factory->New(assetInfo);
result = factory->New(assetInfo);
if (result == nullptr)
{
LOG(Error, "Cannot create asset object. Info: {0}", assetInfo.ToString());
return nullptr;
LOAD_FAILED();
}
ASSERT(result->GetID() == id);
#if ASSETS_LOADING_EXTRA_VERIFICATION
if (IsAssetTypeIdInvalid(type, result->GetTypeHandle()) && !result->Is(type))
{
LOG(Error, "Different loaded asset type! Asset: '{0}'. Expected type: {1}", assetInfo.ToString(), type.ToString());
LOG(Warning, "Different loaded asset type! Asset: '{0}'. Expected type: {1}", assetInfo.ToString(), type.ToString());
result->DeleteObject();
return nullptr;
LOAD_FAILED();
}
#endif
// Register asset
ASSERT(result->GetID() == id);
AssetsLocker.Lock();
#if ASSETS_LOADING_EXTRA_VERIFICATION
ASSERT(!Assets.ContainsKey(id));
@@ -1011,11 +998,14 @@ Asset* Content::load(const Guid& id, const ScriptingTypeHandle& type, AssetInfo&
Assets.Add(id, result);
// Start asset loading
// TODO: refactor this to create asset loading task-chain before AssetsLocker.Lock() to allow better parallelization
result->startLoading();
// Remove from the loading queue and release lock
LoadCallAssets.Remove(id);
AssetsLocker.Unlock();
#undef LOAD_FAILED
return result;
}
-1
View File
@@ -366,7 +366,6 @@ private:
static void onAssetLoaded(Asset* asset);
static void onAssetUnload(Asset* asset);
static void onAssetChangeId(Asset* asset, const Guid& oldId, const Guid& newId);
static Asset* load(const Guid& id, const ScriptingTypeHandle& type, AssetInfo& assetInfo);
private:
static void deleteFileSafety(const StringView& path, const Guid& id);
@@ -6,6 +6,7 @@
#include "Engine/Core/Log.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Engine/EngineService.h"
#include "Engine/Engine/Globals.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Threading/TaskGraph.h"
@@ -185,6 +186,16 @@ void ContentStorageManager::EnsureUnlocked()
Locker.Unlock();
}
void ContentStorageManager::FormatPath(String& path)
{
StringUtils::PathRemoveRelativeParts(path);
if (FileSystem::IsRelative(path))
{
// Convert local-project paths into absolute format which is used by Content Storage system
path = Globals::ProjectFolder / path;
}
}
bool ContentStorageManager::IsFlaxStoragePath(const String& path)
{
auto extension = FileSystem::GetExtension(path).ToLower();
@@ -75,6 +75,9 @@ public:
/// </summary>
static void EnsureUnlocked();
// Formats path into valid format used by the storage system (normalized and absolute).
static void FormatPath(String& path);
public:
/// <summary>
/// Determines whether the specified path can be a binary asset file (based on it's extension).
+19 -4
View File
@@ -8,11 +8,12 @@
#include "Engine/Core/Collections/Sorting.h"
#include "Engine/Debug/DebugLog.h"
#include "Engine/Level/Level.h"
#include "Engine/Level/Scene/Scene.h"
#include "Engine/Level/Actors/Camera.h"
#include "Engine/Level/Actors/PostFxVolume.h"
#include "Engine/Renderer/Renderer.h"
#include "Engine/Render2D/Render2D.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Level/Actors/PostFxVolume.h"
#include "Engine/Profiler/Profiler.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Threading/Threading.h"
@@ -202,15 +203,21 @@ void SceneRenderTask::CollectPostFxVolumes(RenderContext& renderContext)
{
Level::CollectPostFxVolumes(renderContext);
}
if (EnumHasAllFlags(ActorsSource , ActorsSources::CustomActors))
if (EnumHasAllFlags(ActorsSource, ActorsSources::CustomActors))
{
for (Actor* a : CustomActors)
{
auto* postFxVolume = dynamic_cast<PostFxVolume*>(a);
if (postFxVolume && a->GetIsActive())
{
postFxVolume->Collect(renderContext);
}
}
}
if (EnumHasAllFlags(ActorsSource, ActorsSources::CustomScenes))
{
for (Scene* scene : CustomScenes)
{
if (scene && scene->IsActiveInHierarchy())
scene->Rendering.CollectPostFxVolumes(renderContext);
}
}
}
@@ -282,6 +289,14 @@ void SceneRenderTask::OnCollectDrawCalls(RenderContextBatch& renderContextBatch,
ASSERT_LOW_LAYER(_customActorsScene);
_customActorsScene->Draw(renderContextBatch, (SceneRendering::DrawCategory)category);
}
if (EnumHasAllFlags(ActorsSource, ActorsSources::CustomScenes))
{
for (Scene* scene : CustomScenes)
{
if (scene && scene->IsActiveInHierarchy())
scene->Rendering.Draw(renderContextBatch, (SceneRendering::DrawCategory)category);
}
}
if (EnumHasAllFlags(ActorsSource, ActorsSources::Scenes))
{
Level::DrawActors(renderContextBatch, category);
+13 -2
View File
@@ -21,6 +21,7 @@ class PostProcessEffect;
struct RenderContext;
class Camera;
class Actor;
class Scene;
/// <summary>
/// Allows to perform custom rendering using graphics pipeline.
@@ -174,6 +175,11 @@ API_ENUM(Attributes="Flags") enum class ActorsSources
/// </summary>
CustomActors = 2,
/// <summary>
/// The scenes from the custom collection.
/// </summary>
CustomScenes = 4,
/// <summary>
/// The actors from the loaded scenes and custom collection.
/// </summary>
@@ -267,9 +273,14 @@ public:
public:
/// <summary>
/// The custom set of actors to render.
/// The custom set of actors to render. Used when ActorsSources::CustomActors flag is active.
/// </summary>
Array<Actor*> CustomActors;
API_FIELD() Array<Actor*> CustomActors;
/// <summary>
/// The custom set of scenes to render. Used when ActorsSources::CustomScenes flag is active.
/// </summary>
API_FIELD() Array<Scene*> CustomScenes;
/// <summary>
/// Adds the custom actor to the rendering.
@@ -172,6 +172,28 @@ void AnimatedModel::GetNodeTransformation(const StringView& nodeName, Matrix& no
GetNodeTransformation(SkinnedModel ? SkinnedModel->FindNode(nodeName) : -1, nodeTransformation, worldSpace);
}
void AnimatedModel::SetNodeTransformation(int32 nodeIndex, const Matrix& nodeTransformation, bool worldSpace)
{
if (GraphInstance.NodesPose.IsEmpty())
const_cast<AnimatedModel*>(this)->PreInitSkinningData(); // Ensure to have valid nodes pose to return
CHECK(nodeIndex >= 0 && nodeIndex < GraphInstance.NodesPose.Count());
GraphInstance.NodesPose[nodeIndex] = nodeTransformation;
if (worldSpace)
{
Matrix world;
_transform.GetWorld(world);
Matrix invWorld;
Matrix::Invert(world, invWorld);
GraphInstance.NodesPose[nodeIndex] = GraphInstance.NodesPose[nodeIndex] * invWorld;
}
OnAnimationUpdated();
}
void AnimatedModel::SetNodeTransformation(const StringView& nodeName, const Matrix& nodeTransformation, bool worldSpace)
{
SetNodeTransformation(SkinnedModel ? SkinnedModel->FindNode(nodeName) : -1, nodeTransformation, worldSpace);
}
int32 AnimatedModel::FindClosestNode(const Vector3& location, bool worldSpace) const
{
if (GraphInstance.NodesPose.IsEmpty())
@@ -229,6 +229,22 @@ public:
/// <param name="worldSpace">True if convert matrices into world-space, otherwise returned values will be in local-space of the actor.</param>
API_FUNCTION() void GetNodeTransformation(const StringView& nodeName, API_PARAM(Out) Matrix& nodeTransformation, bool worldSpace = false) const;
/// <summary>
/// Sets the node final transformation. If multiple nodes are to be set within a frame, do not use set worldSpace to true, and do the conversion yourself to avoid recalculation of inv matrices.
/// </summary>
/// <param name="nodeIndex">The index of the skinned model skeleton node.</param>
/// <param name="nodeTransformation">The final node transformation matrix.</param>
/// <param name="worldSpace">True if convert matrices from world-space, otherwise values will be in local-space of the actor.</param>
API_FUNCTION() void SetNodeTransformation(int32 nodeIndex, const Matrix& nodeTransformation, bool worldSpace = false);
/// <summary>
/// Sets the node final transformation. If multiple nodes are to be set within a frame, do not use set worldSpace to true, and do the conversion yourself to avoid recalculation of inv matrices.
/// </summary>
/// <param name="nodeName">The name of the skinned model skeleton node.</param>
/// <param name="nodeTransformation">The final node transformation matrix.</param>
/// <param name="worldSpace">True if convert matrices from world-space, otherwise values will be in local-space of the actor.</param>
API_FUNCTION() void SetNodeTransformation(const StringView& nodeName, const Matrix& nodeTransformation, bool worldSpace = false);
/// <summary>
/// Finds the closest node to a given location.
/// </summary>
@@ -28,7 +28,7 @@ public:
/// </summary>
Win32CriticalSection()
{
Windows::InitializeCriticalSectionEx(&_criticalSection, 100, 0x01000000);
Windows::InitializeCriticalSectionEx(&_criticalSection, 4000, 0x01000000);
}
/// <summary>
+2 -2
View File
@@ -1812,7 +1812,7 @@ void* GetStaticMethodPointer(const String& methodName)
PROFILE_CPU();
const int rc = get_function_pointer(NativeInteropTypeName, FLAX_CORECLR_STRING(methodName).Get(), UNMANAGEDCALLERSONLY_METHOD, nullptr, nullptr, &fun);
if (rc != 0)
LOG(Fatal, "Failed to get unmanaged function pointer for method {0}: 0x{1:x}", methodName.Get(), (unsigned int)rc);
LOG(Fatal, "Failed to get unmanaged function pointer for method '{0}': 0x{1:x}", methodName, (unsigned int)rc);
CachedFunctions.Add(methodName, fun);
return fun;
}
@@ -2211,7 +2211,7 @@ void* GetStaticMethodPointer(const String& methodName)
{
const unsigned short errorCode = mono_error_get_error_code(&error);
const char* errorMessage = mono_error_get_message(&error);
LOG(Fatal, "mono_method_get_unmanaged_callers_only_ftnptr failed with error code 0x{0:x}, {1}", errorCode, String(errorMessage));
LOG(Fatal, "Failed to get unmanaged function pointer for method '{0}': 0x{1:x}, {2}", methodName, errorCode, String(errorMessage));
}
mono_error_cleanup(&error);
+3
View File
@@ -180,6 +180,8 @@ namespace FlaxEngine
private static void OnLocalizationChanged()
{
// iOS uses globalization-invariant mode so ignore it
#if !PLATFORM_IOS
var currentThread = Thread.CurrentThread;
var language = Localization.CurrentLanguage;
if (language != null)
@@ -187,6 +189,7 @@ namespace FlaxEngine
var culture = Localization.CurrentCulture;
if (culture != null)
currentThread.CurrentCulture = culture;
#endif
}
/// <summary>
+1 -1
View File
@@ -27,7 +27,7 @@ namespace FlaxEngine.Utilities
where T : new()
{
var json = Json.JsonSerializer.Serialize(instance);
return Json.JsonSerializer.Deserialize<T>(json);
return (T)Json.JsonSerializer.Deserialize(json, instance.GetType());
}
/// <summary>
+1 -1
View File
@@ -32,7 +32,7 @@ public class nethost : ThirdPartyModule
// Get .NET SDK runtime host
var dotnetSdk = DotNetSdk.Instance;
if (!dotnetSdk.IsValid)
throw new Exception($"Missing NET SDK {DotNetSdk.MinimumVersion}.");
throw new DotNetSdk.MissingException();
if (!dotnetSdk.GetHostRuntime(options.Platform.Target, options.Architecture, out var hostRuntime))
{
if (options.Target.IsPreBuilt)
@@ -145,6 +145,20 @@ namespace Flax.Build.Bindings
return $"(void*){result}";
}
private static void GenerateCppAddFileReference(BuildData buildData, ApiTypeInfo caller, TypeInfo typeInfo, ApiTypeInfo apiType)
{
CppReferencesFiles.Add(apiType?.File);
if (typeInfo.GenericArgs != null)
{
for (int i = 0; i < typeInfo.GenericArgs.Count; i++)
{
var g = typeInfo.GenericArgs[i];
GenerateCppAddFileReference(buildData, caller, g, FindApiTypeInfo(buildData, g, caller));
}
}
}
public static string GenerateCppWrapperNativeToVariant(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller, string value)
{
if (typeInfo.Type == "Variant")
@@ -640,15 +654,7 @@ namespace Flax.Build.Bindings
// Register any API types usage
apiType = FindApiTypeInfo(buildData, typeInfo, caller);
CppReferencesFiles.Add(apiType?.File);
if (typeInfo.GenericArgs != null)
{
for (int i = 0; i < typeInfo.GenericArgs.Count; i++)
{
var t = FindApiTypeInfo(buildData, typeInfo.GenericArgs[i], caller);
CppReferencesFiles.Add(t?.File);
}
}
GenerateCppAddFileReference(buildData, caller, typeInfo, apiType);
// Use dynamic array as wrapper container for fixed-size native arrays
if (typeInfo.IsArray)
@@ -1795,15 +1801,7 @@ namespace Flax.Build.Bindings
return true;
// Add includes to properly compile bindings (eg. SoftObjectReference<class Texture>)
CppReferencesFiles.Add(apiTypeInfo?.File);
if (typeInfo.GenericArgs != null)
{
for (int i = 0; i < typeInfo.GenericArgs.Count; i++)
{
var t = FindApiTypeInfo(buildData, typeInfo.GenericArgs[i], caller);
CppReferencesFiles.Add(t?.File);
}
}
GenerateCppAddFileReference(buildData, caller, typeInfo, apiTypeInfo);
return false;
}
@@ -164,7 +164,7 @@ namespace Flax.Build
#if USE_NETCORE
var dotnetSdk = DotNetSdk.Instance;
if (!dotnetSdk.IsValid)
throw new Exception("Cannot compile C# without .NET SDK");
throw new DotNetSdk.MissingException();
string dotnetPath = "dotnet", referenceAnalyzers;
string[] runtimeVersionNameParts = dotnetSdk.RuntimeVersionName.Split('.');
string runtimeVersionShort = runtimeVersionNameParts[0] + '.' + runtimeVersionNameParts[1];
@@ -106,6 +106,20 @@ namespace Flax.Build
}
}
/// <summary>
/// Exception when .NET SDK is missing.
/// </summary>
public sealed class MissingException : Exception
{
/// <summary>
/// Init with a proper message.
/// </summary>
public MissingException()
: base(string.IsNullOrEmpty(Configuration.Dotnet) ? $"Missing .NET SDK {MinimumVersion} (or higher)." : $"Missing .NET SDK {Configuration.Dotnet}.")
{
}
}
private Dictionary<KeyValuePair<TargetPlatform, TargetArchitecture>, HostRuntime> _hostRuntimes = new();
/// <summary>
@@ -223,7 +237,7 @@ namespace Flax.Build
// We need to support two paths here:
// 1. We are running an x64 binary and we are running on an arm64 host machine
// 2. We are running an Arm64 binary and we are targeting an x64 host machine
if (Flax.Build.Platforms.MacPlatform.GetProcessIsTranslated() || isRunningOnArm64Targetx64)
if (Flax.Build.Platforms.MacPlatform.GetProcessIsTranslated() || isRunningOnArm64Targetx64)
{
rid = "osx-x64";
dotnetPath = Path.Combine(dotnetPath, "x64");
@@ -246,10 +260,9 @@ namespace Flax.Build
Log.Warning($"Missing .NET SDK ({dotnetPath})");
return;
}
if (dotnetSdkVersions == null)
dotnetSdkVersions = GetVersions(Path.Combine(dotnetPath, "sdk"));
if (dotnetRuntimeVersions == null)
dotnetRuntimeVersions = GetVersions(Path.Combine(dotnetPath, "shared", "Microsoft.NETCore.App"));
dotnetSdkVersions = MergeVersions(dotnetSdkVersions, GetVersions(Path.Combine(dotnetPath, "sdk")));
dotnetRuntimeVersions = MergeVersions(dotnetRuntimeVersions, GetVersions(Path.Combine(dotnetPath, "shared", "Microsoft.NETCore.App")));
dotnetSdkVersions = dotnetSdkVersions.Where(x => IsValidVersion(Path.Combine(dotnetPath, "sdk", x)));
dotnetRuntimeVersions = dotnetRuntimeVersions.Where(x => IsValidVersion(Path.Combine(dotnetPath, "shared", "Microsoft.NETCore.App", x)));
@@ -260,18 +273,23 @@ namespace Flax.Build
Log.Verbose($"Found the following .NET SDK versions: {string.Join(", ", dotnetSdkVersions)}");
Log.Verbose($"Found the following .NET runtime versions: {string.Join(", ", dotnetRuntimeVersions)}");
string dotnetSdkVersion = dotnetSdkVersions.FirstOrDefault(x => ParseVersion(x).Major >= MinimumVersion.Major && ParseVersion(x).Major <= MaximumVersion.Major);
string dotnetRuntimeVersion = dotnetRuntimeVersions.FirstOrDefault(x => ParseVersion(x).Major >= MinimumVersion.Major && ParseVersion(x).Major <= MaximumVersion.Major);
var dotnetSdkVersion = GetVersion(dotnetSdkVersions);
var dotnetRuntimeVersion = GetVersion(dotnetRuntimeVersions);
var minVer = string.IsNullOrEmpty(Configuration.Dotnet) ? MinimumVersion.ToString() : Configuration.Dotnet;
if (string.IsNullOrEmpty(dotnetSdkVersion))
dotnetSdkVersion = dotnetPath;
if (dotnetSdkVersion == null && dotnetSdkVersions.Count() > 0)
{
Log.Warning($"Unsupported .NET SDK {dotnetSdkVersions.First()} version found. Minimum version required is .NET {MinimumVersion}.");
if (dotnetSdkVersions.Any())
Log.Warning($"Unsupported .NET SDK versions found: {string.Join(", ", dotnetSdkVersions)}. Minimum version required is .NET {minVer}.");
else
Log.Warning($"Missing .NET SDK. Minimum version required is .NET {minVer}.");
return;
}
if (string.IsNullOrEmpty(dotnetSdkVersion) || string.IsNullOrEmpty(dotnetRuntimeVersion))
if (string.IsNullOrEmpty(dotnetRuntimeVersion))
{
Log.Warning("Missing .NET SDK");
if (dotnetRuntimeVersions.Any())
Log.Warning($"Unsupported .NET runtime versions found: {string.Join(", ", dotnetRuntimeVersions)}. Minimum version required is .NET {minVer}.");
else
Log.Warning($"Missing .NET runtime. Minimum version required is .NET {minVer}.");
return;
}
RootPath = dotnetPath;
@@ -434,7 +452,7 @@ namespace Flax.Build
exists = Directory.Exists(path);
if (exists)
_hostRuntimes[new KeyValuePair<TargetPlatform, TargetArchitecture>(platform, arch)] = new HostRuntime(platform, path);
_hostRuntimes[new KeyValuePair<TargetPlatform, TargetArchitecture>(platform, arch)] = new HostRuntime(platform, Utilities.NormalizePath(path));
return exists;
}
@@ -445,6 +463,18 @@ namespace Flax.Build
return Path.Combine(root, version);
}
private static IEnumerable<string> MergeVersions(IEnumerable<string> a, IEnumerable<string> b)
{
if (a == null || !a.Any())
return b;
if (b == null || !b.Any())
return a;
var result = new HashSet<string>();
result.AddRange(a);
result.AddRange(b);
return result;
}
private static Version ParseVersion(string version)
{
// Give precedence to final releases over release candidate / beta releases
@@ -456,6 +486,8 @@ namespace Flax.Build
}
if (!Version.TryParse(version, out var ver))
return null;
if (ver.Build == -1)
return new Version(ver.Major, ver.Minor);
return new Version(ver.Major, ver.Minor, ver.Build, rev);
}
@@ -466,9 +498,42 @@ namespace Flax.Build
private static string GetVersion(IEnumerable<string> versions)
{
return versions.OrderByDescending(ParseVersion)
.Where(x => ParseVersion(x).Major >= MinimumVersion.Major && ParseVersion(x).Major <= MaximumVersion.Major)
.FirstOrDefault();
Version dotnetVer = null;
int dotnetVerNum = -1;
if (!string.IsNullOrEmpty(Configuration.Dotnet))
{
dotnetVer = ParseVersion(Configuration.Dotnet);
if (int.TryParse(Configuration.Dotnet, out var tmp) && tmp >= MinimumVersion.Major)
dotnetVerNum = tmp;
}
var sorted = versions.OrderByDescending(ParseVersion);
foreach (var version in sorted)
{
var v = ParseVersion(version);
// Filter by version specified in command line
if (dotnetVer != null)
{
if (dotnetVer.Major != v.Major)
continue;
if (dotnetVer.Minor != v.Minor)
continue;
if (dotnetVer.Revision != -1 && dotnetVer.Revision != v.Revision)
continue;
if (dotnetVer.Build != -1 && dotnetVer.Build != v.Build)
continue;
}
else if (dotnetVerNum != -1)
{
if (dotnetVerNum != v.Major)
continue;
}
// Filter by min/max versions supported by Flax.Build
if (v.Major >= MinimumVersion.Major && v.Major <= MaximumVersion.Major)
return version;
}
return null;
}
private static bool IsValidVersion(string versionPath)
+14
View File
@@ -225,10 +225,24 @@ namespace Flax.Build
[CommandLine("compiler", "<name>", "Overrides the compiler to use for building. Eg. v140 overrides the toolset when building for Windows.")]
public static string Compiler = null;
/// <summary>
/// Specifies the dotnet SDK version to use for the build. Eg. set to '7' to use .NET 7 even if .NET 8 is installed.
/// </summary>
[CommandLine("dotnet", "<ver>", "Specifies the dotnet SDK version to use for the build. Eg. set to '7' to use .NET 7 even if .NET 8 is installed.")]
public static string Dotnet = null;
/// <summary>
/// Custom configuration defines provided via command line for the build tool.
/// </summary>
public static List<string> CustomDefines = new List<string>();
internal static void PassArgs(ref string cmdLine)
{
if (!string.IsNullOrEmpty(Compiler))
cmdLine += " -compiler=" + Compiler;
if (!string.IsNullOrEmpty(Dotnet))
cmdLine += " -dotnet=" + Dotnet;
}
}
/// <summary>
+1 -2
View File
@@ -17,8 +17,7 @@ namespace Flax.Deploy
var flaxBuildTool = Path.Combine(Globals.EngineRoot, buildPlatform == TargetPlatform.Windows ? "Binaries/Tools/Flax.Build.exe" : "Binaries/Tools/Flax.Build");
var format = "-build -buildtargets={0} -log -logfile= -platform={1} -arch={2} -configuration={3}";
var cmdLine = string.Format(format, target, platform, architecture, configuration);
if (!string.IsNullOrEmpty(Configuration.Compiler))
cmdLine += " -compiler=" + Configuration.Compiler;
Configuration.PassArgs(ref cmdLine);
Log.Info($"Building {target} for {platform} {architecture} {configuration}...");
int result = Utilities.Run(flaxBuildTool, cmdLine, null, root);
+3 -1
View File
@@ -82,7 +82,10 @@ namespace Flax.Build
{
var engineProject = EngineTarget.EngineProject;
if (engineProject != null && engineProject.Configuration != null && engineProject.Configuration.Count != 0)
{
CommandLine.Configure(typeof(EngineConfiguration), engineProject.Configuration);
CommandLine.Configure(typeof(Configuration), engineProject.Configuration);
}
CommandLine.Configure(typeof(EngineConfiguration));
}
@@ -90,7 +93,6 @@ namespace Flax.Build
if (Configuration.Mutex)
{
singleInstanceMutex = new Mutex(true, "Flax.Build", out var oneInstanceMutexCreated);
if (!oneInstanceMutexCreated)
{
try
@@ -172,8 +172,7 @@ namespace Flax.Build.Projects.VisualStudio
configuration.Configuration,
configuration.Platform,
target.Name);
if (!string.IsNullOrEmpty(Configuration.Compiler))
cmdLine += " -compiler=" + Configuration.Compiler;
Configuration.PassArgs(ref cmdLine);
vcProjectFileContent.AppendLine(string.Format(" <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='{0}'\">", configuration.Name));
if (platform is IVisualStudioProjectCustomizer customizer)
@@ -731,8 +731,7 @@ namespace Flax.Build.Projects.VisualStudio
configuration.Configuration,
configuration.Platform,
configuration.Target);
if (!string.IsNullOrEmpty(Configuration.Compiler))
cmdLine += " -compiler=" + Configuration.Compiler;
Configuration.PassArgs(ref cmdLine);
str.AppendLine(string.Format(" <Exec Command=\"{0} {1}\" Condition=\"'$(Configuration)|$(Platform)'=='{2}'\"/>", cmdLine, extraArgs, configuration.Name));
}
@@ -201,6 +201,8 @@ namespace Flax.Build.Projects.VisualStudioCode
json.AddUnnamedField(string.Format("-buildTargets={0}", target.Name));
if (!string.IsNullOrEmpty(Configuration.Compiler))
json.AddUnnamedField(string.Format("-compiler={0}", Configuration.Compiler));
if (!string.IsNullOrEmpty(Configuration.Dotnet))
json.AddUnnamedField(string.Format("-dotnet={0}", Configuration.Dotnet));
}
json.EndArray();
@@ -228,6 +230,8 @@ namespace Flax.Build.Projects.VisualStudioCode
json.AddUnnamedField(string.Format("--buildTargets={0}", target.Name));
if (!string.IsNullOrEmpty(Configuration.Compiler))
json.AddUnnamedField(string.Format("--compiler={0}", Configuration.Compiler));
if (!string.IsNullOrEmpty(Configuration.Dotnet))
json.AddUnnamedField(string.Format("-dotnet={0}", Configuration.Dotnet));
}
json.EndArray();
@@ -255,6 +259,8 @@ namespace Flax.Build.Projects.VisualStudioCode
json.AddUnnamedField(string.Format("--buildTargets={0}", target.Name));
if (!string.IsNullOrEmpty(Configuration.Compiler))
json.AddUnnamedField(string.Format("--compiler={0}", Configuration.Compiler));
if (!string.IsNullOrEmpty(Configuration.Dotnet))
json.AddUnnamedField(string.Format("-dotnet={0}", Configuration.Dotnet));
}
json.EndArray();