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 } -