$ErrorActionPreference = 'Stop' $project = 'C:/projects/ft/Client' $output = 'C:/projects/ft/CodexOutput/upserver' function Invoke-Recorded([string]$name, [string[]]$commandArgs) { $json = & uloop @commandArgs --project-path $project if ($LASTEXITCODE -ne 0) { throw "CLI failure: $name" } $json | Set-Content -LiteralPath (Join-Path $output "$name.json") -Encoding utf8 $value = ($json -join "`n") | ConvertFrom-Json if ($value.Success -eq $false) { throw "Tool failure: $name" } return $value } $version = Invoke-Recorded 'uloop-final-target' @('get-version') if ($version.DataPath -ne "$project/Assets") { throw 'Wrong Unity project' } foreach ($step in @(@{Tag='first101';Id='101'}, @{Tag='relogin101';Id='101'}, @{Tag='switch102';Id='102'}, @{Tag='return101';Id='101'})) { $tag = "uloop-final-$($step.Tag)" if ($step.Tag -ne 'first101') { $exitResult = Invoke-Recorded "$tag-exit" @('execute-dynamic-code','--code-file',"$output/uloop-exit-production-path.cs") foreach ($expected in @('WasConnected=True','OldUserAuthorized=False','OldInternalId=0','OldUserIdCleared=True','OldApiPlayerIdCleared=True','CookieJarReplaced=True','NewJarCount=0','SessionAdvanced=True','OldHubConnected=False')) { if (-not $exitResult.Result.Contains($expected)) { throw "Exit invariant failed: $expected" } } Write-Output "$tag exit identity/cookie/hub checks passed" } $inputFile = if ($step.Id -eq '102') { 'uloop-set-login-102.cs' } else { 'uloop-set-login-id.cs' } $ready = $false for ($attempt=0; $attempt -lt 20; $attempt++) { $inputResult = Invoke-Recorded "$tag-input" @('execute-dynamic-code','--code-file',"$output/$inputFile") if ($inputResult.Result -eq "Active login input set to $($step.Id); no submit") { $ready=$true; break } Start-Sleep -Seconds 3 } if (-not $ready) { throw "Login input unavailable: $tag" } $ui = Invoke-Recorded "$tag-ui" @('screenshot','--window-name','Game','--capture-mode','rendering','--annotate-elements','true','--elements-only','true') $buttons = @($ui.Screenshots.AnnotatedElements | Where-Object Path -eq 'PFLoginAct(Clone)/CustomId/Dialog/OKButton') if ($buttons.Count -ne 1) { throw "Login button ambiguous: $tag" } $button=$buttons[0] $null = Invoke-Recorded "$tag-click" @('simulate-mouse-ui','--action','Click','--x',"$($button.SimX)",'--y',"$($button.SimY)") $loggedIn=$false for ($attempt=0; $attempt -lt 20; $attempt++) { Start-Sleep -Seconds 3 $state = Invoke-Recorded "$tag-state" @('execute-dynamic-code','--code-file',"$output/uloop-login-state.cs") if ($state.Result.Contains('Scene=FishingStage;') -and $state.Result.Contains("ApiPlayerId=$($step.Id);") -and $state.Result.Contains('Authorized=True')) { $loggedIn=$true; break } } if (-not $loggedIn -or -not $state.Result.Contains('ApiBase=http://s101.local:18080/')) { throw "Login failed/wrong endpoint: $tag" } Start-Sleep -Seconds 3 $errors = Invoke-Recorded "$tag-errors" @('get-logs','--log-type','Error','--max-count','100','--include-stack-trace','true') if ($errors.TotalCount -ne 0) { throw "Runtime errors detected: $tag ($($errors.TotalCount))" } Write-Output "$tag authenticated; error count=0" }