[CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory=$true)][string]$WebglRoot, [string]$PatchZip = '' ) $ErrorActionPreference = 'Stop' if (-not $PatchZip) { $PatchZip = Join-Path $PSScriptRoot 'Client-BuddyDefense-15888.zip' } $PatchZip = (Resolve-Path -LiteralPath $PatchZip).Path $WebglRoot = (Resolve-Path -LiteralPath $WebglRoot).Path if (-not (Test-Path -LiteralPath $WebglRoot -PathType Container)) { throw 'WebglRoot must be an existing website directory.' } $versionPath = Join-Path $WebglRoot 'cdn/version.json' if (-not (Test-Path -LiteralPath $versionPath) -and -not (Get-ChildItem -LiteralPath $WebglRoot -Filter '*.webgl.data.unityweb.bin.txt' -File | Select-Object -First 1)) { throw 'This does not look like the existing /game/Friends/webgl website folder. Choose the website folder, not the AIServer folder.' } Add-Type -AssemblyName System.IO.Compression.FileSystem $archive = [IO.Compression.ZipFile]::OpenRead($PatchZip) try { $contents = @{} foreach ($entry in $archive.Entries) { $name = $entry.FullName.Replace('\','/') if ($name -ne 'cdn/version.json' -and $name -notmatch '^yoo/DefaultPackage/[A-Za-z0-9_.-]+$') { throw "Unexpected patch entry: $name" } if ($contents.ContainsKey($name) -or $entry.Length -gt 5242880) { throw "Invalid patch entry: $name" } $reader = $entry.Open(); $memory = New-Object IO.MemoryStream try { $reader.CopyTo($memory); $contents[$name] = $memory.ToArray() } finally { $reader.Dispose(); $memory.Dispose() } } } finally { $archive.Dispose() } if ($contents.Count -ne 5 -or -not $contents.ContainsKey('cdn/version.json')) { throw 'Expected the five-file hot-update patch.' } $version = [Text.Encoding]::UTF8.GetString($contents['cdn/version.json']) | ConvertFrom-Json if ($version.packVersion -notmatch '^[a-f0-9]{32}$') { throw 'Invalid packVersion.' } $indexName = "yoo/DefaultPackage/DefaultPackage_$($version.packVersion).bytes" if (-not $contents.ContainsKey($indexName)) { throw 'Version refers to a missing manifest.' } $md5 = [Security.Cryptography.MD5]::Create() try { $indexHash = [BitConverter]::ToString($md5.ComputeHash($contents[$indexName])).Replace('-','').ToLowerInvariant() } finally { $md5.Dispose() } if ($indexHash -ne $version.packVersion) { throw 'Manifest MD5 does not match packVersion. Nothing published.' } $changed = 0 if ($PSCmdlet.ShouldProcess($WebglRoot,"Publish pack $($version.packVersion); write cdn/version.json last")) { # Content-addressed resources must exist before exposing the new global version. $names = @($contents.Keys | Where-Object { $_ -ne 'cdn/version.json' } | Sort-Object) + @('cdn/version.json') foreach ($name in $names) { $target = Join-Path $WebglRoot $name if (Test-Path -LiteralPath $target) { $old = [IO.File]::ReadAllBytes($target) if ([Convert]::ToBase64String($old) -eq [Convert]::ToBase64String($contents[$name])) { continue } } New-Item -ItemType Directory -Path (Split-Path -Parent $target) -Force | Out-Null if ($name -eq 'cdn/version.json') { $temporary = "$target.publish-$([Guid]::NewGuid().ToString('N')).tmp" try { [IO.File]::WriteAllBytes($temporary,$contents[$name]) if (Test-Path -LiteralPath $target) { [IO.File]::Replace($temporary,$target,"$target.previous") } else { [IO.File]::Move($temporary,$target) } } finally { if (Test-Path -LiteralPath $temporary) { Remove-Item -LiteralPath $temporary } } } else { [IO.File]::WriteAllBytes($target,$contents[$name]) } $changed++ Write-Output "Published $name" } Write-Output "Done: packVersion=$($version.packVersion); changedFiles=$changed. Check the public cdn/version.json, then restart the mini game." }