Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 11 additions & 83 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -25,95 +25,23 @@
<SentryWindowsArtifactsDestination>$(SentryArtifactsDestination)Windows/Sentry/</SentryWindowsArtifactsDestination>
</PropertyGroup>

<PropertyGroup>
<HubSecondaryInstallPathFile>$(AppData)\UnityHub\secondaryInstallPath.json</HubSecondaryInstallPathFile>
<HubDefaultEditorFile>$(AppData)\UnityHub\defaultEditor.json</HubDefaultEditorFile>
<HubDefaultEditor Condition="'$(HubDefaultEditor)' == ''"></HubDefaultEditor>
<HubInstallDir Condition="'$(HubInstallDir)' == '' AND $([MSBuild]::IsOSPlatform('Windows'))">C:\Program Files\Unity\Hub\Editor</HubInstallDir>
<HubInstallDir Condition="'$(HubInstallDir)' == '' AND $([MSBuild]::IsOSPlatform('OSX'))">\Applications\Unity\Hub\Editor</HubInstallDir>
<HubInstallDir Condition="'$(HubInstallDir)' == '' AND $([MSBuild]::IsOSPlatform('Linux'))">$(Home)\Unity\Hub\Editor</HubInstallDir>
<HubInstallDir Condition="!Exists('$(HubInstallDir)')"></HubInstallDir>
</PropertyGroup>

<Target Name="FindHub"
Condition="'$(HubInstallDir)' == '' AND Exists('$(HubSecondaryInstallPathFile)')"
Returns="$(HubInstallDir);$(HubDefaultEditor)">

<ReadLinesFromFile File="$(HubSecondaryInstallPathFile)">
<Output TaskParameter="Lines" ItemName="item1" />
</ReadLinesFromFile>

<ReadLinesFromFile File="$(HubDefaultEditorFile)" Condition="Exists('$(HubDefaultEditorFile)')">
<Output TaskParameter="Lines" ItemName="item2" />
</ReadLinesFromFile>

<PropertyGroup>
<HubInstallDir>@(item1->Replace('"', ''))</HubInstallDir>
<HubInstallDir Condition=" !Exists('$(HubInstallDir)') "></HubInstallDir>

<HubDefaultEditor>@(item2->Replace('"', ''))</HubDefaultEditor>
<HubDefaultEditor Condition=" !Exists('$(HubInstallDir)\$(HubDefaultEditor)') "></HubDefaultEditor>
</PropertyGroup>
</Target>

<!-- Use the Unity Editor version set in the sample project of the repo -->
<Target Name="FindUnity" DependsOnTargets="FindHub" AfterTargets="FindHub">
<Target Name="FindUnity">
<Message Text="Unity Version: $(UnityVersion)" Importance="Normal" />

<!-- Find all the installations of Unity done by the Unity Hub -->
<ItemGroup Condition="'$(HubInstallDir)' != '' AND '$(HubDefaultEditor)' == ''">
<_AllUnityInstallDirs Include="$([System.IO.Directory]::GetDirectories('$(HubInstallDir)'))" />
<_UnityInstalls Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('%(Filename)', '^[\d]{4}.*$'))" Include="@(_AllUnityInstallDirs->'%(Filename)%(Extension)')" />
</ItemGroup>

<!-- Pick the latest one if this version of the Hub doesn't record a default version -->
<PropertyGroup Condition="'$(HubInstallDir)' != '' AND '$(HubDefaultEditor)' == ''">
<HubDefaultEditor>%(_UnityInstalls.Identity)</HubDefaultEditor>
</PropertyGroup>

<PropertyGroup>
<_UnityInnerPath Condition="!$([MSBuild]::IsOSPlatform('OSX'))">Editor\Data</_UnityInnerPath>
<_UnityInnerPath Condition="$([MSBuild]::IsOSPlatform('OSX'))">Unity.App\Contents</_UnityInnerPath>
</PropertyGroup>

