diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml
index 55e3fbd3..9359c2ff 100644
--- a/.github/workflows/test-build.yml
+++ b/.github/workflows/test-build.yml
@@ -13,7 +13,7 @@ concurrency:
jobs:
test:
if: github.event.pull_request.head.repo.fork == false
- name: Build sample app ๐ ๏ธ
+ name: Test sample app ๐ ๏ธ
runs-on: ubuntu-latest-8-cores
steps:
@@ -132,6 +132,7 @@ jobs:
targetPlatform:
- iOS
- Android
+ - StandaloneWindows64
steps:
- uses: actions/checkout@v4
with:
diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml
index b141e609..cd65b7c7 100644
--- a/.github/workflows/ui-tests.yml
+++ b/.github/workflows/ui-tests.yml
@@ -13,7 +13,8 @@ on:
- All
- StandaloneOSX # Builds Unity 2021 macOS only
- StandaloneOSX-Unity6 # Builds Unity 6 macOS only
- - StandaloneWindows64
+ - StandaloneWindows64 # Builds Unity 2021 Windows only
+ - StandaloneWindows64-Unity6 # Builds Unity 6 Windows only
# - Android
# - iOS
push:
@@ -88,8 +89,8 @@ jobs:
name: Build & Test Unity 6 macOS ๐ ๏ธ๐งช
runs-on: [self-hosted, macOS]
concurrency:
- group: ui-tests-email-inbox-macos
- cancel-in-progress: false # Let tests complete rather than canceling
+ group: ui-tests-email-inbox-macos-unity6
+ cancel-in-progress: false # Let tests complete rather than cancelling
if: github.event_name != 'workflow_dispatch' || github.event.inputs.targetPlatform == 'All' || github.event.inputs.targetPlatform == 'StandaloneOSX-Unity6'
steps:
- name: Cleanup old builds
@@ -99,6 +100,8 @@ jobs:
- uses: actions/checkout@v3
with:
lfs: true
+ - name: Setup symlinks for Unity 6 macOS
+ run: ./setup-symlinks.sh
- name: Force clean package resolution
run: |
echo "Removing Library folder to force clean package resolution..."
@@ -171,7 +174,153 @@ jobs:
if: always()
uses: actions/upload-artifact@v4
with:
- name: Unity6-Build-Log
+ name: Unity6-macOS-Build-Log
+ path: sample-unity6/build-log.log
+
+ build-and-test-unity6-windows: # Unity 6 requires a full build cycle to compile AltTester packages properly. This doesn't work well in Game CI, so we have to build it manually.
+ name: Build & Test Unity 6 Windows ๐ ๏ธ๐งช
+ runs-on: [self-hosted, windows]
+ concurrency:
+ group: ui-tests-email-inbox-windows-unity6
+ cancel-in-progress: false # Let tests complete rather than cancelling
+ if: github.event_name != 'workflow_dispatch' || github.event.inputs.targetPlatform == 'All' || github.event.inputs.targetPlatform == 'StandaloneWindows64-Unity6'
+ steps:
+ - name: Cleanup old builds
+ run: |
+ # Remove previous build to save space
+ if (Test-Path "sample-unity6/Tests") { Remove-Item -Recurse -Force "sample-unity6/Tests" -ErrorAction SilentlyContinue }
+ - uses: actions/checkout@v3
+ with:
+ lfs: true
+ - name: Cache Unity Library folder
+ uses: actions/cache@v3
+ with:
+ path: sample-unity6/Library
+ key: Library-Unity6-Windows-${{ hashFiles('sample-unity6/Assets/**', 'sample-unity6/Packages/**', 'sample-unity6/ProjectSettings/**') }}
+ restore-keys: |
+ Library-Unity6-Windows-
+ - name: Setup symlinks for Unity 6 Windows
+ run: .\setup-symlinks.ps1
+ - name: Verify symlinks were created
+ run: |
+ if (-not (Test-Path "sample-unity6/Assets/Editor/WindowsBuilderUnity6.cs")) {
+ Write-Output "โ Build script not found - symlink setup failed"
+ exit 1
+ }
+ Write-Output "โ
Symlinks verified"
+ # Don't delete Library folder - let Unity reuse cached package data if available
+ # Deleting it forces a complete reimport which takes too long
+ - name: Ensure Tests directory exists
+ run: |
+ if (-not (Test-Path "sample-unity6/Tests")) {
+ New-Item -ItemType Directory -Path "sample-unity6/Tests" -Force | Out-Null
+ }
+ - name: First build (resolves packages)
+ run: |
+ Write-Output "Running first build to trigger package resolution..."
+
+ $unityPath = "C:\Program Files\Unity\Hub\Editor\6000.0.58f2\Editor\Unity.exe"
+ $projectPath = "${{ github.workspace }}\sample-unity6"
+ $logFile = "${{ github.workspace }}\sample-unity6\first-build-log.txt"
+ $buildPath = "${{ github.workspace }}\sample-unity6\Tests\Sample Unity 6 Windows.exe"
+
+ $arguments = @(
+ "-projectPath", "`"$projectPath`"",
+ "-executeMethod", "WindowsBuilderUnity6.BuildForAltTester",
+ "-logFile", "`"$logFile`"",
+ "-quit", "-batchmode", "-nographics",
+ "--buildPath", "`"$buildPath`""
+ )
+
+ # Run and ignore exit code (may fail on first attempt)
+ $process = Start-Process -FilePath $unityPath `
+ -ArgumentList $arguments `
+ -Wait -PassThru -NoNewWindow
+
+ Write-Output "First build completed (exit code: $($process.ExitCode), may have failed, that's ok). Checking for AltTester..."
+
+ if (Test-Path "${{ github.workspace }}\sample-unity6\Library\PackageCache") {
+ $altTesterFound = Get-ChildItem "${{ github.workspace }}\sample-unity6\Library\PackageCache" -Filter "*alttester*" -ErrorAction SilentlyContinue
+ if ($altTesterFound) {
+ Write-Output "โ
AltTester found in PackageCache after first build"
+ } else {
+ Write-Output "โ ๏ธ AltTester not found yet, but will be ready for second build"
+ }
+ }
+ - name: Build Unity 6 Windows executable
+ timeout-minutes: 20
+ run: |
+ Write-Output "Building Unity 6 Windows executable..."
+ Write-Output "Started at: $(Get-Date -Format 'HH:mm:ss')"
+
+ # Run Unity build
+ $unityPath = "C:\Program Files\Unity\Hub\Editor\6000.0.58f2\Editor\Unity.exe"
+ $projectPath = "${{ github.workspace }}\sample-unity6"
+ $logFile = "${{ github.workspace }}\sample-unity6\build-log.log"
+ $buildPath = "${{ github.workspace }}\sample-unity6\Tests\Sample Unity 6 Windows.exe"
+
+ # Build argument list with proper quoting for paths with spaces
+ $arguments = @(
+ "-projectPath", "`"$projectPath`"",
+ "-executeMethod", "WindowsBuilderUnity6.BuildForAltTester",
+ "-logFile", "`"$logFile`"",
+ "-quit", "-batchmode", "-nographics",
+ "--buildPath", "`"$buildPath`""
+ )
+
+ $process = Start-Process -FilePath $unityPath `
+ -ArgumentList $arguments `
+ -Wait -PassThru -NoNewWindow
+
+ $buildExitCode = $process.ExitCode
+ Write-Output "Finished at: $(Get-Date -Format 'HH:mm:ss') (exit code: $buildExitCode)"
+
+ # Verify build output
+ Start-Sleep -Seconds 2
+ if (Test-Path $buildPath) {
+ $fileSize = (Get-Item $buildPath).Length / 1MB
+ Write-Output "โ
Build succeeded! ($([math]::Round($fileSize, 2)) MB)"
+ } else {
+ Write-Output "โ Build failed! Executable not found"
+ Write-Output ""
+ Write-Output "Build log:"
+ if (Test-Path $logFile) {
+ Get-Content $logFile
+ } else {
+ Write-Output "โ ๏ธ Log file not found at: $logFile"
+ }
+ exit 1
+ }
+ - uses: actions/setup-python@v4
+ with:
+ python-version: "3.13"
+ - name: Verify test files are accessible
+ run: |
+ if (-not (Test-Path "sample-unity6/Tests/requirements-desktop.txt") -and -not (Test-Path "sample/Tests/requirements-desktop.txt")) {
+ Write-Output "โ Test requirements file not found"
+ exit 1
+ }
+ - name: Install dependencies
+ run: |
+ if (Test-Path "sample-unity6/Tests/requirements-desktop.txt") {
+ pip install -r sample-unity6/Tests/requirements-desktop.txt
+ } else {
+ pip install -r sample/Tests/requirements-desktop.txt
+ }
+ - name: Run UI tests
+ env:
+ UNITY_APP_PATH: Sample Unity 6 Windows.exe
+ UNITY_APP_NAME: Sample Unity 6 Windows
+ MAILSLURP_API_KEY: ${{ secrets.MAILSLURP_API_KEY }}
+ BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
+ BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
+ working-directory: sample-unity6/Tests
+ run: python -m pytest -xs test/test_windows.py::WindowsTest
+ - name: Upload build log
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: Unity6-Windows-Build-Log
path: sample-unity6/build-log.log
test:
diff --git a/README.md b/README.md
index b6bf27a5..d18056d6 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ The Immutable SDK for Unity helps you integrate your game with Immutable Passpor
This repository contains two sample projects:
- **`sample/`** - Unity 2021.3.26f1 sample project
-- **`sample-unity6/`** - Unity 6 sample project *(work in progress)*
+- **`sample-unity6/`** - Unity 6 sample project
Both projects share the same Scenes, Scripts, Editor folders, and Tests via symbolic links, providing a single source of truth for the sample code. See [`sample-unity6/README.md`](sample-unity6/README.md) for setup instructions.
@@ -36,13 +36,14 @@ The `sample-unity6` project uses symbolic links to share Scenes, Scripts, Editor
1. Navigate to `sample-unity6/Assets/` and `sample-unity6/`
2. Check if `Scenes`, `Scripts`, `Editor`, and `Tests` are folders (symlinks work) or small text files (symlinks didn't work)
-If symlinks didn't work, run the setup script:
+If symlinks didn't work, run the setup script as Administrator:
```powershell
+# Right-click PowerShell -> "Run as Administrator"
.\setup-symlinks.ps1
```
-> **Note for Windows users**: You'll need Developer Mode enabled or run PowerShell as Administrator. See [`sample-unity6/README.md`](sample-unity6/README.md) for details.
+> **Note for Windows users**: You must run PowerShell as Administrator. Directory symbolic links (required for Unity to recognise the folders) need admin privileges on Windows. See [`sample-unity6/README.md`](sample-unity6/README.md) for details.
## Contributing
diff --git a/sample-unity6/Assets/Settings/Build Profiles/Windows Profile.asset b/sample-unity6/Assets/Settings/Build Profiles/Windows Profile.asset
new file mode 100644
index 00000000..8e7c9e9c
--- /dev/null
+++ b/sample-unity6/Assets/Settings/Build Profiles/Windows Profile.asset
@@ -0,0 +1,941 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 15003, guid: 0000000000000000e000000000000000, type: 0}
+ m_Name: Windows Profile
+ m_EditorClassIdentifier:
+ m_AssetVersion: 1
+ m_BuildTarget: 19
+ m_Subtarget: 2
+ m_PlatformId: 4e3c793746204150860bf175a9a41a05
+ m_PlatformBuildProfile:
+ rid: 5612885467593965569
+ m_OverrideGlobalSceneList: 0
+ m_Scenes: []
+ m_ScriptingDefines: []
+ m_PlayerSettingsYaml:
+ m_Settings:
+ - line: '| PlayerSettings:'
+ - line: '| m_ObjectHideFlags: 0'
+ - line: '| serializedVersion: 28'
+ - line: '| productGUID: 543e391184db44674bc1eecd92dbc5f3'
+ - line: '| AndroidProfiler: 0'
+ - line: '| AndroidFilterTouchesWhenObscured: 0'
+ - line: '| AndroidEnableSustainedPerformanceMode: 0'
+ - line: '| defaultScreenOrientation: 4'
+ - line: '| targetDevice: 2'
+ - line: '| useOnDemandResources: 0'
+ - line: '| accelerometerFrequency: 60'
+ - line: '| companyName: Immutable'
+ - line: '| productName: Sample Unity 6 Windows'
+ - line: '| defaultCursor: {instanceID: 0}'
+ - line: '| cursorHotspot: {x: 0, y: 0}'
+ - line: '| m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b:
+ 0.1254902, a: 1}'
+ - line: '| m_ShowUnitySplashScreen: 1'
+ - line: '| m_ShowUnitySplashLogo: 1'
+ - line: '| m_SplashScreenOverlayOpacity: 1'
+ - line: '| m_SplashScreenAnimation: 1'
+ - line: '| m_SplashScreenLogoStyle: 1'
+ - line: '| m_SplashScreenDrawMode: 0'
+ - line: '| m_SplashScreenBackgroundAnimationZoom: 1'
+ - line: '| m_SplashScreenLogoAnimationZoom: 1'
+ - line: '| m_SplashScreenBackgroundLandscapeAspect: 1'
+ - line: '| m_SplashScreenBackgroundPortraitAspect: 1'
+ - line: '| m_SplashScreenBackgroundLandscapeUvs:'
+ - line: '| serializedVersion: 2'
+ - line: '| x: 0'
+ - line: '| y: 0'
+ - line: '| width: 1'
+ - line: '| height: 1'
+ - line: '| m_SplashScreenBackgroundPortraitUvs:'
+ - line: '| serializedVersion: 2'
+ - line: '| x: 0'
+ - line: '| y: 0'
+ - line: '| width: 1'
+ - line: '| height: 1'
+ - line: '| m_SplashScreenLogos: []'
+ - line: '| m_VirtualRealitySplashScreen: {instanceID: 0}'
+ - line: '| m_HolographicTrackingLossScreen: {instanceID: 0}'
+ - line: '| defaultScreenWidth: 1920'
+ - line: '| defaultScreenHeight: 1080'
+ - line: '| defaultScreenWidthWeb: 960'
+ - line: '| defaultScreenHeightWeb: 600'
+ - line: '| m_StereoRenderingPath: 0'
+ - line: '| m_ActiveColorSpace: 1'
+ - line: '| unsupportedMSAAFallback: 0'
+ - line: '| m_SpriteBatchMaxVertexCount: 65535'
+ - line: '| m_SpriteBatchVertexThreshold: 300'
+ - line: '| m_MTRendering: 1'
+ - line: '| mipStripping: 0'
+ - line: '| numberOfMipsStripped: 0'
+ - line: '| numberOfMipsStrippedPerMipmapLimitGroup: {}'
+ - line: '| m_StackTraceTypes: 010000000100000001000000010000000100000001000000'
+ - line: '| iosShowActivityIndicatorOnLoading: -1'
+ - line: '| androidShowActivityIndicatorOnLoading: -1'
+ - line: '| iosUseCustomAppBackgroundBehavior: 0'
+ - line: '| allowedAutorotateToPortrait: 1'
+ - line: '| allowedAutorotateToPortraitUpsideDown: 1'
+ - line: '| allowedAutorotateToLandscapeRight: 1'
+ - line: '| allowedAutorotateToLandscapeLeft: 1'
+ - line: '| useOSAutorotation: 1'
+ - line: '| use32BitDisplayBuffer: 1'
+ - line: '| preserveFramebufferAlpha: 0'
+ - line: '| disableDepthAndStencilBuffers: 0'
+ - line: '| androidStartInFullscreen: 1'
+ - line: '| androidRenderOutsideSafeArea: 1'
+ - line: '| androidUseSwappy: 1'
+ - line: '| androidBlitType: 0'
+ - line: '| androidResizeableActivity: 1'
+ - line: '| androidDefaultWindowWidth: 1920'
+ - line: '| androidDefaultWindowHeight: 1080'
+ - line: '| androidMinimumWindowWidth: 400'
+ - line: '| androidMinimumWindowHeight: 300'
+ - line: '| androidFullscreenMode: 1'
+ - line: '| androidAutoRotationBehavior: 1'
+ - line: '| androidPredictiveBackSupport: 0'
+ - line: '| androidApplicationEntry: 2'
+ - line: '| defaultIsNativeResolution: 1'
+ - line: '| macRetinaSupport: 1'
+ - line: '| runInBackground: 0'
+ - line: '| muteOtherAudioSources: 0'
+ - line: '| Prepare IOS For Recording: 0'
+ - line: '| Force IOS Speakers When Recording: 0'
+ - line: '| audioSpatialExperience: 0'
+ - line: '| deferSystemGesturesMode: 0'
+ - line: '| hideHomeButton: 0'
+ - line: '| submitAnalytics: 1'
+ - line: '| usePlayerLog: 1'
+ - line: '| dedicatedServerOptimizations: 1'
+ - line: '| bakeCollisionMeshes: 0'
+ - line: '| forceSingleInstance: 0'
+ - line: '| useFlipModelSwapchain: 1'
+ - line: '| resizableWindow: 0'
+ - line: '| useMacAppStoreValidation: 0'
+ - line: '| macAppStoreCategory: public.app-category.games'
+ - line: '| gpuSkinning: 0'
+ - line: '| meshDeformation: 0'
+ - line: '| xboxPIXTextureCapture: 0'
+ - line: '| xboxEnableAvatar: 0'
+ - line: '| xboxEnableKinect: 0'
+ - line: '| xboxEnableKinectAutoTracking: 0'
+ - line: '| xboxEnableFitness: 0'
+ - line: '| visibleInBackground: 1'
+ - line: '| allowFullscreenSwitch: 1'
+ - line: '| fullscreenMode: 3'
+ - line: '| xboxSpeechDB: 0'
+ - line: '| xboxEnableHeadOrientation: 0'
+ - line: '| xboxEnableGuest: 0'
+ - line: '| xboxEnablePIXSampling: 0'
+ - line: '| metalFramebufferOnly: 0'
+ - line: '| xboxOneResolution: 0'
+ - line: '| xboxOneSResolution: 0'
+ - line: '| xboxOneXResolution: 3'
+ - line: '| xboxOneMonoLoggingLevel: 0'
+ - line: '| xboxOneLoggingLevel: 1'
+ - line: '| xboxOneDisableEsram: 0'
+ - line: '| xboxOneEnableTypeOptimization: 0'
+ - line: '| xboxOnePresentImmediateThreshold: 0'
+ - line: '| switchQueueCommandMemory: 1048576'
+ - line: '| switchQueueControlMemory: 16384'
+ - line: '| switchQueueComputeMemory: 262144'
+ - line: '| switchNVNShaderPoolsGranularity: 33554432'
+ - line: '| switchNVNDefaultPoolsGranularity: 16777216'
+ - line: '| switchNVNOtherPoolsGranularity: 16777216'
+ - line: '| switchGpuScratchPoolGranularity: 2097152'
+ - line: '| switchAllowGpuScratchShrinking: 0'
+ - line: '| switchNVNMaxPublicTextureIDCount: 0'
+ - line: '| switchNVNMaxPublicSamplerIDCount: 0'
+ - line: '| switchMaxWorkerMultiple: 8'
+ - line: '| switchNVNGraphicsFirmwareMemory: 32'
+ - line: '| vulkanNumSwapchainBuffers: 3'
+ - line: '| vulkanEnableSetSRGBWrite: 0'
+ - line: '| vulkanEnablePreTransform: 0'
+ - line: '| vulkanEnableLateAcquireNextImage: 0'
+ - line: '| vulkanEnableCommandBufferRecycling: 1'
+ - line: '| loadStoreDebugModeEnabled: 0'
+ - line: '| visionOSBundleVersion: 1.0'
+ - line: '| tvOSBundleVersion: 1.0'
+ - line: '| bundleVersion: 1.0'
+ - line: '| preloadedAssets:'
+ - line: '| - {fileID: -944628639613478452, guid: 2bcd2660ca9b64942af0de543d8d7100,
+ type: 3}'
+ - line: '| metroInputSource: 0'
+ - line: '| wsaTransparentSwapchain: 0'
+ - line: '| m_HolographicPauseOnTrackingLoss: 1'
+ - line: '| xboxOneDisableKinectGpuReservation: 1'
+ - line: '| xboxOneEnable7thCore: 1'
+ - line: '| vrSettings:'
+ - line: '| enable360StereoCapture: 0'
+ - line: '| isWsaHolographicRemotingEnabled: 0'
+ - line: '| enableFrameTimingStats: 0'
+ - line: '| enableOpenGLProfilerGPURecorders: 1'
+ - line: '| allowHDRDisplaySupport: 0'
+ - line: '| useHDRDisplay: 0'
+ - line: '| hdrBitDepth: 0'
+ - line: '| m_ColorGamuts: 00000000'
+ - line: '| targetPixelDensity: 30'
+ - line: '| resolutionScalingMode: 0'
+ - line: '| resetResolutionOnWindowResize: 0'
+ - line: '| androidSupportedAspectRatio: 1'
+ - line: '| androidMaxAspectRatio: 2.4'
+ - line: '| androidMinAspectRatio: 1'
+ - line: '| applicationIdentifier:'
+ - line: '| Standalone: com.DefaultCompany.2D-URP'
+ - line: '| buildNumber:'
+ - line: '| Standalone: 0'
+ - line: '| VisionOS: 0'
+ - line: '| iPhone: 0'
+ - line: '| tvOS: 0'
+ - line: '| overrideDefaultApplicationIdentifier: 1'
+ - line: '| AndroidBundleVersionCode: 1'
+ - line: '| AndroidMinSdkVersion: 23'
+ - line: '| AndroidTargetSdkVersion: 0'
+ - line: '| AndroidPreferredInstallLocation: 1'
+ - line: '| aotOptions: '
+ - line: '| stripEngineCode: 1'
+ - line: '| iPhoneStrippingLevel: 0'
+ - line: '| iPhoneScriptCallOptimization: 0'
+ - line: '| ForceInternetPermission: 0'
+ - line: '| ForceSDCardPermission: 0'
+ - line: '| CreateWallpaper: 0'
+ - line: '| androidSplitApplicationBinary: 0'
+ - line: '| keepLoadedShadersAlive: 0'
+ - line: '| StripUnusedMeshComponents: 0'
+ - line: '| strictShaderVariantMatching: 0'
+ - line: '| VertexChannelCompressionMask: 4054'
+ - line: '| iPhoneSdkVersion: 988'
+ - line: '| iOSSimulatorArchitecture: 0'
+ - line: '| iOSTargetOSVersionString: 13.0'
+ - line: '| tvOSSdkVersion: 0'
+ - line: '| tvOSSimulatorArchitecture: 0'
+ - line: '| tvOSRequireExtendedGameController: 0'
+ - line: '| tvOSTargetOSVersionString: 13.0'
+ - line: '| VisionOSSdkVersion: 0'
+ - line: '| VisionOSTargetOSVersionString: 1.0'
+ - line: '| uIPrerenderedIcon: 0'
+ - line: '| uIRequiresPersistentWiFi: 0'
+ - line: '| uIRequiresFullScreen: 1'
+ - line: '| uIStatusBarHidden: 1'
+ - line: '| uIExitOnSuspend: 0'
+ - line: '| uIStatusBarStyle: 0'
+ - line: '| appleTVSplashScreen: {instanceID: 0}'
+ - line: '| appleTVSplashScreen2x: {instanceID: 0}'
+ - line: '| tvOSSmallIconLayers: []'
+ - line: '| tvOSSmallIconLayers2x: []'
+ - line: '| tvOSLargeIconLayers: []'
+ - line: '| tvOSLargeIconLayers2x: []'
+ - line: '| tvOSTopShelfImageLayers: []'
+ - line: '| tvOSTopShelfImageLayers2x: []'
+ - line: '| tvOSTopShelfImageWideLayers: []'
+ - line: '| tvOSTopShelfImageWideLayers2x: []'
+ - line: '| iOSLaunchScreenType: 0'
+ - line: '| iOSLaunchScreenPortrait: {instanceID: 0}'
+ - line: '| iOSLaunchScreenLandscape: {instanceID: 0}'
+ - line: '| iOSLaunchScreenBackgroundColor:'
+ - line: '| serializedVersion: 2'
+ - line: '| rgba: 0'
+ - line: '| iOSLaunchScreenFillPct: 100'
+ - line: '| iOSLaunchScreenSize: 100'
+ - line: '| iOSLaunchScreeniPadType: 0'
+ - line: '| iOSLaunchScreeniPadImage: {instanceID: 0}'
+ - line: '| iOSLaunchScreeniPadBackgroundColor:'
+ - line: '| serializedVersion: 2'
+ - line: '| rgba: 0'
+ - line: '| iOSLaunchScreeniPadFillPct: 100'
+ - line: '| iOSLaunchScreeniPadSize: 100'
+ - line: '| iOSLaunchScreenCustomStoryboardPath: '
+ - line: '| iOSLaunchScreeniPadCustomStoryboardPath: '
+ - line: '| iOSDeviceRequirements: []'
+ - line: '| iOSURLSchemes:'
+ - line: '| - immutablerunner'
+ - line: '| macOSURLSchemes:'
+ - line: '| - immutablerunner'
+ - line: '| iOSBackgroundModes: 0'
+ - line: '| iOSMetalForceHardShadows: 0'
+ - line: '| metalEditorSupport: 1'
+ - line: '| metalAPIValidation: 1'
+ - line: '| metalCompileShaderBinary: 0'
+ - line: '| iOSRenderExtraFrameOnPause: 0'
+ - line: '| iosCopyPluginsCodeInsteadOfSymlink: 0'
+ - line: '| appleDeveloperTeamID: '
+ - line: '| iOSManualSigningProvisioningProfileID: '
+ - line: '| tvOSManualSigningProvisioningProfileID: '
+ - line: '| VisionOSManualSigningProvisioningProfileID: '
+ - line: '| iOSManualSigningProvisioningProfileType: 0'
+ - line: '| tvOSManualSigningProvisioningProfileType: 0'
+ - line: '| VisionOSManualSigningProvisioningProfileType: 0'
+ - line: '| appleEnableAutomaticSigning: 0'
+ - line: '| iOSRequireARKit: 0'
+ - line: '| iOSAutomaticallyDetectAndAddCapabilities: 1'
+ - line: '| appleEnableProMotion: 0'
+ - line: '| shaderPrecisionModel: 0'
+ - line: '| clonedFromGUID: c19f32bac17ee4170b3bf8a6a0333fb9'
+ - line: '| templatePackageId: com.unity.template.universal-2d@5.1.0'
+ - line: '| templateDefaultScene: Assets/Scenes/SampleScene.unity'
+ - line: '| useCustomMainManifest: 1'
+ - line: '| useCustomLauncherManifest: 0'
+ - line: '| useCustomMainGradleTemplate: 1'
+ - line: '| useCustomLauncherGradleManifest: 0'
+ - line: '| useCustomBaseGradleTemplate: 0'
+ - line: '| useCustomGradlePropertiesTemplate: 0'
+ - line: '| useCustomGradleSettingsTemplate: 0'
+ - line: '| useCustomProguardFile: 1'
+ - line: '| AndroidTargetArchitectures: 2'
+ - line: '| AndroidSplashScreenScale: 0'
+ - line: '| androidSplashScreen: {instanceID: 0}'
+ - line: '| AndroidKeystoreName: '
+ - line: '| AndroidKeyaliasName: '
+ - line: '| AndroidEnableArmv9SecurityFeatures: 0'
+ - line: '| AndroidEnableArm64MTE: 0'
+ - line: '| AndroidBuildApkPerCpuArchitecture: 0'
+ - line: '| AndroidTVCompatibility: 0'
+ - line: '| AndroidIsGame: 1'
+ - line: '| androidAppCategory: 3'
+ - line: '| useAndroidAppCategory: 1'
+ - line: '| androidAppCategoryOther: '
+ - line: '| AndroidEnableTango: 0'
+ - line: '| androidEnableBanner: 1'
+ - line: '| androidUseLowAccuracyLocation: 0'
+ - line: '| androidUseCustomKeystore: 0'
+ - line: '| m_AndroidBanners:'
+ - line: '| - width: 320'
+ - line: '| height: 180'
+ - line: '| banner: {instanceID: 0}'
+ - line: '| androidGamepadSupportLevel: 0'
+ - line: '| AndroidMinifyRelease: 0'
+ - line: '| AndroidMinifyDebug: 0'
+ - line: '| AndroidValidateAppBundleSize: 1'
+ - line: '| AndroidAppBundleSizeToValidate: 150'
+ - line: '| AndroidReportGooglePlayAppDependencies: 1'
+ - line: '| androidSymbolsSizeThreshold: 800'
+ - line: '| m_BuildTargetIcons: []'
+ - line: '| m_BuildTargetPlatformIcons:'
+ - line: '| - m_BuildTarget: iPhone'
+ - line: '| m_Icons:'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 180'
+ - line: '| m_Height: 180'
+ - line: '| m_Kind: 0'
+ - line: '| m_SubKind: iPhone'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 120'
+ - line: '| m_Height: 120'
+ - line: '| m_Kind: 0'
+ - line: '| m_SubKind: iPhone'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 167'
+ - line: '| m_Height: 167'
+ - line: '| m_Kind: 0'
+ - line: '| m_SubKind: iPad'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 152'
+ - line: '| m_Height: 152'
+ - line: '| m_Kind: 0'
+ - line: '| m_SubKind: iPad'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 76'
+ - line: '| m_Height: 76'
+ - line: '| m_Kind: 0'
+ - line: '| m_SubKind: iPad'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 120'
+ - line: '| m_Height: 120'
+ - line: '| m_Kind: 3'
+ - line: '| m_SubKind: iPhone'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 80'
+ - line: '| m_Height: 80'
+ - line: '| m_Kind: 3'
+ - line: '| m_SubKind: iPhone'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 80'
+ - line: '| m_Height: 80'
+ - line: '| m_Kind: 3'
+ - line: '| m_SubKind: iPad'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 40'
+ - line: '| m_Height: 40'
+ - line: '| m_Kind: 3'
+ - line: '| m_SubKind: iPad'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 87'
+ - line: '| m_Height: 87'
+ - line: '| m_Kind: 1'
+ - line: '| m_SubKind: iPhone'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 58'
+ - line: '| m_Height: 58'
+ - line: '| m_Kind: 1'
+ - line: '| m_SubKind: iPhone'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 29'
+ - line: '| m_Height: 29'
+ - line: '| m_Kind: 1'
+ - line: '| m_SubKind: iPhone'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 58'
+ - line: '| m_Height: 58'
+ - line: '| m_Kind: 1'
+ - line: '| m_SubKind: iPad'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 29'
+ - line: '| m_Height: 29'
+ - line: '| m_Kind: 1'
+ - line: '| m_SubKind: iPad'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 60'
+ - line: '| m_Height: 60'
+ - line: '| m_Kind: 2'
+ - line: '| m_SubKind: iPhone'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 40'
+ - line: '| m_Height: 40'
+ - line: '| m_Kind: 2'
+ - line: '| m_SubKind: iPhone'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 40'
+ - line: '| m_Height: 40'
+ - line: '| m_Kind: 2'
+ - line: '| m_SubKind: iPad'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 20'
+ - line: '| m_Height: 20'
+ - line: '| m_Kind: 2'
+ - line: '| m_SubKind: iPad'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 1024'
+ - line: '| m_Height: 1024'
+ - line: '| m_Kind: 4'
+ - line: '| m_SubKind: App Store'
+ - line: '| - m_BuildTarget: Android'
+ - line: '| m_Icons:'
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 432'
+ - line: '| m_Height: 432'
+ - line: '| m_Kind: 2'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 324'
+ - line: '| m_Height: 324'
+ - line: '| m_Kind: 2'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 216'
+ - line: '| m_Height: 216'
+ - line: '| m_Kind: 2'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 162'
+ - line: '| m_Height: 162'
+ - line: '| m_Kind: 2'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 108'
+ - line: '| m_Height: 108'
+ - line: '| m_Kind: 2'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 81'
+ - line: '| m_Height: 81'
+ - line: '| m_Kind: 2'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 192'
+ - line: '| m_Height: 192'
+ - line: '| m_Kind: 1'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 144'
+ - line: '| m_Height: 144'
+ - line: '| m_Kind: 1'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 96'
+ - line: '| m_Height: 96'
+ - line: '| m_Kind: 1'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 72'
+ - line: '| m_Height: 72'
+ - line: '| m_Kind: 1'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 48'
+ - line: '| m_Height: 48'
+ - line: '| m_Kind: 1'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 36'
+ - line: '| m_Height: 36'
+ - line: '| m_Kind: 1'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 192'
+ - line: '| m_Height: 192'
+ - line: '| m_Kind: 0'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 144'
+ - line: '| m_Height: 144'
+ - line: '| m_Kind: 0'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 96'
+ - line: '| m_Height: 96'
+ - line: '| m_Kind: 0'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 72'
+ - line: '| m_Height: 72'
+ - line: '| m_Kind: 0'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 48'
+ - line: '| m_Height: 48'
+ - line: '| m_Kind: 0'
+ - line: '| m_SubKind: '
+ - line: '| - m_Textures: []'
+ - line: '| m_Width: 36'
+ - line: '| m_Height: 36'
+ - line: '| m_Kind: 0'
+ - line: '| m_SubKind: '
+ - line: '| m_BuildTargetBatching: []'
+ - line: '| m_BuildTargetShaderSettings: []'
+ - line: '| m_BuildTargetGraphicsJobs: []'
+ - line: '| m_BuildTargetGraphicsJobMode: []'
+ - line: '| m_BuildTargetGraphicsAPIs: []'
+ - line: '| m_BuildTargetVRSettings: []'
+ - line: '| m_DefaultShaderChunkSizeInMB: 16'
+ - line: '| m_DefaultShaderChunkCount: 0'
+ - line: '| openGLRequireES31: 0'
+ - line: '| openGLRequireES31AEP: 0'
+ - line: '| openGLRequireES32: 0'
+ - line: '| m_TemplateCustomTags: {}'
+ - line: '| mobileMTRendering:'
+ - line: '| Android: 1'
+ - line: '| iPhone: 1'
+ - line: '| tvOS: 1'
+ - line: '| m_BuildTargetGroupLightmapEncodingQuality: []'
+ - line: '| m_BuildTargetGroupHDRCubemapEncodingQuality: []'
+ - line: '| m_BuildTargetGroupLightmapSettings: []'
+ - line: '| m_BuildTargetGroupLoadStoreDebugModeSettings: []'
+ - line: '| m_BuildTargetNormalMapEncoding: []'
+ - line: '| m_BuildTargetDefaultTextureCompressionFormat:'
+ - line: '| - serializedVersion: 3'
+ - line: '| m_BuildTarget: iOS'
+ - line: '| m_Formats: 03000000'
+ - line: '| - serializedVersion: 3'
+ - line: '| m_BuildTarget: Android'
+ - line: '| m_Formats: 01000000'
+ - line: '| playModeTestRunnerEnabled: 0'
+ - line: '| runPlayModeTestAsEditModeTest: 0'
+ - line: '| actionOnDotNetUnhandledException: 1'
+ - line: '| editorGfxJobOverride: 1'
+ - line: '| enableInternalProfiler: 0'
+ - line: '| logObjCUncaughtExceptions: 1'
+ - line: '| enableCrashReportAPI: 0'
+ - line: '| cameraUsageDescription: '
+ - line: '| locationUsageDescription: '
+ - line: '| microphoneUsageDescription: '
+ - line: '| bluetoothUsageDescription: '
+ - line: '| macOSTargetOSVersion: 11.0'
+ - line: '| switchNMETAOverride: '
+ - line: '| switchNetLibKey: '
+ - line: '| switchSocketMemoryPoolSize: 6144'
+ - line: '| switchSocketAllocatorPoolSize: 128'
+ - line: '| switchSocketConcurrencyLimit: 14'
+ - line: '| switchScreenResolutionBehavior: 2'
+ - line: '| switchUseCPUProfiler: 0'
+ - line: '| switchEnableFileSystemTrace: 0'
+ - line: '| switchLTOSetting: 0'
+ - line: '| switchApplicationID: 0x01004b9000490000'
+ - line: '| switchNSODependencies: '
+ - line: '| switchCompilerFlags: '
+ - line: '| switchTitleNames_0: '
+ - line: '| switchTitleNames_1: '
+ - line: '| switchTitleNames_2: '
+ - line: '| switchTitleNames_3: '
+ - line: '| switchTitleNames_4: '
+ - line: '| switchTitleNames_5: '
+ - line: '| switchTitleNames_6: '
+ - line: '| switchTitleNames_7: '
+ - line: '| switchTitleNames_8: '
+ - line: '| switchTitleNames_9: '
+ - line: '| switchTitleNames_10: '
+ - line: '| switchTitleNames_11: '
+ - line: '| switchTitleNames_12: '
+ - line: '| switchTitleNames_13: '
+ - line: '| switchTitleNames_14: '
+ - line: '| switchTitleNames_15: '
+ - line: '| switchPublisherNames_0: '
+ - line: '| switchPublisherNames_1: '
+ - line: '| switchPublisherNames_2: '
+ - line: '| switchPublisherNames_3: '
+ - line: '| switchPublisherNames_4: '
+ - line: '| switchPublisherNames_5: '
+ - line: '| switchPublisherNames_6: '
+ - line: '| switchPublisherNames_7: '
+ - line: '| switchPublisherNames_8: '
+ - line: '| switchPublisherNames_9: '
+ - line: '| switchPublisherNames_10: '
+ - line: '| switchPublisherNames_11: '
+ - line: '| switchPublisherNames_12: '
+ - line: '| switchPublisherNames_13: '
+ - line: '| switchPublisherNames_14: '
+ - line: '| switchPublisherNames_15: '
+ - line: '| switchIcons_0: {instanceID: 0}'
+ - line: '| switchIcons_1: {instanceID: 0}'
+ - line: '| switchIcons_2: {instanceID: 0}'
+ - line: '| switchIcons_3: {instanceID: 0}'
+ - line: '| switchIcons_4: {instanceID: 0}'
+ - line: '| switchIcons_5: {instanceID: 0}'
+ - line: '| switchIcons_6: {instanceID: 0}'
+ - line: '| switchIcons_7: {instanceID: 0}'
+ - line: '| switchIcons_8: {instanceID: 0}'
+ - line: '| switchIcons_9: {instanceID: 0}'
+ - line: '| switchIcons_10: {instanceID: 0}'
+ - line: '| switchIcons_11: {instanceID: 0}'
+ - line: '| switchIcons_12: {instanceID: 0}'
+ - line: '| switchIcons_13: {instanceID: 0}'
+ - line: '| switchIcons_14: {instanceID: 0}'
+ - line: '| switchIcons_15: {instanceID: 0}'
+ - line: '| switchSmallIcons_0: {instanceID: 0}'
+ - line: '| switchSmallIcons_1: {instanceID: 0}'
+ - line: '| switchSmallIcons_2: {instanceID: 0}'
+ - line: '| switchSmallIcons_3: {instanceID: 0}'
+ - line: '| switchSmallIcons_4: {instanceID: 0}'
+ - line: '| switchSmallIcons_5: {instanceID: 0}'
+ - line: '| switchSmallIcons_6: {instanceID: 0}'
+ - line: '| switchSmallIcons_7: {instanceID: 0}'
+ - line: '| switchSmallIcons_8: {instanceID: 0}'
+ - line: '| switchSmallIcons_9: {instanceID: 0}'
+ - line: '| switchSmallIcons_10: {instanceID: 0}'
+ - line: '| switchSmallIcons_11: {instanceID: 0}'
+ - line: '| switchSmallIcons_12: {instanceID: 0}'
+ - line: '| switchSmallIcons_13: {instanceID: 0}'
+ - line: '| switchSmallIcons_14: {instanceID: 0}'
+ - line: '| switchSmallIcons_15: {instanceID: 0}'
+ - line: '| switchManualHTML: '
+ - line: '| switchAccessibleURLs: '
+ - line: '| switchLegalInformation: '
+ - line: '| switchMainThreadStackSize: 1048576'
+ - line: '| switchPresenceGroupId: '
+ - line: '| switchLogoHandling: 0'
+ - line: '| switchReleaseVersion: 0'
+ - line: '| switchDisplayVersion: 1.0.0'
+ - line: '| switchStartupUserAccount: 0'
+ - line: '| switchSupportedLanguagesMask: 0'
+ - line: '| switchLogoType: 0'
+ - line: '| switchApplicationErrorCodeCategory: '
+ - line: '| switchUserAccountSaveDataSize: 0'
+ - line: '| switchUserAccountSaveDataJournalSize: 0'
+ - line: '| switchApplicationAttribute: 0'
+ - line: '| switchCardSpecSize: -1'
+ - line: '| switchCardSpecClock: -1'
+ - line: '| switchRatingsMask: 0'
+ - line: '| switchRatingsInt_0: 0'
+ - line: '| switchRatingsInt_1: 0'
+ - line: '| switchRatingsInt_2: 0'
+ - line: '| switchRatingsInt_3: 0'
+ - line: '| switchRatingsInt_4: 0'
+ - line: '| switchRatingsInt_5: 0'
+ - line: '| switchRatingsInt_6: 0'
+ - line: '| switchRatingsInt_7: 0'
+ - line: '| switchRatingsInt_8: 0'
+ - line: '| switchRatingsInt_9: 0'
+ - line: '| switchRatingsInt_10: 0'
+ - line: '| switchRatingsInt_11: 0'
+ - line: '| switchRatingsInt_12: 0'
+ - line: '| switchLocalCommunicationIds_0: '
+ - line: '| switchLocalCommunicationIds_1: '
+ - line: '| switchLocalCommunicationIds_2: '
+ - line: '| switchLocalCommunicationIds_3: '
+ - line: '| switchLocalCommunicationIds_4: '
+ - line: '| switchLocalCommunicationIds_5: '
+ - line: '| switchLocalCommunicationIds_6: '
+ - line: '| switchLocalCommunicationIds_7: '
+ - line: '| switchParentalControl: 0'
+ - line: '| switchAllowsScreenshot: 1'
+ - line: '| switchAllowsVideoCapturing: 1'
+ - line: '| switchAllowsRuntimeAddOnContentInstall: 0'
+ - line: '| switchDataLossConfirmation: 0'
+ - line: '| switchUserAccountLockEnabled: 0'
+ - line: '| switchSystemResourceMemory: 16777216'
+ - line: '| switchSupportedNpadStyles: 22'
+ - line: '| switchNativeFsCacheSize: 32'
+ - line: '| switchIsHoldTypeHorizontal: 0'
+ - line: '| switchSupportedNpadCount: 8'
+ - line: '| switchEnableTouchScreen: 1'
+ - line: '| switchSocketConfigEnabled: 0'
+ - line: '| switchTcpInitialSendBufferSize: 32'
+ - line: '| switchTcpInitialReceiveBufferSize: 64'
+ - line: '| switchTcpAutoSendBufferSizeMax: 256'
+ - line: '| switchTcpAutoReceiveBufferSizeMax: 256'
+ - line: '| switchUdpSendBufferSize: 9'
+ - line: '| switchUdpReceiveBufferSize: 42'
+ - line: '| switchSocketBufferEfficiency: 4'
+ - line: '| switchSocketInitializeEnabled: 1'
+ - line: '| switchNetworkInterfaceManagerInitializeEnabled: 1'
+ - line: '| switchDisableHTCSPlayerConnection: 0'
+ - line: '| switchUseNewStyleFilepaths: 0'
+ - line: '| switchUseLegacyFmodPriorities: 0'
+ - line: '| switchUseMicroSleepForYield: 1'
+ - line: '| switchEnableRamDiskSupport: 0'
+ - line: '| switchMicroSleepForYieldTime: 25'
+ - line: '| switchRamDiskSpaceSize: 12'
+ - line: '| switchUpgradedPlayerSettingsToNMETA: 0'
+ - line: '| ps4NPAgeRating: 12'
+ - line: '| ps4NPTitleSecret: '
+ - line: '| ps4NPTrophyPackPath: '
+ - line: '| ps4ParentalLevel: 11'
+ - line: '| ps4ContentID: ED1633-NPXX51362_00-0000000000000000'
+ - line: '| ps4Category: 0'
+ - line: '| ps4MasterVersion: 01.00'
+ - line: '| ps4AppVersion: 01.00'
+ - line: '| ps4AppType: 0'
+ - line: '| ps4ParamSfxPath: '
+ - line: '| ps4VideoOutPixelFormat: 0'
+ - line: '| ps4VideoOutInitialWidth: 1920'
+ - line: '| ps4VideoOutBaseModeInitialWidth: 1920'
+ - line: '| ps4VideoOutReprojectionRate: 60'
+ - line: '| ps4PronunciationXMLPath: '
+ - line: '| ps4PronunciationSIGPath: '
+ - line: '| ps4BackgroundImagePath: '
+ - line: '| ps4StartupImagePath: '
+ - line: '| ps4StartupImagesFolder: '
+ - line: '| ps4IconImagesFolder: '
+ - line: '| ps4SaveDataImagePath: '
+ - line: '| ps4SdkOverride: '
+ - line: '| ps4BGMPath: '
+ - line: '| ps4ShareFilePath: '
+ - line: '| ps4ShareOverlayImagePath: '
+ - line: '| ps4PrivacyGuardImagePath: '
+ - line: '| ps4ExtraSceSysFile: '
+ - line: '| ps4NPtitleDatPath: '
+ - line: '| ps4RemotePlayKeyAssignment: -1'
+ - line: '| ps4RemotePlayKeyMappingDir: '
+ - line: '| ps4PlayTogetherPlayerCount: 0'
+ - line: '| ps4EnterButtonAssignment: 2'
+ - line: '| ps4ApplicationParam1: 0'
+ - line: '| ps4ApplicationParam2: 0'
+ - line: '| ps4ApplicationParam3: 0'
+ - line: '| ps4ApplicationParam4: 0'
+ - line: '| ps4DownloadDataSize: 0'
+ - line: '| ps4GarlicHeapSize: 2048'
+ - line: '| ps4ProGarlicHeapSize: 2560'
+ - line: '| playerPrefsMaxSize: 32768'
+ - line: '| ps4Passcode: 0Pape6FiQQRvhBFUZoo8oDxKV0Ptz5wt'
+ - line: '| ps4pnSessions: 1'
+ - line: '| ps4pnPresence: 1'
+ - line: '| ps4pnFriends: 1'
+ - line: '| ps4pnGameCustomData: 1'
+ - line: '| playerPrefsSupport: 0'
+ - line: '| enableApplicationExit: 0'
+ - line: '| resetTempFolder: 1'
+ - line: '| restrictedAudioUsageRights: 0'
+ - line: '| ps4UseResolutionFallback: 0'
+ - line: '| ps4ReprojectionSupport: 0'
+ - line: '| ps4UseAudio3dBackend: 0'
+ - line: '| ps4UseLowGarlicFragmentationMode: 1'
+ - line: '| ps4SocialScreenEnabled: 0'
+ - line: '| ps4ScriptOptimizationLevel: 2'
+ - line: '| ps4Audio3dVirtualSpeakerCount: 14'
+ - line: '| ps4attribCpuUsage: 0'
+ - line: '| ps4PatchPkgPath: '
+ - line: '| ps4PatchLatestPkgPath: '
+ - line: '| ps4PatchChangeinfoPath: '
+ - line: '| ps4PatchDayOne: 0'
+ - line: '| ps4attribUserManagement: 0'
+ - line: '| ps4attribMoveSupport: 0'
+ - line: '| ps4attrib3DSupport: 0'
+ - line: '| ps4attribShareSupport: 0'
+ - line: '| ps4attribExclusiveVR: 0'
+ - line: '| ps4disableAutoHideSplash: 0'
+ - line: '| ps4videoRecordingFeaturesUsed: 0'
+ - line: '| ps4contentSearchFeaturesUsed: 0'
+ - line: '| ps4CompatibilityPS5: 0'
+ - line: '| ps4AllowPS5Detection: 0'
+ - line: '| ps4GPU800MHz: 1'
+ - line: '| ps4attribEyeToEyeDistanceSettingVR: 0'
+ - line: '| ps4IncludedModules: []'
+ - line: '| ps4attribVROutputEnabled: 0'
+ - line: '| monoEnv: '
+ - line: '| splashScreenBackgroundSourceLandscape: {instanceID: 0}'
+ - line: '| splashScreenBackgroundSourcePortrait: {instanceID: 0}'
+ - line: '| blurSplashScreenBackground: 1'
+ - line: '| spritePackerPolicy: '
+ - line: '| webGLMemorySize: 32'
+ - line: '| webGLExceptionSupport: 1'
+ - line: '| webGLNameFilesAsHashes: 0'
+ - line: '| webGLShowDiagnostics: 0'
+ - line: '| webGLDataCaching: 1'
+ - line: '| webGLDebugSymbols: 0'
+ - line: '| webGLEmscriptenArgs: '
+ - line: '| webGLModulesDirectory: '
+ - line: '| webGLTemplate: APPLICATION:Default'
+ - line: '| webGLAnalyzeBuildSize: 0'
+ - line: '| webGLUseEmbeddedResources: 0'
+ - line: '| webGLCompressionFormat: 0'
+ - line: '| webGLWasmArithmeticExceptions: 0'
+ - line: '| webGLLinkerTarget: 1'
+ - line: '| webGLThreadsSupport: 0'
+ - line: '| webGLDecompressionFallback: 0'
+ - line: '| webGLInitialMemorySize: 32'
+ - line: '| webGLMaximumMemorySize: 2048'
+ - line: '| webGLMemoryGrowthMode: 2'
+ - line: '| webGLMemoryLinearGrowthStep: 16'
+ - line: '| webGLMemoryGeometricGrowthStep: 0.2'
+ - line: '| webGLMemoryGeometricGrowthCap: 96'
+ - line: '| webGLEnableWebGPU: 0'
+ - line: '| webGLPowerPreference: 2'
+ - line: '| webGLWebAssemblyTable: 0'
+ - line: '| webGLWebAssemblyBigInt: 0'
+ - line: '| webGLCloseOnQuit: 0'
+ - line: '| webWasm2023: 0'
+ - line: '| scriptingDefineSymbols: {}'
+ - line: '| additionalCompilerArguments: {}'
+ - line: '| platformArchitecture: {}'
+ - line: '| scriptingBackend:'
+ - line: '| Android: 1'
+ - line: '| il2cppCompilerConfiguration: {}'
+ - line: '| il2cppCodeGeneration: {}'
+ - line: '| il2cppStacktraceInformation: {}'
+ - line: '| managedStrippingLevel: {}'
+ - line: '| incrementalIl2cppBuild: {}'
+ - line: '| suppressCommonWarnings: 1'
+ - line: '| allowUnsafeCode: 0'
+ - line: '| useDeterministicCompilation: 1'
+ - line: '| additionalIl2CppArgs: '
+ - line: '| scriptingRuntimeVersion: 1'
+ - line: '| gcIncremental: 1'
+ - line: '| gcWBarrierValidation: 0'
+ - line: '| apiCompatibilityLevelPerPlatform: {}'
+ - line: '| editorAssembliesCompatibilityLevel: 1'
+ - line: '| m_RenderingPath: 1'
+ - line: '| m_MobileRenderingPath: 1'
+ - line: '| metroPackageName: sample-unity6'
+ - line: '| metroPackageVersion: '
+ - line: '| metroCertificatePath: '
+ - line: '| metroCertificatePassword: '
+ - line: '| metroCertificateSubject: '
+ - line: '| metroCertificateIssuer: '
+ - line: '| metroCertificateNotAfter: 0000000000000000'
+ - line: '| metroApplicationDescription: sample-unity6'
+ - line: '| wsaImages: {}'
+ - line: '| metroTileShortName: '
+ - line: '| metroTileShowName: 0'
+ - line: '| metroMediumTileShowName: 0'
+ - line: '| metroLargeTileShowName: 0'
+ - line: '| metroWideTileShowName: 0'
+ - line: '| metroSupportStreamingInstall: 0'
+ - line: '| metroLastRequiredScene: 0'
+ - line: '| metroDefaultTileSize: 1'
+ - line: '| metroTileForegroundText: 2'
+ - line: '| metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628,
+ a: 0}'
+ - line: '| metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902,
+ b: 0.21568628, a: 1}'
+ - line: '| metroSplashScreenUseBackgroundColor: 0'
+ - line: '| syncCapabilities: 0'
+ - line: '| platformCapabilities: {}'
+ - line: '| metroTargetDeviceFamilies: {}'
+ - line: '| metroFTAName: '
+ - line: '| metroFTAFileTypes: []'
+ - line: '| metroProtocolName: '
+ - line: '| vcxProjDefaultLanguage: '
+ - line: '| XboxOneProductId: '
+ - line: '| XboxOneUpdateKey: '
+ - line: '| XboxOneSandboxId: '
+ - line: '| XboxOneContentId: '
+ - line: '| XboxOneTitleId: '
+ - line: '| XboxOneSCId: '
+ - line: '| XboxOneGameOsOverridePath: '
+ - line: '| XboxOnePackagingOverridePath: '
+ - line: '| XboxOneAppManifestOverridePath: '
+ - line: '| XboxOneVersion: 1.0.0.0'
+ - line: '| XboxOnePackageEncryption: 0'
+ - line: '| XboxOnePackageUpdateGranularity: 2'
+ - line: '| XboxOneDescription: '
+ - line: '| XboxOneLanguage:'
+ - line: '| - enus'
+ - line: '| XboxOneCapability: []'
+ - line: '| XboxOneGameRating: {}'
+ - line: '| XboxOneIsContentPackage: 0'
+ - line: '| XboxOneEnhancedXboxCompatibilityMode: 0'
+ - line: '| XboxOneEnableGPUVariability: 1'
+ - line: '| XboxOneSockets: {}'
+ - line: '| XboxOneSplashScreen: {instanceID: 0}'
+ - line: '| XboxOneAllowedProductIds: []'
+ - line: '| XboxOnePersistentLocalStorageSize: 0'
+ - line: '| XboxOneXTitleMemory: 8'
+ - line: '| XboxOneOverrideIdentityName: '
+ - line: '| XboxOneOverrideIdentityPublisher: '
+ - line: '| vrEditorSettings: {}'
+ - line: '| cloudServicesEnabled: {}'
+ - line: '| luminIcon:'
+ - line: '| m_Name: '
+ - line: '| m_ModelFolderPath: '
+ - line: '| m_PortalFolderPath: '
+ - line: '| luminCert:'
+ - line: '| m_CertPath: '
+ - line: '| m_SignPackage: 1'
+ - line: '| luminIsChannelApp: 0'
+ - line: '| luminVersion:'
+ - line: '| m_VersionCode: 1'
+ - line: '| m_VersionName: '
+ - line: '| hmiPlayerDataPath: '
+ - line: '| hmiForceSRGBBlit: 1'
+ - line: '| embeddedLinuxEnableGamepadInput: 0'
+ - line: '| hmiCpuConfiguration: '
+ - line: '| hmiLogStartupTiming: 0'
+ - line: '| qnxGraphicConfPath: '
+ - line: '| apiCompatibilityLevel: 6'
+ - line: '| captureStartupLogs: {}'
+ - line: '| activeInputHandler: 0'
+ - line: '| windowsGamepadBackendHint: 0'
+ - line: '| cloudProjectId: '
+ - line: '| framebufferDepthMemorylessMode: 0'
+ - line: '| qualitySettingsNames: []'
+ - line: '| projectName: '
+ - line: '| organizationId: '
+ - line: '| cloudEnabled: 0'
+ - line: '| legacyClampBlendShapeWeights: 0'
+ - line: '| hmiLoadingImage: {instanceID: 0}'
+ - line: '| platformRequiresReadableAssets: 0'
+ - line: '| virtualTexturingSupportEnabled: 0'
+ - line: '| insecureHttpOption: 0'
+ - line: '| androidVulkanDenyFilterList: []'
+ - line: '| androidVulkanAllowFilterList: []'
+ - line: '| '
+ references:
+ version: 2
+ RefIds:
+ - rid: 5612885467593965569
+ type: {class: WindowsPlatformSettings, ns: UnityEditor.WindowsStandalone, asm: UnityEditor.WindowsStandalone.Extensions}
+ data:
+ m_Development: 0
+ m_ConnectProfiler: 0
+ m_BuildWithDeepProfilingSupport: 0
+ m_AllowDebugging: 0
+ m_WaitForManagedDebugger: 0
+ m_ManagedDebuggerFixedPort: 0
+ m_ExplicitNullChecks: 0
+ m_ExplicitDivideByZeroChecks: 0
+ m_ExplicitArrayBoundsChecks: 0
+ m_CompressionType: 0
+ m_InstallInBuildFolder: 0
+ m_WindowsBuildAndRunDeployTarget: 0
+ m_Architecture: 0
+ m_CreateSolution: 0
+ m_CopyPDBFiles: 0
+ m_WindowsDevicePortalAddress:
+ m_WindowsDevicePortalUsername:
diff --git a/sample-unity6/Assets/Settings/Build Profiles/Windows Profile.asset.meta b/sample-unity6/Assets/Settings/Build Profiles/Windows Profile.asset.meta
new file mode 100644
index 00000000..1db8fb41
--- /dev/null
+++ b/sample-unity6/Assets/Settings/Build Profiles/Windows Profile.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 08b7bbc70fe5fc54eb36588f2e43c496
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/sample-unity6/Packages/manifest.json b/sample-unity6/Packages/manifest.json
index bd7431c6..5c075a3d 100644
--- a/sample-unity6/Packages/manifest.json
+++ b/sample-unity6/Packages/manifest.json
@@ -5,6 +5,7 @@
"com.immutable.api.zkevm": "file:../../src/Packages/ZkEvmApi",
"com.immutable.marketplace": "file:../../src/Packages/Marketplace",
"com.immutable.passport": "file:../../src/Packages/Passport",
+ "com.unity.2d.pixel-perfect": "5.1.1",
"com.unity.collab-proxy": "2.9.3",
"com.unity.feature.2d": "2.0.1",
"com.unity.ide.rider": "3.0.38",
diff --git a/sample-unity6/Packages/packages-lock.json b/sample-unity6/Packages/packages-lock.json
index 75a82859..e7300057 100644
--- a/sample-unity6/Packages/packages-lock.json
+++ b/sample-unity6/Packages/packages-lock.json
@@ -82,10 +82,12 @@
"url": "https://packages.unity.com"
},
"com.unity.2d.pixel-perfect": {
- "version": "5.0.3",
- "depth": 1,
+ "version": "5.1.1",
+ "depth": 0,
"source": "registry",
- "dependencies": {},
+ "dependencies": {
+ "com.unity.modules.imgui": "1.0.0"
+ },
"url": "https://packages.unity.com"
},
"com.unity.2d.psdimporter": {
diff --git a/sample-unity6/ProjectSettings/EditorBuildSettings.asset b/sample-unity6/ProjectSettings/EditorBuildSettings.asset
index 708d4c2a..c2710c23 100644
--- a/sample-unity6/ProjectSettings/EditorBuildSettings.asset
+++ b/sample-unity6/ProjectSettings/EditorBuildSettings.asset
@@ -8,15 +8,18 @@ EditorBuildSettings:
- enabled: 1
path: Assets/Scenes/Passport/Initialisation.unity
guid: bb0668e0c95b745ce8e2f127d5940ede
- - enabled: 1
+ - enabled: 0
path: Assets/Scenes/Passport/InitialisationWithUI.unity
guid: b588e10e8f614e0458aee90c7d02a499
+ - enabled: 1
+ path: Assets/Scenes/Passport/UnauthenticatedScene.unity
+ guid: ac550d22a7a5f4909be272e42b0c7b46
- enabled: 1
path: Assets/Scenes/Passport/AuthenticatedScene.unity
guid: 48b17d6cb0b0f409a9edf831addcbc0a
- enabled: 1
- path: Assets/Scenes/Passport/Imx/ImxNftTransfer.unity
- guid: 2f14d9e7f1e6941d3bc021f86377a3c9
+ path: Assets/Scenes/Passport/ZkEvm/ZkEvmSendTransaction.unity
+ guid: a7c5223614c2d4ff7ac5b06a02ef956c
- enabled: 1
path: Assets/Scenes/Passport/ZkEvm/ZkEvmGetBalance.unity
guid: 996b0bbb9b6464417b845459e3e8d764
@@ -24,30 +27,27 @@ EditorBuildSettings:
path: Assets/Scenes/Passport/ZkEvm/ZkEvmGetTransactionReceipt.unity
guid: ee999224a19ee442d998a452e74dab8c
- enabled: 1
- path: Assets/Scenes/Passport/ZkEvm/ZkEvmSendTransaction.unity
- guid: a7c5223614c2d4ff7ac5b06a02ef956c
+ path: Assets/Scenes/Passport/Imx/ImxNftTransfer.unity
+ guid: 2f14d9e7f1e6941d3bc021f86377a3c9
- enabled: 1
path: Assets/Scenes/Passport/ZkEvm/ZkEvmSignTypedData.unity
guid: 7947e157cd8d541138343d5eba099466
- enabled: 1
- path: Assets/Scenes/Passport/UnauthenticatedScene.unity
- guid: ac550d22a7a5f4909be272e42b0c7b46
- - enabled: 1
+ path: Assets/Scenes/Passport/Other/SetCallTimeout.unity
+ guid: 73ba07ed56efd1949b722042d50dc444
+ - enabled: 0
path: Assets/Scenes/Marketplace/BridgeScene.unity
guid: ce7072a24f12e4c91b658c798755b355
- - enabled: 1
+ - enabled: 0
path: Assets/Scenes/Marketplace/MarketplaceScene.unity
guid: 18f278ca9e9d34901bcc2919a143809c
- - enabled: 1
+ - enabled: 0
path: Assets/Scenes/Marketplace/OnRampScene.unity
guid: 27e0bb5e5d04a4955b88c9f329422c89
- - enabled: 1
+ - enabled: 0
path: Assets/Scenes/Marketplace/SwapScene.unity
guid: a0a7416ea738d4bea8cd720ed33efbde
- - enabled: 1
- path: Assets/Scenes/Passport/Other/SetCallTimeout.unity
- guid: 73ba07ed56efd1949b722042d50dc444
- - enabled: 1
+ - enabled: 0
path: Assets/Scenes/Passport/WebViewTest.unity
guid: c8e2712d59c2d9a479d9177e52dd28c5
m_configObjects:
diff --git a/sample-unity6/ProjectSettings/GraphicsSettings.asset b/sample-unity6/ProjectSettings/GraphicsSettings.asset
index c1d387d1..db8dd247 100644
--- a/sample-unity6/ProjectSettings/GraphicsSettings.asset
+++ b/sample-unity6/ProjectSettings/GraphicsSettings.asset
@@ -34,6 +34,20 @@ GraphicsSettings:
- {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0}
+ - {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3}
+ - {fileID: 4800000, guid: 36e335017ad71d54fbb10842863188ae, type: 3}
+ - {fileID: 4800000, guid: da07703fcc09f8d4799221050659bd55, type: 3}
+ - {fileID: 4800000, guid: 0e9d5a909a1f7e84882a534d0d11e49f, type: 3}
+ - {fileID: 4800000, guid: 5c81372d981403744adbdda4433c9c11, type: 3}
+ - {fileID: 4800000, guid: 80aa867ac363ac043847b06ad71604cd, type: 3}
+ - {fileID: 4800000, guid: 0f4122b9a743b744abe2fb6a0a88868b, type: 3}
+ - {fileID: 4800000, guid: 5ec81c81908db34429b4f6ddecadd3bd, type: 3}
+ - {fileID: -6465566751694194690, guid: 9920c1f1781549a46ba081a2a15a16ec, type: 3}
+ - {fileID: -6465566751694194690, guid: cbd3e1cc4ae141c42a30e33b4d666a61, type: 3}
+ - {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3}
+ - {fileID: 4800000, guid: 0a7e590f3cf1d4ee8a8fab5b6eff09ef, type: 3}
+ - {fileID: 4800000, guid: 21322c8b137c66e49b86085d3c8161f6, type: 3}
+ - {fileID: 4800000, guid: 8fbe92a9edfe6074e841d6dd1509bc59, type: 3}
m_PreloadedShaders: []
m_PreloadShadersBatchTimeLimit: -1
m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0}
diff --git a/sample-unity6/README.md b/sample-unity6/README.md
index b5aba283..a674a27d 100644
--- a/sample-unity6/README.md
+++ b/sample-unity6/README.md
@@ -1,7 +1,5 @@
# Unity 6 Sample Project
-> **Note:** This Unity 6 sample is a work in progress.
-
This project shares Scenes, Scripts, Editor folders, and Tests with the Unity 2021 sample project located in `../sample`.
## Setup
@@ -17,17 +15,17 @@ The `Assets/Scenes`, `Assets/Scripts`, `Assets/Editor` folders, and `Tests` are
```
#### On Windows:
-1. **Enable Developer Mode** (Recommended):
- - Open Settings โ Update & Security โ For developers
- - Turn on "Developer Mode"
+1. **Run PowerShell as Administrator**:
+ - Right-click on PowerShell in the Start menu
+ - Select "Run as Administrator"
-2. Run the setup script in PowerShell:
+2. Run the setup script:
```powershell
# From the repository root
.\setup-symlinks.ps1
```
- Or run PowerShell as Administrator if you don't want to enable Developer Mode.
+> **Note**: Administrator privileges are required because the script creates directory symbolic links (`mklink /D`) which Unity on Windows needs to properly recognise the linked folders. Developer Mode alone is not sufficient for directory symlinks.
### Git Configuration (Windows Users)
@@ -54,10 +52,17 @@ Note: This should be done **before** cloning the repository for best results.
## Troubleshooting
-### Symlinks appear as text files
-- On Windows: Enable Developer Mode or run the setup script as Administrator
+### Symlinks appear as text files (on Windows)
+- You must run the setup script as Administrator
+- Right-click PowerShell โ "Run as Administrator", then run `.\setup-symlinks.ps1`
- Ensure `git config core.symlinks` is set to `true`
+### Folders don't appear in Unity's Project window (on Windows)
+- The script must create directory symbolic links (`mklink /D`) not junctions
+- Close Unity completely
+- Delete the existing links and run setup script as Administrator
+- Reopen Unity and let it reimport assets
+
### Unity shows missing references
- Close Unity
- Run the appropriate setup script for your platform
diff --git a/sample/Assets/Editor/MacBuilderUnity6.cs b/sample/Assets/Editor/MacBuilderUnity6.cs
index 5ca5080f..c7e07db5 100644
--- a/sample/Assets/Editor/MacBuilderUnity6.cs
+++ b/sample/Assets/Editor/MacBuilderUnity6.cs
@@ -82,12 +82,6 @@ private static void BuildPlayer(string defaultBuildPath, bool setupForAltTester
EditorApplication.Exit(1);
}
- // Restore Build Profile to original state (empty scenes)
- Debug.Log("Restoring Build Profile to original state...");
- buildProfile.scenes = new EditorBuildSettingsScene[0];
- EditorUtility.SetDirty(buildProfile);
- AssetDatabase.SaveAssets();
- Debug.Log("Build Profile restored");
if (setupForAltTester)
{
diff --git a/sample/Assets/Editor/WindowsBuilderUnity6.cs b/sample/Assets/Editor/WindowsBuilderUnity6.cs
new file mode 100644
index 00000000..bf2cd0d1
--- /dev/null
+++ b/sample/Assets/Editor/WindowsBuilderUnity6.cs
@@ -0,0 +1,198 @@
+#if UNITY_6000_0_OR_NEWER
+using UnityEngine;
+using UnityEditor;
+using UnityEditor.Build.Reporting;
+using UnityEditor.Build.Profile;
+using UnityEditor.SceneManagement;
+using AltTester.AltTesterUnitySDK.Editor;
+using System;
+using System.Linq;
+using AltTester.AltTesterUnitySDK.Commands;
+using AltTester.AltTesterSDK.Driver;
+using TMPro;
+
+///
+/// Unity 6+ builder for Windows builds using Build Profiles.
+/// Ensures TextMeshPro Settings are available for AltTester UI components.
+/// This class is only available in Unity 6.0.0 and newer due to Build Profile API requirements.
+///
+public class WindowsBuilderUnity6
+{
+ private const string DefaultBuildPath = "Builds/Windows64/Sample Unity 6 Windows.exe";
+ private const string BuildProfilePath = "Assets/Settings/Build Profiles/Windows Profile.asset";
+
+ public static void Build()
+ {
+ BuildPlayer(DefaultBuildPath, false);
+ }
+
+ public static void BuildForAltTester()
+ {
+ BuildPlayer(DefaultBuildPath, true);
+ }
+
+ private static void BuildPlayer(string defaultBuildPath, bool setupForAltTester = false)
+ {
+ try
+ {
+ string buildPath = GetBuildPathFromArgs(defaultBuildPath);
+
+ // Get scenes from the build profile or use default scenes
+ string[] scenes = GetScenesToBuild(setupForAltTester);
+
+ if (setupForAltTester)
+ {
+ Debug.Log("๐งช Building with AltTester support enabled");
+ SetupAltTester(scenes);
+ }
+ else
+ {
+ Debug.Log("Building without AltTester (regular build)");
+ }
+
+ BuildProfile buildProfile = AssetDatabase.LoadAssetAtPath(BuildProfilePath);
+ if (buildProfile == null)
+ {
+ Debug.LogError($"Build Profile not found at path: {BuildProfilePath}");
+ EditorApplication.Exit(1);
+ return;
+ }
+
+ Debug.Log($"Using Build Profile: {buildProfile.name}");
+
+ BuildPlayerWithProfileOptions options = new BuildPlayerWithProfileOptions
+ {
+ buildProfile = buildProfile,
+ locationPathName = buildPath,
+ options = setupForAltTester ? (BuildOptions.Development | BuildOptions.IncludeTestAssemblies) : BuildOptions.None
+ };
+
+ Debug.Log($"Build options: {options.options}");
+ Debug.Log($"Starting build to: {buildPath}");
+
+ var result = BuildPipeline.BuildPlayer(options);
+
+ if (result.summary.result == UnityEditor.Build.Reporting.BuildResult.Succeeded)
+ {
+ Debug.Log($"Build succeeded: {result.summary.totalSize} bytes");
+ }
+ else
+ {
+ Debug.LogError($"Build failed: {result.summary.result}");
+ EditorApplication.Exit(1);
+ }
+
+
+ if (setupForAltTester)
+ {
+ // Clean up AltTester settings after build
+ AltBuilder.RemoveAltTesterFromScriptingDefineSymbols(BuildTargetGroup.Standalone);
+
+ // Clean up custom e2e testing define
+ var defineSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone);
+ defineSymbols = defineSymbols.Replace("IMMUTABLE_E2E_TESTING;", "").Replace(";IMMUTABLE_E2E_TESTING", "").Replace("IMMUTABLE_E2E_TESTING", "");
+ PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, defineSymbols);
+
+ var cleanedDefineSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone);
+
+ RemoveAltFromScene(scenes[0]);
+ }
+ }
+ catch (Exception exception)
+ {
+ Debug.LogException(exception);
+ EditorApplication.Exit(1);
+ }
+ }
+
+ private static string GetBuildPathFromArgs(string defaultBuildPath)
+ {
+ string[] args = Environment.GetCommandLineArgs();
+ for (int i = 0; i < args.Length; i++)
+ {
+ if (args[i] == "--buildPath" && i + 1 < args.Length)
+ {
+ return args[i + 1];
+ }
+ }
+ return defaultBuildPath;
+ }
+
+ private static string[] GetScenesToBuild(bool setupForAltTester = false)
+ {
+ return new[]
+ {
+ "Assets/Scenes/Passport/Initialisation.unity",
+ "Assets/Scenes/Passport/UnauthenticatedScene.unity",
+ "Assets/Scenes/Passport/AuthenticatedScene.unity",
+ "Assets/Scenes/Passport/ZkEvm/ZkEvmGetBalance.unity",
+ "Assets/Scenes/Passport/ZkEvm/ZkEvmGetTransactionReceipt.unity",
+ "Assets/Scenes/Passport/ZkEvm/ZkEvmSendTransaction.unity",
+ "Assets/Scenes/Passport/Imx/ImxNftTransfer.unity",
+ "Assets/Scenes/Passport/ZkEvm/ZkEvmSignTypedData.unity",
+ "Assets/Scenes/Passport/Other/SetCallTimeout.unity"
+ };
+ }
+
+ private static void SetupAltTester(string[] scenes)
+ {
+ AltBuilder.AddAltTesterInScriptingDefineSymbolsGroup(BuildTargetGroup.Standalone);
+
+ var defineSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone);
+ if (!defineSymbols.Contains("IMMUTABLE_E2E_TESTING"))
+ {
+ defineSymbols += ";IMMUTABLE_E2E_TESTING";
+ PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, defineSymbols);
+ }
+
+ AltBuilder.CreateJsonFileForInputMappingOfAxis();
+
+ var instrumentationSettings = new AltInstrumentationSettings();
+ var host = System.Environment.GetEnvironmentVariable("ALTSERVER_HOST");
+ if (!string.IsNullOrEmpty(host))
+ {
+ instrumentationSettings.AltServerHost = host;
+ }
+
+ var port = System.Environment.GetEnvironmentVariable("ALTSERVER_PORT");
+ if (!string.IsNullOrEmpty(port))
+ {
+ instrumentationSettings.AltServerPort = int.Parse(port);
+ }
+ else
+ {
+ instrumentationSettings.AltServerPort = 13000;
+ }
+
+ instrumentationSettings.ResetConnectionData = true;
+ AltBuilder.InsertAltInScene(scenes[0], instrumentationSettings);
+ }
+
+ public static void RemoveAltFromScene(string scene)
+ {
+ Debug.Log("Removing AltTesterPrefab from the [" + scene + "] scene.");
+
+ var sceneToModify = EditorSceneManager.OpenScene(scene);
+
+ // Find the AltTesterPrefab instance in the scene
+ var altRunner = GameObject.FindFirstObjectByType();
+
+ if (altRunner != null)
+ {
+ // Destroy the AltTesterPrefab instance
+ GameObject.DestroyImmediate(altRunner.gameObject);
+
+ // Mark the scene as dirty and save it
+ EditorSceneManager.MarkSceneDirty(sceneToModify);
+ EditorSceneManager.SaveOpenScenes();
+
+ Debug.Log("AltTesterPrefab successfully removed from the [" + scene + "] scene.");
+ }
+ else
+ {
+ Debug.LogWarning("AltTesterPrefab was not found in the [" + scene + "] scene.");
+ }
+ }
+}
+#endif // UNITY_6000_0_OR_NEWER
+
diff --git a/sample/Assets/Editor/WindowsBuilderUnity6.cs.meta b/sample/Assets/Editor/WindowsBuilderUnity6.cs.meta
new file mode 100644
index 00000000..ac47103b
--- /dev/null
+++ b/sample/Assets/Editor/WindowsBuilderUnity6.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 34aec597a3706d441a4819e20c3ea02e
\ No newline at end of file
diff --git a/sample/Tests/test/test_windows_helpers.py b/sample/Tests/test/test_windows_helpers.py
index e90c47e4..f89ee7b1 100644
--- a/sample/Tests/test/test_windows_helpers.py
+++ b/sample/Tests/test/test_windows_helpers.py
@@ -64,9 +64,11 @@ def get_auth_url_from_unity_logs():
import tempfile
import os
+ product_name = os.getenv("UNITY_APP_NAME", get_product_name())
+
# Unity log file locations on Windows
log_paths = [
- os.path.join(os.path.expanduser("~"), "AppData", "LocalLow", "Immutable", "Immutable Sample", "Player.log"),
+ os.path.join(os.path.expanduser("~"), "AppData", "LocalLow", "Immutable", product_name, "Player.log"),
os.path.join(tempfile.gettempdir(), "UnityPlayer.log"),
"Player.log" # Current directory
]
@@ -112,9 +114,11 @@ def get_logout_url_from_unity_logs():
import tempfile
import os
+ product_name = os.getenv("UNITY_APP_NAME", get_product_name())
+
# Unity log file locations on Windows
log_paths = [
- os.path.join(os.path.expanduser("~"), "AppData", "LocalLow", "Immutable", "Immutable Sample", "Player.log"),
+ os.path.join(os.path.expanduser("~"), "AppData", "LocalLow", "Immutable", product_name, "Player.log"),
os.path.join(tempfile.gettempdir(), "UnityPlayer.log"),
"Player.log" # Current directory
]
@@ -210,10 +214,13 @@ def handle_cached_authentication(driver):
print("CI environment - checking if authentication completed automatically")
print("Monitoring Unity logs for authentication completion...")
+ product_name = os.getenv("UNITY_APP_NAME", get_product_name())
+ log_path = os.path.join("C:\\Users\\WindowsBuildsdkServi\\AppData\\LocalLow\\Immutable", product_name, "Player.log")
+
auth_success = False
for check_attempt in range(30): # Check for 30 seconds
try:
- with open("C:\\Users\\WindowsBuildsdkServi\\AppData\\LocalLow\\Immutable\\Immutable Sample\\Player.log", 'r', encoding='utf-8', errors='ignore') as f:
+ with open(log_path, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
# Look for signs of successful authentication
if any(phrase in content for phrase in [
@@ -374,10 +381,13 @@ def login():
print("This means authentication was successful, just need to wait for Unity to process it")
# Wait and check Unity logs for authentication success instead of relying on scene changes
+ product_name = os.getenv("UNITY_APP_NAME", get_product_name())
+ log_path = os.path.join("C:\\Users\\WindowsBuildsdkServi\\AppData\\LocalLow\\Immutable", product_name, "Player.log")
+
auth_success = False
for check_attempt in range(20): # Check for 20 seconds
try:
- with open("C:\\Users\\WindowsBuildsdkServi\\AppData\\LocalLow\\Immutable\\Immutable Sample\\Player.log", 'r', encoding='utf-8', errors='ignore') as f:
+ with open(log_path, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
# Look for signs of successful authentication in logs
if any(phrase in content for phrase in [
@@ -539,9 +549,10 @@ def login():
except:
pass
- # Wait for the deep link dialog to appear and click "Open Immutable Sample.cmd"
+ # Wait for the deep link dialog to appear and click the button
# Use more specific selector to avoid clicking "Restore" button
- deep_link_button = wait.until(EC.element_to_be_clickable((By.XPATH, "//button[text()='Open Immutable Sample.cmd']")))
+ product_name = os.getenv("UNITY_APP_NAME", get_product_name())
+ deep_link_button = wait.until(EC.element_to_be_clickable((By.XPATH, f"//button[text()='Open {product_name}.cmd']")))
deep_link_button.click()
print("Clicked deep link permission dialog - Unity should receive redirect")
except Exception as e:
@@ -555,10 +566,12 @@ def clear_unity_data():
"""Clear Unity's persistent data to force fresh start"""
print("Clearing Unity persistent data...")
+ product_name = os.getenv("UNITY_APP_NAME", get_product_name())
+
# Clear PlayerPrefs from Windows Registry
try:
import winreg
- registry_path = r"SOFTWARE\Immutable\Immutable Sample"
+ registry_path = f"SOFTWARE\\Immutable\\{product_name}"
# Try both HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE
for root_key in [winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE]:
@@ -577,7 +590,7 @@ def clear_unity_data():
# Clear Application.persistentDataPath
try:
- data_path = os.path.join(os.path.expanduser("~"), "AppData", "LocalLow", "Immutable", "Immutable Sample")
+ data_path = os.path.join(os.path.expanduser("~"), "AppData", "LocalLow", "Immutable", product_name)
if os.path.exists(data_path):
import shutil
shutil.rmtree(data_path)
@@ -598,16 +611,27 @@ def open_sample_app(clear_data=False):
print(f"Opening {product_name}...")
- # Look for the executable in build folder first, then current directory
- exe_paths = [
- f"../build/{product_name}.exe", # Relative to Tests folder
- f"{product_name}.exe" # Current directory (fallback)
- ]
+ # Check if UNITY_APP_PATH is provided (takes precedence)
+ app_path_env = os.getenv("UNITY_APP_PATH")
+
+ # Look for the executable in multiple locations
+ exe_paths = []
+
+ # First priority: use UNITY_APP_PATH if provided
+ if app_path_env:
+ exe_paths.append(app_path_env)
+
+ # Then check standard locations
+ exe_paths.extend([
+ f"{product_name}.exe", # Current directory (for Unity 6 builds in Tests/)
+ f"../build/{product_name}.exe", # Relative to Tests folder (for Unity 2021)
+ f"./{product_name}.exe", # Explicit current directory
+ ])
exe_launched = False
for exe_path in exe_paths:
if os.path.exists(exe_path):
- print(f"Found executable at: {exe_path}")
+ print(f"Found executable at: {os.path.abspath(exe_path)}")
subprocess.Popen([exe_path], shell=True)
exe_launched = True
break
@@ -639,7 +663,7 @@ def stop_sample_app():
print(f"{product_name} stopped successfully.")
def bring_sample_app_to_foreground():
- product_name = get_product_name()
+ product_name = os.getenv("UNITY_APP_NAME", get_product_name())
powershell_script_path = "./switch-app.ps1"
print(f"Bring {product_name} to the foreground.")
@@ -694,32 +718,34 @@ def setup_protocol_association():
"""Set up immutablerunner:// protocol association to avoid permission dialogs"""
print("Setting up protocol association for immutablerunner://...")
+ product_name = os.getenv("UNITY_APP_NAME", get_product_name())
+
# PowerShell script to register the protocol
- ps_script = '''
+ ps_script = f'''
# Register immutablerunner protocol
$protocolKey = "HKCU:\\Software\\Classes\\immutablerunner"
$commandKey = "$protocolKey\\shell\\open\\command"
# Create the registry keys
- if (!(Test-Path $protocolKey)) {
+ if (!(Test-Path $protocolKey)) {{
New-Item -Path $protocolKey -Force | Out-Null
- }
- if (!(Test-Path $commandKey)) {
+ }}
+ if (!(Test-Path $commandKey)) {{
New-Item -Path $commandKey -Force | Out-Null
- }
+ }}
# Set the protocol values
Set-ItemProperty -Path $protocolKey -Name "(Default)" -Value "URL:immutablerunner Protocol"
Set-ItemProperty -Path $protocolKey -Name "URL Protocol" -Value ""
# Find the Unity sample app executable
- $sampleAppPath = "C:\\Immutable\\unity-immutable-sdk\\sample\\build\\Immutable Sample.exe"
- if (Test-Path $sampleAppPath) {
+ $sampleAppPath = "C:\\Immutable\\unity-immutable-sdk\\sample\\build\\{product_name}.exe"
+ if (Test-Path $sampleAppPath) {{
Set-ItemProperty -Path $commandKey -Name "(Default)" -Value "`"$sampleAppPath`" `"%1`""
Write-Host "Protocol association set up successfully"
- } else {
+ }} else {{
Write-Host "Sample app not found at expected path"
- }
+ }}
'''
try:
diff --git a/setup-symlinks.ps1 b/setup-symlinks.ps1
index a01155b9..2a34f62c 100644
--- a/setup-symlinks.ps1
+++ b/setup-symlinks.ps1
@@ -30,14 +30,20 @@ if (Test-Path "Scenes.meta") { Remove-Item -Path "Scenes.meta" -Force }
if (Test-Path "Scripts.meta") { Remove-Item -Path "Scripts.meta" -Force }
if (Test-Path "Editor.meta") { Remove-Item -Path "Editor.meta" -Force }
-# Create symlinks for Assets
+# Create symlinks using relative paths (so they work cross-platform)
+# Use relative paths like the bash script does
try {
- New-Item -ItemType SymbolicLink -Path "Scenes" -Target "..\..\sample\Assets\Scenes" | Out-Null
- New-Item -ItemType SymbolicLink -Path "Scripts" -Target "..\..\sample\Assets\Scripts" | Out-Null
- New-Item -ItemType SymbolicLink -Path "Editor" -Target "..\..\sample\Assets\Editor" | Out-Null
- New-Item -ItemType SymbolicLink -Path "Scenes.meta" -Target "..\..\sample\Assets\Scenes.meta" | Out-Null
- New-Item -ItemType SymbolicLink -Path "Scripts.meta" -Target "..\..\sample\Assets\Scripts.meta" | Out-Null
- New-Item -ItemType SymbolicLink -Path "Editor.meta" -Target "..\..\sample\Assets\Editor.meta" | Out-Null
+ # Create directory symbolic links (Unity recognises these on Windows)
+ # Note: Requires administrator privileges
+ # Using relative paths so symlinks work on all platforms
+ cmd /c mklink /D "Scenes" "..\..\sample\Assets\Scenes" | Out-Null
+ cmd /c mklink /D "Scripts" "..\..\sample\Assets\Scripts" | Out-Null
+ cmd /c mklink /D "Editor" "..\..\sample\Assets\Editor" | Out-Null
+
+ # Create file symbolic links for .meta files
+ cmd /c mklink "Scenes.meta" "..\..\sample\Assets\Scenes.meta" | Out-Null
+ cmd /c mklink "Scripts.meta" "..\..\sample\Assets\Scripts.meta" | Out-Null
+ cmd /c mklink "Editor.meta" "..\..\sample\Assets\Editor.meta" | Out-Null
Write-Output ""
Write-Output "โ
Asset symlinks created successfully!"
@@ -45,10 +51,11 @@ try {
Write-Output "Scenes, Scripts, and Editor in sample-unity6 now point to sample/Assets"
Get-ChildItem | Where-Object { $_.Name -match "Scenes|Scripts|Editor" } | Format-Table Name, LinkType, Target
- # Create symlink for Tests
+ # Create directory symbolic link for Tests
Set-Location $sampleUnity6
if (Test-Path "Tests") { Remove-Item -Path "Tests" -Recurse -Force }
- New-Item -ItemType SymbolicLink -Path "Tests" -Target "..\sample\Tests" | Out-Null
+ # Use relative path
+ cmd /c mklink /D "Tests" "..\sample\Tests" | Out-Null
Write-Output ""
Write-Output "โ
Tests symlink created successfully!"
@@ -65,4 +72,3 @@ catch {
Write-Output "Then run this script again."
exit 1
}
-