Merge remote-tracking branch 'origin/1.6'
This commit is contained in:
19
.github/workflows/build_android.yml
vendored
19
.github/workflows/build_android.yml
vendored
@@ -1,21 +1,36 @@
|
||||
name: Build Android
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Game
|
||||
game-windows:
|
||||
name: Game (Android, Release ARM64)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Setup .NET Workload
|
||||
run: |
|
||||
dotnet workload install android
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=ARM64 -platform=Android -configuration=Release -buildtargets=FlaxGame
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -arch=ARM64 -platform=Android -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
36
.github/workflows/build_ios.yml
vendored
Normal file
36
.github/workflows/build_ios.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Build iOS
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Game
|
||||
game-windows:
|
||||
name: Game (iOS, Release ARM64)
|
||||
runs-on: "macos-latest"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Setup .NET Workload
|
||||
run: |
|
||||
dotnet workload install ios
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame
|
||||
24
.github/workflows/build_linux.yml
vendored
24
.github/workflows/build_linux.yml
vendored
@@ -1,6 +1,10 @@
|
||||
name: Build Linux
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Editor
|
||||
@@ -18,13 +22,21 @@ 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: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxEditor
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxEditor
|
||||
|
||||
# Game
|
||||
game-linux:
|
||||
@@ -38,10 +50,18 @@ jobs:
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Release -buildtargets=FlaxGame
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Linux -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
24
.github/workflows/build_mac.yml
vendored
24
.github/workflows/build_mac.yml
vendored
@@ -1,6 +1,10 @@
|
||||
name: Build macOS
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Editor
|
||||
@@ -12,13 +16,21 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -arch=x64 -platform=Mac -configuration=Development -buildtargets=FlaxEditor
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Mac -configuration=Development -buildtargets=FlaxEditor
|
||||
|
||||
# Game
|
||||
game-mac:
|
||||
@@ -29,10 +41,18 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -arch=x64 -platform=Mac -configuration=Release -buildtargets=FlaxGame
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Mac -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
28
.github/workflows/build_windows.yml
vendored
28
.github/workflows/build_windows.yml
vendored
@@ -1,38 +1,58 @@
|
||||
name: Build Windows
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Editor
|
||||
editor-windows:
|
||||
name: Editor (Windows, Development x64)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor
|
||||
|
||||
# Game
|
||||
game-windows:
|
||||
name: Game (Windows, Release x64)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Release -buildtargets=FlaxGame
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -arch=x64 -platform=Windows -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
56
.github/workflows/cd.yml
vendored
56
.github/workflows/cd.yml
vendored
@@ -4,12 +4,16 @@ on:
|
||||
- cron: '15 4 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Windows
|
||||
package-windows-editor:
|
||||
name: Editor (Windows)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
@@ -19,6 +23,14 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Build
|
||||
run: |
|
||||
.\PackageEditor.bat -arch=x64 -platform=Windows -deployOutput=Output
|
||||
@@ -34,7 +46,7 @@ jobs:
|
||||
path: Output/EditorDebugSymbols.zip
|
||||
package-windows-game:
|
||||
name: Game (Windows)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
@@ -44,6 +56,14 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Build
|
||||
run: |
|
||||
.\PackagePlatforms.bat -arch=x64 -platform=Windows -deployOutput=Output
|
||||
@@ -72,6 +92,14 @@ 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: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Build
|
||||
run: |
|
||||
./PackageEditor.sh -arch=x64 -platform=Linux -deployOutput=Output
|
||||
@@ -98,6 +126,14 @@ 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: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Build
|
||||
run: |
|
||||
./PackagePlatforms.sh -arch=x64 -platform=Linux -deployOutput=Output
|
||||
@@ -120,6 +156,14 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Build
|
||||
run: |
|
||||
./PackageEditor.command -arch=x64 -platform=Mac -deployOutput=Output
|
||||
@@ -140,6 +184,14 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Build
|
||||
run: |
|
||||
./PackagePlatforms.command -arch=x64 -platform=Mac -deployOutput=Output
|
||||
|
||||
53
.github/workflows/tests.yml
vendored
53
.github/workflows/tests.yml
vendored
@@ -1,6 +1,10 @@
|
||||
name: Tests
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
|
||||
jobs:
|
||||
|
||||
# Tests on Linux
|
||||
@@ -10,6 +14,14 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
@@ -22,39 +34,52 @@ 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 -vs2019
|
||||
./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxTestsTarget
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Debug -buildtargets=FlaxEditor -BuildBindingsOnly
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Debug -buildtargets="Flax.Build.Tests"
|
||||
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
|
||||
run: |
|
||||
Binaries/Editor/Linux/Development/FlaxTests
|
||||
mono Source/Platforms/DotNet/NUnit/nunit3-console.exe Binaries/Tools/Flax.Build.Tests.dll --framework=mono-4.0
|
||||
${GITHUB_WORKSPACE}/Binaries/Editor/Linux/Development/FlaxTests
|
||||
dotnet test -f net7.0 Binaries/Tests/Flax.Build.Tests.dll
|
||||
cp Binaries/Editor/Linux/Development/FlaxEngine.CSharp.dll Binaries/Tests
|
||||
cp Binaries/Editor/Linux/Development/FlaxEngine.CSharp.runtimeconfig.json Binaries/Tests
|
||||
cp Binaries/Editor/Linux/Development/Newtonsoft.Json.dll Binaries/Tests
|
||||
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
|
||||
Binaries/Editor/Linux/Development/FlaxTests
|
||||
${GITHUB_WORKSPACE}/Binaries/Editor/Linux/Development/FlaxTests
|
||||
|
||||
# Tests on Windows
|
||||
tests-windows:
|
||||
name: Tests (Windows)
|
||||
runs-on: "windows-2019"
|
||||
runs-on: "windows-2022"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Print .NET info
|
||||
run: |
|
||||
dotnet --info
|
||||
dotnet workload --info
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
.\GenerateProjectFiles.bat -vs2019
|
||||
.\GenerateProjectFiles.bat -vs2022 -log -verbose -printSDKs
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxTestsTarget
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Debug -buildtargets=FlaxEditor -BuildBindingsOnly
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Debug -buildtargets="FlaxEngine.Tests"
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Debug -buildtargets="Flax.Build.Tests"
|
||||
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: |
|
||||
Binaries\Editor\Win64\Development\FlaxTests.exe
|
||||
Source\Platforms\DotNet\NUnit\nunit3-console.exe Binaries\Tools\FlaxEngine.Tests.dll --framework=net-4.5.2
|
||||
Source\Platforms\DotNet\NUnit\nunit3-console.exe Binaries\Tools\Flax.Build.Tests.dll --framework=net-4.5.2
|
||||
.\Binaries\Editor\Win64\Development\FlaxTests.exe
|
||||
dotnet test -f net7.0 Binaries\Tests\Flax.Build.Tests.dll
|
||||
xcopy /y Binaries\Editor\Win64\Development\FlaxEngine.CSharp.dll Binaries\Tests
|
||||
xcopy /y Binaries\Editor\Win64\Development\FlaxEngine.CSharp.runtimeconfig.json Binaries\Tests
|
||||
xcopy /y Binaries\Editor\Win64\Development\Newtonsoft.Json.dll Binaries\Tests
|
||||
dotnet test -f net7.0 Binaries\Tests\FlaxEngine.CSharp.dll
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -25,6 +25,7 @@ PackagePlatforms_Cert.bat
|
||||
*.opendb
|
||||
*.DS_Store
|
||||
*.xcodeproj
|
||||
launchSettings.json
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
|
||||
BIN
Content/Editor/IconsAtlas.flax
(Stored with Git LFS)
BIN
Content/Editor/IconsAtlas.flax
(Stored with Git LFS)
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Deferred Shading: Defines
|
||||
@1// Deferred Shading: Includes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Distortion: Defines
|
||||
@1// Distortion: Includes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Forward Shading: Defines
|
||||
#define MAX_LOCAL_LIGHTS 4
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Global Illumination: Defines
|
||||
#define USE_GI 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Lightmap: Defines
|
||||
#define CAN_USE_LIGHTMAP 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Motion Vectors: Defines
|
||||
@1// Motion Vectors: Includes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
@0// Tessellation: Defines
|
||||
#define TessalationProjectOntoPlane(planeNormal, planePosition, pointToProject) pointToProject - dot(pointToProject - planePosition, planeNormal) * planeNormal
|
||||
|
||||
BIN
Content/Shaders/Lights.flax
(Stored with Git LFS)
BIN
Content/Shaders/Lights.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/VolumetricFog.flax
(Stored with Git LFS)
BIN
Content/Shaders/VolumetricFog.flax
(Stored with Git LFS)
Binary file not shown.
@@ -10,8 +10,7 @@ if [ $testfilesize -le 1000 ]; then
|
||||
fi
|
||||
|
||||
# Compile the build tool.
|
||||
xbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /property:Platform=AnyCPU /target:Build
|
||||
dotnet msbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /target:Restore,Build /property:RestorePackagesConfig=True /p:RuntimeIdentifiers=linux-x64
|
||||
|
||||
# Run the build tool using the provided arguments.
|
||||
#mono --debug --debugger-agent=transport=dt_socket,server=y,address=127.0.0.1:55555 Binaries/Tools/Flax.Build.exe "$@"
|
||||
mono Binaries/Tools/Flax.Build.exe "$@"
|
||||
Binaries/Tools/Flax.Build "$@"
|
||||
|
||||
@@ -10,8 +10,7 @@ if [ $testfilesize -le 1000 ]; then
|
||||
fi
|
||||
|
||||
# Compile the build tool.
|
||||
xbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /property:Platform=AnyCPU /target:Build
|
||||
dotnet msbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /target:Restore,Build /property:RestorePackagesConfig=True /p:RuntimeIdentifiers=osx-x64
|
||||
|
||||
# Run the build tool using the provided arguments.
|
||||
#mono --debug --debugger-agent=transport=dt_socket,server=y,address=127.0.0.1:55555 Binaries/Tools/Flax.Build.exe "$@"
|
||||
mono Binaries/Tools/Flax.Build.exe "$@"
|
||||
Binaries/Tools/Flax.Build "$@"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Copyright (c) 2012-2023 Wojciech Figat. All rights reserved
|
||||
|
||||
# Fix mono bin to be in a path
|
||||
export PATH=/Library/Frameworks/Mono.framework/Versions/Current/Commands:$PATH
|
||||
#export PATH=/Library/Frameworks/Mono.framework/Versions/Current/Commands:$PATH
|
||||
|
||||
echo "Running Flax.Build $*"
|
||||
mono Binaries/Tools/Flax.Build.exe "$@"
|
||||
Binaries/Tools/Flax.Build "$@"
|
||||
|
||||
@@ -28,9 +28,9 @@ fc /b Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Fla
|
||||
if not errorlevel 1 goto SkipClean
|
||||
|
||||
copy /y Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Flax.Build.PrevFiles.txt >nul
|
||||
%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /property:Platform=AnyCPU /target:Clean
|
||||
%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /target:Restore,Clean /property:RestorePackagesConfig=True /p:RuntimeIdentifiers=win-x64
|
||||
:SkipClean
|
||||
%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /property:Platform=AnyCPU /target:Build
|
||||
%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /target:Build /property:SelfContained=False /property:RuntimeIdentifiers=win-x64
|
||||
if errorlevel 1 goto Error_CompilationFailed
|
||||
|
||||
Binaries\Tools\Flax.Build.exe %*
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"Name": "Flax",
|
||||
"Version": {
|
||||
"Major": 1,
|
||||
"Minor": 5,
|
||||
"Build": 6341
|
||||
"Minor": 6,
|
||||
"Build": 6342
|
||||
},
|
||||
"Company": "Flax",
|
||||
"Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.",
|
||||
@@ -11,6 +11,7 @@
|
||||
"EditorTarget": "FlaxEditor",
|
||||
"Configuration": {
|
||||
"UseCSharp": true,
|
||||
"UseLargeWorlds": false
|
||||
"UseLargeWorlds": false,
|
||||
"UseDotNet": true
|
||||
}
|
||||
}
|
||||
@@ -321,6 +321,9 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Reimports/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=reimported/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=renderable/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=retarget/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=retargeting/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=retargets/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=reverb/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=rigidbodies/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=rigidbody/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
41
README.md
41
README.md
@@ -26,16 +26,12 @@ This repository contains full source code of the Flax Engine (excluding NDA-prot
|
||||
|
||||
Follow the instructions below to compile and run the engine from source.
|
||||
|
||||
## Flax plugin for Visual Studio
|
||||
|
||||
Flax Visual Studio extension provides better programming workflow, C# scripts debugging functionality and allows to attach to running engine instance to debug C# source. This extension is available to download [here](https://marketplace.visualstudio.com/items?itemName=Flax.FlaxVS).
|
||||
|
||||
## Windows
|
||||
|
||||
* Install Visual Studio 2015 or newer
|
||||
* 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 Framework 4.5.2 SDK/Targeting Pack (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 Git with LFS
|
||||
* Clone repo (with LFS)
|
||||
* Run **GenerateProjectFiles.bat**
|
||||
@@ -44,16 +40,13 @@ Flax Visual Studio extension provides better programming workflow, C# scripts de
|
||||
* Compile Flax project (hit F7 or CTRL+Shift+B)
|
||||
* Run Flax (hit F5 key)
|
||||
|
||||
> When building on Windows to support Vulkan rendering, first install the Vulkan SDK then set an environment variable to provide the path to the SDK prior to running GenerateProjectFiles.bat: `set VULKAN_SDK=%sdk_path%`
|
||||
|
||||
## Linux
|
||||
|
||||
* Install Visual Studio Code
|
||||
* Install Mono
|
||||
* Ubuntu: see the instructions here: ([https://www.mono-project.com/download/stable](https://www.mono-project.com/download/stable))
|
||||
* Arch: `sudo pacman -S mono`
|
||||
* Install Vulkan SDK
|
||||
* Ubuntu: see the instructions here: ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
||||
* 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`
|
||||
* Arch: `sudo pacman -S spirv-tools vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||
* Install Git with LFS
|
||||
* Ubuntu: `sudo apt-get install git git-lfs`
|
||||
@@ -73,13 +66,31 @@ Flax Visual Studio extension provides better programming workflow, C# scripts de
|
||||
## Mac
|
||||
|
||||
* Install XCode
|
||||
* Install Mono ([https://www.mono-project.com/download/stable](https://www.mono-project.com/download/stable))
|
||||
* 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`
|
||||
* Open workspace with XCode or Visual Studio Code
|
||||
* Build and run (configuration `Editor.Mac.Development`)
|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
* `Could not execute because the specified command or file was not found.`
|
||||
|
||||
Restart PC - ensure DotNet is added to PATH for command line tools execution.
|
||||
|
||||
* `Microsoft.NET.TargetFrameworkInference.targets(141,5): error NETSDK1045: The current .NET SDK does not support targeting .NET 7.0. Either target .NET 5.0 or lower, or use a version of the .NET SDK that supports .NET 7.0`
|
||||
|
||||
Use Visual Studio 2022, older versions are not supported by .NET SDK 7.
|
||||
|
||||
* `Building for Windows without Vulkan rendering backend (Vulkan SDK is missing)`
|
||||
|
||||
Install the Vulkan SDK then set an environment variable to provide the path to the SDK prior to running GenerateProjectFiles.bat: `set VULKAN_SDK=%sdk_path%`.
|
||||
|
||||
* `The NuGetSdkResolver did not resolve this SDK`
|
||||
|
||||
Install `.NET SDK`, `NuGet package manager` and `NuGet targets and build tasks` in Visual Studio components.
|
||||
|
||||
## Workspace directory
|
||||
|
||||
- **Binaries/** - executable files
|
||||
@@ -93,7 +104,6 @@ Flax Visual Studio extension provides better programming workflow, C# scripts de
|
||||
- **Content/** - assets and binary files used by the engine and editor
|
||||
- **Development/** - engine development files
|
||||
- **Scripts/** - utility scripts
|
||||
- **packages/** - NuGet packages cache location
|
||||
- **Source/** - source code location
|
||||
- **Editor/** - Flax Editor source code
|
||||
- **Engine/** - Flax Engine source code
|
||||
@@ -103,7 +113,6 @@ Flax Visual Studio extension provides better programming workflow, C# scripts de
|
||||
- ***PlatformName*/** - per-platform files
|
||||
- **Binaries/** - per-platform binaries
|
||||
- **Game/** - Flax Game binaries
|
||||
- **Mono/** - Mono runtime files and data
|
||||
- **ThirdParty/** - prebuilt 3rd Party binaries
|
||||
- **Shaders/** - shaders source code
|
||||
- **ThirdParty/** - 3rd Party source code
|
||||
|
||||
@@ -1,49 +1,103 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "EditorAnalytics.h"
|
||||
#include "EditorAnalyticsController.h"
|
||||
#include "Editor/Editor.h"
|
||||
#include "Editor/ProjectInfo.h"
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
#include "Engine/Threading/Task.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/MemoryStats.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Types/DateTime.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Editor/Editor.h"
|
||||
#include "Editor/ProjectInfo.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Utilities/StringConverter.h"
|
||||
#include "Engine/Utilities/TextWriter.h"
|
||||
#include "Engine/ShadowsOfMordor/Builder.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include <ThirdParty/UniversalAnalytics/universal-analytics.h>
|
||||
#include <ThirdParty/UniversalAnalytics/http.h>
|
||||
|
||||
#define FLAX_EDITOR_GOOGLE_ID "UA-88357703-3"
|
||||
// Docs:
|
||||
// https://developers.google.com/analytics/devguides/collection/ga4
|
||||
// https://developers.google.com/analytics/devguides/collection/protocol/ga4
|
||||
|
||||
// Helper doc: https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters
|
||||
// [GA4] Flax Editor
|
||||
#define GA_MEASUREMENT_ID "G-2SNY6RW6VX"
|
||||
#define GA_API_SECRET "wFlau4khTPGFRnx-AIZ1zg"
|
||||
#define GA_DEBUG 0
|
||||
#if GA_DEBUG
|
||||
#define GA_URL "https://www.google-analytics.com/debug/mp/collect"
|
||||
#else
|
||||
#define GA_URL "https://www.google-analytics.com/mp/collect"
|
||||
#endif
|
||||
|
||||
namespace EditorAnalyticsImpl
|
||||
namespace
|
||||
{
|
||||
UATracker Tracker = nullptr;
|
||||
|
||||
StringAnsi Url;
|
||||
StringAnsi ClientId;
|
||||
StringAnsi ProjectName;
|
||||
StringAnsi ScreenResolution;
|
||||
StringAnsi UserLanguage;
|
||||
StringAnsi GPU;
|
||||
DateTime SessionStartTime;
|
||||
|
||||
CriticalSection Locker;
|
||||
bool IsSessionActive = false;
|
||||
EditorAnalyticsController Controller;
|
||||
Array<char> TmpBuffer;
|
||||
TextWriterANSI JsonBuffer;
|
||||
curl_slist* CurlHttpHeadersList = nullptr;
|
||||
}
|
||||
|
||||
using namespace EditorAnalyticsImpl;
|
||||
size_t curl_null_data_handler(char* ptr, size_t size, size_t nmemb, void* userdata)
|
||||
{
|
||||
return nmemb * size;
|
||||
}
|
||||
|
||||
void RegisterGameCookingStart(GameCooker::EventType type)
|
||||
{
|
||||
if (type == GameCooker::EventType::BuildStarted)
|
||||
{
|
||||
auto& data = *GameCooker::GetCurrentData();
|
||||
StringAnsi name = "Build " + StringAnsi(ToString(data.Platform));
|
||||
const Pair<const char*, const char*> params[1] = { { "GameCooker", name.Get() } };
|
||||
EditorAnalytics::SendEvent("Actions", ToSpan(params, ARRAY_COUNT(params)));
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterLightmapsBuildingStart()
|
||||
{
|
||||
const Pair<const char*, const char*> params[1] = { { "ShadowsOfMordor", "Build" }, };
|
||||
EditorAnalytics::SendEvent("Actions", ToSpan(params, ARRAY_COUNT(params)));
|
||||
}
|
||||
|
||||
void RegisterError(LogType type, const StringView& msg)
|
||||
{
|
||||
if (type == LogType::Error && false)
|
||||
{
|
||||
StringAnsi value(msg);
|
||||
const int32 MaxLength = 300;
|
||||
if (msg.Length() > MaxLength)
|
||||
value = value.Substring(0, MaxLength);
|
||||
value.Replace('\n', ' ');
|
||||
value.Replace('\r', ' ');
|
||||
const Pair<const char*, const char*> params[1] = { { "Error", value.Get() }, };
|
||||
EditorAnalytics::SendEvent("Errors", ToSpan(params, ARRAY_COUNT(params)));
|
||||
}
|
||||
else if (type == LogType::Fatal)
|
||||
{
|
||||
StringAnsi value(msg);
|
||||
const int32 MaxLength = 300;
|
||||
if (msg.Length() > MaxLength)
|
||||
value = value.Substring(0, MaxLength);
|
||||
value.Replace('\n', ' ');
|
||||
value.Replace('\r', ' ');
|
||||
const Pair<const char*, const char*> params[1] = { { "Fatal", value.Get() }, };
|
||||
EditorAnalytics::SendEvent("Errors", ToSpan(params, ARRAY_COUNT(params)));
|
||||
}
|
||||
}
|
||||
|
||||
class EditorAnalyticsService : public EngineService
|
||||
{
|
||||
public:
|
||||
|
||||
EditorAnalyticsService()
|
||||
: EngineService(TEXT("Editor Analytics"))
|
||||
{
|
||||
@@ -57,192 +111,141 @@ EditorAnalyticsService EditorAnalyticsServiceInstance;
|
||||
|
||||
bool EditorAnalytics::IsSessionActive()
|
||||
{
|
||||
return EditorAnalyticsImpl::IsSessionActive;
|
||||
return ::IsSessionActive;
|
||||
}
|
||||
|
||||
void EditorAnalytics::StartSession()
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
if (EditorAnalyticsImpl::IsSessionActive)
|
||||
if (::IsSessionActive)
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
|
||||
// Prepare client metadata
|
||||
if (ClientId.IsEmpty())
|
||||
{
|
||||
ClientId = Platform::GetUniqueDeviceId().ToString(Guid::FormatType::N).ToStringAnsi();
|
||||
}
|
||||
if (ScreenResolution.IsEmpty())
|
||||
{
|
||||
const auto desktopSize = Platform::GetDesktopSize();
|
||||
ScreenResolution = StringAnsi(StringUtils::ToString((int32)desktopSize.X)) + "x" + StringAnsi(StringUtils::ToString((int32)desktopSize.Y));
|
||||
}
|
||||
if (UserLanguage.IsEmpty())
|
||||
{
|
||||
UserLanguage = Platform::GetUserLocaleName().ToStringAnsi();
|
||||
}
|
||||
if (GPU.IsEmpty())
|
||||
{
|
||||
const auto gpu = GPUDevice::Instance;
|
||||
if (gpu && gpu->GetState() == GPUDevice::DeviceState::Ready)
|
||||
GPU = StringAsANSI<>(gpu->GetAdapter()->GetDescription().GetText()).Get();
|
||||
}
|
||||
if (ProjectName.IsEmpty())
|
||||
{
|
||||
ProjectName = Editor::Project->Name.ToStringAnsi();
|
||||
}
|
||||
ClientId = Platform::GetUniqueDeviceId().ToString(Guid::FormatType::N).ToStringAnsi();
|
||||
StringAnsi ProjectName = Editor::Project->Name.ToStringAnsi();
|
||||
const auto desktopSize = Platform::GetDesktopSize();
|
||||
StringAnsi ScreenResolution = StringAnsi::Format("{0}x{1}", (int32)desktopSize.X, (int32)desktopSize.Y);
|
||||
const auto memoryStats = Platform::GetMemoryStats();
|
||||
StringAnsi Memory = StringAnsi::Format("{0} GB", (int32)(memoryStats.TotalPhysicalMemory / 1024 / 1024 / 1000));
|
||||
StringAnsi UserLocale = Platform::GetUserLocaleName().ToStringAnsi();
|
||||
StringAnsi GPU;
|
||||
if (GPUDevice::Instance && GPUDevice::Instance->GetState() == GPUDevice::DeviceState::Ready)
|
||||
GPU = StringAsANSI<>(GPUDevice::Instance->GetAdapter()->GetDescription().GetText()).Get();
|
||||
SessionStartTime = DateTime::Now();
|
||||
|
||||
// Initialize the analytics tracker
|
||||
Tracker = createTracker(FLAX_EDITOR_GOOGLE_ID, ClientId.Get(), nullptr);
|
||||
Tracker->user_agent = "Flax Editor";
|
||||
|
||||
// Store these options permanently (for the lifetime of the tracker)
|
||||
setTrackerOption(Tracker, UA_OPTION_QUEUE, 1);
|
||||
UASettings GlobalSettings =
|
||||
{
|
||||
{
|
||||
{ UA_DOCUMENT_PATH, 0, "Flax Editor" },
|
||||
{ UA_DOCUMENT_TITLE, 0, "Flax Editor" },
|
||||
StringAnsiView EngineVersion = FLAXENGINE_VERSION_TEXT;
|
||||
#if PLATFORM_WINDOWS
|
||||
{ UA_USER_AGENT, 0, "Windows " FLAXENGINE_VERSION_TEXT },
|
||||
StringAnsiView PlatformName = "Windows";
|
||||
#elif PLATFORM_LINUX
|
||||
{ UA_USER_AGENT, 0, "Linux " FLAXENGINE_VERSION_TEXT },
|
||||
StringAnsiView PlatformName = "Linux";
|
||||
#elif PLATFORM_MAC
|
||||
{ UA_USER_AGENT, 0, "Mac " FLAXENGINE_VERSION_TEXT },
|
||||
StringAnsiView PlatformName = "Mac";
|
||||
#else
|
||||
#error "Unknown platform"
|
||||
#endif
|
||||
{ UA_ANONYMIZE_IP, 0, "0" },
|
||||
{ UA_APP_ID, 0, "Flax Editor " FLAXENGINE_VERSION_TEXT },
|
||||
{ UA_APP_INSTALLER_ID, 0, "Flax Editor" },
|
||||
{ UA_APP_NAME, 0, "Flax Editor" },
|
||||
{ UA_APP_VERSION, 0, FLAXENGINE_VERSION_TEXT },
|
||||
{ UA_SCREEN_NAME, 0, "Flax Editor " FLAXENGINE_VERSION_TEXT },
|
||||
{ UA_SCREEN_RESOLUTION, 0, ScreenResolution.Get() },
|
||||
{ UA_USER_LANGUAGE, 0, UserLanguage.Get() },
|
||||
}
|
||||
};
|
||||
setParameters(Tracker, &GlobalSettings);
|
||||
|
||||
// Send the initial session event
|
||||
UAOptions sessionViewOptions =
|
||||
// Initialize HTTP
|
||||
Url = StringAnsi::Format("{0}?measurement_id={1}&api_secret={2}", GA_URL, GA_MEASUREMENT_ID, GA_API_SECRET);
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
CurlHttpHeadersList = curl_slist_append(nullptr, "Content-Type: application/json");
|
||||
::IsSessionActive = true;
|
||||
|
||||
// Start session
|
||||
{
|
||||
{
|
||||
{ UA_EVENT_CATEGORY, 0, "Session" },
|
||||
{ UA_EVENT_ACTION, 0, "Start Editor" },
|
||||
{ UA_EVENT_LABEL, 0, "Start Editor" },
|
||||
{ UA_SESSION_CONTROL, 0, "start" },
|
||||
{ UA_DOCUMENT_TITLE, 0, ProjectName.Get() },
|
||||
}
|
||||
};
|
||||
sendTracking(Tracker, UA_SCREENVIEW, &sessionViewOptions);
|
||||
|
||||
EditorAnalyticsImpl::IsSessionActive = true;
|
||||
|
||||
Controller.Init();
|
||||
|
||||
// Report GPU model
|
||||
if (GPU.HasChars())
|
||||
{
|
||||
SendEvent("Telemetry", "GPU.Model", GPU.Get());
|
||||
const Pair<const char*, const char*> params[1] = { { "Project", ProjectName.Get() }, };
|
||||
SendEvent("Session", ToSpan(params, ARRAY_COUNT(params)));
|
||||
}
|
||||
|
||||
// Report telemetry stats
|
||||
#define SEND_TELEMETRY(name, value) \
|
||||
if (value.HasChars()) \
|
||||
{ \
|
||||
const Pair<const char*, const char*> params[1] = { { name, value.Get() } }; \
|
||||
SendEvent("Telemetry", ToSpan(params, ARRAY_COUNT(params))); \
|
||||
}
|
||||
SEND_TELEMETRY("Platform", PlatformName);
|
||||
SEND_TELEMETRY("GPU", GPU);
|
||||
SEND_TELEMETRY("Memory", Memory);
|
||||
SEND_TELEMETRY("Locale", UserLocale);
|
||||
SEND_TELEMETRY("Screen", ScreenResolution);
|
||||
SEND_TELEMETRY("Version", EngineVersion);
|
||||
#undef SEND_TELEMETRY
|
||||
|
||||
// Bind events
|
||||
GameCooker::OnEvent.Bind<RegisterGameCookingStart>();
|
||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Bind<RegisterLightmapsBuildingStart>();
|
||||
Log::Logger::OnError.Bind<RegisterError>();
|
||||
}
|
||||
|
||||
void EditorAnalytics::EndSession()
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
if (!EditorAnalyticsImpl::IsSessionActive)
|
||||
if (!::IsSessionActive)
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
|
||||
Controller.Cleanup();
|
||||
// Unbind events
|
||||
GameCooker::OnEvent.Unbind<RegisterGameCookingStart>();
|
||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Unbind<RegisterLightmapsBuildingStart>();
|
||||
Log::Logger::OnError.Unbind<RegisterError>();
|
||||
|
||||
StringAnsi sessionLength = StringAnsi::Format("{0}", (int32)(DateTime::Now() - SessionStartTime).GetTotalSeconds());
|
||||
|
||||
// Send the end session event
|
||||
UAOptions sessionEventOptions =
|
||||
// End session
|
||||
{
|
||||
StringAnsi sessionLength = StringAnsi::Format("{}", (int32)(DateTime::Now() - SessionStartTime).GetTotalSeconds());
|
||||
const Pair<const char*, const char*> params[1] =
|
||||
{
|
||||
{ UA_EVENT_CATEGORY, 0, "Session" },
|
||||
{ UA_EVENT_ACTION, 0, "Session Length" },
|
||||
{ UA_EVENT_LABEL, 0, "Session Length" },
|
||||
{ UA_EVENT_VALUE, 0, sessionLength.Get() },
|
||||
{ UA_CUSTOM_DIMENSION, 1, "Session Length" },
|
||||
{ UA_CUSTOM_METRIC, 1, sessionLength.Get() },
|
||||
}
|
||||
};
|
||||
sendTracking(Tracker, UA_EVENT, &sessionEventOptions);
|
||||
|
||||
// Send the end session event
|
||||
UAOptions sessionViewOptions =
|
||||
{
|
||||
{
|
||||
{ UA_EVENT_CATEGORY, 0, "Session" },
|
||||
{ UA_EVENT_ACTION, 0, "End Editor" },
|
||||
{ UA_EVENT_LABEL, 0, "End Editor" },
|
||||
{ UA_EVENT_VALUE, 0, sessionLength.Get() },
|
||||
{ UA_SESSION_CONTROL, 0, "end" },
|
||||
}
|
||||
};
|
||||
sendTracking(Tracker, UA_SCREENVIEW, &sessionViewOptions);
|
||||
{ "Duration", sessionLength.Get() },
|
||||
};
|
||||
SendEvent("Session", ToSpan(params, ARRAY_COUNT(params)));
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
removeTracker(Tracker);
|
||||
Tracker = nullptr;
|
||||
|
||||
EditorAnalyticsImpl::IsSessionActive = false;
|
||||
curl_slist_free_all(CurlHttpHeadersList);
|
||||
CurlHttpHeadersList = nullptr;
|
||||
curl_global_cleanup();
|
||||
::IsSessionActive = false;
|
||||
}
|
||||
|
||||
void EditorAnalytics::SendEvent(const char* category, const char* name, const char* label)
|
||||
void EditorAnalytics::SendEvent(const char* name, Span<Pair<const char*, const char*>> parameters)
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
if (!EditorAnalyticsImpl::IsSessionActive)
|
||||
if (!::IsSessionActive)
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
|
||||
UAOptions opts =
|
||||
// Create Json request contents
|
||||
JsonBuffer.Clear();
|
||||
JsonBuffer.Write("{ \"client_id\": \"");
|
||||
JsonBuffer.Write(ClientId);
|
||||
JsonBuffer.Write("\", \"events\": [ { \"name\": \"");
|
||||
JsonBuffer.Write(name);
|
||||
JsonBuffer.Write("\", \"params\": {");
|
||||
for (int32 i = 0; i < parameters.Length(); i++)
|
||||
{
|
||||
{
|
||||
{ UA_EVENT_CATEGORY, 0, (char*)category },
|
||||
{ UA_EVENT_ACTION, 0, (char*)name },
|
||||
{ UA_EVENT_LABEL, 0, (char*)label },
|
||||
}
|
||||
};
|
||||
if (i != 0)
|
||||
JsonBuffer.Write(",");
|
||||
const auto& e = parameters[i];
|
||||
JsonBuffer.Write("\"");
|
||||
JsonBuffer.Write(e.First);
|
||||
JsonBuffer.Write("\":\"");
|
||||
JsonBuffer.Write(e.Second);
|
||||
JsonBuffer.Write("\"");
|
||||
}
|
||||
JsonBuffer.Write("}}]}");
|
||||
const StringAnsiView json((const char*)JsonBuffer.GetBuffer()->GetHandle(), (int32)JsonBuffer.GetBuffer()->GetPosition());
|
||||
|
||||
sendTracking(Tracker, UA_EVENT, &opts);
|
||||
}
|
||||
|
||||
void EditorAnalytics::SendEvent(const char* category, const char* name, const StringView& label)
|
||||
{
|
||||
SendEvent(category, name, label.Get());
|
||||
}
|
||||
|
||||
void EditorAnalytics::SendEvent(const char* category, const char* name, const Char* label)
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
if (!EditorAnalyticsImpl::IsSessionActive)
|
||||
return;
|
||||
|
||||
ASSERT(category && name && label);
|
||||
|
||||
const int32 labelLength = StringUtils::Length(label);
|
||||
TmpBuffer.Clear();
|
||||
TmpBuffer.Resize(labelLength + 1);
|
||||
StringUtils::ConvertUTF162ANSI(label, TmpBuffer.Get(), labelLength);
|
||||
TmpBuffer[labelLength] = 0;
|
||||
|
||||
UAOptions opts =
|
||||
{
|
||||
{
|
||||
{ UA_EVENT_CATEGORY, 0, (char*)category },
|
||||
{ UA_EVENT_ACTION, 0, (char*)name },
|
||||
{ UA_EVENT_LABEL, 0, (char*)TmpBuffer.Get() },
|
||||
}
|
||||
};
|
||||
|
||||
sendTracking(Tracker, UA_EVENT, &opts);
|
||||
// Send HTTP request
|
||||
CURL* curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, Url.Get());
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, CurlHttpHeadersList);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.Get());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, json.Length());
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Flax Editor");
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_null_data_handler);
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
bool EditorAnalyticsService::Init()
|
||||
@@ -265,8 +268,7 @@ bool EditorAnalyticsService::Init()
|
||||
}
|
||||
|
||||
LOG(Info, "Editor analytics service is enabled. Curl version: {0}", TEXT(LIBCURL_VERSION));
|
||||
|
||||
EditorAnalytics::StartSession();
|
||||
Task::StartNew(EditorAnalytics::StartSession);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -10,11 +10,9 @@
|
||||
class EditorAnalytics
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether analytics session is active.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if there is active analytics session running; otherwise, <c>false</c>.</returns>
|
||||
static bool IsSessionActive();
|
||||
|
||||
/// <summary>
|
||||
@@ -30,24 +28,7 @@ public:
|
||||
/// <summary>
|
||||
/// Sends the custom event.
|
||||
/// </summary>
|
||||
/// <param name="category">The event category name.</param>
|
||||
/// <param name="name">The event name.</param>
|
||||
/// <param name="label">The event label.</param>
|
||||
static void SendEvent(const char* category, const char* name, const char* label = nullptr);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the custom event.
|
||||
/// </summary>
|
||||
/// <param name="category">The event category name.</param>
|
||||
/// <param name="name">The event name.</param>
|
||||
/// <param name="label">The event label.</param>
|
||||
static void SendEvent(const char* category, const char* name, const StringView& label);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the custom event.
|
||||
/// </summary>
|
||||
/// <param name="category">The event category name.</param>
|
||||
/// <param name="name">The event name.</param>
|
||||
/// <param name="label">The event label.</param>
|
||||
static void SendEvent(const char* category, const char* name, const Char* label);
|
||||
/// <param name="parameters">The event parameters (key and value pairs).</param>
|
||||
static void SendEvent(const char* name, Span<Pair<const char*, const char*>> parameters);
|
||||
};
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "EditorAnalyticsController.h"
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
#include "EditorAnalytics.h"
|
||||
#include "Engine/ShadowsOfMordor/Builder.h"
|
||||
|
||||
void RegisterGameCookingStart(GameCooker::EventType type)
|
||||
{
|
||||
auto& data = *GameCooker::GetCurrentData();
|
||||
auto platform = ToString(data.Platform);
|
||||
if (type == GameCooker::EventType::BuildStarted)
|
||||
{
|
||||
EditorAnalytics::SendEvent("Actions", "GameCooker.Start", platform);
|
||||
}
|
||||
else if (type == GameCooker::EventType::BuildFailed)
|
||||
{
|
||||
EditorAnalytics::SendEvent("Actions", "GameCooker.Failed", platform);
|
||||
}
|
||||
else if (type == GameCooker::EventType::BuildDone)
|
||||
{
|
||||
EditorAnalytics::SendEvent("Actions", "GameCooker.End", platform);
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterLightmapsBuildingStart()
|
||||
{
|
||||
EditorAnalytics::SendEvent("Actions", "ShadowsOfMordor.Build", "ShadowsOfMordor.Build");
|
||||
}
|
||||
|
||||
void RegisterError(LogType type, const StringView& msg)
|
||||
{
|
||||
if (type == LogType::Error && false)
|
||||
{
|
||||
String value = msg.ToString();
|
||||
const int32 MaxLength = 300;
|
||||
if (msg.Length() > MaxLength)
|
||||
value = value.Substring(0, MaxLength);
|
||||
value.Replace('\n', ' ');
|
||||
value.Replace('\r', ' ');
|
||||
|
||||
EditorAnalytics::SendEvent("Errors", "Log.Error", value);
|
||||
}
|
||||
else if (type == LogType::Fatal)
|
||||
{
|
||||
String value = msg.ToString();
|
||||
const int32 MaxLength = 300;
|
||||
if (msg.Length() > MaxLength)
|
||||
value = value.Substring(0, MaxLength);
|
||||
value.Replace('\n', ' ');
|
||||
value.Replace('\r', ' ');
|
||||
|
||||
EditorAnalytics::SendEvent("Errors", "Log.Fatal", value);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorAnalyticsController::Init()
|
||||
{
|
||||
GameCooker::OnEvent.Bind<RegisterGameCookingStart>();
|
||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Bind<RegisterLightmapsBuildingStart>();
|
||||
Log::Logger::OnError.Bind<RegisterError>();
|
||||
}
|
||||
|
||||
void EditorAnalyticsController::Cleanup()
|
||||
{
|
||||
GameCooker::OnEvent.Unbind<RegisterGameCookingStart>();
|
||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Unbind<RegisterLightmapsBuildingStart>();
|
||||
Log::Logger::OnError.Unbind<RegisterError>();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
/// <summary>
|
||||
/// The controller object for the tracking events for the editor analytics.
|
||||
/// </summary>
|
||||
class EditorAnalyticsController
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Starts the service (registers to event handlers).
|
||||
/// </summary>
|
||||
void Init();
|
||||
|
||||
/// <summary>
|
||||
/// Ends the service (unregisters to event handlers).
|
||||
/// </summary>
|
||||
void Cleanup();
|
||||
};
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Interop;
|
||||
|
||||
namespace FlaxEditor.Content.Import
|
||||
{
|
||||
@@ -93,6 +93,7 @@ namespace FlaxEditor.Content.Import
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct InternalOptions
|
||||
{
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public AudioFormat Format;
|
||||
public byte DisableStreaming;
|
||||
public byte Is3D;
|
||||
@@ -144,7 +145,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// Audio asset import entry.
|
||||
/// </summary>
|
||||
/// <seealso cref="AssetImportEntry" />
|
||||
public class AudioImportEntry : AssetImportEntry
|
||||
public partial class AudioImportEntry : AssetImportEntry
|
||||
{
|
||||
private AudioImportSettings _settings = new AudioImportSettings();
|
||||
|
||||
@@ -182,8 +183,9 @@ namespace FlaxEditor.Content.Import
|
||||
|
||||
#region Internal Calls
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_GetAudioImportOptions(string path, out AudioImportSettings.InternalOptions result);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "AudioImportEntryInternal_GetAudioImportOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_GetAudioImportOptions(string path, out AudioImportSettings.InternalOptions result);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,88 +1,47 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Tools;
|
||||
|
||||
namespace FlaxEngine.Tools
|
||||
{
|
||||
partial class ModelTool
|
||||
{
|
||||
partial struct Options
|
||||
{
|
||||
private bool ShowGeometry => Type == ModelTool.ModelType.Model || Type == ModelTool.ModelType.SkinnedModel;
|
||||
private bool ShowModel => Type == ModelTool.ModelType.Model;
|
||||
private bool ShowSkinnedModel => Type == ModelTool.ModelType.SkinnedModel;
|
||||
private bool ShowAnimation => Type == ModelTool.ModelType.Animation;
|
||||
private bool ShowSmoothingNormalsAngle => ShowGeometry && CalculateNormals;
|
||||
private bool ShowSmoothingTangentsAngle => ShowGeometry && CalculateTangents;
|
||||
private bool ShowFramesRange => ShowAnimation && Duration == ModelTool.AnimationDuration.Custom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for <see cref="FlaxEngine.Tools.ModelTool.Options"/>.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(FlaxEngine.Tools.ModelTool.Options)), DefaultEditor]
|
||||
public class ModelToolOptionsEditor : GenericEditor
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override List<ItemInfo> GetItemsForType(ScriptType type)
|
||||
{
|
||||
// Show both fields and properties
|
||||
return GetItemsForType(type, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace FlaxEditor.Content.Import
|
||||
{
|
||||
/// <summary>
|
||||
/// Importing model lightmap UVs source
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public enum ModelLightmapUVsSource : int
|
||||
{
|
||||
/// <summary>
|
||||
/// No lightmap UVs.
|
||||
/// </summary>
|
||||
Disable = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Generate lightmap UVs from model geometry.
|
||||
/// </summary>
|
||||
Generate = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The texcoords channel 0.
|
||||
/// </summary>
|
||||
Channel0 = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The texcoords channel 1.
|
||||
/// </summary>
|
||||
Channel1 = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The texcoords channel 2.
|
||||
/// </summary>
|
||||
Channel2 = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The texcoords channel 3.
|
||||
/// </summary>
|
||||
Channel3 = 5
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Declares the imported data type.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public enum ModelType : int
|
||||
{
|
||||
/// <summary>
|
||||
/// The model asset.
|
||||
/// </summary>
|
||||
Model = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The skinned model asset.
|
||||
/// </summary>
|
||||
SkinnedModel = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The animation asset.
|
||||
/// </summary>
|
||||
Animation = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Declares the imported animation clip duration.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public enum AnimationDuration : int
|
||||
{
|
||||
/// <summary>
|
||||
/// The imported duration.
|
||||
/// </summary>
|
||||
Imported = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The custom duration specified via keyframes range.
|
||||
/// </summary>
|
||||
Custom = 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Proxy object to present model import settings in <see cref="ImportFilesDialog"/>.
|
||||
/// </summary>
|
||||
@@ -90,431 +49,10 @@ namespace FlaxEditor.Content.Import
|
||||
public class ModelImportSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of the imported asset.
|
||||
/// The settings data.
|
||||
/// </summary>
|
||||
[EditorOrder(0)]
|
||||
public ModelType Type { get; set; } = ModelType.Model;
|
||||
|
||||
/// <summary>
|
||||
/// Enable model normal vectors recalculating.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(20), DefaultValue(false)]
|
||||
public bool CalculateNormals { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the maximum angle (in degrees) that may be between two face normals at the same vertex position that their are smoothed together. The default value is 175.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowSmoothingNormalsAngle))]
|
||||
[EditorOrder(30), DefaultValue(175.0f), Limit(0, 175, 0.1f)]
|
||||
public float SmoothingNormalsAngle { get; set; } = 175.0f;
|
||||
|
||||
private bool ShowSmoothingNormalsAngle => ShowGeometry && CalculateNormals;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the imported normal vectors of the mesh will be flipped (scaled by -1).
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(35), DefaultValue(false)]
|
||||
public bool FlipNormals { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Enable model tangent vectors recalculating.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(40), DefaultValue(false)]
|
||||
public bool CalculateTangents { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the maximum angle (in degrees) that may be between two vertex tangents that their tangents and bi-tangents are smoothed. The default value is 45.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowSmoothingTangentsAngle))]
|
||||
[EditorOrder(45), DefaultValue(45.0f), Limit(0, 45, 0.1f)]
|
||||
public float SmoothingTangentsAngle { get; set; } = 45.0f;
|
||||
|
||||
private bool ShowSmoothingTangentsAngle => ShowGeometry && CalculateTangents;
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable meshes geometry optimization.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(50), DefaultValue(true)]
|
||||
public bool OptimizeMeshes { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable geometry merge for meshes with the same materials.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(60), DefaultValue(true)]
|
||||
public bool MergeMeshes { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable importing meshes Level of Details.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry", "Import LODs"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(70), DefaultValue(true)]
|
||||
public bool ImportLODs { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable importing vertex colors (channel 0 only).
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowModel))]
|
||||
[EditorOrder(80), DefaultValue(true)]
|
||||
public bool ImportVertexColors { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable importing blend shapes (morph targets).
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowSkinnedModel))]
|
||||
[EditorOrder(85), DefaultValue(false)]
|
||||
public bool ImportBlendShapes { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The lightmap UVs source.
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry", "Lightmap UVs Source"), VisibleIf(nameof(ShowModel))]
|
||||
[EditorOrder(90), DefaultValue(ModelLightmapUVsSource.Disable)]
|
||||
public ModelLightmapUVsSource LightmapUVsSource { get; set; } = ModelLightmapUVsSource.Disable;
|
||||
|
||||
/// <summary>
|
||||
/// If specified, all meshes which name starts with this prefix will be imported as a separate collision data (excluded used for rendering).
|
||||
/// </summary>
|
||||
[EditorDisplay("Geometry"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(100), DefaultValue("")]
|
||||
public string CollisionMeshesPrefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Custom uniform import scale.
|
||||
/// </summary>
|
||||
[EditorOrder(500), DefaultValue(1.0f), EditorDisplay("Transform")]
|
||||
public float Scale { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Custom import geometry rotation.
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Quaternion), "0,0,0,1")]
|
||||
[EditorOrder(510), EditorDisplay("Transform")]
|
||||
public Quaternion Rotation { get; set; } = Quaternion.Identity;
|
||||
|
||||
/// <summary>
|
||||
/// Custom import geometry offset.
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Float3), "0,0,0")]
|
||||
[EditorOrder(520), EditorDisplay("Transform")]
|
||||
public Float3 Translation { get; set; } = Float3.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the imported geometry will be shifted to the center of mass.
|
||||
/// </summary>
|
||||
[EditorOrder(530), DefaultValue(false), EditorDisplay("Transform")]
|
||||
public bool CenterGeometry { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Imported animation duration mode. Can use the original value or overriden by settings.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1000), DefaultValue(AnimationDuration.Imported)]
|
||||
public AnimationDuration Duration { get; set; } = AnimationDuration.Imported;
|
||||
|
||||
/// <summary>
|
||||
/// Imported animation first frame index. Used only if Duration mode is set to Custom.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowFramesRange))]
|
||||
[EditorOrder(1010), DefaultValue(0.0f), Limit(0)]
|
||||
public float FramesRangeStart { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Imported animation last frame index. Used only if Duration mode is set to Custom.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowFramesRange))]
|
||||
[EditorOrder(1020), DefaultValue(0.0f), Limit(0)]
|
||||
public float FramesRangeEnd { get; set; } = 0;
|
||||
|
||||
private bool ShowFramesRange => ShowAnimation && Duration == AnimationDuration.Custom;
|
||||
|
||||
/// <summary>
|
||||
/// The imported animation default frame rate. Can specify the default frames per second amount for imported animation. If value is 0 then the original animation frame rate will be used.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1025), DefaultValue(0.0f), Limit(0, 1000, 0.01f)]
|
||||
public float DefaultFrameRate { get; set; } = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The imported animation sampling rate. If value is 0 then the original animation speed will be used.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1030), DefaultValue(0.0f), Limit(0, 1000, 0.01f)]
|
||||
public float SamplingRate { get; set; } = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The imported animation will have removed tracks with no keyframes or unspecified data.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1040), DefaultValue(true)]
|
||||
public bool SkipEmptyCurves { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The imported animation channels will be optimized to remove redundant keyframes.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1050), DefaultValue(true)]
|
||||
public bool OptimizeKeyframes { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the importer will import scale animation tracks (otherwise scale animation will be ignored).
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1055), DefaultValue(false)]
|
||||
public bool ImportScaleTracks { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Enables root motion extraction support from this animation.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1060), DefaultValue(false)]
|
||||
public bool EnableRootMotion { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The custom node name to be used as a root motion source. If not specified the actual root node will be used.
|
||||
/// </summary>
|
||||
[EditorDisplay("Animation"), VisibleIf(nameof(ShowAnimation))]
|
||||
[EditorOrder(1070), DefaultValue(typeof(string), "")]
|
||||
public string RootNodeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the importer will generate a sequence of LODs based on the base LOD index.
|
||||
/// </summary>
|
||||
[EditorDisplay("Level Of Detail", "Generate LODs"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(1100), DefaultValue(false)]
|
||||
public bool GenerateLODs { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The index of the LOD from the source model data to use as a reference for following LODs generation.
|
||||
/// </summary>
|
||||
[EditorDisplay("Level Of Detail", "Base LOD"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(1110), DefaultValue(0), Limit(0, Model.MaxLODs - 1)]
|
||||
public int BaseLOD { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of LODs to include in the model (all remaining ones starting from Base LOD will be generated).
|
||||
/// </summary>
|
||||
[EditorDisplay("Level Of Detail", "LOD Count"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(1120), DefaultValue(4), Limit(1, Model.MaxLODs)]
|
||||
public int LODCount { get; set; } = 4;
|
||||
|
||||
/// <summary>
|
||||
/// The target amount of triangles for the generated LOD (based on the higher LOD). Normalized to range 0-1. For instance 0.4 cuts the triangle count to 40%.
|
||||
/// </summary>
|
||||
[EditorDisplay("Level Of Detail"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(1130), DefaultValue(0.5f), Limit(0, 1, 0.001f)]
|
||||
public float TriangleReduction { get; set; } = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the importer will create materials for model meshes as specified in the file.
|
||||
/// </summary>
|
||||
[EditorDisplay("Materials"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(400), DefaultValue(true)]
|
||||
public bool ImportMaterials { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the importer will import texture files used by the model and any embedded texture resources.
|
||||
/// </summary>
|
||||
[EditorDisplay("Materials"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(410), DefaultValue(true)]
|
||||
public bool ImportTextures { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the importer will try to restore the model material slots.
|
||||
/// </summary>
|
||||
[EditorDisplay("Materials", "Restore Materials On Reimport"), VisibleIf(nameof(ShowGeometry))]
|
||||
[EditorOrder(420), DefaultValue(true)]
|
||||
public bool RestoreMaterialsOnReimport { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, enables generation of Signed Distance Field (SDF).
|
||||
/// </summary>
|
||||
[EditorDisplay("SDF"), VisibleIf(nameof(ShowModel))]
|
||||
[EditorOrder(1500), DefaultValue(false)]
|
||||
public bool GenerateSDF { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Resolution scale for generated Signed Distance Field (SDF) texture. Higher values improve accuracy but increase memory usage and reduce performance.
|
||||
/// </summary>
|
||||
[EditorDisplay("SDF"), VisibleIf(nameof(ShowModel))]
|
||||
[EditorOrder(1510), DefaultValue(1.0f), Limit(0.0001f, 100.0f)]
|
||||
public float SDFResolution { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, the imported mesh/animations are splitted into separate assets. Used if ObjectIndex is set to -1.
|
||||
/// </summary>
|
||||
[EditorOrder(2000), DefaultValue(false), EditorDisplay("Splitting")]
|
||||
public bool SplitObjects { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The zero-based index for the mesh/animation clip to import. If the source file has more than one mesh/animation it can be used to pick a desire object. Default -1 imports all objects.
|
||||
/// </summary>
|
||||
[EditorOrder(2010), DefaultValue(-1), EditorDisplay("Splitting")]
|
||||
public int ObjectIndex { get; set; } = -1;
|
||||
|
||||
private bool ShowGeometry => Type == ModelType.Model || Type == ModelType.SkinnedModel;
|
||||
private bool ShowModel => Type == ModelType.Model;
|
||||
private bool ShowSkinnedModel => Type == ModelType.SkinnedModel;
|
||||
private bool ShowAnimation => Type == ModelType.Animation;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct InternalOptions
|
||||
{
|
||||
public ModelType Type;
|
||||
|
||||
// Geometry
|
||||
public byte CalculateNormals;
|
||||
public float SmoothingNormalsAngle;
|
||||
public byte FlipNormals;
|
||||
public float SmoothingTangentsAngle;
|
||||
public byte CalculateTangents;
|
||||
public byte OptimizeMeshes;
|
||||
public byte MergeMeshes;
|
||||
public byte ImportLODs;
|
||||
public byte ImportVertexColors;
|
||||
public byte ImportBlendShapes;
|
||||
public ModelLightmapUVsSource LightmapUVsSource;
|
||||
public string CollisionMeshesPrefix;
|
||||
|
||||
// Transform
|
||||
public float Scale;
|
||||
public Quaternion Rotation;
|
||||
public Float3 Translation;
|
||||
public byte CenterGeometry;
|
||||
|
||||
// Animation
|
||||
public AnimationDuration Duration;
|
||||
public float FramesRangeStart;
|
||||
public float FramesRangeEnd;
|
||||
public float DefaultFrameRate;
|
||||
public float SamplingRate;
|
||||
public byte SkipEmptyCurves;
|
||||
public byte OptimizeKeyframes;
|
||||
public byte ImportScaleTracks;
|
||||
public byte EnableRootMotion;
|
||||
public string RootNodeName;
|
||||
|
||||
// Level Of Detail
|
||||
public byte GenerateLODs;
|
||||
public int BaseLOD;
|
||||
public int LODCount;
|
||||
public float TriangleReduction;
|
||||
|
||||
// Misc
|
||||
public byte ImportMaterials;
|
||||
public byte ImportTextures;
|
||||
public byte RestoreMaterialsOnReimport;
|
||||
|
||||
// SDF
|
||||
public byte GenerateSDF;
|
||||
public float SDFResolution;
|
||||
|
||||
// Splitting
|
||||
public byte SplitObjects;
|
||||
public int ObjectIndex;
|
||||
}
|
||||
|
||||
internal void ToInternal(out InternalOptions options)
|
||||
{
|
||||
options = new InternalOptions
|
||||
{
|
||||
Type = Type,
|
||||
CalculateNormals = (byte)(CalculateNormals ? 1 : 0),
|
||||
SmoothingNormalsAngle = SmoothingNormalsAngle,
|
||||
FlipNormals = (byte)(FlipNormals ? 1 : 0),
|
||||
SmoothingTangentsAngle = SmoothingTangentsAngle,
|
||||
CalculateTangents = (byte)(CalculateTangents ? 1 : 0),
|
||||
OptimizeMeshes = (byte)(OptimizeMeshes ? 1 : 0),
|
||||
MergeMeshes = (byte)(MergeMeshes ? 1 : 0),
|
||||
ImportLODs = (byte)(ImportLODs ? 1 : 0),
|
||||
ImportVertexColors = (byte)(ImportVertexColors ? 1 : 0),
|
||||
ImportBlendShapes = (byte)(ImportBlendShapes ? 1 : 0),
|
||||
LightmapUVsSource = LightmapUVsSource,
|
||||
CollisionMeshesPrefix = CollisionMeshesPrefix,
|
||||
Scale = Scale,
|
||||
Rotation = Rotation,
|
||||
Translation = Translation,
|
||||
CenterGeometry = (byte)(CenterGeometry ? 1 : 0),
|
||||
Duration = Duration,
|
||||
FramesRangeStart = FramesRangeStart,
|
||||
FramesRangeEnd = FramesRangeEnd,
|
||||
DefaultFrameRate = DefaultFrameRate,
|
||||
SamplingRate = SamplingRate,
|
||||
SkipEmptyCurves = (byte)(SkipEmptyCurves ? 1 : 0),
|
||||
OptimizeKeyframes = (byte)(OptimizeKeyframes ? 1 : 0),
|
||||
ImportScaleTracks = (byte)(ImportScaleTracks ? 1 : 0),
|
||||
EnableRootMotion = (byte)(EnableRootMotion ? 1 : 0),
|
||||
RootNodeName = RootNodeName,
|
||||
GenerateLODs = (byte)(GenerateLODs ? 1 : 0),
|
||||
BaseLOD = BaseLOD,
|
||||
LODCount = LODCount,
|
||||
TriangleReduction = TriangleReduction,
|
||||
ImportMaterials = (byte)(ImportMaterials ? 1 : 0),
|
||||
ImportTextures = (byte)(ImportTextures ? 1 : 0),
|
||||
RestoreMaterialsOnReimport = (byte)(RestoreMaterialsOnReimport ? 1 : 0),
|
||||
GenerateSDF = (byte)(GenerateSDF ? 1 : 0),
|
||||
SDFResolution = SDFResolution,
|
||||
SplitObjects = (byte)(SplitObjects ? 1 : 0),
|
||||
ObjectIndex = ObjectIndex,
|
||||
};
|
||||
}
|
||||
|
||||
internal void FromInternal(ref InternalOptions options)
|
||||
{
|
||||
Type = options.Type;
|
||||
CalculateNormals = options.CalculateNormals != 0;
|
||||
SmoothingNormalsAngle = options.SmoothingNormalsAngle;
|
||||
FlipNormals = options.FlipNormals != 0;
|
||||
SmoothingTangentsAngle = options.SmoothingTangentsAngle;
|
||||
CalculateTangents = options.CalculateTangents != 0;
|
||||
OptimizeMeshes = options.OptimizeMeshes != 0;
|
||||
MergeMeshes = options.MergeMeshes != 0;
|
||||
ImportLODs = options.ImportLODs != 0;
|
||||
ImportVertexColors = options.ImportVertexColors != 0;
|
||||
ImportBlendShapes = options.ImportBlendShapes != 0;
|
||||
LightmapUVsSource = options.LightmapUVsSource;
|
||||
CollisionMeshesPrefix = options.CollisionMeshesPrefix;
|
||||
Scale = options.Scale;
|
||||
Rotation = options.Rotation;
|
||||
Translation = options.Translation;
|
||||
CenterGeometry = options.CenterGeometry != 0;
|
||||
FramesRangeStart = options.FramesRangeStart;
|
||||
FramesRangeEnd = options.FramesRangeEnd;
|
||||
DefaultFrameRate = options.DefaultFrameRate;
|
||||
SamplingRate = options.SamplingRate;
|
||||
SkipEmptyCurves = options.SkipEmptyCurves != 0;
|
||||
OptimizeKeyframes = options.OptimizeKeyframes != 0;
|
||||
ImportScaleTracks = options.ImportScaleTracks != 0;
|
||||
EnableRootMotion = options.EnableRootMotion != 0;
|
||||
RootNodeName = options.RootNodeName;
|
||||
GenerateLODs = options.GenerateLODs != 0;
|
||||
BaseLOD = options.BaseLOD;
|
||||
LODCount = options.LODCount;
|
||||
TriangleReduction = options.TriangleReduction;
|
||||
ImportMaterials = options.ImportMaterials != 0;
|
||||
ImportTextures = options.ImportTextures != 0;
|
||||
RestoreMaterialsOnReimport = options.RestoreMaterialsOnReimport != 0;
|
||||
GenerateSDF = options.GenerateSDF != 0;
|
||||
SDFResolution = options.SDFResolution;
|
||||
SplitObjects = options.SplitObjects != 0;
|
||||
ObjectIndex = options.ObjectIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries the restore the asset import options from the target resource file. Applies the project default options too.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="assetPath">The asset path.</param>
|
||||
/// <returns>True settings has been restored, otherwise false.</returns>
|
||||
public static void TryRestore(ref ModelImportSettings options, string assetPath)
|
||||
{
|
||||
ModelImportEntry.Internal_GetModelImportOptions(assetPath, out var internalOptions);
|
||||
options.FromInternal(ref internalOptions);
|
||||
}
|
||||
[EditorDisplay(null, EditorDisplayAttribute.InlineStyle)]
|
||||
public ModelTool.Options Settings = ModelTool.Options.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -523,7 +61,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// <seealso cref="AssetImportEntry" />
|
||||
public class ModelImportEntry : AssetImportEntry
|
||||
{
|
||||
private ModelImportSettings _settings = new ModelImportSettings();
|
||||
private ModelImportSettings _settings = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ModelImportEntry"/> class.
|
||||
@@ -533,7 +71,7 @@ namespace FlaxEditor.Content.Import
|
||||
: base(ref request)
|
||||
{
|
||||
// Try to restore target asset model import options (useful for fast reimport)
|
||||
ModelImportSettings.TryRestore(ref _settings, ResultUrl);
|
||||
Editor.TryRestoreImportOptions(ref _settings.Settings, ResultUrl);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -542,9 +80,14 @@ namespace FlaxEditor.Content.Import
|
||||
/// <inheritdoc />
|
||||
public override bool TryOverrideSettings(object settings)
|
||||
{
|
||||
if (settings is ModelImportSettings o)
|
||||
if (settings is ModelImportSettings s)
|
||||
{
|
||||
_settings = o;
|
||||
_settings.Settings = s.Settings;
|
||||
return true;
|
||||
}
|
||||
if (settings is ModelTool.Options o)
|
||||
{
|
||||
_settings.Settings = o;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -553,14 +96,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// <inheritdoc />
|
||||
public override bool Import()
|
||||
{
|
||||
return Editor.Import(SourceUrl, ResultUrl, _settings);
|
||||
return Editor.Import(SourceUrl, ResultUrl, _settings.Settings);
|
||||
}
|
||||
|
||||
#region Internal Calls
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_GetModelImportOptions(string path, out ModelImportSettings.InternalOptions result);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,56 +3,94 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Tools;
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace FlaxEngine.Tools
|
||||
{
|
||||
partial class TextureTool
|
||||
{
|
||||
partial struct Options
|
||||
{
|
||||
#pragma warning disable CS1591
|
||||
public enum CustomMaxSizes
|
||||
{
|
||||
_32 = 32,
|
||||
_64 = 64,
|
||||
_128 = 128,
|
||||
_256 = 256,
|
||||
_512 = 512,
|
||||
_1024 = 1024,
|
||||
_2048 = 2048,
|
||||
_4096 = 4096,
|
||||
_8192 = 8192,
|
||||
_16384 = 16384,
|
||||
}
|
||||
#pragma warning restore CS1591
|
||||
|
||||
/// <summary>
|
||||
/// The size of the imported texture. If Resize property is set to true then texture will be resized during the import to this value. Otherwise it will be ignored.
|
||||
/// </summary>
|
||||
[EditorOrder(110), VisibleIf(nameof(Resize)), DefaultValue(typeof(Int2), "1024,1024")]
|
||||
public Int2 Size
|
||||
{
|
||||
get => new Int2(SizeX, SizeY);
|
||||
set
|
||||
{
|
||||
SizeX = value.X;
|
||||
SizeY = value.Y;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maximum size of the texture (for both width and height). Higher resolution textures will be resized during importing process.
|
||||
/// </summary>
|
||||
[EditorOrder(90), DefaultValue(CustomMaxSizes._8192), EditorDisplay(null, "Max Size")]
|
||||
public CustomMaxSizes CustomMaxSize
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = MaxSize;
|
||||
if (!Mathf.IsPowerOfTwo(value))
|
||||
value = Mathf.NextPowerOfTwo(value);
|
||||
FieldInfo[] fields = typeof(CustomMaxSizes).GetFields();
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
{
|
||||
var field = fields[i];
|
||||
if (field.Name.Equals("value__"))
|
||||
continue;
|
||||
if (value == (int)field.GetRawConstantValue())
|
||||
return (CustomMaxSizes)value;
|
||||
}
|
||||
return CustomMaxSizes._8192;
|
||||
}
|
||||
set => MaxSize = (int)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for <see cref="FlaxEngine.Tools.TextureTool.Options"/>.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(FlaxEngine.Tools.TextureTool.Options)), DefaultEditor]
|
||||
public class TextureToolOptionsEditor : GenericEditor
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override List<ItemInfo> GetItemsForType(ScriptType type)
|
||||
{
|
||||
// Show both fields and properties
|
||||
return GetItemsForType(type, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace FlaxEditor.Content.Import
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture format types.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public enum TextureFormatType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// The unknown.
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The color with RGB channels.
|
||||
/// </summary>
|
||||
ColorRGB = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The color with RGBA channels.
|
||||
/// </summary>
|
||||
ColorRGBA = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The normal map (packed and compressed).
|
||||
/// </summary>
|
||||
NormalMap = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The gray scale (R channel).
|
||||
/// </summary>
|
||||
GrayScale = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The HDR color (RGBA channels).
|
||||
/// </summary>
|
||||
HdrRGBA = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The HDR color (RGB channels).
|
||||
/// </summary>
|
||||
HdrRGB = 6
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Proxy object to present texture import settings in <see cref="ImportFilesDialog"/>.
|
||||
/// </summary>
|
||||
@@ -60,346 +98,10 @@ namespace FlaxEditor.Content.Import
|
||||
public class TextureImportSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// A custom version of <see cref="TextureFormatType"/> for GUI.
|
||||
/// The settings data.
|
||||
/// </summary>
|
||||
public enum CustomTextureFormatType
|
||||
{
|
||||
/// <summary>
|
||||
/// The color with RGB channels.
|
||||
/// </summary>
|
||||
ColorRGB = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The color with RGBA channels.
|
||||
/// </summary>
|
||||
ColorRGBA = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The normal map (packed and compressed).
|
||||
/// </summary>
|
||||
NormalMap = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The gray scale (R channel).
|
||||
/// </summary>
|
||||
GrayScale = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The HDR color (RGBA channels).
|
||||
/// </summary>
|
||||
HdrRGBA = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The HDR color (RGB channels).
|
||||
/// </summary>
|
||||
HdrRGB = 6
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A custom set of max texture import sizes.
|
||||
/// </summary>
|
||||
public enum CustomMaxSizeType
|
||||
{
|
||||
/// <summary>
|
||||
/// The 32.
|
||||
/// </summary>
|
||||
_32 = 32,
|
||||
|
||||
/// <summary>
|
||||
/// The 64.
|
||||
/// </summary>
|
||||
_64 = 64,
|
||||
|
||||
/// <summary>
|
||||
/// The 128.
|
||||
/// </summary>
|
||||
_128 = 128,
|
||||
|
||||
/// <summary>
|
||||
/// The 256.
|
||||
/// </summary>
|
||||
_256 = 256,
|
||||
|
||||
/// <summary>
|
||||
/// The 512.
|
||||
/// </summary>
|
||||
_512 = 512,
|
||||
|
||||
/// <summary>
|
||||
/// The 1024.
|
||||
/// </summary>
|
||||
_1024 = 1024,
|
||||
|
||||
/// <summary>
|
||||
/// The 2048.
|
||||
/// </summary>
|
||||
_2048 = 2048,
|
||||
|
||||
/// <summary>
|
||||
/// The 4096.
|
||||
/// </summary>
|
||||
_4096 = 4096,
|
||||
|
||||
/// <summary>
|
||||
/// The 8192.
|
||||
/// </summary>
|
||||
_8192 = 8192,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the maximum size to enum.
|
||||
/// </summary>
|
||||
/// <param name="f">The max size.</param>
|
||||
/// <returns>The converted enum.</returns>
|
||||
public static CustomMaxSizeType ConvertMaxSize(int f)
|
||||
{
|
||||
if (!Mathf.IsPowerOfTwo(f))
|
||||
f = Mathf.NextPowerOfTwo(f);
|
||||
|
||||
FieldInfo[] fields = typeof(CustomMaxSizeType).GetFields();
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
{
|
||||
var field = fields[i];
|
||||
if (field.Name.Equals("value__"))
|
||||
continue;
|
||||
|
||||
if (f == (int)field.GetRawConstantValue())
|
||||
return (CustomMaxSizeType)f;
|
||||
}
|
||||
|
||||
return CustomMaxSizeType._8192;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The sprite info.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SpriteInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The sprite area.
|
||||
/// </summary>
|
||||
public Rectangle Area;
|
||||
|
||||
/// <summary>
|
||||
/// The sprite name.
|
||||
/// </summary>
|
||||
public string Name;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SpriteInfo"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="area">The area.</param>
|
||||
/// <param name="name">The name.</param>
|
||||
public SpriteInfo(Rectangle area, string name)
|
||||
{
|
||||
Area = area;
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Texture format type
|
||||
/// </summary>
|
||||
[EditorOrder(0), DefaultValue(CustomTextureFormatType.ColorRGB), Tooltip("Texture import format type")]
|
||||
public CustomTextureFormatType Type { get; set; } = CustomTextureFormatType.ColorRGB;
|
||||
|
||||
/// <summary>
|
||||
/// True if texture should be imported as a texture atlas resource
|
||||
/// </summary>
|
||||
[EditorOrder(10), DefaultValue(false), Tooltip("True if texture should be imported as a texture atlas (with sprites)")]
|
||||
public bool IsAtlas { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if disable dynamic texture streaming
|
||||
/// </summary>
|
||||
[EditorOrder(20), DefaultValue(false), Tooltip("True if disable dynamic texture streaming")]
|
||||
public bool NeverStream { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables/disables texture data compression.
|
||||
/// </summary>
|
||||
[EditorOrder(30), DefaultValue(true), Tooltip("True if compress texture data")]
|
||||
public bool Compress { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// True if texture channels have independent data
|
||||
/// </summary>
|
||||
[EditorOrder(40), DefaultValue(false), Tooltip("True if texture channels have independent data (for compression methods)")]
|
||||
public bool IndependentChannels { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if use sRGB format for texture data. Recommended for color maps and diffuse color textures.
|
||||
/// </summary>
|
||||
[EditorOrder(50), DefaultValue(false), EditorDisplay(null, "sRGB"), Tooltip("True if use sRGB format for texture data. Recommended for color maps and diffuse color textures.")]
|
||||
public bool sRGB { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if generate mip maps chain for the texture.
|
||||
/// </summary>
|
||||
[EditorOrder(60), DefaultValue(true), Tooltip("True if generate mip maps chain for the texture")]
|
||||
public bool GenerateMipMaps { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// True if flip Y coordinate of the texture.
|
||||
/// </summary>
|
||||
[EditorOrder(65), DefaultValue(false), EditorDisplay(null, "Flip Y"), Tooltip("True if flip Y coordinate of the texture.")]
|
||||
public bool FlipY { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The import texture scale.
|
||||
/// </summary>
|
||||
[EditorOrder(70), DefaultValue(1.0f), Tooltip("Texture scale. Default is 1.")]
|
||||
public float Scale { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum size of the texture (for both width and height).
|
||||
/// Higher resolution textures will be resized during importing process.
|
||||
/// </summary>
|
||||
[EditorOrder(80), DefaultValue(CustomMaxSizeType._8192), Tooltip("Maximum texture size (will be resized if need to)")]
|
||||
public CustomMaxSizeType MaxSize { get; set; } = CustomMaxSizeType._8192;
|
||||
|
||||
/// <summary>
|
||||
/// True if resize texture on import. Use Size property to define texture width and height. Texture scale property will be ignored.
|
||||
/// </summary>
|
||||
[EditorOrder(90), DefaultValue(false), Tooltip("True if resize texture on import. Use Size property to define texture width and height. Texture scale property will be ignored.")]
|
||||
public bool Resize { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size of the imported texture. If Resize property is set to true then texture will be resized during the import to this value. Otherwise it will be ignored.
|
||||
/// </summary>
|
||||
[EditorOrder(100), VisibleIf("Resize"), DefaultValue(typeof(Int2), "1024,1024"), Tooltip("The size of the imported texture. If Resize property is set to true then texture will be resized during the import to this value. Otherwise it will be ignored.")]
|
||||
public Int2 Size { get; set; } = new Int2(1024, 1024);
|
||||
|
||||
/// <summary>
|
||||
/// True if preserve alpha coverage in generated mips for alpha test reference. Scales mipmap alpha values to preserve alpha coverage based on an alpha test reference value.
|
||||
/// </summary>
|
||||
[EditorOrder(240), DefaultValue(false), Tooltip("Check to preserve alpha coverage in generated mips for alpha test reference. Scales mipmap alpha values to preserve alpha coverage based on an alpha test reference value.")]
|
||||
public bool PreserveAlphaCoverage { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The reference value for the alpha coverage preserving.
|
||||
/// </summary>
|
||||
[EditorOrder(250), VisibleIf("PreserveAlphaCoverage"), DefaultValue(0.5f), Tooltip("The reference value for the alpha coverage preserving.")]
|
||||
public float PreserveAlphaCoverageReference { get; set; } = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Texture group for streaming (negative if unused). See Streaming Settings.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(CustomEditors.Dedicated.TextureGroupEditor))]
|
||||
[EditorOrder(300), Tooltip("Texture group for streaming (negative if unused). See Streaming Settings.")]
|
||||
public int TextureGroup = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The sprites. Used to keep created sprites on sprite atlas reimport.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public List<SpriteInfo> Sprites = new List<SpriteInfo>();
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct InternalOptions
|
||||
{
|
||||
public TextureFormatType Type;
|
||||
public byte IsAtlas;
|
||||
public byte NeverStream;
|
||||
public byte Compress;
|
||||
public byte IndependentChannels;
|
||||
public byte sRGB;
|
||||
public byte GenerateMipMaps;
|
||||
public byte FlipY;
|
||||
public byte Resize;
|
||||
public byte PreserveAlphaCoverage;
|
||||
public float PreserveAlphaCoverageReference;
|
||||
public float Scale;
|
||||
public int MaxSize;
|
||||
public int TextureGroup;
|
||||
public Int2 Size;
|
||||
public Rectangle[] SpriteAreas;
|
||||
public string[] SpriteNames;
|
||||
}
|
||||
|
||||
internal void ToInternal(out InternalOptions options)
|
||||
{
|
||||
options = new InternalOptions
|
||||
{
|
||||
Type = (TextureFormatType)(int)Type,
|
||||
IsAtlas = (byte)(IsAtlas ? 1 : 0),
|
||||
NeverStream = (byte)(NeverStream ? 1 : 0),
|
||||
Compress = (byte)(Compress ? 1 : 0),
|
||||
IndependentChannels = (byte)(IndependentChannels ? 1 : 0),
|
||||
sRGB = (byte)(sRGB ? 1 : 0),
|
||||
GenerateMipMaps = (byte)(GenerateMipMaps ? 1 : 0),
|
||||
FlipY = (byte)(FlipY ? 1 : 0),
|
||||
Resize = (byte)(Resize ? 1 : 0),
|
||||
PreserveAlphaCoverage = (byte)(PreserveAlphaCoverage ? 1 : 0),
|
||||
PreserveAlphaCoverageReference = PreserveAlphaCoverageReference,
|
||||
Scale = Scale,
|
||||
Size = Size,
|
||||
MaxSize = (int)MaxSize,
|
||||
TextureGroup = TextureGroup,
|
||||
};
|
||||
if (Sprites != null && Sprites.Count > 0)
|
||||
{
|
||||
int count = Sprites.Count;
|
||||
options.SpriteAreas = new Rectangle[count];
|
||||
options.SpriteNames = new string[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
options.SpriteAreas[i] = Sprites[i].Area;
|
||||
options.SpriteNames[i] = Sprites[i].Name;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
options.SpriteAreas = null;
|
||||
options.SpriteNames = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal void FromInternal(ref InternalOptions options)
|
||||
{
|
||||
Type = (CustomTextureFormatType)(int)options.Type;
|
||||
IsAtlas = options.IsAtlas != 0;
|
||||
NeverStream = options.NeverStream != 0;
|
||||
Compress = options.Compress != 0;
|
||||
IndependentChannels = options.IndependentChannels != 0;
|
||||
sRGB = options.sRGB != 0;
|
||||
GenerateMipMaps = options.GenerateMipMaps != 0;
|
||||
FlipY = options.FlipY != 0;
|
||||
Resize = options.Resize != 0;
|
||||
PreserveAlphaCoverage = options.PreserveAlphaCoverage != 0;
|
||||
PreserveAlphaCoverageReference = options.PreserveAlphaCoverageReference;
|
||||
Scale = options.Scale;
|
||||
MaxSize = ConvertMaxSize(options.MaxSize);
|
||||
TextureGroup = options.TextureGroup;
|
||||
Size = options.Size;
|
||||
if (options.SpriteAreas != null)
|
||||
{
|
||||
int spritesCount = options.SpriteAreas.Length;
|
||||
Sprites.Capacity = spritesCount;
|
||||
for (int i = 0; i < spritesCount; i++)
|
||||
{
|
||||
Sprites.Add(new SpriteInfo(options.SpriteAreas[i], options.SpriteNames[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries the restore the asset import options from the target resource file.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="assetPath">The asset path.</param>
|
||||
/// <returns>True settings has been restored, otherwise false.</returns>
|
||||
public static bool TryRestore(ref TextureImportSettings options, string assetPath)
|
||||
{
|
||||
if (TextureImportEntry.Internal_GetTextureImportOptions(assetPath, out var internalOptions))
|
||||
{
|
||||
// Restore settings
|
||||
options.FromInternal(ref internalOptions);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
[EditorDisplay(null, EditorDisplayAttribute.InlineStyle)]
|
||||
public TextureTool.Options Settings = TextureTool.Options.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -408,7 +110,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// <seealso cref="AssetImportEntry" />
|
||||
public class TextureImportEntry : AssetImportEntry
|
||||
{
|
||||
private TextureImportSettings _settings = new TextureImportSettings();
|
||||
private TextureImportSettings _settings = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TextureImportEntry"/> class.
|
||||
@@ -423,15 +125,15 @@ namespace FlaxEditor.Content.Import
|
||||
if (extension == ".raw")
|
||||
{
|
||||
// Raw image data in 16bit gray-scale, preserve the quality
|
||||
_settings.Type = TextureImportSettings.CustomTextureFormatType.HdrRGBA;
|
||||
_settings.Compress = false;
|
||||
_settings.Settings.Type = TextureFormatType.HdrRGBA;
|
||||
_settings.Settings.Compress = false;
|
||||
}
|
||||
else if (extension == ".hdr")
|
||||
{
|
||||
// HDR sky texture
|
||||
_settings.Type = TextureImportSettings.CustomTextureFormatType.HdrRGB;
|
||||
_settings.Settings.Type = TextureFormatType.HdrRGB;
|
||||
}
|
||||
else if (_settings.Type != TextureImportSettings.CustomTextureFormatType.ColorRGB)
|
||||
else if (_settings.Settings.Type != TextureFormatType.ColorRGB)
|
||||
{
|
||||
// Skip checking
|
||||
}
|
||||
@@ -443,7 +145,7 @@ namespace FlaxEditor.Content.Import
|
||||
|| snl.EndsWith("normals"))
|
||||
{
|
||||
// Normal map
|
||||
_settings.Type = TextureImportSettings.CustomTextureFormatType.NormalMap;
|
||||
_settings.Settings.Type = TextureFormatType.NormalMap;
|
||||
}
|
||||
else if (snl.EndsWith("_d")
|
||||
|| snl.Contains("diffuse")
|
||||
@@ -454,8 +156,8 @@ namespace FlaxEditor.Content.Import
|
||||
|| snl.Contains("albedo"))
|
||||
{
|
||||
// Albedo or diffuse map
|
||||
_settings.Type = TextureImportSettings.CustomTextureFormatType.ColorRGB;
|
||||
_settings.sRGB = true;
|
||||
_settings.Settings.Type = TextureFormatType.ColorRGB;
|
||||
_settings.Settings.sRGB = true;
|
||||
}
|
||||
else if (snl.EndsWith("ao")
|
||||
|| snl.EndsWith("ambientocclusion")
|
||||
@@ -478,11 +180,11 @@ namespace FlaxEditor.Content.Import
|
||||
|| snl.EndsWith("metallic"))
|
||||
{
|
||||
// Glossiness, metalness, ambient occlusion, displacement, height, cavity or specular
|
||||
_settings.Type = TextureImportSettings.CustomTextureFormatType.GrayScale;
|
||||
_settings.Settings.Type = TextureFormatType.GrayScale;
|
||||
}
|
||||
|
||||
// Try to restore target asset texture import options (useful for fast reimport)
|
||||
TextureImportSettings.TryRestore(ref _settings, ResultUrl);
|
||||
Editor.TryRestoreImportOptions(ref _settings.Settings, ResultUrl);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -491,11 +193,18 @@ namespace FlaxEditor.Content.Import
|
||||
/// <inheritdoc />
|
||||
public override bool TryOverrideSettings(object settings)
|
||||
{
|
||||
if (settings is TextureImportSettings o)
|
||||
if (settings is TextureImportSettings s)
|
||||
{
|
||||
var sprites = o.Sprites ?? _settings.Sprites; // Preserve sprites if not specified to override
|
||||
_settings = o;
|
||||
_settings.Sprites = sprites;
|
||||
var sprites = s.Settings.Sprites ?? _settings.Settings.Sprites; // Preserve sprites if not specified to override
|
||||
_settings.Settings = s.Settings;
|
||||
_settings.Settings.Sprites = sprites;
|
||||
return true;
|
||||
}
|
||||
if (settings is TextureTool.Options o)
|
||||
{
|
||||
var sprites = o.Sprites ?? _settings.Settings.Sprites; // Preserve sprites if not specified to override
|
||||
_settings.Settings = o;
|
||||
_settings.Settings.Sprites = sprites;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -504,14 +213,7 @@ namespace FlaxEditor.Content.Import
|
||||
/// <inheritdoc />
|
||||
public override bool Import()
|
||||
{
|
||||
return Editor.Import(SourceUrl, ResultUrl, _settings);
|
||||
return Editor.Import(SourceUrl, ResultUrl, _settings.Settings);
|
||||
}
|
||||
|
||||
#region Internal Calls
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_GetTextureImportOptions(string path, out TextureImportSettings.InternalOptions result);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,15 @@ namespace FlaxEditor.Content
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the asset.
|
||||
/// </summary>
|
||||
/// <returns>The asset object.</returns>
|
||||
public Asset LoadAsync()
|
||||
{
|
||||
return FlaxEngine.Content.LoadAsync<Asset>(ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads the asset (if it's loaded).
|
||||
/// </summary>
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Reflection;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Utilities;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
@@ -134,7 +135,7 @@ namespace FlaxEditor.Content
|
||||
_index = index;
|
||||
type.Asset.GetMethodSignature(index, out _name, out _flags, out var returnTypeName, out var paramNames, out var paramTypeNames, out var paramOuts);
|
||||
_returnType = TypeUtils.GetType(returnTypeName);
|
||||
if (paramNames.Length != 0)
|
||||
if (paramNames != null && paramNames.Length != 0)
|
||||
{
|
||||
_parameters = new ScriptMemberInfo.Parameter[paramNames.Length];
|
||||
for (int i = 0; i < _parameters.Length; i++)
|
||||
@@ -310,7 +311,10 @@ namespace FlaxEditor.Content
|
||||
|
||||
internal void Dispose()
|
||||
{
|
||||
OnAssetReloading(_asset);
|
||||
if (_parameters != null)
|
||||
{
|
||||
OnAssetReloading(_asset);
|
||||
}
|
||||
_asset = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
@@ -42,7 +43,7 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
|
||||
{
|
||||
var type = Scripting.TypeUtils.GetType(typeName).Type;
|
||||
var type = TypeUtils.GetType(typeName).Type;
|
||||
|
||||
if (typeof(TextureBase).IsAssignableFrom(type))
|
||||
return new TextureAssetItem(path, ref id, typeName, type);
|
||||
|
||||
@@ -59,7 +59,10 @@ namespace FlaxEditor.Content
|
||||
|
||||
// Check if asset is streamed enough
|
||||
var asset = (SkinnedModel)request.Asset;
|
||||
return asset.LoadedLODs >= Mathf.Max(1, (int)(asset.LODs.Length * ThumbnailsModule.MinimumRequiredResourcesQuality));
|
||||
var lods = asset.LODs.Length;
|
||||
if (asset.IsLoaded && lods == 0)
|
||||
return true; // Skeleton-only model
|
||||
return asset.LoadedLODs >= Mathf.Max(1, (int)(lods * ThumbnailsModule.MinimumRequiredResourcesQuality));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -8,6 +8,7 @@ using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
|
||||
@@ -115,9 +115,19 @@ API_ENUM() enum class BuildPlatform
|
||||
/// </summary>
|
||||
API_ENUM(Attributes="EditorDisplay(null, \"Mac x64\")")
|
||||
MacOSx64 = 12,
|
||||
};
|
||||
|
||||
extern FLAXENGINE_API const Char* ToString(const BuildPlatform platform);
|
||||
/// <summary>
|
||||
/// MacOS (ARM64 Apple Silicon)
|
||||
/// </summary>
|
||||
API_ENUM(Attributes="EditorDisplay(null, \"Mac ARM64\")")
|
||||
MacOSARM64 = 13,
|
||||
|
||||
/// <summary>
|
||||
/// iOS (ARM64)
|
||||
/// </summary>
|
||||
API_ENUM(Attributes="EditorDisplay(null, \"iOS ARM64\")")
|
||||
iOSARM64 = 14,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Game build configuration modes.
|
||||
@@ -140,7 +150,35 @@ API_ENUM() enum class BuildConfiguration
|
||||
Release = 2,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// .NET Ahead of Time Compilation (AOT) modes.
|
||||
/// </summary>
|
||||
enum class DotNetAOTModes
|
||||
{
|
||||
/// <summary>
|
||||
/// AOT is not used.
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Use .NET Native IL Compiler (shorten as ILC) to convert all C# assemblies in native platform executable binary.
|
||||
/// </summary>
|
||||
ILC,
|
||||
|
||||
/// <summary>
|
||||
/// Use Mono AOT to cross-compile all used C# assemblies into native platform shared libraries.
|
||||
/// </summary>
|
||||
MonoAOTDynamic,
|
||||
|
||||
/// <summary>
|
||||
/// Use Mono AOT to cross-compile all used C# assemblies into native platform static libraries which can be linked into a single shared library.
|
||||
/// </summary>
|
||||
MonoAOTStatic,
|
||||
};
|
||||
|
||||
extern FLAXENGINE_API const Char* ToString(const BuildPlatform platform);
|
||||
extern FLAXENGINE_API const Char* ToString(const BuildConfiguration configuration);
|
||||
extern FLAXENGINE_API const Char* ToString(const DotNetAOTModes mode);
|
||||
|
||||
#define BUILD_STEP_CANCEL_CHECK if (GameCooker::IsCancelRequested()) return true
|
||||
|
||||
@@ -188,7 +226,7 @@ public:
|
||||
API_FIELD(ReadOnly) String OriginalOutputPath;
|
||||
|
||||
/// <summary>
|
||||
/// The output path for data files (Content, Mono, etc.).
|
||||
/// The output path for data files (Content, Dotnet, Mono, etc.).
|
||||
/// </summary>
|
||||
API_FIELD(ReadOnly) String DataOutputPath;
|
||||
|
||||
@@ -300,15 +338,18 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the absolute path to the Platform Data folder that contains the binary files used by the current build configuration.
|
||||
/// </summary>
|
||||
/// <returns>The platform data folder path.</returns>
|
||||
String GetGameBinariesPath() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the absolute path to the platform folder that contains the dependency files used by the current build configuration.
|
||||
/// </summary>
|
||||
/// <returns>The platform deps folder path.</returns>
|
||||
String GetPlatformBinariesRoot() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the platform and architecture for the current BuildPlatform.
|
||||
/// </summary>
|
||||
void GetBuildPlatformName(const Char*& platform, const Char*& architecture) const;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
@@ -368,17 +409,15 @@ public:
|
||||
|
||||
public:
|
||||
|
||||
void Error(const String& msg);
|
||||
void Error(const StringView& msg);
|
||||
|
||||
void Error(const String& msg)
|
||||
{
|
||||
Error(StringView(msg));
|
||||
}
|
||||
|
||||
void Error(const Char* msg)
|
||||
{
|
||||
Error(String(msg));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Error(const Char* format, const Args& ... args)
|
||||
{
|
||||
const String msg = String::Format(format, args...);
|
||||
Error(msg);
|
||||
Error(StringView(msg));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
#include "GameCooker.h"
|
||||
#include "PlatformTools.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include "Engine/Scripting/MainThreadManagedInvokeAction.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MTypes.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MException.h"
|
||||
#include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
#include "Engine/Scripting/BinaryModule.h"
|
||||
@@ -23,12 +24,12 @@
|
||||
#include "Steps/CookAssetsStep.h"
|
||||
#include "Steps/PostProcessStep.h"
|
||||
#include "Engine/Platform/ConditionVariable.h"
|
||||
#include "Engine/Platform/CreateProcessSettings.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MDomain.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MCore.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
|
||||
#include "Engine/Content/JsonAsset.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Scripting/MException.h"
|
||||
#if PLATFORM_TOOLS_WINDOWS
|
||||
#include "Platform/Windows/WindowsPlatformTools.h"
|
||||
#include "Engine/Platform/Windows/WindowsPlatformSettings.h"
|
||||
@@ -63,6 +64,10 @@
|
||||
#include "Platform/Mac/MacPlatformTools.h"
|
||||
#include "Engine/Platform/Mac/MacPlatformSettings.h"
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_IOS
|
||||
#include "Platform/iOS/iOSPlatformTools.h"
|
||||
#include "Engine/Platform/iOS/iOSPlatformSettings.h"
|
||||
#endif
|
||||
|
||||
namespace GameCookerImpl
|
||||
{
|
||||
@@ -139,8 +144,12 @@ const Char* ToString(const BuildPlatform platform)
|
||||
return TEXT("PlayStation 5");
|
||||
case BuildPlatform::MacOSx64:
|
||||
return TEXT("Mac x64");
|
||||
case BuildPlatform::MacOSARM64:
|
||||
return TEXT("Mac ARM64");
|
||||
case BuildPlatform::iOSARM64:
|
||||
return TEXT("iOS ARM64");
|
||||
default:
|
||||
return TEXT("?");
|
||||
return TEXT("");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,10 +164,37 @@ const Char* ToString(const BuildConfiguration configuration)
|
||||
case BuildConfiguration::Release:
|
||||
return TEXT("Release");
|
||||
default:
|
||||
return TEXT("?");
|
||||
return TEXT("");
|
||||
}
|
||||
}
|
||||
|
||||
const Char* ToString(const DotNetAOTModes mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case DotNetAOTModes::None:
|
||||
return TEXT("None");
|
||||
case DotNetAOTModes::ILC:
|
||||
return TEXT("ILC");
|
||||
case DotNetAOTModes::MonoAOTDynamic:
|
||||
return TEXT("MonoAOTDynamic");
|
||||
case DotNetAOTModes::MonoAOTStatic:
|
||||
return TEXT("MonoAOTStatic");
|
||||
default:
|
||||
return TEXT("");
|
||||
}
|
||||
}
|
||||
|
||||
bool PlatformTools::IsNativeCodeFile(CookingData& data, const String& file)
|
||||
{
|
||||
const String filename = StringUtils::GetFileName(file);
|
||||
if (filename.Contains(TEXT(".CSharp")) ||
|
||||
filename.Contains(TEXT("Newtonsoft.Json")))
|
||||
return false;
|
||||
// TODO: maybe use Mono.Cecil via Flax.Build to read assembly image metadata and check if it contains C#?
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CookingData::AssetTypeStatistics::operator<(const AssetTypeStatistics& other) const
|
||||
{
|
||||
if (ContentSize != other.ContentSize)
|
||||
@@ -211,6 +247,71 @@ String CookingData::GetPlatformBinariesRoot() const
|
||||
return Globals::StartupFolder / TEXT("Source/Platforms") / Tools->GetName() / TEXT("Binaries");
|
||||
}
|
||||
|
||||
void CookingData::GetBuildPlatformName(const Char*& platform, const Char*& architecture) const
|
||||
{
|
||||
switch (Platform)
|
||||
{
|
||||
case BuildPlatform::Windows32:
|
||||
platform = TEXT("Windows");
|
||||
architecture = TEXT("x86");
|
||||
break;
|
||||
case BuildPlatform::Windows64:
|
||||
platform = TEXT("Windows");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::UWPx86:
|
||||
platform = TEXT("UWP");
|
||||
architecture = TEXT("x86");
|
||||
break;
|
||||
case BuildPlatform::UWPx64:
|
||||
platform = TEXT("UWP");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::XboxOne:
|
||||
platform = TEXT("XboxOne");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::LinuxX64:
|
||||
platform = TEXT("Linux");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::PS4:
|
||||
platform = TEXT("PS4");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::XboxScarlett:
|
||||
platform = TEXT("XboxScarlett");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::AndroidARM64:
|
||||
platform = TEXT("Android");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
case BuildPlatform::Switch:
|
||||
platform = TEXT("Switch");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
case BuildPlatform::PS5:
|
||||
platform = TEXT("PS5");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::MacOSx64:
|
||||
platform = TEXT("Mac");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::MacOSARM64:
|
||||
platform = TEXT("Mac");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
case BuildPlatform::iOSARM64:
|
||||
platform = TEXT("iOS");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
default:
|
||||
LOG(Fatal, "Unknown or unsupported build platform.");
|
||||
}
|
||||
}
|
||||
|
||||
void CookingData::StepProgress(const String& info, const float stepProgress) const
|
||||
{
|
||||
const float singleStepProgress = 1.0f / (StepsCount + 1);
|
||||
@@ -242,7 +343,7 @@ void CookingData::AddRootEngineAsset(const String& internalPath)
|
||||
}
|
||||
}
|
||||
|
||||
void CookingData::Error(const String& msg)
|
||||
void CookingData::Error(const StringView& msg)
|
||||
{
|
||||
LOG_STR(Error, msg);
|
||||
}
|
||||
@@ -340,6 +441,14 @@ PlatformTools* GameCooker::GetTools(BuildPlatform platform)
|
||||
case BuildPlatform::MacOSx64:
|
||||
result = New<MacPlatformTools>(ArchitectureType::x64);
|
||||
break;
|
||||
case BuildPlatform::MacOSARM64:
|
||||
result = New<MacPlatformTools>(ArchitectureType::ARM64);
|
||||
break;
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_IOS
|
||||
case BuildPlatform::iOSARM64:
|
||||
result = New<iOSPlatformTools>();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
Tools.Add(platform, result);
|
||||
@@ -470,7 +579,10 @@ void GameCooker::GetCurrentPlatform(PlatformType& platform, BuildPlatform& build
|
||||
buildPlatform = BuildPlatform::PS5;
|
||||
break;
|
||||
case PlatformType::Mac:
|
||||
buildPlatform = BuildPlatform::MacOSx64;
|
||||
buildPlatform = PLATFORM_ARCH_ARM || PLATFORM_ARCH_ARM64 ? BuildPlatform::MacOSARM64 : BuildPlatform::MacOSx64;
|
||||
break;
|
||||
case PlatformType::iOS:
|
||||
buildPlatform = BuildPlatform::iOSARM64;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
@@ -511,9 +623,9 @@ void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
|
||||
ASSERT(GameCookerImpl::Internal_OnCollectAssets);
|
||||
}
|
||||
|
||||
MCore::AttachThread();
|
||||
MCore::Thread::Attach();
|
||||
MObject* exception = nullptr;
|
||||
auto list = (MonoArray*)Internal_OnCollectAssets->Invoke(nullptr, nullptr, &exception);
|
||||
auto list = (MArray*)Internal_OnCollectAssets->Invoke(nullptr, nullptr, &exception);
|
||||
if (exception)
|
||||
{
|
||||
MException ex(exception);
|
||||
@@ -547,13 +659,13 @@ bool GameCookerImpl::Build()
|
||||
Steps.Add(New<PostProcessStep>());
|
||||
}
|
||||
|
||||
MCore::AttachThread();
|
||||
MCore::Thread::Attach();
|
||||
|
||||
// Build Started
|
||||
CallEvent(GameCooker::EventType::BuildStarted);
|
||||
data.Tools->OnBuildStarted(data);
|
||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||
Steps[stepIndex]->OnBuildStarted(data);
|
||||
data.Tools->OnBuildStarted(data);
|
||||
data.InitProgress(Steps.Count());
|
||||
|
||||
// Execute all steps in a sequence
|
||||
@@ -602,7 +714,15 @@ bool GameCookerImpl::Build()
|
||||
const String commandLine = commandLineFormat.HasChars() ? String::Format(*commandLineFormat, gameArgs) : gameArgs;
|
||||
if (workingDir.IsEmpty())
|
||||
workingDir = data.NativeCodeOutputPath;
|
||||
Platform::StartProcess(executableFile, commandLine, workingDir);
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = executableFile;
|
||||
procSettings.Arguments = commandLine;
|
||||
procSettings.WorkingDirectory = workingDir;
|
||||
procSettings.HiddenWindow = false;
|
||||
procSettings.WaitForEnd = false;
|
||||
procSettings.LogOutput = false;
|
||||
procSettings.ShellExecute = true;
|
||||
Platform::CreateProcess(procSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -612,9 +732,9 @@ bool GameCookerImpl::Build()
|
||||
}
|
||||
IsRunning = false;
|
||||
CancelFlag = 0;
|
||||
data.Tools->OnBuildEnded(data, failed);
|
||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||
Steps[stepIndex]->OnBuildEnded(data, failed);
|
||||
data.Tools->OnBuildEnded(data, failed);
|
||||
CallEvent(failed ? GameCooker::EventType::BuildFailed : GameCooker::EventType::BuildDone);
|
||||
Delete(Data);
|
||||
Data = nullptr;
|
||||
@@ -667,7 +787,7 @@ void GameCookerService::Update()
|
||||
}
|
||||
|
||||
MainThreadManagedInvokeAction::ParamsBuilder params;
|
||||
params.AddParam(ProgressMsg, Scripting::GetScriptsDomain()->GetNative());
|
||||
params.AddParam(ProgressMsg, Scripting::GetScriptsDomain());
|
||||
params.AddParam(ProgressValue);
|
||||
MainThreadManagedInvokeAction::Invoke(Internal_OnProgress, params);
|
||||
GameCooker::OnProgress(ProgressMsg, ProgressValue);
|
||||
|
||||
@@ -103,7 +103,9 @@ namespace FlaxEditor
|
||||
case BuildPlatform.AndroidARM64: return PlatformType.Android;
|
||||
case BuildPlatform.XboxScarlett: return PlatformType.XboxScarlett;
|
||||
case BuildPlatform.Switch: return PlatformType.Switch;
|
||||
case BuildPlatform.MacOSARM64:
|
||||
case BuildPlatform.MacOSx64: return PlatformType.Mac;
|
||||
case BuildPlatform.iOSARM64: return PlatformType.iOS;
|
||||
default: throw new ArgumentOutOfRangeException(nameof(buildPlatform), buildPlatform, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/CreateProcessSettings.h"
|
||||
#include "Engine/Platform/Android/AndroidPlatformSettings.h"
|
||||
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||
#include "Engine/Graphics/Textures/TextureData.h"
|
||||
@@ -115,8 +116,6 @@ void AndroidPlatformTools::OnBuildStarted(CookingData& data)
|
||||
data.DataOutputPath /= TEXT("app/assets");
|
||||
data.NativeCodeOutputPath /= TEXT("app/assets");
|
||||
data.ManagedCodeOutputPath /= TEXT("app/assets");
|
||||
|
||||
PlatformTools::OnBuildStarted(data);
|
||||
}
|
||||
|
||||
bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
@@ -140,33 +139,8 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
|
||||
// Setup package name (eg. com.company.project)
|
||||
String packageName = platformSettings->PackageName;
|
||||
{
|
||||
String productName = gameSettings->ProductName;
|
||||
productName.Replace(TEXT(" "), TEXT(""));
|
||||
productName.Replace(TEXT("."), TEXT(""));
|
||||
productName.Replace(TEXT("-"), TEXT(""));
|
||||
String companyName = gameSettings->CompanyName;
|
||||
companyName.Replace(TEXT(" "), TEXT(""));
|
||||
companyName.Replace(TEXT("."), TEXT(""));
|
||||
companyName.Replace(TEXT("-"), TEXT(""));
|
||||
packageName.Replace(TEXT("${PROJECT_NAME}"), *productName, StringSearchCase::IgnoreCase);
|
||||
packageName.Replace(TEXT("${COMPANY_NAME}"), *companyName, StringSearchCase::IgnoreCase);
|
||||
packageName = packageName.ToLower();
|
||||
for (int32 i = 0; i < packageName.Length(); i++)
|
||||
{
|
||||
const auto c = packageName[i];
|
||||
if (c != '_' && c != '.' && !StringUtils::IsAlnum(c))
|
||||
{
|
||||
LOG(Error, "Android Package Name \'{0}\' contains invalid character. Only letters, numbers, dots and underscore characters are allowed.", packageName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (packageName.IsEmpty())
|
||||
{
|
||||
LOG(Error, "Android Package Name is empty.", packageName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (EditorUtilities::FormatAppPackageName(packageName))
|
||||
return true;
|
||||
|
||||
// Setup Android application permissions
|
||||
HashSet<String> permissionsList;
|
||||
@@ -267,7 +241,7 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate Mono files hash id used to skip deploying Mono files if already extracted on device (Mono cannot access files packed into .apk via unix file access)
|
||||
// Generate Dotnet files hash id used to skip deploying Dotnet files if already extracted on device (Dotnet cannot access files packed into .apk via unix file access)
|
||||
File::WriteAllText(assetsPath / TEXT("hash.txt"), Guid::New().ToString(), Encoding::ANSI);
|
||||
|
||||
// TODO: expose event to inject custom gradle and manifest options or custom binaries into app
|
||||
@@ -309,11 +283,13 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
Platform::RunProcess(String::Format(TEXT("chmod +x \"{0}/gradlew\""), data.OriginalOutputPath), data.OriginalOutputPath, Dictionary<String, String>(), true);
|
||||
#endif
|
||||
const bool distributionPackage = buildSettings->ForDistribution;
|
||||
const String gradleCommand = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));
|
||||
const int32 result = Platform::RunProcess(gradleCommand, data.OriginalOutputPath, Dictionary<String, String>(), true);
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));
|
||||
procSettings.WorkingDirectory = data.OriginalOutputPath;
|
||||
const int32 result = Platform::CreateProcess(procSettings);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(TEXT("Failed to build Gradle project into package (result code: {0}). See log for more info."), result);
|
||||
data.Error(String::Format(TEXT("Failed to build Gradle project into package (result code: {0}). See log for more info."), result));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "GDKPlatformTools.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/CreateProcessSettings.h"
|
||||
#include "Engine/Platform/GDK/GDKPlatformSettings.h"
|
||||
#include "Engine/Core/Types/StringBuilder.h"
|
||||
#include "Engine/Core/Collections/Sorting.h"
|
||||
@@ -36,24 +37,9 @@ GDKPlatformTools::GDKPlatformTools()
|
||||
}
|
||||
}
|
||||
|
||||
bool GDKPlatformTools::UseAOT() const
|
||||
DotNetAOTModes GDKPlatformTools::UseAOT() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GDKPlatformTools::OnScriptsStepDone(CookingData& data)
|
||||
{
|
||||
// Override Newtonsoft.Json.dll for some platforms (that don't support runtime code generation)
|
||||
const String customBinPath = data.GetPlatformBinariesRoot() / TEXT("Newtonsoft.Json.dll");
|
||||
const String assembliesPath = data.ManagedCodeOutputPath;
|
||||
if (FileSystem::CopyFile(assembliesPath / TEXT("Newtonsoft.Json.dll"), customBinPath))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy deloy custom assembly."));
|
||||
return true;
|
||||
}
|
||||
FileSystem::DeleteFile(assembliesPath / TEXT("Newtonsoft.Json.pdb"));
|
||||
|
||||
return false;
|
||||
return DotNetAOTModes::MonoAOTDynamic;
|
||||
}
|
||||
|
||||
bool GDKPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
@@ -66,7 +52,7 @@ bool GDKPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
files.Add(binPath / executableFilename);
|
||||
if (!FileSystem::FileExists(files[0]))
|
||||
{
|
||||
data.Error(TEXT("Missing executable file ({0})."), files[0]);
|
||||
data.Error(String::Format(TEXT("Missing executable file ({0})."), files[0]));
|
||||
return true;
|
||||
}
|
||||
FileSystem::DirectoryGetFiles(files, binPath, TEXT("*.dll"), DirectorySearchOption::TopDirectoryOnly);
|
||||
@@ -74,7 +60,7 @@ bool GDKPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
{
|
||||
if (FileSystem::CopyFile(data.NativeCodeOutputPath / StringUtils::GetFileName(files[i]), files[i]))
|
||||
{
|
||||
data.Error(TEXT("Failed to setup output directory (file {0})."), files[i]);
|
||||
data.Error(String::Format(TEXT("Failed to setup output directory (file {0})."), files[i]));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -82,85 +68,6 @@ bool GDKPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
return false;
|
||||
}
|
||||
|
||||
void GDKPlatformTools::OnConfigureAOT(CookingData& data, AotConfig& config)
|
||||
{
|
||||
const auto platformDataPath = data.GetPlatformBinariesRoot();
|
||||
const bool useInterpreter = true; // TODO: use Full AOT on GDK
|
||||
const bool enableDebug = data.Configuration != BuildConfiguration::Release;
|
||||
const Char* aotMode = useInterpreter ? TEXT("full,interp") : TEXT("full");
|
||||
const Char* debugMode = enableDebug ? TEXT("soft-debug") : TEXT("nodebug");
|
||||
config.AotCompilerArgs = String::Format(TEXT("--aot={0},verbose,stats,print-skipped,{1} -O=all"), aotMode, debugMode);
|
||||
if (enableDebug)
|
||||
config.AotCompilerArgs = TEXT("--debug ") + config.AotCompilerArgs;
|
||||
config.AotCompilerPath = platformDataPath / TEXT("Tools/mono.exe");
|
||||
}
|
||||
|
||||
bool GDKPlatformTools::OnPerformAOT(CookingData& data, AotConfig& config, const String& assemblyPath)
|
||||
{
|
||||
// Skip .dll.dll which could be a false result from the previous AOT which could fail
|
||||
if (assemblyPath.EndsWith(TEXT(".dll.dll")))
|
||||
{
|
||||
LOG(Warning, "Skip AOT for file '{0}' as it can be a result from the previous task", assemblyPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if skip this assembly (could be already processed)
|
||||
const String filename = StringUtils::GetFileName(assemblyPath);
|
||||
const String outputPath = config.AotCachePath / filename + TEXT(".dll");
|
||||
if (FileSystem::FileExists(outputPath) && FileSystem::GetFileLastEditTime(assemblyPath) < FileSystem::GetFileLastEditTime(outputPath))
|
||||
return false;
|
||||
LOG(Info, "Calling AOT tool for \"{0}\"", assemblyPath);
|
||||
|
||||
// Cleanup temporary results (fromm the previous AT that fail or sth)
|
||||
const String resultPath = assemblyPath + TEXT(".dll");
|
||||
const String resultPathExp = resultPath + TEXT(".exp");
|
||||
const String resultPathLib = resultPath + TEXT(".lib");
|
||||
const String resultPathPdb = resultPath + TEXT(".pdb");
|
||||
if (FileSystem::FileExists(resultPath))
|
||||
FileSystem::DeleteFile(resultPath);
|
||||
if (FileSystem::FileExists(resultPathExp))
|
||||
FileSystem::DeleteFile(resultPathExp);
|
||||
if (FileSystem::FileExists(resultPathLib))
|
||||
FileSystem::DeleteFile(resultPathLib);
|
||||
if (FileSystem::FileExists(resultPathPdb))
|
||||
FileSystem::DeleteFile(resultPathPdb);
|
||||
|
||||
// Call tool
|
||||
const String workingDir = StringUtils::GetDirectoryName(config.AotCompilerPath);
|
||||
const String command = String::Format(TEXT("\"{0}\" {1} \"{2}\""), config.AotCompilerPath, config.AotCompilerArgs, assemblyPath);
|
||||
const int32 result = Platform::RunProcess(command, workingDir, config.EnvVars);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(TEXT("AOT tool execution failed with result code {1} for assembly \"{0}\". See log for more info."), assemblyPath, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy result
|
||||
if (FileSystem::CopyFile(outputPath, resultPath))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy the AOT tool result file. It can be missing."));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy pdb file if exists
|
||||
if (data.Configuration != BuildConfiguration::Release && FileSystem::FileExists(resultPathPdb))
|
||||
{
|
||||
FileSystem::CopyFile(config.AotCachePath / StringUtils::GetFileName(resultPathPdb), resultPathPdb);
|
||||
}
|
||||
|
||||
// Clean intermediate results
|
||||
if (FileSystem::DeleteFile(resultPath)
|
||||
|| (FileSystem::FileExists(resultPathExp) && FileSystem::DeleteFile(resultPathExp))
|
||||
|| (FileSystem::FileExists(resultPathLib) && FileSystem::DeleteFile(resultPathLib))
|
||||
|| (FileSystem::FileExists(resultPathPdb) && FileSystem::DeleteFile(resultPathPdb))
|
||||
)
|
||||
{
|
||||
LOG(Warning, "Failed to remove the AOT tool result file(s).");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GDKPlatformTools::OnPostProcess(CookingData& data, GDKPlatformSettings* platformSettings)
|
||||
{
|
||||
// Configuration
|
||||
@@ -275,8 +182,10 @@ bool GDKPlatformTools::OnPostProcess(CookingData& data, GDKPlatformSettings* pla
|
||||
data.StepProgress(TEXT("Generating package layout"), 0.3f);
|
||||
const String gdkBinPath = _gdkPath / TEXT("../bin");
|
||||
const String makePkgPath = gdkBinPath / TEXT("MakePkg.exe");
|
||||
const String command = String::Format(TEXT("\"{0}\" genmap /f layout.xml /d \"{1}\""), makePkgPath, data.DataOutputPath);
|
||||
const int32 result = Platform::RunProcess(command, data.DataOutputPath);
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = String::Format(TEXT("\"{0}\" genmap /f layout.xml /d \"{1}\""), makePkgPath, data.DataOutputPath);
|
||||
procSettings.WorkingDirectory = data.DataOutputPath;
|
||||
const int32 result = Platform::CreateProcess(procSettings);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(TEXT("Failed to generate package layout."));
|
||||
|
||||
@@ -26,11 +26,8 @@ public:
|
||||
public:
|
||||
|
||||
// [PlatformTools]
|
||||
bool UseAOT() const override;
|
||||
bool OnScriptsStepDone(CookingData& data) override;
|
||||
DotNetAOTModes UseAOT() const override;
|
||||
bool OnDeployBinaries(CookingData& data) override;
|
||||
void OnConfigureAOT(CookingData& data, AotConfig& config) override;
|
||||
bool OnPerformAOT(CookingData& data, AotConfig& config, const String& assemblyPath) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_TOOLS_LINUX
|
||||
|
||||
@@ -34,6 +34,11 @@ ArchitectureType LinuxPlatformTools::GetArchitecture() const
|
||||
return ArchitectureType::x64;
|
||||
}
|
||||
|
||||
bool LinuxPlatformTools::UseSystemDotnet() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinuxPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
{
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
const Char* GetName() const override;
|
||||
PlatformType GetPlatform() const override;
|
||||
ArchitectureType GetArchitecture() const override;
|
||||
bool UseSystemDotnet() const override;
|
||||
bool OnDeployBinaries(CookingData& data) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_TOOLS_MAC
|
||||
|
||||
@@ -59,6 +59,11 @@ ArchitectureType MacPlatformTools::GetArchitecture() const
|
||||
return _arch;
|
||||
}
|
||||
|
||||
bool MacPlatformTools::UseSystemDotnet() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacPlatformTools::IsNativeCodeFile(CookingData& data, const String& file)
|
||||
{
|
||||
String extension = FileSystem::GetExtension(file);
|
||||
@@ -87,33 +92,8 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
|
||||
// Setup package name (eg. com.company.project)
|
||||
String appIdentifier = platformSettings->AppIdentifier;
|
||||
{
|
||||
String productName = gameSettings->ProductName;
|
||||
productName.Replace(TEXT(" "), TEXT(""));
|
||||
productName.Replace(TEXT("."), TEXT(""));
|
||||
productName.Replace(TEXT("-"), TEXT(""));
|
||||
String companyName = gameSettings->CompanyName;
|
||||
companyName.Replace(TEXT(" "), TEXT(""));
|
||||
companyName.Replace(TEXT("."), TEXT(""));
|
||||
companyName.Replace(TEXT("-"), TEXT(""));
|
||||
appIdentifier.Replace(TEXT("${PROJECT_NAME}"), *productName, StringSearchCase::IgnoreCase);
|
||||
appIdentifier.Replace(TEXT("${COMPANY_NAME}"), *companyName, StringSearchCase::IgnoreCase);
|
||||
appIdentifier = appIdentifier.ToLower();
|
||||
for (int32 i = 0; i < appIdentifier.Length(); i++)
|
||||
{
|
||||
const auto c = appIdentifier[i];
|
||||
if (c != '_' && c != '.' && !StringUtils::IsAlnum(c))
|
||||
{
|
||||
LOG(Error, "Apple app identifier \'{0}\' contains invalid character. Only letters, numbers, dots and underscore characters are allowed.", appIdentifier);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (appIdentifier.IsEmpty())
|
||||
{
|
||||
LOG(Error, "Apple app identifier is empty.", appIdentifier);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (EditorUtilities::FormatAppPackageName(appIdentifier))
|
||||
return true;
|
||||
|
||||
// Find executable
|
||||
String executableName;
|
||||
@@ -187,7 +167,7 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
ADD_ENTRY("CFBundlePackageType", "APPL");
|
||||
ADD_ENTRY("NSPrincipalClass", "NSApplication");
|
||||
ADD_ENTRY("LSApplicationCategoryType", "public.app-category.games");
|
||||
ADD_ENTRY("LSMinimumSystemVersion", "10.14");
|
||||
ADD_ENTRY("LSMinimumSystemVersion", "10.15");
|
||||
ADD_ENTRY("CFBundleIconFile", "icon.icns");
|
||||
ADD_ENTRY_STR("CFBundleExecutable", executableName);
|
||||
ADD_ENTRY_STR("CFBundleIdentifier", appIdentifier);
|
||||
@@ -201,10 +181,19 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
|
||||
dict.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("LSMinimumSystemVersionByArchitecture"));
|
||||
xml_node LSMinimumSystemVersionByArchitecture = dict.append_child(PUGIXML_TEXT("dict"));
|
||||
LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("x86_64"));
|
||||
LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("string")).set_child_value(PUGIXML_TEXT("10.14"));
|
||||
switch (_arch)
|
||||
{
|
||||
case ArchitectureType::x64:
|
||||
LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("x86_64"));
|
||||
break;
|
||||
case ArchitectureType::ARM64:
|
||||
LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("key")).set_child_value(PUGIXML_TEXT("arm64"));
|
||||
break;
|
||||
}
|
||||
LSMinimumSystemVersionByArchitecture.append_child(PUGIXML_TEXT("string")).set_child_value(PUGIXML_TEXT("10.15"));
|
||||
|
||||
#undef ADD_ENTRY
|
||||
#undef ADD_ENTRY_STR
|
||||
|
||||
if (!doc.save_file(*StringAnsi(plistPath)))
|
||||
{
|
||||
@@ -215,8 +204,6 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
|
||||
// TODO: sign binaries
|
||||
|
||||
// TODO: expose event to inject custom post-processing before app packaging (eg. third-party plugins)
|
||||
|
||||
// Package application
|
||||
const auto buildSettings = BuildSettings::Get();
|
||||
if (buildSettings->SkipPackaging)
|
||||
@@ -228,7 +215,7 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
const int32 result = Platform::RunProcess(dmgCommand, data.OriginalOutputPath);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(TEXT("Failed to package app (result code: {0}). See log for more info."), result);
|
||||
data.Error(String::Format(TEXT("Failed to package app (result code: {0}). See log for more info."), result));
|
||||
return true;
|
||||
}
|
||||
// TODO: sign dmg
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
const Char* GetName() const override;
|
||||
PlatformType GetPlatform() const override;
|
||||
ArchitectureType GetArchitecture() const override;
|
||||
bool UseSystemDotnet() const override;
|
||||
bool IsNativeCodeFile(CookingData& data, const String& file) override;
|
||||
void OnBuildStarted(CookingData& data) override;
|
||||
bool OnPostProcess(CookingData& data) override;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_TOOLS_UWP
|
||||
|
||||
#include "UWPPlatformTools.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/CreateProcessSettings.h"
|
||||
#include "Engine/Platform/UWP/UWPPlatformSettings.h"
|
||||
#include "Engine/Core/Config/GameSettings.h"
|
||||
#include "Engine/Core/Types/StringBuilder.h"
|
||||
@@ -36,24 +37,9 @@ ArchitectureType UWPPlatformTools::GetArchitecture() const
|
||||
return _arch;
|
||||
}
|
||||
|
||||
bool UWPPlatformTools::UseAOT() const
|
||||
DotNetAOTModes UWPPlatformTools::UseAOT() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UWPPlatformTools::OnScriptsStepDone(CookingData& data)
|
||||
{
|
||||
// Override Newtonsoft.Json.dll for some platforms (that don't support runtime code generation)
|
||||
const String customBinPath = data.GetPlatformBinariesRoot() / TEXT("Newtonsoft.Json.dll");
|
||||
const String assembliesPath = data.ManagedCodeOutputPath;
|
||||
if (FileSystem::CopyFile(assembliesPath / TEXT("Newtonsoft.Json.dll"), customBinPath))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy deploy custom assembly."));
|
||||
return true;
|
||||
}
|
||||
FileSystem::DeleteFile(assembliesPath / TEXT("Newtonsoft.Json.pdb"));
|
||||
|
||||
return false;
|
||||
return DotNetAOTModes::MonoAOTDynamic;
|
||||
}
|
||||
|
||||
bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
@@ -79,7 +65,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
{
|
||||
if (!FileSystem::FileExists(files[i]))
|
||||
{
|
||||
data.Error(TEXT("Missing source file {0}."), files[i]);
|
||||
data.Error(String::Format(TEXT("Missing source file {0}."), files[i]));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -414,90 +400,9 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
return false;
|
||||
}
|
||||
|
||||
void UWPPlatformTools::OnConfigureAOT(CookingData& data, AotConfig& config)
|
||||
{
|
||||
const auto platformDataPath = data.GetPlatformBinariesRoot();
|
||||
const bool useInterpreter = true; // TODO: support using Full AOT instead of interpreter
|
||||
const bool enableDebug = data.Configuration != BuildConfiguration::Release;
|
||||
const Char* aotMode = useInterpreter ? TEXT("full,interp") : TEXT("full");
|
||||
const Char* debugMode = enableDebug ? TEXT("soft-debug") : TEXT("nodebug");
|
||||
config.AotCompilerArgs = String::Format(TEXT("--aot={0},verbose,stats,print-skipped,{1} -O=all"),
|
||||
aotMode,
|
||||
debugMode);
|
||||
if (enableDebug)
|
||||
config.AotCompilerArgs = TEXT("--debug ") + config.AotCompilerArgs;
|
||||
config.AotCompilerPath = platformDataPath / TEXT("Tools/mono.exe");
|
||||
}
|
||||
|
||||
bool UWPPlatformTools::OnPerformAOT(CookingData& data, AotConfig& config, const String& assemblyPath)
|
||||
{
|
||||
// Skip .dll.dll which could be a false result from the previous AOT which could fail
|
||||
if (assemblyPath.EndsWith(TEXT(".dll.dll")))
|
||||
{
|
||||
LOG(Warning, "Skip AOT for file '{0}' as it can be a result from the previous task", assemblyPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if skip this assembly (could be already processed)
|
||||
const String filename = StringUtils::GetFileName(assemblyPath);
|
||||
const String outputPath = config.AotCachePath / filename + TEXT(".dll");
|
||||
if (FileSystem::FileExists(outputPath) && FileSystem::GetFileLastEditTime(assemblyPath) < FileSystem::GetFileLastEditTime(outputPath))
|
||||
return false;
|
||||
LOG(Info, "Calling AOT tool for \"{0}\"", assemblyPath);
|
||||
|
||||
// Cleanup temporary results (fromm the previous AT that fail or sth)
|
||||
const String resultPath = assemblyPath + TEXT(".dll");
|
||||
const String resultPathExp = resultPath + TEXT(".exp");
|
||||
const String resultPathLib = resultPath + TEXT(".lib");
|
||||
const String resultPathPdb = resultPath + TEXT(".pdb");
|
||||
if (FileSystem::FileExists(resultPath))
|
||||
FileSystem::DeleteFile(resultPath);
|
||||
if (FileSystem::FileExists(resultPathExp))
|
||||
FileSystem::DeleteFile(resultPathExp);
|
||||
if (FileSystem::FileExists(resultPathLib))
|
||||
FileSystem::DeleteFile(resultPathLib);
|
||||
if (FileSystem::FileExists(resultPathPdb))
|
||||
FileSystem::DeleteFile(resultPathPdb);
|
||||
|
||||
// Call tool
|
||||
String workingDir = StringUtils::GetDirectoryName(config.AotCompilerPath);
|
||||
String command = String::Format(TEXT("\"{0}\" {1} \"{2}\""), config.AotCompilerPath, config.AotCompilerArgs, assemblyPath);
|
||||
const int32 result = Platform::RunProcess(command, workingDir, config.EnvVars);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(TEXT("AOT tool execution failed with result code {1} for assembly \"{0}\". See log for more info."), assemblyPath, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy result
|
||||
if (FileSystem::CopyFile(outputPath, resultPath))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy the AOT tool result file. It can be missing."));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy pdb file if exists
|
||||
if (data.Configuration != BuildConfiguration::Release && FileSystem::FileExists(resultPathPdb))
|
||||
{
|
||||
FileSystem::CopyFile(config.AotCachePath / StringUtils::GetFileName(resultPathPdb), resultPathPdb);
|
||||
}
|
||||
|
||||
// Clean intermediate results
|
||||
if (FileSystem::DeleteFile(resultPath)
|
||||
|| (FileSystem::FileExists(resultPathExp) && FileSystem::DeleteFile(resultPathExp))
|
||||
|| (FileSystem::FileExists(resultPathLib) && FileSystem::DeleteFile(resultPathLib))
|
||||
|| (FileSystem::FileExists(resultPathPdb) && FileSystem::DeleteFile(resultPathPdb))
|
||||
)
|
||||
{
|
||||
LOG(Warning, "Failed to remove the AOT tool result file(s).");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UWPPlatformTools::OnPostProcess(CookingData& data)
|
||||
{
|
||||
LOG(Error, "UWP (Windows Store) platform has been deprecated and soon will be removed!");
|
||||
LOG(Error, "UWP (Windows Store) platform has been deprecated and is no longer supported");
|
||||
|
||||
// Special case for UWP
|
||||
// FlaxEngine.dll cannot be added to the solution as `Content` item (due to conflicts with C++ /CX FlaxEngine.dll)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -29,11 +29,8 @@ public:
|
||||
const Char* GetName() const override;
|
||||
PlatformType GetPlatform() const override;
|
||||
ArchitectureType GetArchitecture() const override;
|
||||
bool UseAOT() const override;
|
||||
bool OnScriptsStepDone(CookingData& data) override;
|
||||
DotNetAOTModes UseAOT() const override;
|
||||
bool OnDeployBinaries(CookingData& data) override;
|
||||
void OnConfigureAOT(CookingData& data, AotConfig& config) override;
|
||||
bool OnPerformAOT(CookingData& data, AotConfig& config, const String& assemblyPath) override;
|
||||
bool OnPostProcess(CookingData& data) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_TOOLS_WINDOWS
|
||||
|
||||
@@ -33,6 +33,11 @@ ArchitectureType WindowsPlatformTools::GetArchitecture() const
|
||||
return _arch;
|
||||
}
|
||||
|
||||
bool WindowsPlatformTools::UseSystemDotnet() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowsPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
{
|
||||
const auto platformSettings = WindowsPlatformSettings::Get();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
const Char* GetName() const override;
|
||||
PlatformType GetPlatform() const override;
|
||||
ArchitectureType GetArchitecture() const override;
|
||||
bool UseSystemDotnet() const override;
|
||||
bool OnDeployBinaries(CookingData& data) override;
|
||||
void OnRun(CookingData& data, String& executableFile, String& commandLineFormat, String& workingDir) override;
|
||||
};
|
||||
|
||||
284
Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp
Normal file
284
Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp
Normal file
@@ -0,0 +1,284 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_TOOLS_IOS
|
||||
|
||||
#include "iOSPlatformTools.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/CreateProcessSettings.h"
|
||||
#include "Engine/Platform/iOS/iOSPlatformSettings.h"
|
||||
#include "Engine/Core/Config/GameSettings.h"
|
||||
#include "Engine/Core/Config/BuildSettings.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Graphics/Textures/TextureData.h"
|
||||
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/JsonAsset.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Editor/Editor.h"
|
||||
#include "Editor/ProjectInfo.h"
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
|
||||
IMPLEMENT_SETTINGS_GETTER(iOSPlatformSettings, iOSPlatform);
|
||||
|
||||
namespace
|
||||
{
|
||||
String GetAppName()
|
||||
{
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
String productName = gameSettings->ProductName;
|
||||
productName.Replace(TEXT(" "), TEXT(""));
|
||||
productName.Replace(TEXT("."), TEXT(""));
|
||||
productName.Replace(TEXT("-"), TEXT(""));
|
||||
return productName;
|
||||
}
|
||||
|
||||
const Char* GetExportMethod(iOSPlatformSettings::ExportMethods method)
|
||||
{
|
||||
switch (method)
|
||||
{
|
||||
case iOSPlatformSettings::ExportMethods::AppStore: return TEXT("app-store");
|
||||
case iOSPlatformSettings::ExportMethods::Development: return TEXT("development");
|
||||
case iOSPlatformSettings::ExportMethods::AdHoc: return TEXT("ad-hoc");
|
||||
case iOSPlatformSettings::ExportMethods::Enterprise: return TEXT("enterprise");
|
||||
default: return TEXT("");
|
||||
}
|
||||
}
|
||||
|
||||
String GetUIInterfaceOrientation(iOSPlatformSettings::UIInterfaceOrientations orientations)
|
||||
{
|
||||
String result;
|
||||
if (EnumHasAnyFlags(orientations, iOSPlatformSettings::UIInterfaceOrientations::Portrait))
|
||||
result += TEXT("UIInterfaceOrientationPortrait ");
|
||||
if (EnumHasAnyFlags(orientations, iOSPlatformSettings::UIInterfaceOrientations::PortraitUpsideDown))
|
||||
result += TEXT("UIInterfaceOrientationPortraitUpsideDown ");
|
||||
if (EnumHasAnyFlags(orientations, iOSPlatformSettings::UIInterfaceOrientations::LandscapeLeft))
|
||||
result += TEXT("UIInterfaceOrientationLandscapeLeft ");
|
||||
if (EnumHasAnyFlags(orientations, iOSPlatformSettings::UIInterfaceOrientations::LandscapeRight))
|
||||
result += TEXT("UIInterfaceOrientationLandscapeRight ");
|
||||
result = result.TrimTrailing();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
const Char* iOSPlatformTools::GetDisplayName() const
|
||||
{
|
||||
return TEXT("iOS");
|
||||
}
|
||||
|
||||
const Char* iOSPlatformTools::GetName() const
|
||||
{
|
||||
return TEXT("iOS");
|
||||
}
|
||||
|
||||
PlatformType iOSPlatformTools::GetPlatform() const
|
||||
{
|
||||
return PlatformType::iOS;
|
||||
}
|
||||
|
||||
ArchitectureType iOSPlatformTools::GetArchitecture() const
|
||||
{
|
||||
return ArchitectureType::ARM64;
|
||||
}
|
||||
|
||||
DotNetAOTModes iOSPlatformTools::UseAOT() const
|
||||
{
|
||||
return DotNetAOTModes::MonoAOTDynamic;
|
||||
}
|
||||
|
||||
PixelFormat iOSPlatformTools::GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format)
|
||||
{
|
||||
// TODO: add ETC compression support for iOS
|
||||
// TODO: add ASTC compression support for iOS
|
||||
|
||||
if (PixelFormatExtensions::IsCompressedBC(format))
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case PixelFormat::BC1_Typeless:
|
||||
case PixelFormat::BC2_Typeless:
|
||||
case PixelFormat::BC3_Typeless:
|
||||
return PixelFormat::R8G8B8A8_Typeless;
|
||||
case PixelFormat::BC1_UNorm:
|
||||
case PixelFormat::BC2_UNorm:
|
||||
case PixelFormat::BC3_UNorm:
|
||||
return PixelFormat::R8G8B8A8_UNorm;
|
||||
case PixelFormat::BC1_UNorm_sRGB:
|
||||
case PixelFormat::BC2_UNorm_sRGB:
|
||||
case PixelFormat::BC3_UNorm_sRGB:
|
||||
return PixelFormat::R8G8B8A8_UNorm_sRGB;
|
||||
case PixelFormat::BC4_Typeless:
|
||||
return PixelFormat::R8_Typeless;
|
||||
case PixelFormat::BC4_UNorm:
|
||||
return PixelFormat::R8_UNorm;
|
||||
case PixelFormat::BC4_SNorm:
|
||||
return PixelFormat::R8_SNorm;
|
||||
case PixelFormat::BC5_Typeless:
|
||||
return PixelFormat::R16G16_Typeless;
|
||||
case PixelFormat::BC5_UNorm:
|
||||
return PixelFormat::R16G16_UNorm;
|
||||
case PixelFormat::BC5_SNorm:
|
||||
return PixelFormat::R16G16_SNorm;
|
||||
case PixelFormat::BC7_Typeless:
|
||||
case PixelFormat::BC6H_Typeless:
|
||||
return PixelFormat::R16G16B16A16_Typeless;
|
||||
case PixelFormat::BC7_UNorm:
|
||||
case PixelFormat::BC6H_Uf16:
|
||||
case PixelFormat::BC6H_Sf16:
|
||||
return PixelFormat::R16G16B16A16_Float;
|
||||
case PixelFormat::BC7_UNorm_sRGB:
|
||||
return PixelFormat::R16G16B16A16_UNorm;
|
||||
default:
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
bool iOSPlatformTools::IsNativeCodeFile(CookingData& data, const String& file)
|
||||
{
|
||||
String extension = FileSystem::GetExtension(file);
|
||||
return extension.IsEmpty() || extension == TEXT("dylib");
|
||||
}
|
||||
|
||||
void iOSPlatformTools::OnBuildStarted(CookingData& data)
|
||||
{
|
||||
// Adjust the cooking output folders for packaging app
|
||||
const Char* subDir = TEXT("FlaxGame/Data");
|
||||
data.DataOutputPath /= subDir;
|
||||
data.NativeCodeOutputPath /= subDir;
|
||||
data.ManagedCodeOutputPath /= subDir;
|
||||
|
||||
PlatformTools::OnBuildStarted(data);
|
||||
}
|
||||
|
||||
bool iOSPlatformTools::OnPostProcess(CookingData& data)
|
||||
{
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
const auto platformSettings = iOSPlatformSettings::Get();
|
||||
const auto platformDataPath = data.GetPlatformBinariesRoot();
|
||||
const auto projectVersion = Editor::Project->Version.ToString();
|
||||
const auto appName = GetAppName();
|
||||
|
||||
// Setup package name (eg. com.company.project)
|
||||
String appIdentifier = platformSettings->AppIdentifier;
|
||||
if (EditorUtilities::FormatAppPackageName(appIdentifier))
|
||||
return true;
|
||||
|
||||
// Copy fresh Gradle project template
|
||||
if (FileSystem::CopyDirectory(data.OriginalOutputPath, platformDataPath / TEXT("Project"), true))
|
||||
{
|
||||
LOG(Error, "Failed to deploy XCode project to {0} from {1}", data.OriginalOutputPath, platformDataPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Format project template files
|
||||
Dictionary<String, String> configReplaceMap;
|
||||
configReplaceMap[TEXT("${AppName}")] = appName;
|
||||
configReplaceMap[TEXT("${AppIdentifier}")] = appIdentifier;
|
||||
configReplaceMap[TEXT("${AppTeamId}")] = platformSettings->AppTeamId;
|
||||
configReplaceMap[TEXT("${AppVersion}")] = platformSettings->AppVersion;
|
||||
configReplaceMap[TEXT("${ProjectName}")] = gameSettings->ProductName;
|
||||
configReplaceMap[TEXT("${ProjectVersion}")] = projectVersion;
|
||||
configReplaceMap[TEXT("${HeaderSearchPaths}")] = Globals::StartupFolder;
|
||||
configReplaceMap[TEXT("${ExportMethod}")] = GetExportMethod(platformSettings->ExportMethod);
|
||||
configReplaceMap[TEXT("${UISupportedInterfaceOrientations_iPhone}")] = GetUIInterfaceOrientation(platformSettings->SupportedInterfaceOrientationsiPhone);
|
||||
configReplaceMap[TEXT("${UISupportedInterfaceOrientations_iPad}")] = GetUIInterfaceOrientation(platformSettings->SupportedInterfaceOrientationsiPad);
|
||||
{
|
||||
// Initialize auto-generated areas as empty
|
||||
configReplaceMap[TEXT("${PBXBuildFile}")] = String::Empty;
|
||||
configReplaceMap[TEXT("${PBXCopyFilesBuildPhaseFiles}")] = String::Empty;
|
||||
configReplaceMap[TEXT("${PBXFileReference}")] = String::Empty;
|
||||
configReplaceMap[TEXT("${PBXFrameworksBuildPhase}")] = String::Empty;
|
||||
configReplaceMap[TEXT("${PBXFrameworksGroup}")] = String::Empty;
|
||||
configReplaceMap[TEXT("${PBXFilesGroup}")] = String::Empty;
|
||||
configReplaceMap[TEXT("${PBXResourcesGroup}")] = String::Empty;
|
||||
}
|
||||
{
|
||||
// Rename dotnet license files to not mislead the actual game licensing
|
||||
FileSystem::MoveFile(data.DataOutputPath / TEXT("Dotnet/DOTNET-LICENSE.TXT"), data.DataOutputPath / TEXT("Dotnet/LICENSE.TXT"), true);
|
||||
FileSystem::MoveFile(data.DataOutputPath / TEXT("Dotnet/DOTNET-THIRD-PARTY-NOTICES.TXT"), data.DataOutputPath / TEXT("Dotnet/THIRD-PARTY-NOTICES.TXT"), true);
|
||||
}
|
||||
Array<String> files;
|
||||
FileSystem::DirectoryGetFiles(files, data.DataOutputPath, TEXT("*"), DirectorySearchOption::AllDirectories);
|
||||
for (const String& file : files)
|
||||
{
|
||||
String name = StringUtils::GetFileName(file);
|
||||
if (name == TEXT(".DS_Store") || name == TEXT("FlaxGame"))
|
||||
continue;
|
||||
String fileId = Guid::New().ToString(Guid::FormatType::N).Left(24);
|
||||
String projectPath = FileSystem::ConvertAbsolutePathToRelative(data.DataOutputPath, file);
|
||||
if (name.EndsWith(TEXT(".dylib")))
|
||||
{
|
||||
String frameworkId = Guid::New().ToString(Guid::FormatType::N).Left(24);
|
||||
String frameworkEmbedId = Guid::New().ToString(Guid::FormatType::N).Left(24);
|
||||
configReplaceMap[TEXT("${PBXBuildFile}")] += String::Format(TEXT("\t\t{0} /* {1} in Frameworks */ = {{isa = PBXBuildFile; fileRef = {2} /* {1} */; }};\n"), frameworkId, name, fileId);
|
||||
configReplaceMap[TEXT("${PBXBuildFile}")] += String::Format(TEXT("\t\t{0} /* {1} in Embed Frameworks */ = {{isa = PBXBuildFile; fileRef = {2} /* {1} */; settings = {{ATTRIBUTES = (CodeSignOnCopy, ); }}; }};\n"), frameworkEmbedId, name, fileId);
|
||||
configReplaceMap[TEXT("${PBXCopyFilesBuildPhaseFiles}")] += String::Format(TEXT("\t\t\t\t{0} /* {1} in Embed Frameworks */,\n"), frameworkEmbedId, name);
|
||||
configReplaceMap[TEXT("${PBXFileReference}")] += String::Format(TEXT("\t\t{0} /* {1} */ = {{isa = PBXFileReference; lastKnownFileType = \"compiled.mach-o.dylib\"; name = \"{1}\"; path = \"FlaxGame/Data/{2}\"; sourceTree = \"<group>\"; }};\n"), fileId, name, projectPath);
|
||||
configReplaceMap[TEXT("${PBXFrameworksBuildPhase}")] += String::Format(TEXT("\t\t\t\t{0} /* {1} in Frameworks */,\n"), frameworkId, name);
|
||||
configReplaceMap[TEXT("${PBXFrameworksGroup}")] += String::Format(TEXT("\t\t\t\t{0} /* {1} */,\n"), fileId, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
String fileRefId = Guid::New().ToString(Guid::FormatType::N).Left(24);
|
||||
configReplaceMap[TEXT("${PBXBuildFile}")] += String::Format(TEXT("\t\t{0} /* {1} in Resources */ = {{isa = PBXBuildFile; fileRef = {2} /* {1} */; }};\n"), fileRefId, name, fileId);
|
||||
configReplaceMap[TEXT("${PBXFileReference}")] += String::Format(TEXT("\t\t{0} /* {1} */ = {{isa = PBXFileReference; lastKnownFileType = file; name = \"{1}\"; path = \"Data/{2}\"; sourceTree = \"<group>\"; }};\n"), fileId, name, projectPath);
|
||||
configReplaceMap[TEXT("${PBXFilesGroup}")] += String::Format(TEXT("\t\t\t\t{0} /* {1} */,\n"), fileId, name);
|
||||
configReplaceMap[TEXT("${PBXResourcesGroup}")] += String::Format(TEXT("\t\t\t\t{0} /* {1} in Resources */,\n"), fileRefId, name);
|
||||
}
|
||||
}
|
||||
bool failed = false;
|
||||
failed |= EditorUtilities::ReplaceInFile(data.OriginalOutputPath / TEXT("FlaxGame.xcodeproj/project.pbxproj"), configReplaceMap);
|
||||
failed |= EditorUtilities::ReplaceInFile(data.OriginalOutputPath / TEXT("ExportOptions.plist"), configReplaceMap);
|
||||
if (failed)
|
||||
{
|
||||
LOG(Error, "Failed to format XCode project");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Export images
|
||||
// TODO: provide per-device icons (eg. iPad 1x, iPad 2x) instead of a single icon size
|
||||
TextureData iconData;
|
||||
if (!EditorUtilities::GetApplicationImage(platformSettings->OverrideIcon, iconData))
|
||||
{
|
||||
String outputPath = data.OriginalOutputPath / TEXT("FlaxGame/Assets.xcassets/AppIcon.appiconset/ios_store_icon.png");
|
||||
if (EditorUtilities::ExportApplicationImage(iconData, 1024, 1024, PixelFormat::R8G8B8A8_UNorm, outputPath))
|
||||
{
|
||||
LOG(Error, "Failed to export application icon.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Package application
|
||||
const auto buildSettings = BuildSettings::Get();
|
||||
if (buildSettings->SkipPackaging)
|
||||
return false;
|
||||
GameCooker::PackageFiles();
|
||||
{
|
||||
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);
|
||||
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);
|
||||
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 ipaPath = data.OriginalOutputPath / TEXT("FlaxGame.ipa");
|
||||
LOG(Info, "Output application package: {0} (size: {1} MB)", ipaPath, FileSystem::GetFileSize(ipaPath) / 1024 / 1024);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
27
Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.h
Normal file
27
Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if PLATFORM_TOOLS_IOS
|
||||
|
||||
#include "../../PlatformTools.h"
|
||||
|
||||
/// <summary>
|
||||
/// The iOS platform support tools.
|
||||
/// </summary>
|
||||
class iOSPlatformTools : public PlatformTools
|
||||
{
|
||||
public:
|
||||
// [PlatformTools]
|
||||
const Char* GetDisplayName() const override;
|
||||
const Char* GetName() const override;
|
||||
PlatformType GetPlatform() const override;
|
||||
ArchitectureType GetArchitecture() const override;
|
||||
DotNetAOTModes UseAOT() const override;
|
||||
PixelFormat GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format) override;
|
||||
bool IsNativeCodeFile(CookingData& data, const String& file) override;
|
||||
void OnBuildStarted(CookingData& data) override;
|
||||
bool OnPostProcess(CookingData& data) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2012-2019 Wojciech Figat. All rights reserved.
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CookingData.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Editor/Scripting/ScriptsBuilder.h"
|
||||
#include "Engine/Graphics/PixelFormat.h"
|
||||
|
||||
@@ -15,7 +14,6 @@ class TextureBase;
|
||||
class FLAXENGINE_API PlatformTools
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="PlatformTools"/> class.
|
||||
/// </summary>
|
||||
@@ -24,32 +22,35 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the name of the platform for UI and logging.
|
||||
/// </summary>
|
||||
/// <returns>The name.</returns>
|
||||
virtual const Char* GetDisplayName() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the platform for filesystem cache directories, deps folder.
|
||||
/// </summary>
|
||||
/// <returns>The name.</returns>
|
||||
virtual const Char* GetName() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the platform.
|
||||
/// </summary>
|
||||
/// <returns>The platform type.</returns>
|
||||
virtual PlatformType GetPlatform() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the architecture of the platform.
|
||||
/// </summary>
|
||||
/// <returns>The architecture type.</returns>
|
||||
virtual ArchitectureType GetArchitecture() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value indicating whenever platform requires AOT.
|
||||
/// Gets the value indicating whenever platform requires AOT (needs C# assemblies to be precompiled).
|
||||
/// </summary>
|
||||
/// <returns>True if platform uses AOT and needs C# assemblies to be precompiled, otherwise false.</returns>
|
||||
virtual bool UseAOT() const
|
||||
virtual DotNetAOTModes UseAOT() const
|
||||
{
|
||||
return DotNetAOTModes::None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value indicating whenever platform supports using system-installed .Net Runtime.
|
||||
/// </summary>
|
||||
virtual bool UseSystemDotnet() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -72,13 +73,9 @@ public:
|
||||
/// <param name="data">The cooking data.</param>
|
||||
/// <param name="file">The file path.</param>
|
||||
/// <returns>True if it's a native file, otherwise false.<returns>
|
||||
virtual bool IsNativeCodeFile(CookingData& data, const String& file)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool IsNativeCodeFile(CookingData& data, const String& file);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Called when game building starts.
|
||||
/// </summary>
|
||||
@@ -136,64 +133,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The C# scripts AOT configuration options.
|
||||
/// </summary>
|
||||
struct AotConfig
|
||||
{
|
||||
String AotCompilerPath;
|
||||
String AotCompilerArgs;
|
||||
String AssemblerPath;
|
||||
String AssemblerArgs;
|
||||
String ArchiverPath;
|
||||
String ArchiverArgs;
|
||||
String AuxToolPath;
|
||||
String AuxToolArgs;
|
||||
String AotCachePath;
|
||||
Dictionary<String, String> EnvVars;
|
||||
Array<String> AssembliesSearchDirs;
|
||||
Array<String> Assemblies;
|
||||
|
||||
AotConfig(CookingData& data)
|
||||
{
|
||||
Platform::GetEnvironmentVariables(EnvVars);
|
||||
EnvVars[TEXT("MONO_PATH")] = data.DataOutputPath / TEXT("Mono/lib/mono/4.5");
|
||||
AssembliesSearchDirs.Add(data.DataOutputPath / TEXT("Mono/lib/mono/4.5"));
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Called to configure AOT options.
|
||||
/// </summary>
|
||||
/// <param name="data">The cooking data.</param>
|
||||
/// <param name="config">The configuration.</param>
|
||||
virtual void OnConfigureAOT(CookingData& data, AotConfig& config)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to execute AOT for the given assembly.
|
||||
/// </summary>
|
||||
/// <param name="data">The cooking data.</param>
|
||||
/// <param name="config">The configuration.</param>
|
||||
/// <param name="assemblyPath">The input managed library file path.</param>
|
||||
/// <returns>True if failed, otherwise false.<returns>
|
||||
virtual bool OnPerformAOT(CookingData& data, AotConfig& config, const String& assemblyPath)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after AOT execution for the assemblies.
|
||||
/// </summary>
|
||||
/// <param name="data">The cooking data.</param>
|
||||
/// <param name="config">The configuration.</param>
|
||||
/// <returns>True if failed, otherwise false.<returns>
|
||||
virtual bool OnPostProcessAOT(CookingData& data, AotConfig& config)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called during staged build post-processing.
|
||||
/// </summary>
|
||||
|
||||
@@ -95,8 +95,8 @@ bool CompileScriptsStep::DeployBinaries(CookingData& data, const String& path, c
|
||||
Scripting::ProcessBuildInfoPath(e.NativePath, projectFolderPath);
|
||||
Scripting::ProcessBuildInfoPath(e.ManagedPath, projectFolderPath);
|
||||
|
||||
e.NativePath = StringUtils::GetFileName(e.NativePath);
|
||||
e.ManagedPath = StringUtils::GetFileName(e.ManagedPath);
|
||||
e.NativePath = String(StringUtils::GetFileName(e.NativePath));
|
||||
e.ManagedPath = String(StringUtils::GetFileName(e.ManagedPath));
|
||||
|
||||
LOG(Info, "Collecting binary module {0}", e.Name);
|
||||
}
|
||||
@@ -129,7 +129,7 @@ bool CompileScriptsStep::DeployBinaries(CookingData& data, const String& path, c
|
||||
continue;
|
||||
if (FileSystem::CopyFile(dst, file))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy file from {0} to {1}."), file, dst);
|
||||
data.Error(String::Format(TEXT("Failed to copy file from {0} to {1}."), file, dst));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -154,60 +154,7 @@ bool CompileScriptsStep::Perform(CookingData& data)
|
||||
String target = project->GameTarget;
|
||||
StringView workingDir;
|
||||
const Char *platform, *architecture, *configuration = ::ToString(data.Configuration);
|
||||
switch (data.Platform)
|
||||
{
|
||||
case BuildPlatform::Windows32:
|
||||
platform = TEXT("Windows");
|
||||
architecture = TEXT("x86");
|
||||
break;
|
||||
case BuildPlatform::Windows64:
|
||||
platform = TEXT("Windows");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::UWPx86:
|
||||
platform = TEXT("UWP");
|
||||
architecture = TEXT("x86");
|
||||
break;
|
||||
case BuildPlatform::UWPx64:
|
||||
platform = TEXT("UWP");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::XboxOne:
|
||||
platform = TEXT("XboxOne");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::LinuxX64:
|
||||
platform = TEXT("Linux");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::PS4:
|
||||
platform = TEXT("PS4");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::XboxScarlett:
|
||||
platform = TEXT("XboxScarlett");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::AndroidARM64:
|
||||
platform = TEXT("Android");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
case BuildPlatform::Switch:
|
||||
platform = TEXT("Switch");
|
||||
architecture = TEXT("ARM64");
|
||||
break;
|
||||
case BuildPlatform::PS5:
|
||||
platform = TEXT("PS5");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
case BuildPlatform::MacOSx64:
|
||||
platform = TEXT("Mac");
|
||||
architecture = TEXT("x64");
|
||||
break;
|
||||
default:
|
||||
LOG(Error, "Unknown or unsupported build platform.");
|
||||
return true;
|
||||
}
|
||||
data.GetBuildPlatformName(platform, architecture);
|
||||
String targetBuildInfo = project->ProjectFolderPath / TEXT("Binaries") / target / platform / architecture / configuration / target + TEXT(".Build.json");
|
||||
if (target.IsEmpty())
|
||||
{
|
||||
@@ -241,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}"),
|
||||
target, platform, architecture, configuration, logFile);
|
||||
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()));
|
||||
#if PLATFORM_WINDOWS
|
||||
if (data.Platform == BuildPlatform::LinuxX64)
|
||||
#elif PLATFORM_LINUX
|
||||
@@ -257,7 +204,7 @@ bool CompileScriptsStep::Perform(CookingData& data)
|
||||
// Assume FlaxGame was prebuilt for target platform
|
||||
args += TEXT(" -SkipTargets=FlaxGame");
|
||||
}
|
||||
for (auto& define : data.CustomDefines)
|
||||
for (const String& define : data.CustomDefines)
|
||||
{
|
||||
args += TEXT(" -D");
|
||||
args += define;
|
||||
|
||||
@@ -410,7 +410,7 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass
|
||||
assetBase->InitCompilationOptions(options); \
|
||||
if (ShadersCompilation::Compile(options)) \
|
||||
{ \
|
||||
data.Data.Error(TEXT("Failed to compile shader '{0}' (profile: {1})."), asset->ToString(), ::ToString(options.Profile)); \
|
||||
data.Data.Error(String::Format(TEXT("Failed to compile shader '{0}' (profile: {1})."), asset->ToString(), ::ToString(options.Profile))); \
|
||||
return true; \
|
||||
} \
|
||||
includes.Clear(); \
|
||||
@@ -529,11 +529,20 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_MAC
|
||||
case BuildPlatform::MacOSx64:
|
||||
case BuildPlatform::MacOSARM64:
|
||||
{
|
||||
const char* platformDefineName = "PLATFORM_MAC";
|
||||
COMPILE_PROFILE(Vulkan_SM5, SHADER_FILE_CHUNK_INTERNAL_VULKAN_SM5_CACHE);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if PLATFORM_TOOLS_IOS
|
||||
case BuildPlatform::iOSARM64:
|
||||
{
|
||||
const char* platformDefineName = "PLATFORM_IOS";
|
||||
COMPILE_PROFILE(Vulkan_SM5, SHADER_FILE_CHUNK_INTERNAL_VULKAN_SM5_CACHE);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "DeployDataStep.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Engine/Core/Collections/Sorting.h"
|
||||
#include "Engine/Core/Config/BuildSettings.h"
|
||||
#include "Engine/Core/Config/GameSettings.h"
|
||||
#include "Engine/Renderer/ReflectionsPass.h"
|
||||
#include "Engine/Renderer/AntiAliasing/SMAA.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
|
||||
bool DeployDataStep::Perform(CookingData& data)
|
||||
{
|
||||
data.StepProgress(TEXT("Deploying engine data"), 0);
|
||||
const String depsRoot = data.GetPlatformBinariesRoot();
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
const auto& gameSettings = *GameSettings::Get();
|
||||
const auto& buildSettings = *BuildSettings::Get();
|
||||
|
||||
// Setup output folders and copy required data
|
||||
const auto contentDir = data.DataOutputPath / TEXT("Content");
|
||||
@@ -26,22 +30,275 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
Platform::Sleep(10);
|
||||
}
|
||||
FileSystem::CreateDirectory(contentDir);
|
||||
const auto srcMono = depsRoot / TEXT("Mono");
|
||||
const auto dstMono = data.DataOutputPath / TEXT("Mono");
|
||||
const String dstMono = data.DataOutputPath / TEXT("Mono");
|
||||
#if USE_NETCORE
|
||||
{
|
||||
// Remove old Mono files
|
||||
FileSystem::DeleteDirectory(dstMono);
|
||||
FileSystem::DeleteFile(data.DataOutputPath / TEXT("MonoPosixHelper.dll"));
|
||||
}
|
||||
String dstDotnet = data.DataOutputPath / TEXT("Dotnet");
|
||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||
const bool usAOT = aotMode != DotNetAOTModes::None;
|
||||
if (usAOT)
|
||||
{
|
||||
// Deploy Dotnet files into intermediate cooking directory for AOT
|
||||
FileSystem::DeleteDirectory(dstDotnet);
|
||||
dstDotnet = data.ManagedCodeOutputPath;
|
||||
}
|
||||
if (buildSettings.SkipDotnetPackaging && data.Tools->UseSystemDotnet())
|
||||
{
|
||||
// Use system-installed .Net Runtime
|
||||
FileSystem::DeleteDirectory(dstDotnet);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Deploy .Net Runtime files
|
||||
FileSystem::CreateDirectory(dstDotnet);
|
||||
String srcDotnet = depsRoot / TEXT("Dotnet");
|
||||
if (FileSystem::DirectoryExists(srcDotnet))
|
||||
{
|
||||
// Use prebuilt .Net installation for that platform
|
||||
LOG(Info, "Using .Net Runtime {} at {}", data.Tools->GetName(), srcDotnet);
|
||||
if (EditorUtilities::CopyDirectoryIfNewer(dstDotnet, srcDotnet, true))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy .Net runtime data files."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool canUseSystemDotnet = false;
|
||||
switch (data.Platform)
|
||||
{
|
||||
case BuildPlatform::Windows32:
|
||||
case BuildPlatform::Windows64:
|
||||
canUseSystemDotnet = PLATFORM_TYPE == PlatformType::Windows;
|
||||
break;
|
||||
case BuildPlatform::LinuxX64:
|
||||
canUseSystemDotnet = PLATFORM_TYPE == PlatformType::Linux;
|
||||
break;
|
||||
case BuildPlatform::MacOSx64:
|
||||
case BuildPlatform::MacOSARM64:
|
||||
canUseSystemDotnet = PLATFORM_TYPE == PlatformType::Mac;
|
||||
break;
|
||||
}
|
||||
if (canUseSystemDotnet && (aotMode == DotNetAOTModes::None || aotMode == DotNetAOTModes::ILC))
|
||||
{
|
||||
// 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);
|
||||
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
||||
int32 idx = sdks.Find(TEXT("DotNetSdk, "), StringSearchCase::CaseSensitive);
|
||||
if (idx != -1)
|
||||
{
|
||||
idx = sdks.Find(TEXT(", "), StringSearchCase::CaseSensitive, idx + 12);
|
||||
idx += 2;
|
||||
int32 end = sdks.Find(TEXT("\n"), StringSearchCase::CaseSensitive, idx);
|
||||
if (sdks[end] == '\r')
|
||||
end--;
|
||||
srcDotnet = String(sdks.Get() + idx, end - idx).TrimTrailing();
|
||||
}
|
||||
if (failed || !FileSystem::DirectoryExists(srcDotnet))
|
||||
{
|
||||
data.Error(TEXT("Failed to get .Net SDK location for a current platform."));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Select version to use
|
||||
Array<String> versions;
|
||||
FileSystem::GetChildDirectories(versions, srcDotnet / TEXT("host/fxr"));
|
||||
if (versions.Count() == 0)
|
||||
{
|
||||
data.Error(TEXT("Failed to get .Net SDK location for a current platform."));
|
||||
return true;
|
||||
}
|
||||
for (String& version : versions)
|
||||
{
|
||||
version = String(StringUtils::GetFileName(version));
|
||||
if (!version.StartsWith(TEXT("7.")))
|
||||
version.Clear();
|
||||
}
|
||||
Sorting::QuickSort(versions.Get(), versions.Count());
|
||||
const String version = versions.Last();
|
||||
FileSystem::NormalizePath(srcDotnet);
|
||||
LOG(Info, "Using .Net Runtime {} at {}", version, srcDotnet);
|
||||
|
||||
// Check if previously deployed files are valid (eg. system-installed .NET was updated from version 7.0.3 to 7.0.5)
|
||||
{
|
||||
const String dotnetCacheFilePath = data.CacheDirectory / TEXT("SystemDotnetInfo.txt");
|
||||
String dotnetCachedValue = String::Format(TEXT("{};{}"), version, srcDotnet);
|
||||
if (FileSystem::DirectoryExists(dstDotnet))
|
||||
{
|
||||
String cachedData;
|
||||
File::ReadAllText(dotnetCacheFilePath, cachedData);
|
||||
if (cachedData != dotnetCachedValue)
|
||||
{
|
||||
FileSystem::DeleteDirectory(dstDotnet);
|
||||
FileSystem::CreateDirectory(dstDotnet);
|
||||
}
|
||||
}
|
||||
File::WriteAllText(dotnetCacheFilePath, dotnetCachedValue, Encoding::ANSI);
|
||||
}
|
||||
|
||||
// Deploy runtime files
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), srcDotnet / TEXT("LICENSE.txt"));
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), srcDotnet / TEXT("LICENSE.TXT"));
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), srcDotnet / TEXT("ThirdPartyNotices.txt"));
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), srcDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"));
|
||||
if (usAOT)
|
||||
{
|
||||
failed |= EditorUtilities::CopyDirectoryIfNewer(dstDotnet, srcDotnet / TEXT("shared/Microsoft.NETCore.App") / version, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
failed |= EditorUtilities::CopyDirectoryIfNewer(dstDotnet / TEXT("host/fxr") / version, srcDotnet / TEXT("host/fxr") / version, true);
|
||||
failed |= EditorUtilities::CopyDirectoryIfNewer(dstDotnet / TEXT("shared/Microsoft.NETCore.App") / version, srcDotnet / TEXT("shared/Microsoft.NETCore.App") / version, true);
|
||||
}
|
||||
if (failed)
|
||||
{
|
||||
data.Error(TEXT("Failed to copy .Net runtime data files."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ask Flax.Build to provide .Net Host Runtime location for the target platform
|
||||
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);
|
||||
bool failed = ScriptsBuilder::RunBuildTool(args, data.CacheDirectory);
|
||||
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
||||
Array<String> parts;
|
||||
sdks.Split(',', parts);
|
||||
failed |= parts.Count() != 3;
|
||||
if (!failed)
|
||||
{
|
||||
srcDotnet = parts[2].TrimTrailing();
|
||||
}
|
||||
if (failed || !FileSystem::DirectoryExists(srcDotnet))
|
||||
{
|
||||
data.Error(TEXT("Failed to get .Net SDK location for a current platform."));
|
||||
return true;
|
||||
}
|
||||
FileSystem::NormalizePath(srcDotnet);
|
||||
LOG(Info, "Using .Net Runtime {} at {}", TEXT("Host"), srcDotnet);
|
||||
|
||||
// Deploy runtime files
|
||||
const Char* corlibPrivateName = TEXT("System.Private.CoreLib.dll");
|
||||
const bool srcDotnetFromEngine = srcDotnet.Contains(TEXT("Source/Platforms"));
|
||||
String packFolder = srcDotnet / TEXT("../../../");
|
||||
String dstDotnetLibs = dstDotnet, srcDotnetLibs = srcDotnet;
|
||||
StringUtils::PathRemoveRelativeParts(packFolder);
|
||||
if (usAOT)
|
||||
{
|
||||
if (srcDotnetFromEngine)
|
||||
{
|
||||
// AOT runtime files inside Engine Platform folder
|
||||
packFolder /= TEXT("Dotnet");
|
||||
dstDotnetLibs /= TEXT("lib/net7.0");
|
||||
srcDotnetLibs = packFolder / TEXT("lib/net7.0");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Runtime files inside Dotnet SDK folder but placed for AOT
|
||||
dstDotnetLibs /= TEXT("lib/net7.0");
|
||||
srcDotnetLibs /= TEXT("../lib/net7.0");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (srcDotnetFromEngine)
|
||||
{
|
||||
// Runtime files inside Engine Platform folder
|
||||
dstDotnetLibs /= TEXT("lib/net7.0");
|
||||
srcDotnetLibs /= TEXT("lib/net7.0");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Runtime files inside Dotnet SDK folder
|
||||
dstDotnetLibs /= TEXT("shared/Microsoft.NETCore.App");
|
||||
srcDotnetLibs /= TEXT("../lib/net7.0");
|
||||
}
|
||||
}
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), packFolder / TEXT("LICENSE.txt"));
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), packFolder / TEXT("LICENSE.TXT"));
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), packFolder / TEXT("ThirdPartyNotices.txt"));
|
||||
FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), packFolder / TEXT("THIRD-PARTY-NOTICES.TXT"));
|
||||
failed |= EditorUtilities::CopyDirectoryIfNewer(dstDotnetLibs, srcDotnetLibs, true);
|
||||
if (FileSystem::FileExists(srcDotnet / corlibPrivateName))
|
||||
failed |= EditorUtilities::CopyFileIfNewer(dstDotnetLibs / corlibPrivateName, srcDotnet / corlibPrivateName);
|
||||
switch (data.Platform)
|
||||
{
|
||||
#define DEPLOY_NATIVE_FILE(filename) failed |= FileSystem::CopyFile(data.NativeCodeOutputPath / TEXT(filename), srcDotnet / TEXT(filename));
|
||||
case BuildPlatform::AndroidARM64:
|
||||
if (data.Configuration != BuildConfiguration::Release)
|
||||
{
|
||||
DEPLOY_NATIVE_FILE("libmono-component-debugger.so");
|
||||
DEPLOY_NATIVE_FILE("libmono-component-diagnostics_tracing.so");
|
||||
DEPLOY_NATIVE_FILE("libmono-component-hot_reload.so");
|
||||
}
|
||||
DEPLOY_NATIVE_FILE("libmonosgen-2.0.so");
|
||||
DEPLOY_NATIVE_FILE("libSystem.IO.Compression.Native.so");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Native.so");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Security.Cryptography.Native.Android.so");
|
||||
break;
|
||||
case BuildPlatform::iOSARM64:
|
||||
DEPLOY_NATIVE_FILE("libmonosgen-2.0.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.IO.Compression.Native.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Native.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Net.Security.Native.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Security.Cryptography.Native.Apple.dylib");
|
||||
break;
|
||||
#undef DEPLOY_NATIVE_FILE
|
||||
default: ;
|
||||
}
|
||||
if (failed)
|
||||
{
|
||||
data.Error(TEXT("Failed to copy .Net runtime data files."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Optimize deployed C# class library (remove DLLs unused by scripts)
|
||||
if (aotMode == DotNetAOTModes::None && buildSettings.SkipUnusedDotnetLibsPackaging)
|
||||
{
|
||||
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);
|
||||
for (const String& define : data.CustomDefines)
|
||||
{
|
||||
args += TEXT(" -D");
|
||||
args += define;
|
||||
}
|
||||
if (ScriptsBuilder::RunBuildTool(args))
|
||||
{
|
||||
data.Error(TEXT("Failed to optimize .Net class library."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!FileSystem::DirectoryExists(dstMono))
|
||||
{
|
||||
// Deploy Mono files (from platform data folder)
|
||||
const String srcMono = depsRoot / TEXT("Mono");
|
||||
if (!FileSystem::DirectoryExists(srcMono))
|
||||
{
|
||||
data.Error(TEXT("Missing Mono runtime data files."));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FileSystem::CopyDirectory(dstMono, srcMono, true))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy Mono runtime data files."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Deploy engine data for the target platform
|
||||
if (data.Tools->OnDeployBinaries(data))
|
||||
@@ -82,7 +339,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
data.AddRootEngineAsset(TEXT("Engine/DefaultMaterial"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/DefaultDeformableMaterial"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/DefaultTerrainMaterial"));
|
||||
if (!gameSettings->NoSplashScreen && !gameSettings->SplashScreen.IsValid())
|
||||
if (!gameSettings.NoSplashScreen && !gameSettings.SplashScreen.IsValid())
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/Logo"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/NormalTexture"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/BlackTexture"));
|
||||
@@ -112,7 +369,6 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
|
||||
// Register game assets
|
||||
data.StepProgress(TEXT("Deploying game data"), 50);
|
||||
auto& buildSettings = *BuildSettings::Get();
|
||||
for (auto& e : buildSettings.AdditionalAssets)
|
||||
data.AddRootAsset(e.GetID());
|
||||
for (auto& e : buildSettings.AdditionalScenes)
|
||||
|
||||
@@ -2,9 +2,20 @@
|
||||
|
||||
#include "PostProcessStep.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
|
||||
bool PostProcessStep::Perform(CookingData& data)
|
||||
{
|
||||
// Print .NET stats
|
||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||
uint64 outputSize = FileSystem::GetDirectorySize(data.DataOutputPath / TEXT("Dotnet"));
|
||||
if (aotMode == DotNetAOTModes::None)
|
||||
{
|
||||
for (auto& binaryModule : data.BinaryModules)
|
||||
outputSize += FileSystem::GetFileSize(data.DataOutputPath / binaryModule.ManagedPath);
|
||||
}
|
||||
LOG(Info, "Output .NET files size: {0} MB", (uint32)(outputSize / (1024ull * 1024)));
|
||||
|
||||
GameCooker::PostProcessFiles();
|
||||
return data.Tools->OnPostProcess(data);
|
||||
}
|
||||
|
||||
@@ -1,78 +1,86 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "PrecompileAssembliesStep.h"
|
||||
#include "Editor/Scripting/ScriptsBuilder.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Core/Config/BuildSettings.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Editor/Scripting/ScriptsBuilder.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
|
||||
void PrecompileAssembliesStep::OnBuildStarted(CookingData& data)
|
||||
{
|
||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||
if (aotMode == DotNetAOTModes::None)
|
||||
return;
|
||||
const auto& buildSettings = *BuildSettings::Get();
|
||||
|
||||
// Redirect C# assemblies to intermediate cooking directory (processed by ILC)
|
||||
data.ManagedCodeOutputPath = data.CacheDirectory / TEXT("AOTAssemblies");
|
||||
|
||||
// Reset any AOT cache from previous run if the AOT mode has changed (eg. Mono AOT -> ILC on Desktop)
|
||||
const String aotModeCacheFilePath = data.ManagedCodeOutputPath / TEXT("AOTMode.txt");
|
||||
String aotModeCacheValue = String::Format(TEXT("{};{};{};{}"),
|
||||
(int32)aotMode,
|
||||
(int32)data.Configuration,
|
||||
(int32)buildSettings.SkipUnusedDotnetLibsPackaging,
|
||||
FileSystem::GetFileLastEditTime(ScriptsBuilder::GetBuildToolPath()).Ticks);
|
||||
for (const String& define : data.CustomDefines)
|
||||
aotModeCacheValue += define;
|
||||
if (FileSystem::DirectoryExists(data.ManagedCodeOutputPath))
|
||||
{
|
||||
String cachedData;
|
||||
File::ReadAllText(aotModeCacheFilePath, cachedData);
|
||||
if (cachedData != aotModeCacheValue)
|
||||
{
|
||||
LOG(Info, "AOT cache invalidation");
|
||||
FileSystem::DeleteDirectory(data.ManagedCodeOutputPath);
|
||||
}
|
||||
}
|
||||
if (!FileSystem::DirectoryExists(data.ManagedCodeOutputPath))
|
||||
{
|
||||
FileSystem::CreateDirectory(data.ManagedCodeOutputPath);
|
||||
File::WriteAllText(aotModeCacheFilePath, aotModeCacheValue, Encoding::ANSI);
|
||||
}
|
||||
}
|
||||
|
||||
bool PrecompileAssembliesStep::Perform(CookingData& data)
|
||||
{
|
||||
// Skip for some platforms
|
||||
if (!data.Tools->UseAOT())
|
||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||
if (aotMode == DotNetAOTModes::None)
|
||||
return false;
|
||||
const auto& buildSettings = *BuildSettings::Get();
|
||||
if (buildSettings.SkipDotnetPackaging && data.Tools->UseSystemDotnet())
|
||||
return false;
|
||||
LOG(Info, "Using AOT...");
|
||||
|
||||
// Useful references about AOT:
|
||||
// http://www.mono-project.com/docs/advanced/runtime/docs/aot/
|
||||
// http://www.mono-project.com/docs/advanced/aot/
|
||||
|
||||
const String infoMsg = TEXT("Running AOT");
|
||||
data.StepProgress(infoMsg, 0);
|
||||
|
||||
// Setup
|
||||
PlatformTools::AotConfig config(data);
|
||||
data.Tools->OnConfigureAOT(data, config);
|
||||
// Override Newtonsoft.Json with AOT-version (one that doesn't use System.Reflection.Emit)
|
||||
EditorUtilities::CopyFileIfNewer(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.dll"), Globals::StartupFolder / TEXT("Source/Platforms/DotNet/AOT/Newtonsoft.Json.dll"));
|
||||
FileSystem::DeleteFile(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.xml"));
|
||||
FileSystem::DeleteFile(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.pdb"));
|
||||
|
||||
// Prepare output directory
|
||||
config.AotCachePath = data.DataOutputPath / TEXT("Mono/lib/mono/aot-cache");
|
||||
switch (data.Tools->GetArchitecture())
|
||||
// Run AOT by Flax.Build (see DotNetAOT)
|
||||
const Char *platform, *architecture, *configuration = ::ToString(data.Configuration);
|
||||
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);
|
||||
if (!buildSettings.SkipUnusedDotnetLibsPackaging)
|
||||
args += TEXT(" -skipUnusedDotnetLibs=false"); // Run AOT on whole class library (not just used libs)
|
||||
for (const String& define : data.CustomDefines)
|
||||
{
|
||||
case ArchitectureType::x86:
|
||||
config.AotCachePath /= TEXT("x86");
|
||||
break;
|
||||
case ArchitectureType::x64:
|
||||
config.AotCachePath /= TEXT("amd64");
|
||||
break;
|
||||
default:
|
||||
data.Error(TEXT("Not supported AOT architecture"));
|
||||
args += TEXT(" -D");
|
||||
args += define;
|
||||
}
|
||||
if (ScriptsBuilder::RunBuildTool(args))
|
||||
{
|
||||
data.Error(TEXT("Failed to precompile game scripts."));
|
||||
return true;
|
||||
}
|
||||
if (!FileSystem::DirectoryExists(config.AotCachePath))
|
||||
{
|
||||
if (FileSystem::CreateDirectory(config.AotCachePath))
|
||||
{
|
||||
data.Error(TEXT("Failed to setup AOT output directory."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect assemblies for AOT
|
||||
// TODO: don't perform AOT on all assemblies but only ones used by the game and engine assemblies
|
||||
for (auto& dir : config.AssembliesSearchDirs)
|
||||
FileSystem::DirectoryGetFiles(config.Assemblies, dir, TEXT("*.dll"), DirectorySearchOption::TopDirectoryOnly);
|
||||
for (auto& binaryModule : data.BinaryModules)
|
||||
if (binaryModule.ManagedPath.HasChars())
|
||||
config.Assemblies.Add(data.ManagedCodeOutputPath / binaryModule.ManagedPath);
|
||||
// TODO: move AOT to Flax.Build and perform it on all C# assemblies used in target build
|
||||
config.Assemblies.Add(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.dll"));
|
||||
|
||||
// Perform AOT for the assemblies
|
||||
for (int32 i = 0; i < config.Assemblies.Count(); i++)
|
||||
{
|
||||
BUILD_STEP_CANCEL_CHECK;
|
||||
|
||||
if (data.Tools->OnPerformAOT(data, config, config.Assemblies[i]))
|
||||
return true;
|
||||
|
||||
data.StepProgress(infoMsg, static_cast<float>(i) / config.Assemblies.Count());
|
||||
}
|
||||
|
||||
BUILD_STEP_CANCEL_CHECK;
|
||||
|
||||
if (data.Tools->OnPostProcessAOT(data, config))
|
||||
return true;
|
||||
|
||||
// TODO: maybe remove GAC/assemblies? aot-cache could be only used in the build game
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
#include "Editor/Cooker/GameCooker.h"
|
||||
|
||||
/// <summary>
|
||||
/// Optional step used only on selected platform that precompiles C# script assemblies.
|
||||
/// Uses Mono Ahead of Time Compilation (AOT) feature.
|
||||
/// Optional step used only on selected platform that precompiles C# script assemblies. Uses Ahead of Time Compilation (AOT) feature.
|
||||
/// </summary>
|
||||
/// <seealso cref="GameCooker::BuildStep" />
|
||||
class PrecompileAssembliesStep : public GameCooker::BuildStep
|
||||
@@ -14,5 +13,6 @@ class PrecompileAssembliesStep : public GameCooker::BuildStep
|
||||
public:
|
||||
|
||||
// [BuildStep]
|
||||
void OnBuildStarted(CookingData& data) override;
|
||||
bool Perform(CookingData& data) override;
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ using FlaxEditor.CustomEditors.GUI;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
using JsonSerializer = FlaxEngine.Json.JsonSerializer;
|
||||
|
||||
@@ -625,9 +626,7 @@ namespace FlaxEditor.CustomEditors
|
||||
JsonSerializer.Deserialize(obj, text);
|
||||
}
|
||||
}
|
||||
#pragma warning disable 618
|
||||
else if (Newtonsoft.Json.Schema.JsonSchema.Parse(text) == null)
|
||||
#pragma warning restore 618
|
||||
else if (!text.StartsWith("{") || !text.EndsWith("}"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -650,7 +649,14 @@ namespace FlaxEditor.CustomEditors
|
||||
else
|
||||
{
|
||||
// Default
|
||||
obj = JsonConvert.DeserializeObject(text, TypeUtils.GetType(Values.Type), JsonSerializer.Settings);
|
||||
try
|
||||
{
|
||||
obj = JsonConvert.DeserializeObject(text, TypeUtils.GetType(Values.Type), JsonSerializer.Settings);
|
||||
}
|
||||
catch
|
||||
{
|
||||
obj = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj == null || Values.Type.IsInstanceOfType(obj))
|
||||
@@ -817,6 +823,8 @@ namespace FlaxEditor.CustomEditors
|
||||
/// <returns>True if allow to handle this event, otherwise false.</returns>
|
||||
protected virtual bool OnDirty(CustomEditor editor, object value, object token = null)
|
||||
{
|
||||
if (ParentEditor == null)
|
||||
return false;
|
||||
return ParentEditor.OnDirty(editor, value, token);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/reflection.h>
|
||||
|
||||
#define TRACK_ASSEMBLY(assembly) \
|
||||
if (assembly->IsLoaded()) \
|
||||
@@ -49,24 +48,24 @@ struct Entry
|
||||
}
|
||||
};
|
||||
|
||||
Dictionary<MonoType*, Entry> Cache(512);
|
||||
Dictionary<MType*, Entry> Cache(512);
|
||||
|
||||
void OnAssemblyLoaded(MAssembly* assembly);
|
||||
void OnAssemblyUnloading(MAssembly* assembly);
|
||||
void OnBinaryModuleLoaded(BinaryModule* module);
|
||||
|
||||
MonoReflectionType* CustomEditorsUtil::GetCustomEditor(MonoReflectionType* refType)
|
||||
MTypeObject* CustomEditorsUtil::GetCustomEditor(MTypeObject* refType)
|
||||
{
|
||||
if (!refType)
|
||||
return nullptr;
|
||||
MonoType* type = mono_reflection_type_get_type(refType);
|
||||
MType* type = INTERNAL_TYPE_OBJECT_GET(refType);
|
||||
Entry result;
|
||||
if (Cache.TryGet(type, result))
|
||||
{
|
||||
const auto editor = result.CustomEditor ? result.CustomEditor : result.DefaultEditor;
|
||||
MClass* editor = result.CustomEditor ? result.CustomEditor : result.DefaultEditor;
|
||||
if (editor)
|
||||
{
|
||||
return MUtils::GetType(editor->GetNative());
|
||||
return MUtils::GetType(editor);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -123,19 +122,19 @@ void OnAssemblyLoaded(MAssembly* assembly)
|
||||
continue;
|
||||
|
||||
const auto attribute = mclass->GetAttribute(customEditorAttribute);
|
||||
if (attribute == nullptr || mono_object_get_class(attribute) != customEditorAttribute->GetNative())
|
||||
if (attribute == nullptr || MCore::Object::GetClass(attribute) != customEditorAttribute)
|
||||
continue;
|
||||
|
||||
// Check if attribute references a valid class
|
||||
MonoReflectionType* refType = nullptr;
|
||||
MTypeObject* refType = nullptr;
|
||||
customEditorTypeField->GetValue(attribute, &refType);
|
||||
if (refType == nullptr)
|
||||
continue;
|
||||
|
||||
MonoType* type = mono_reflection_type_get_type(refType);
|
||||
MType* type = INTERNAL_TYPE_OBJECT_GET(refType);
|
||||
if (type == nullptr)
|
||||
continue;
|
||||
MonoClass* typeClass = mono_type_get_class(type);
|
||||
MClass* typeClass = MCore::Type::GetClass(type);
|
||||
|
||||
// Check if it's a custom editor class
|
||||
if (mclass->IsSubClassOf(customEditor))
|
||||
@@ -152,18 +151,14 @@ void OnAssemblyLoaded(MAssembly* assembly)
|
||||
entry.CustomEditor = mclass;
|
||||
}
|
||||
|
||||
//LOG(Info, "Custom Editor {0} for type {1} (default: {2})", String(mclass->GetFullName()), String(mono_type_get_name(type)), isDefault);
|
||||
//LOG(Info, "Custom Editor {0} for type {1} (default: {2})", String(mclass->GetFullName()), MCore::Type::ToString(type), isDefault);
|
||||
}
|
||||
else if (typeClass)
|
||||
{
|
||||
MClass* referencedClass = Scripting::FindClass(typeClass);
|
||||
if (referencedClass)
|
||||
{
|
||||
auto& entry = Cache[mono_class_get_type(mclass->GetNative())];
|
||||
entry.CustomEditor = referencedClass;
|
||||
auto& entry = Cache[mclass->GetType()];
|
||||
entry.CustomEditor = typeClass;
|
||||
|
||||
//LOG(Info, "Custom Editor {0} for type {1}", String(referencedClass->GetFullName()), String(mclass->GetFullName()));
|
||||
}
|
||||
//LOG(Info, "Custom Editor {0} for type {1}", String(typeClass->GetFullName()), String(mclass->GetFullName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,17 +178,16 @@ void OnAssemblyUnloading(MAssembly* assembly)
|
||||
// Remove entries with user classes
|
||||
for (auto i = Cache.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
MonoClass* monoClass = (MonoClass*)(void*)i->Key;
|
||||
|
||||
if (assembly->GetClass(monoClass))
|
||||
MClass* mClass = MCore::Type::GetClass(i->Key);
|
||||
if (mClass && mClass->GetAssembly() == assembly)
|
||||
{
|
||||
Cache.Remove(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i->Value.DefaultEditor && assembly->GetClass(i->Value.DefaultEditor->GetNative()))
|
||||
if (i->Value.DefaultEditor && i->Value.DefaultEditor->GetAssembly() == assembly)
|
||||
i->Value.DefaultEditor = nullptr;
|
||||
if (i->Value.CustomEditor && assembly->GetClass(i->Value.CustomEditor->GetNative()))
|
||||
if (i->Value.CustomEditor && i->Value.CustomEditor->GetAssembly() == assembly)
|
||||
i->Value.CustomEditor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using FlaxEditor.CustomEditors.Dedicated;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Interop;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
internal static class CustomEditorsUtil
|
||||
internal static partial class CustomEditorsUtil
|
||||
{
|
||||
internal static readonly Dictionary<Type, string> InBuildTypeNames = new Dictionary<Type, string>()
|
||||
{
|
||||
@@ -126,7 +129,8 @@ namespace FlaxEditor.CustomEditors
|
||||
return new GenericEditor();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern Type Internal_GetCustomEditor(Type targetType);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "CustomEditorsUtilInternal_GetCustomEditor", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalUsing(typeof(SystemTypeMarshaller))]
|
||||
internal static partial Type Internal_GetCustomEditor([MarshalUsing(typeof(SystemTypeMarshaller))] Type targetType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class CustomEditorsUtil
|
||||
{
|
||||
public:
|
||||
|
||||
#if USE_MONO
|
||||
static MonoReflectionType* GetCustomEditor(MonoReflectionType* refType);
|
||||
#if USE_CSHARP
|
||||
static MTypeObject* GetCustomEditor(MTypeObject* refType);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
@@ -94,19 +95,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
if (actor != null)
|
||||
group.Panel.TooltipText = Surface.SurfaceUtils.GetVisualScriptTypeDescription(TypeUtils.GetObjectType(actor));
|
||||
float settingsButtonSize = group.Panel.HeaderHeight;
|
||||
var settingsButton = new Image
|
||||
{
|
||||
TooltipText = "Settings",
|
||||
AutoFocus = true,
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = group.Panel,
|
||||
Bounds = new Rectangle(group.Panel.Width - settingsButtonSize, 0, settingsButtonSize, settingsButtonSize),
|
||||
IsScrollable = false,
|
||||
Color = FlaxEngine.GUI.Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(FlaxEngine.GUI.Style.Current.Settings),
|
||||
};
|
||||
var settingsButton = group.AddSettingsButton();
|
||||
settingsButton.Clicked += OnSettingsButtonClicked;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using FlaxEditor.GUI.Drag;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
@@ -461,20 +462,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
var group = layout.Group("Missing script");
|
||||
|
||||
// Add settings button to the group
|
||||
const float settingsButtonSize = 14;
|
||||
var settingsButton = new Image
|
||||
{
|
||||
TooltipText = "Settings",
|
||||
AutoFocus = true,
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = group.Panel,
|
||||
Bounds = new Rectangle(group.Panel.Width - settingsButtonSize, 0, settingsButtonSize, settingsButtonSize),
|
||||
IsScrollable = false,
|
||||
Color = FlaxEngine.GUI.Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(FlaxEngine.GUI.Style.Current.Settings),
|
||||
Tag = index,
|
||||
};
|
||||
var settingsButton = group.AddSettingsButton();
|
||||
settingsButton.Tag = index;
|
||||
settingsButton.Clicked += MissingSettingsButtonOnClicked;
|
||||
}
|
||||
|
||||
@@ -664,19 +653,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
};
|
||||
|
||||
// Add settings button to the group
|
||||
var settingsButton = new Image
|
||||
{
|
||||
TooltipText = "Settings",
|
||||
AutoFocus = true,
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = group.Panel,
|
||||
Bounds = new Rectangle(group.Panel.Width - headerHeight, 0, headerHeight, headerHeight),
|
||||
IsScrollable = false,
|
||||
Color = FlaxEngine.GUI.Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(FlaxEngine.GUI.Style.Current.Settings),
|
||||
Tag = script,
|
||||
};
|
||||
var settingsButton = group.AddSettingsButton();
|
||||
settingsButton.Tag = script;
|
||||
settingsButton.Clicked += OnSettingsButtonClicked;
|
||||
|
||||
group.Panel.HeaderTextMargin = new Margin(scriptDrag.Right - 12, 15, 2, 2);
|
||||
|
||||
@@ -698,7 +698,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
string newName = controlType.Name + uiControl.Name.Substring(previousName.Length);
|
||||
if (uiControl.Parent != null)
|
||||
newName = StringUtils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null);
|
||||
newName = Utilities.Utils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null);
|
||||
uiControl.Name = newName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.Collections;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using FlaxEditor.Content;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ using FlaxEditor.SceneGraph;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
@@ -12,6 +12,7 @@ using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
@@ -20,7 +21,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
var listType = Values.Type;
|
||||
var list = (IList)listType.CreateInstance();
|
||||
var defaultValue = Scripting.TypeUtils.GetDefaultValue(ElementType);
|
||||
var defaultValue = TypeUtils.GetDefaultValue(ElementType);
|
||||
for (int i = 0; i < size; i++)
|
||||
list.Add(defaultValue);
|
||||
return list;
|
||||
@@ -55,7 +56,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
else
|
||||
{
|
||||
// Initialize new entries with default values
|
||||
var defaultValue = Scripting.TypeUtils.GetDefaultValue(elementType);
|
||||
var defaultValue = TypeUtils.GetDefaultValue(elementType);
|
||||
for (int i = oldSize; i < newSize; i++)
|
||||
newValues.Add(defaultValue);
|
||||
}
|
||||
@@ -63,7 +64,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
else if (newSize > 0)
|
||||
{
|
||||
// Fill new entries with default value
|
||||
var defaultValue = Scripting.TypeUtils.GetDefaultValue(elementType);
|
||||
var defaultValue = TypeUtils.GetDefaultValue(elementType);
|
||||
for (int i = oldSize; i < newSize; i++)
|
||||
newValues.Add(defaultValue);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ using FlaxEditor.GUI.Drag;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Elements
|
||||
@@ -25,5 +26,27 @@ namespace FlaxEditor.CustomEditors.Elements
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContainerControl ContainerControl => Panel;
|
||||
|
||||
/// <summary>
|
||||
/// Adds utility settings button to the group header.
|
||||
/// </summary>
|
||||
/// <returns>The created control.</returns>
|
||||
public Image AddSettingsButton()
|
||||
{
|
||||
var style = Style.Current;
|
||||
var settingsButtonSize = Panel.HeaderHeight;
|
||||
return new Image
|
||||
{
|
||||
TooltipText = "Settings",
|
||||
AutoFocus = true,
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = Panel,
|
||||
Bounds = new Rectangle(Panel.Width - settingsButtonSize, 0, settingsButtonSize, settingsButtonSize),
|
||||
IsScrollable = false,
|
||||
Color = style.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(style.Settings),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
@@ -242,7 +243,7 @@ namespace FlaxEditor.CustomEditors
|
||||
if (objA == null && objB is string objBStr && objBStr.Length == 0)
|
||||
return true;
|
||||
|
||||
return Newtonsoft.Json.Utilities.MiscellaneousUtils.DefaultValueEquals(objA, objB);
|
||||
return Newtonsoft.Json.Utilities.MiscellaneousUtils.ValueEquals(objA, objB);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Flax.Build;
|
||||
@@ -36,9 +37,13 @@ public class Editor : EditorModule
|
||||
{
|
||||
base.Setup(options);
|
||||
|
||||
options.ScriptingAPI.SystemReferences.Add("System.Private.Xml");
|
||||
options.ScriptingAPI.SystemReferences.Add("System.Text.RegularExpressions");
|
||||
options.ScriptingAPI.SystemReferences.Add("System.ComponentModel.TypeConverter");
|
||||
|
||||
options.PublicDependencies.Add("Engine");
|
||||
options.PrivateDependencies.Add("pugixml");
|
||||
options.PrivateDependencies.Add("UniversalAnalytics");
|
||||
options.PrivateDependencies.Add("curl");
|
||||
options.PrivateDependencies.Add("ContentImporters");
|
||||
options.PrivateDependencies.Add("ContentExporters");
|
||||
options.PrivateDependencies.Add("ShadowsOfMordor");
|
||||
@@ -72,12 +77,15 @@ public class Editor : EditorModule
|
||||
{
|
||||
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Mac", "PLATFORM_TOOLS_MAC");
|
||||
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Android", "PLATFORM_TOOLS_ANDROID");
|
||||
AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "iOS", "PLATFORM_TOOLS_IOS");
|
||||
}
|
||||
|
||||
// Visual Studio integration
|
||||
if (options.Platform.Target == TargetPlatform.Windows && Flax.Build.Platform.BuildTargetPlatform == TargetPlatform.Windows)
|
||||
{
|
||||
#pragma warning disable CA1416
|
||||
var path = Registry.GetValue("HKEY_CLASSES_ROOT\\TypeLib\\{80CC9F66-E7D8-4DDD-85B6-D9E6CD0E93E2}\\8.0\\0\\win32", null, null) as string;
|
||||
#pragma warning restore CA1416
|
||||
if (path != null && File.Exists(path))
|
||||
options.PrivateDefinitions.Add("USE_VISUAL_STUDIO_DTE");
|
||||
}
|
||||
|
||||
@@ -259,13 +259,13 @@ bool Editor::CheckProjectUpgrade()
|
||||
|
||||
LOG(Warning, "Project layout upgraded!");
|
||||
}
|
||||
// Check if last version was the same
|
||||
// Check if last version was the same
|
||||
else if (lastMajor == FLAXENGINE_VERSION_MAJOR && lastMinor == FLAXENGINE_VERSION_MINOR)
|
||||
{
|
||||
// Do nothing
|
||||
IsOldProjectOpened = false;
|
||||
}
|
||||
// Check if last version was older
|
||||
// Check if last version was older
|
||||
else if (lastMajor < FLAXENGINE_VERSION_MAJOR || (lastMajor == FLAXENGINE_VERSION_MAJOR && lastMinor < FLAXENGINE_VERSION_MINOR))
|
||||
{
|
||||
LOG(Warning, "The project was opened with the older editor version last time");
|
||||
@@ -288,7 +288,7 @@ bool Editor::CheckProjectUpgrade()
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Check if last version was newer
|
||||
// Check if last version was newer
|
||||
else if (lastMajor > FLAXENGINE_VERSION_MAJOR || (lastMajor == FLAXENGINE_VERSION_MAJOR && lastMinor > FLAXENGINE_VERSION_MINOR))
|
||||
{
|
||||
LOG(Warning, "The project was opened with the newer editor version last time");
|
||||
@@ -312,6 +312,14 @@ bool Editor::CheckProjectUpgrade()
|
||||
}
|
||||
}
|
||||
|
||||
// When changing between major/minor version clear some caches to prevent possible issues
|
||||
if (lastMajor != FLAXENGINE_VERSION_MAJOR || lastMinor != FLAXENGINE_VERSION_MINOR)
|
||||
{
|
||||
LOG(Info, "Cleaning cache files from different engine version");
|
||||
FileSystem::DeleteDirectory(Globals::ProjectFolder / TEXT("Cache/Cooker"));
|
||||
FileSystem::DeleteDirectory(Globals::ProjectFolder / TEXT("Cache/Intermediate"));
|
||||
}
|
||||
|
||||
// Upgrade old 0.7 projects
|
||||
// [Deprecated: 01.11.2020, expires 01.11.2021]
|
||||
if (lastMajor == 0 && lastMinor == 7 && lastBuild <= 6197)
|
||||
@@ -330,12 +338,11 @@ bool Editor::CheckProjectUpgrade()
|
||||
file->WriteInt32(FLAXENGINE_VERSION_MAJOR);
|
||||
file->WriteInt32(FLAXENGINE_VERSION_MINOR);
|
||||
file->WriteInt32(FLAXENGINE_VERSION_BUILD);
|
||||
|
||||
Delete(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Warning, "Failed to create version cache file");
|
||||
LOG(Error, "Failed to create version cache file");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -664,9 +671,7 @@ bool Editor::Init()
|
||||
|
||||
void Editor::BeforeRun()
|
||||
{
|
||||
// If during last lightmaps baking engine crashed we could try to restore the progress
|
||||
if (ShadowsOfMordor::Builder::Instance()->RestoreState())
|
||||
Managed->GetClass()->GetMethod("Internal_StartLightingBake")->Invoke(Managed->GetOrCreateManagedInstance(), nullptr, nullptr);
|
||||
Managed->BeforeRun();
|
||||
}
|
||||
|
||||
void Editor::BeforeExit()
|
||||
@@ -696,12 +701,6 @@ void EditorImpl::OnUpdate()
|
||||
// Boost our priority back to normal
|
||||
Platform::SetThreadPriority(ThreadPriority::Normal);
|
||||
}
|
||||
if (!hasFocus)
|
||||
{
|
||||
// Sleep for a bit to not eat up all CPU time
|
||||
PROFILE_CPU_NAMED("Sleep");
|
||||
Platform::Sleep(5);
|
||||
}
|
||||
HasFocus = hasFocus;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.Content.Import;
|
||||
using FlaxEditor.Content.Settings;
|
||||
@@ -18,8 +19,11 @@ using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Assertions;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Interop;
|
||||
using FlaxEngine.Json;
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace FlaxEditor
|
||||
{
|
||||
/// <summary>
|
||||
@@ -62,17 +66,20 @@ namespace FlaxEditor
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this Editor is running a dev instance of the engine.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool IsDevInstance();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsDevInstance", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool IsDevInstance();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this Editor is running as official build (distributed via Flax services).
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool IsOfficialBuild();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsOfficialBuild", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool IsOfficialBuild();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_IsPlayMode();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsPlayMode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_IsPlayMode();
|
||||
|
||||
/// <summary>
|
||||
/// True if the editor is running now in a play mode. Assigned by the managed editor instance.
|
||||
@@ -724,9 +731,16 @@ namespace FlaxEditor
|
||||
// Invoke new instance if need to open a project
|
||||
if (!string.IsNullOrEmpty(_projectToOpen))
|
||||
{
|
||||
string args = string.Format("-project \"{0}\"", _projectToOpen);
|
||||
var procSettings = new CreateProcessSettings
|
||||
{
|
||||
FileName = Platform.ExecutableFilePath,
|
||||
Arguments = string.Format("-project \"{0}\"", _projectToOpen),
|
||||
ShellExecute = true,
|
||||
WaitForEnd = false,
|
||||
HiddenWindow = false,
|
||||
};
|
||||
_projectToOpen = null;
|
||||
Platform.StartProcess(Platform.ExecutableFilePath, args, null);
|
||||
Platform.CreateProcess(ref procSettings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -919,47 +933,6 @@ namespace FlaxEditor
|
||||
Animation = 11,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imports the asset file to the target location.
|
||||
/// </summary>
|
||||
/// <param name="inputPath">The source file path.</param>
|
||||
/// <param name="outputPath">The result asset file path.</param>
|
||||
/// <returns>True if importing failed, otherwise false.</returns>
|
||||
public static bool Import(string inputPath, string outputPath)
|
||||
{
|
||||
return Internal_Import(inputPath, outputPath, IntPtr.Zero);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imports the texture asset file to the target location.
|
||||
/// </summary>
|
||||
/// <param name="inputPath">The source file path.</param>
|
||||
/// <param name="outputPath">The result asset file path.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>True if importing failed, otherwise false.</returns>
|
||||
public static bool Import(string inputPath, string outputPath, TextureImportSettings settings)
|
||||
{
|
||||
if (settings == null)
|
||||
throw new ArgumentNullException();
|
||||
settings.ToInternal(out var internalOptions);
|
||||
return Internal_ImportTexture(inputPath, outputPath, ref internalOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imports the model asset file to the target location.
|
||||
/// </summary>
|
||||
/// <param name="inputPath">The source file path.</param>
|
||||
/// <param name="outputPath">The result asset file path.</param>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>True if importing failed, otherwise false.</returns>
|
||||
public static bool Import(string inputPath, string outputPath, ModelImportSettings settings)
|
||||
{
|
||||
if (settings == null)
|
||||
throw new ArgumentNullException();
|
||||
settings.ToInternal(out var internalOptions);
|
||||
return Internal_ImportModel(inputPath, outputPath, ref internalOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imports the audio asset file to the target location.
|
||||
/// </summary>
|
||||
@@ -1318,6 +1291,7 @@ namespace FlaxEditor
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[NativeMarshalling(typeof(VisualScriptLocalMarshaller))]
|
||||
internal struct VisualScriptLocal
|
||||
{
|
||||
public string Value;
|
||||
@@ -1326,7 +1300,52 @@ namespace FlaxEditor
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(VisualScriptLocal), MarshalMode.Default, typeof(VisualScriptLocalMarshaller))]
|
||||
internal static class VisualScriptLocalMarshaller
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct VisualScriptLocalNative
|
||||
{
|
||||
public IntPtr Value;
|
||||
public IntPtr ValueTypeName;
|
||||
public uint NodeId;
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
internal static VisualScriptLocal ConvertToManaged(VisualScriptLocalNative unmanaged) => ToManaged(unmanaged);
|
||||
internal static VisualScriptLocalNative ConvertToUnmanaged(VisualScriptLocal managed) => ToNative(managed);
|
||||
|
||||
internal static VisualScriptLocal ToManaged(VisualScriptLocalNative managed)
|
||||
{
|
||||
return new VisualScriptLocal()
|
||||
{
|
||||
Value = ManagedString.ToManaged(managed.Value),
|
||||
ValueTypeName = ManagedString.ToManaged(managed.ValueTypeName),
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
};
|
||||
}
|
||||
|
||||
internal static VisualScriptLocalNative ToNative(VisualScriptLocal managed)
|
||||
{
|
||||
return new VisualScriptLocalNative()
|
||||
{
|
||||
Value = ManagedString.ToNative(managed.Value),
|
||||
ValueTypeName = ManagedString.ToNative(managed.ValueTypeName),
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
};
|
||||
}
|
||||
|
||||
internal static void Free(VisualScriptLocalNative unmanaged)
|
||||
{
|
||||
ManagedString.Free(unmanaged.Value);
|
||||
ManagedString.Free(unmanaged.ValueTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[NativeMarshalling(typeof(VisualScriptStackFrameMarshaller))]
|
||||
internal struct VisualScriptStackFrame
|
||||
{
|
||||
public VisualScript Script;
|
||||
@@ -1334,6 +1353,45 @@ namespace FlaxEditor
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(VisualScriptStackFrame), MarshalMode.Default, typeof(VisualScriptStackFrameMarshaller))]
|
||||
internal static class VisualScriptStackFrameMarshaller
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct VisualScriptStackFrameNative
|
||||
{
|
||||
public IntPtr Script;
|
||||
public uint NodeId;
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
internal static VisualScriptStackFrame ConvertToManaged(VisualScriptStackFrameNative unmanaged) => ToManaged(unmanaged);
|
||||
internal static VisualScriptStackFrameNative ConvertToUnmanaged(VisualScriptStackFrame managed) => ToNative(managed);
|
||||
|
||||
internal static VisualScriptStackFrame ToManaged(VisualScriptStackFrameNative managed)
|
||||
{
|
||||
return new VisualScriptStackFrame()
|
||||
{
|
||||
Script = VisualScriptMarshaller.ConvertToManaged(managed.Script),
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
};
|
||||
}
|
||||
|
||||
internal static VisualScriptStackFrameNative ToNative(VisualScriptStackFrame managed)
|
||||
{
|
||||
return new VisualScriptStackFrameNative()
|
||||
{
|
||||
Script = VisualScriptMarshaller.ConvertToUnmanaged(managed.Script),
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
};
|
||||
}
|
||||
|
||||
internal static void Free(VisualScriptStackFrameNative unmanaged)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal void BuildCommand(string arg)
|
||||
{
|
||||
if (TryBuildCommand(arg))
|
||||
@@ -1531,116 +1589,121 @@ namespace FlaxEditor
|
||||
Instance.StateMachine.StateChanged += RequestStartPlayOnEditMode;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern int Internal_ReadOutputLogs(string[] outMessages, byte[] outLogTypes, long[] outLogTimes);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_ReadOutputLogs", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||
internal static partial int Internal_ReadOutputLogs([MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref string[] outMessages, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref byte[] outLogTypes, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref long[] outLogTimes, int outCapacity);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_SetPlayMode(bool value);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetPlayMode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||
internal static partial void Internal_SetPlayMode([MarshalAs(UnmanagedType.U1)] bool value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern string Internal_GetProjectPath();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetProjectPath", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial string Internal_GetProjectPath();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CloneAssetFile(string dstPath, string srcPath, ref Guid dstId);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CloneAssetFile", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CloneAssetFile(string dstPath, string srcPath, ref Guid dstId);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_Import(string inputPath, string outputPath, IntPtr arg);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_ImportAudio", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_ImportAudio(string inputPath, string outputPath, ref AudioImportSettings.InternalOptions options);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_ImportTexture(string inputPath, string outputPath, ref TextureImportSettings.InternalOptions options);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAudioClipMetadata", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_GetAudioClipMetadata(IntPtr obj, out int originalSize, out int importedSize);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_ImportModel(string inputPath, string outputPath, ref ModelImportSettings.InternalOptions options);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SaveJsonAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_SaveJsonAsset(string outputPath, string data, string typename);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_ImportAudio(string inputPath, string outputPath, ref AudioImportSettings.InternalOptions options);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CopyCache", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_CopyCache(ref Guid dstId, ref Guid srcId);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_GetAudioClipMetadata(IntPtr obj, out int originalSize, out int importedSize);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_BakeLightmaps", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_BakeLightmaps([MarshalAs(UnmanagedType.U1)] bool cancel);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_SaveJsonAsset(string outputPath, string data, string typename);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetShaderAssetSourceCode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial string Internal_GetShaderAssetSourceCode(IntPtr obj);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_CopyCache(ref Guid dstId, ref Guid srcId);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CookMeshCollision", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, uint materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_BakeLightmaps(bool cancel);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetCollisionWires", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_GetCollisionWires(IntPtr collisionData, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "trianglesCount")] out Float3[] triangles, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "indicesCount")] out int[] indices, out int trianglesCount, out int indicesCount);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern string Internal_GetShaderAssetSourceCode(IntPtr obj);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetEditorBoxWithChildren", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_GetEditorBoxWithChildren(IntPtr obj, out BoundingBox resultAsRef);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, uint materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_SetOptions(ref InternalOptions options);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_GetCollisionWires(IntPtr collisionData, out Float3[] triangles, out int[] indices);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_DrawNavMesh", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_DrawNavMesh();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_GetEditorBoxWithChildren(IntPtr obj, out BoundingBox resultAsRef);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CloseSplashScreen", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_CloseSplashScreen();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_SetOptions(ref InternalOptions options);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CreateAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CreateAsset(NewAssetType type, string outputPath);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_DrawNavMesh();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CreateVisualScript", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CreateVisualScript(string outputPath, string baseTypename);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_CloseSplashScreen();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanImport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial string Internal_CanImport(string extension);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CreateAsset(NewAssetType type, string outputPath);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanExport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CanExport(string path);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CreateVisualScript(string outputPath, string baseTypename);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_Export", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_Export(string inputPath, string outputFolder);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern string Internal_CanImport(string extension);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetIsEveryAssemblyLoaded", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_GetIsEveryAssemblyLoaded();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CanExport(string path);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetLastProjectOpenedEngineBuild", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial int Internal_GetLastProjectOpenedEngineBuild();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_Export(string inputPath, string outputFolder);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetIsCSGActive", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_GetIsCSGActive();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_GetIsEveryAssemblyLoaded();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_RunVisualScriptBreakpointLoopTick", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern int Internal_GetLastProjectOpenedEngineBuild();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetVisualScriptLocals", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "localsCount")]
|
||||
internal static partial VisualScriptLocal[] Internal_GetVisualScriptLocals(out int localsCount);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_GetIsCSGActive();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetVisualScriptStackFrames", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "stackFrameCount")]
|
||||
internal static partial VisualScriptStackFrame[] Internal_GetVisualScriptStackFrames(out int stackFrameCount);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetVisualScriptPreviousScopeFrame", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial VisualScriptStackFrame Internal_GetVisualScriptPreviousScopeFrame();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern VisualScriptLocal[] Internal_GetVisualScriptLocals();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_EvaluateVisualScriptLocal", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_EvaluateVisualScriptLocal(IntPtr script, ref VisualScriptLocal local);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern VisualScriptStackFrame[] Internal_GetVisualScriptStackFrames();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_DeserializeSceneObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_DeserializeSceneObject(IntPtr sceneObject, string json);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern VisualScriptStackFrame Internal_GetVisualScriptPreviousScopeFrame();
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_LoadAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_LoadAsset(ref Guid id);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_EvaluateVisualScriptLocal(IntPtr script, ref VisualScriptLocal local);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanSetToRoot", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_DeserializeSceneObject(IntPtr sceneObject, string json);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial float Internal_GetAnimationTime(IntPtr animatedModel);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_LoadAsset(ref Guid id);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern float Internal_GetAnimationTime(IntPtr animatedModel);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Internal_SetAnimationTime(IntPtr animatedModel, float time);
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_SetAnimationTime(IntPtr animatedModel, float time);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -137,11 +137,13 @@ namespace FlaxEditor
|
||||
public SpriteHandle PS4Icon128;
|
||||
public SpriteHandle PS5Icon128;
|
||||
public SpriteHandle MacOSIcon128;
|
||||
public SpriteHandle IOSIcon128;
|
||||
public SpriteHandle FlaxLogo128;
|
||||
public SpriteHandle SwitchIcon128;
|
||||
public SpriteHandle SwitchSettings128;
|
||||
public SpriteHandle LocalizationSettings128;
|
||||
public SpriteHandle Json128;
|
||||
public SpriteHandle AppleSettings128;
|
||||
|
||||
internal void LoadIcons()
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ using FlaxEditor.GUI.Drag;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.GUI
|
||||
{
|
||||
@@ -205,6 +206,11 @@ namespace FlaxEditor.GUI
|
||||
/// </summary>
|
||||
public event Action SelectedItemChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The custom callback for assets validation. Cane be used to implement a rule for assets to pick.
|
||||
/// </summary>
|
||||
public Func<ContentItem, bool> CheckValid;
|
||||
|
||||
/// <summary>
|
||||
/// False if changing selected item is disabled.
|
||||
/// </summary>
|
||||
@@ -214,6 +220,8 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
if (_fileExtension != null && !item.Path.EndsWith(_fileExtension))
|
||||
return false;
|
||||
if (CheckValid != null && !CheckValid(item))
|
||||
return false;
|
||||
if (_type == ScriptType.Null)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.GUI
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Xml;
|
||||
using System.Globalization;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Assertions;
|
||||
using FlaxEngine.GUI;
|
||||
@@ -423,6 +424,29 @@ namespace FlaxEditor.GUI.Docking
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes splitter panel value into the saved layout.
|
||||
/// </summary>
|
||||
/// <param name="writer">The Xml writer.</param>
|
||||
/// <param name="name">The Xml attribute name to use for value.</param>
|
||||
/// <param name="splitter">The splitter panel.</param>
|
||||
protected void LayoutSerializeSplitter(XmlWriter writer, string name, SplitPanel splitter)
|
||||
{
|
||||
writer.WriteAttributeString(name, splitter.SplitterValue.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes splitter panel value from the saved layout.
|
||||
/// </summary>
|
||||
/// <param name="node">The Xml document node.</param>
|
||||
/// <param name="name">The Xml attribute name to use for value.</param>
|
||||
/// <param name="splitter">The splitter panel.</param>
|
||||
protected void LayoutDeserializeSplitter(XmlElement node, string name, SplitPanel splitter)
|
||||
{
|
||||
if (float.TryParse(node.GetAttribute(name), CultureInfo.InvariantCulture, out float value) && value > 0.01f && value < 0.99f)
|
||||
splitter.SplitterValue = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using FlaxEditor.SceneGraph;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.GUI.Drag
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEditor.Scripting;
|
||||
@@ -170,7 +171,7 @@ namespace FlaxEditor.GUI
|
||||
BuildEntriesDefault(type, _entries, formatMode);
|
||||
|
||||
var hasTooltips = false;
|
||||
var entries = Utils.ExtractArrayFromList(_entries);
|
||||
var entries = CollectionsMarshal.AsSpan(_entries);
|
||||
for (int i = 0; i < _entries.Count; i++)
|
||||
{
|
||||
ref var e = ref entries[i];
|
||||
|
||||
@@ -92,6 +92,7 @@ namespace FlaxEditor.GUI
|
||||
new PlatformData(PlatformType.Switch, icons.SwitchIcon128, "Switch"),
|
||||
new PlatformData(PlatformType.PS5, icons.PS5Icon128, "PlayStation 5"),
|
||||
new PlatformData(PlatformType.Mac, icons.MacOSIcon128, "macOS"),
|
||||
new PlatformData(PlatformType.iOS, icons.IOSIcon128, "iOS"),
|
||||
};
|
||||
|
||||
const float IconSize = 64.0f;
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.GUI
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.GUI
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ using FlaxEditor.GUI.Timeline.Tracks;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEditor.Viewport.Previews;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.GUI.Timeline
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Text;
|
||||
using FlaxEditor.GUI.Timeline.Undo;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
{
|
||||
@@ -539,7 +540,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
throw new Exception("Invalid track data.");
|
||||
|
||||
var keyframes = new object[keyframesCount];
|
||||
var propertyType = Scripting.TypeUtils.GetType(e.MemberTypeName).Type;
|
||||
var propertyType = TypeUtils.GetType(e.MemberTypeName).Type;
|
||||
if (propertyType == null)
|
||||
{
|
||||
stream.ReadBytes(keyframesCount * (sizeof(float) + valueSize * 3));
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Text;
|
||||
using FlaxEditor.GUI.Timeline.Undo;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
{
|
||||
@@ -51,7 +52,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
{
|
||||
e.EventParamsSizes[i] = stream.ReadInt32();
|
||||
var paramTypeName = LoadName(stream);
|
||||
e.EventParamsTypes[i] = Scripting.TypeUtils.GetManagedType(paramTypeName);
|
||||
e.EventParamsTypes[i] = TypeUtils.GetManagedType(paramTypeName);
|
||||
if (e.EventParamsTypes[i] == null)
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Text;
|
||||
using FlaxEditor.GUI.Timeline.Undo;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
{
|
||||
@@ -56,7 +57,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
|
||||
var keyframes = new KeyframesEditor.Keyframe[keyframesCount];
|
||||
var dataBuffer = new byte[e.ValueSize];
|
||||
var propertyType = Scripting.TypeUtils.GetManagedType(e.MemberTypeName);
|
||||
var propertyType = TypeUtils.GetManagedType(e.MemberTypeName);
|
||||
if (propertyType == null)
|
||||
{
|
||||
e.Keyframes.ResetKeyframes();
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
{
|
||||
@@ -48,7 +49,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
if (stream.ReadChar() != 0)
|
||||
throw new Exception("Invalid track data.");
|
||||
|
||||
var propertyType = Scripting.TypeUtils.GetType(e.MemberTypeName);
|
||||
var propertyType = TypeUtils.GetType(e.MemberTypeName);
|
||||
if (!propertyType)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.MemberTypeName))
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
{
|
||||
@@ -51,7 +52,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
throw new Exception("Invalid track data.");
|
||||
|
||||
var keyframes = new KeyframesEditor.Keyframe[keyframesCount];
|
||||
var propertyType = Scripting.TypeUtils.GetType(e.MemberTypeName);
|
||||
var propertyType = TypeUtils.GetType(e.MemberTypeName);
|
||||
if (!propertyType)
|
||||
{
|
||||
e.Keyframes.ResetKeyframes();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user