<ItemGroup>
<_PotentialUnityPaths Condition="$([MSBuild]::IsOSPlatform('Linux')) AND '$(UNITY_PATH)' != ''" Include="$(UNITY_PATH)\$(_UnityInnerPath)\Managed\UnityEngine.dll" />
<_PotentialUnityPaths Condition="'$(HubInstallDir)' != ''" Include="$(HubInstallDir)\$(UnityVersion)\$(_UnityInnerPath)\Managed\UnityEngine.dll" />
<_PotentialUnityPaths Condition="'$(HubInstallDir)' != '' AND '$(HubDefaultEditor)' != '' AND '$(UnityVersion)' != '$(HubDefaultEditor)'" Include="$(HubInstallDir)\$(HubDefaultEditor)\$(_UnityInnerPath)\Managed\UnityEngine.dll" />
<_PotentialUnityPaths Condition="$([MSBuild]::IsOSPlatform('Windows'))" Include="C:\Program Files\Unity\$(_UnityInnerPath)\Managed\UnityEngine.dll" />
<_PotentialUnityPaths Condition="$([MSBuild]::IsOSPlatform('OSX'))" Include="\Applications\Unity\$(_UnityInnerPath)\Managed\UnityEngine.dll" />
<_UnityPathsFound Include="@(_PotentialUnityPaths->Exists())" />
<_UnityPathsFoundReversed Include="@(_UnityPathsFound->Reverse())" />
</ItemGroup>
<Exec
Command="pwsh -NoProfile -File &quot;$(RepoRoot)scripts/find-unity.ps1&quot; -UnityVersion &quot;$(UnityVersion)&quot; -HubInstallDir &quot;$(HubInstallDir)&quot; -HubDefaultEditor &quot;$(HubDefaultEditor)&quot;"
ConsoleToMSBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="_FindUnityOutput" />
</Exec>

<PropertyGroup>
<!--This is a little hack to grab the first item found on the list - properties are repeatedly set for each item on the list, so they end up with the last one (we reversed the list so we get the first one) -->
<_UnityPathProp>%(_UnityPathsFoundReversed.Identity)</_UnityPathProp>
<UnityRoot>$([System.Text.RegularExpressions.Regex]::Match($(_FindUnityOutput), 'UnityRoot=([^;\r\n]+)').Groups[1].Value)</UnityRoot>
<UnityDataPath>$([System.Text.RegularExpressions.Regex]::Match($(_FindUnityOutput), 'UnityDataPath=([^;\r\n]+)').Groups[1].Value)</UnityDataPath>
<UnityManagedPath>$([System.Text.RegularExpressions.Regex]::Match($(_FindUnityOutput), 'UnityManagedPath=([^;\r\n]+)').Groups[1].Value)</UnityManagedPath>
<UnityLibcache>$(UnityDataPath)Resources/PackageManager/ProjectTemplates/libcache/</UnityLibcache>
</PropertyGroup>

<Message
Condition="'$(UnityVersion)' != '' AND '$(HubInstallDir)' != '' AND !Exists('$(HubInstallDir)\$(UnityVersion)\$(_UnityInnerPath)\Managed\UnityEngine.dll') AND '$(_UnityPathProp)' != ''"
Text="Unity version $(UnityVersion) is not installed. Falling back to default Unity installation."
Importance="High" />

<ItemGroup>
<!-- Turn the property back into an item so we can use DirectoryName() below. -->
<_UnityPath Include="$(_UnityPathProp)" />
</ItemGroup>

<PropertyGroup Condition="'$(_UnityPathProp)' != ''">
<UnityManagedPath>@(_UnityPath->DirectoryName())\</UnityManagedPath>
<UnityDataPath>@(_UnityPath->DirectoryName()->DirectoryName())\</UnityDataPath>
<UnityRoot>@(_UnityPath->DirectoryName()->DirectoryName()->DirectoryName())\</UnityRoot>
<UnityLibcache>$(UnityDataPath)Resources\PackageManager\ProjectTemplates\libcache\</UnityLibcache>
</PropertyGroup>

<Error Condition="'$(UnityRoot)' == ''" Text="UnityRoot not found. Ensure Unity is installed.
See the CONTRIBUTING.md.
UnityVersion: '$(UnityVersion)'
Expected to exist:
* @(_PotentialUnityPaths, '%0a or %0a * ')" />

<Error Condition="'$(UnityRoot)' == ''" Text="UnityRoot not resolved — see scripts/find-unity.ps1 output above." />

<!-- Unity paths on Windows -->
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Windows'))">
Expand Down
119 changes: 119 additions & 0 deletions scripts/find-unity.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#!/usr/bin/env pwsh
# Locate a Unity installation and emit the paths the build needs.
#
# Output (stdout, one per line):
# UnityRoot=<dir containing the Unity executable, trailing slash>
# UnityDataPath=<dir containing the Editor data, trailing slash>
# UnityManagedPath=<dir containing UnityEngine.dll, trailing slash>
#
# Warnings + the "candidates tried" error go to stderr. Exits non-zero on failure.

[CmdletBinding()]
param (
[string] $UnityVersion = '',
[string] $HubInstallDir = '',
[string] $HubDefaultEditor = ''
)

$ErrorActionPreference = 'Stop'

function Read-HubFile([string] $path) {
if (-not (Test-Path $path)) { return '' }
# Unity Hub writes a single quoted string per file (not strict JSON).
return (Get-Content -Raw $path).Trim().Trim('"')
}

