|
param ( |
|
#Path to the valheim root directory, for case of using an alternate installation such as a server |
|
[String]$Path, |
|
#Name of the release if you want to download a specific version e.g. 0.9.3 |
|
[String]$Release |
|
) |
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 |
|
$ErrorActionPreference = 'Stop' |
|
#region Helpers |
|
function get-SteamInstallPath { |
|
try { |
|
Get-ItemPropertyValue 'HKLM:\Software\WOW6432Node\Valve\Steam' InstallPath |
|
} catch { |
|
throw 'Could not find Steam on your computer. Is it installed?' |
|
} |
|
} |
|
|
|
function get-SteamLibraryPaths { |
|
$libraryPaths = @() |
|
$libraryPaths += get-steamInstallPath |
|
$baseSteamAppsPath = Resolve-Path (Join-Path $(get-SteamInstallPath) 'steamapps') |
|
|
|
$libraryManifest = Join-Path $baseSteamAppsPath 'libraryfolders.vdf' |
|
|
|
if (Test-Path $libraryManifest) { |
|
Get-Content $libraryManifest | |
|
Where-Object { $PSItem -match '^\t\"\d+\"' } | |
|
ConvertFrom-Csv -Delimiter "`t" -Header 'blank','index','blank2','path' | |
|
Select-Object -Expand Path | |
|
ForEach-Object { |
|
$candidatePath = [Regex]::Unescape($PSItem) |
|
if (-not (Test-Path (Join-Path $candidatePath 'steamapps'))) { |
|
Write-Warning "Library $candidatePath was detected in $libraryManifest but we could not find it. Did you delete it? We will ignore it in the search." |
|
} else { |
|
$libraryPaths += $candidatePath #Warning this may not be foolproof! |
|
} |
|
} |
|
} |
|
return $libraryPaths |
|
} |
|
|
|
function convertFrom-SteamAppState { |
|
[CmdletBinding()] |
|
param( |
|
[Parameter(ValueFromPipeline)][String]$SteamAppInfo |
|
) |
|
if ($steamAppInfo -notmatch '^AppState') { throw [FormatException]'This is not a steam AppState file' } |
|
} |
|
|
|
function get-SteamAppInstallDir ([int]$AppId) { |
|
[String[]]$appManifestPath = foreach ($libraryPath in (get-SteamLibraryPaths)) { |
|
$appManifestFolderPath = Join-Path $libraryPath 'steamapps' |
|
Get-Item (Join-Path $appManifestFolderPath "appmanifest_$AppId.acf") -ErrorAction SilentlyContinue |
|
} |
|
if (-not $appManifestPath) { throw "Steam App with ID $AppId was not found in any of the following detected Steam libraries: $((get-SteamLibraryPaths) -join ',')" } |
|
if ($appManifestPath.count -gt 1) { throw "Multiple installations of the app with ID $AppId were found: $($appManifestPath -join ','). This should not happen, you need to clean up your folders!" } |
|
[String]$appFolderName = Get-Content $appManifestPath | ForEach-Object { |
|
if ($_ -match '^\t\"installdir\"\t+\"(.+?)\"') { |
|
return $matches[1] |
|
} |
|
} |
|
if (-not $appFolderName) { throw [InvalidFormatException]"$appManifestPath does not appear to be a valid app manifest (missing or invalid installdir property)" } |
|
$candidateAppPath = [IO.Path]::Combine( |
|
(Split-Path $appManifestPath), |
|
'common', |
|
[Regex]::Unescape($appFolderName) |
|
) |
|
try { |
|
return Resolve-Path $candidateAppPath |
|
} catch { |
|
throw "$candidateAppPath was detected as the app path for $AppId, but the actual folder was not found. Did you delete it?" |
|
} |
|
} |
|
|
|
function get-GithubReleaseFileUri ([String]$user,[String]$repoName,[String]$assetName,[String]$tag) { |
|
$releaseInfo = Invoke-RestMethod -useb "https://api.github.com/repos/$user/$repoName/releases" |
|
if ($tag) { |
|
$release = $releaseInfo | Where-Object tag -EQ $tag |
|
if (-not $release) { throw "Release $tag not found in $user/$repoName" } |
|
} else { |
|
$release = $releaseInfo[0] |
|
if (-not $release) { throw "No releases have been published in $user/$reponame yet" } |
|
} |
|
|
|
$asset = $release.assets | Where-Object name -EQ $assetName |
|
if (-not $asset) { throw "Artifact $assetName not found in release $($release.name)" } |
|
|
|
return $asset.browser_download_url |
|
} |
|
#endregion Helpers |
|
|
|
#region Main |
|
Write-Progress 'Detecting Valheim Directory' |
|
$assetName = 'WindowsClient.zip' |
|
[int]$ValheimAppId = 892970 |
|
if (-not $Path) {$Path = get-SteamAppInstallDir $ValheimAppId} |
|
if (Test-Path (Join-Path $Path 'valheim_server.exe')) { |
|
Write-Host -fore Cyan "Valhalla Dedicated Server detected, installing server release" |
|
$assetName = 'WindowsServer.zip' |
|
} else { |
|
if (-not (Test-Path (Join-Path $Path 'valheim.exe'))) {throw "Valheim Steam Install folder detected at $Path but valheim.exe was not present. Is it corrupted or did you specify the wrong path override with -Path?"} |
|
} |
|
Write-Host -Fore Green "Found Valheim at $Path" |
|
|
|
#Download latest V+ release |
|
Write-Progress "Getting Release" |
|
|
|
if ($Server) {$assetName = 'WindowsServer.zip'} |
|
$releaseUri = get-GithubReleaseFileUri -User valheimPlus -repoName ValheimPlus -assetName 'WindowsClient.zip' -tag $release |
|
|
|
Write-Progress "Downloading Release" |
|
|
|
$tempZipPath = Join-Path ([io.path]::GetTempPath()) "$(New-Guid).zip" |
|
|
|
try { |
|
$configToProtect = Get-ChildItem "$Path\BepInEx\config" -Exclude '*.bak' -ErrorAction SilentlyContinue |
|
$configToProtect.foreach{ |
|
Copy-Item $PSItem.FullName -Destination "$($PSItem.fullname).bak" -Force |
|
} |
|
Invoke-RestMethod -useb $releaseUri -OutFile $tempZipPath |
|
Write-Progress "Installing to $Path" |
|
Expand-Archive -Path $tempZipPath -DestinationPath $Path -Force |
|
Write-Host -fore green '===========' |
|
Write-Host -fore green "Installed Valheim Plus $assetName to $Path succsesfully!" |
|
Write-Host -fore green "Customize your experience by editing config $Pat0\BepInEx\config\valheim_plus.cfg" |
|
Write-Host -fore green '===========' |
|
|
|
} catch { |
|
throw |
|
} finally { |
|
$configToProtect.foreach{ |
|
Copy-Item "$($PSItem.fullname).bak" $PSItem.fullname -Force |
|
} |
|
Remove-Item $tempZipPath -force -ErrorAction SilentlyContinue |
|
} |
|
|
|
#endregion Main |