# --- Resolve Hub install dir + default editor -------------------------------

# AppData is Windows-only; on macOS/Linux we just rely on the platform default below.
$hubConfigDir = if ($env:APPDATA) { Join-Path $env:APPDATA 'UnityHub' } else { '' }

if (-not $HubInstallDir -and $hubConfigDir) {
$HubInstallDir = Read-HubFile (Join-Path $hubConfigDir 'secondaryInstallPath.json')
}
if (-not $HubInstallDir) {
$HubInstallDir = if ($IsWindows) { 'C:/Program Files/Unity/Hub/Editor' }
elseif ($IsMacOS) { '/Applications/Unity/Hub/Editor' }
elseif ($IsLinux) { Join-Path $env:HOME 'Unity/Hub/Editor' }
}
if (-not (Test-Path $HubInstallDir)) { $HubInstallDir = '' }

if (-not $HubDefaultEditor -and $hubConfigDir) {
$HubDefaultEditor = Read-HubFile (Join-Path $hubConfigDir 'defaultEditor.json')
if ($HubDefaultEditor -and -not (Test-Path (Join-Path $HubInstallDir $HubDefaultEditor))) {
$HubDefaultEditor = ''
}
}
# Fallback: pick the highest version-named dir under the hub install root.
if (-not $HubDefaultEditor -and $HubInstallDir) {
$HubDefaultEditor = Get-ChildItem -Path $HubInstallDir -Directory -ErrorAction SilentlyContinue |
Where-Object Name -Match '^\d{4}' |
Sort-Object Name -Descending |
Select-Object -First 1 -ExpandProperty Name
}

# --- Build the probe list ---------------------------------------------------

# Layout pieces. macOS Unity ships as a .app bundle so the inner path differs.
$inner = if ($IsMacOS) { 'Unity.app/Contents' } else { 'Editor/Data' }
$rootName = if ($IsMacOS) { 'Unity.app' } else { 'Editor' }

# Each "install" candidate is a directory like <hub>/<version>/ that contains
# either Editor/ (win/linux) or Unity.app/ (mac).
$installs = [System.Collections.Generic.List[string]]::new()
if ($IsLinux -and $env:UNITY_PATH) { $installs.Add($env:UNITY_PATH) }
if ($HubInstallDir -and $UnityVersion) { $installs.Add((Join-Path $HubInstallDir $UnityVersion)) }
if ($HubInstallDir -and $HubDefaultEditor -and $UnityVersion -ne $HubDefaultEditor) {
$installs.Add((Join-Path $HubInstallDir $HubDefaultEditor))
}
if ($IsWindows) { $installs.Add('C:/Program Files/Unity') }
if ($IsMacOS) { $installs.Add('/Applications/Unity') }

# Unity 6000.3+ moved managed assemblies under Resources/Scripting/Managed.
# Probe the new layout first within each install.
$dllRelatives = @('Resources/Scripting/Managed/UnityEngine.dll', 'Managed/UnityEngine.dll')

function Find-UnityDll([string] $install) {
foreach ($rel in $dllRelatives) {
$dll = Join-Path $install (Join-Path $inner $rel)
if (Test-Path $dll) { return $dll }
}
return $null
}

# Did the requested-version install yield a DLL? Drives the fallback warning below.
$expected = if ($UnityVersion -and $HubInstallDir) { Join-Path $HubInstallDir $UnityVersion } else { '' }
$shouldWarnFallback = $expected -and -not (Find-UnityDll $expected)

$tried = [System.Collections.Generic.List[string]]::new()

foreach ($install in $installs) {
$dll = Find-UnityDll $install
if (-not $dll) {
$dllRelatives | ForEach-Object { $tried.Add((Join-Path $install (Join-Path $inner $_))) }
continue
}

if ($shouldWarnFallback) {
Write-Warning "Unity version $UnityVersion is not installed. Falling back to default Unity installation."
}

$unityRoot = (Join-Path $install $rootName) + '/'
$unityDataPath = (Join-Path $install $inner) + '/'
$unityManagedPath = (Split-Path $dll -Parent) + '/'

# Normalize to forward slashes — MSBuild accepts both, and it keeps the output diff-clean across platforms.
Write-Output ("UnityRoot=" + ($unityRoot -replace '\\', '/'))
Write-Output ("UnityDataPath=" + ($unityDataPath -replace '\\', '/'))
Write-Output ("UnityManagedPath=" + ($unityManagedPath -replace '\\', '/'))
exit 0
}

$msg = @"
Unity installation not found. See CONTRIBUTING.md.
UnityVersion: '$UnityVersion'
Expected one of:
* $($tried -join "`n * ")
"@
Write-Error $msg
exit 1
Loading