From 7d8aa4a029747457f29e78ad5f80e2acf0f2a1ca Mon Sep 17 00:00:00 2001 From: esefxdz Date: Thu, 15 Oct 2026 21:15:20 +0300 Subject: [PATCH] windows: find the Steam error box among all server windows, up to 3 starts Co-Authored-By: Claude Opus 5.5 --- windows/common.ps1 | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/windows/common.ps1 b/windows/common.ps1 index bccf091..355f5bb 100644 --- a/windows/common.ps1 +++ b/windows/common.ps1 @@ -334,31 +334,53 @@ function Start-CsServer($root) { $y = $y -replace '(?m)^yb_difficulty ".*"', ('yb_difficulty "' + [int]$s.CS_BOT_DIFFICULTY + '"') Write-TextFile $ycfg $y $hargs = "-console -condebug -game cstrike -port $([int]$s.CS_PORT) +maxplayers $([int]$s.CS_MAXPLAYERS) +map $($s.CS_MAP) +log on" - # On the very first start after an install, the server's Steam part sets itself up (appcache, - # config) and the server stops with a "Fatal error: Unable to initialize Steam" box. The next - # start works, so that one case gets a second try. - for ($try = 1; $try -le 2; $try++) { + # On the first start after an install, the server's Steam part sets itself up and the server + # stops with a "Fatal error: Unable to initialize Steam" box. A new start works, so that box + # gets the server closed and started again. + for ($try = 1; $try -le 3; $try++) { $p = Start-Process -FilePath (Join-Path $h 'hlds.exe') -WorkingDirectory $h -ArgumentList $hargs -PassThru if (-not (Test-SteamFailure $p ([int]$s.CS_PORT))) { break } Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue - if ($try -eq 1) { Write-Host ' (first start: Steam needed a second try)' } + Start-Sleep -Seconds 2 + Write-Host " (Steam wasn't ready yet, starting again)" } return $true } -# Waits up to 40 s for the server to answer or to show the "Unable to initialize Steam" box. +# Waits up to 40 s for the server to answer or to show its "Fatal error" box. # Returns $true for that box. function Test-SteamFailure($p, [int]$port) { $end = (Get-Date).AddSeconds(40) while ((Get-Date) -lt $end -and -not $p.HasExited) { if (Get-A2SInfo '127.0.0.1' $port 1000) { return $false } - $p.Refresh() - if ($p.MainWindowTitle -like 'Fatal error*') { return $true } + if (@(Get-ProcessWindowTitles $p.Id | Where-Object { $_ -like 'Fatal error*' }).Count) { return $true } Start-Sleep -Milliseconds 500 } return $false } +# Titles of all top-level windows of a process (the error box is not always its main window) +function Get-ProcessWindowTitles([int]$processId) { + if (-not ('Cs16Win' -as [type])) { + Add-Type @' +using System; using System.Text; using System.Collections.Generic; using System.Runtime.InteropServices; +public static class Cs16Win { + delegate bool EnumProc(IntPtr h, IntPtr l); + [DllImport("user32.dll")] static extern bool EnumWindows(EnumProc f, IntPtr l); + [DllImport("user32.dll")] static extern int GetWindowThreadProcessId(IntPtr h, out int pid); + [DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern int GetWindowText(IntPtr h, StringBuilder s, int n); + public static string[] Titles(int want) { + var r = new List(); + EnumWindows((h, l) => { int pid; GetWindowThreadProcessId(h, out pid); + if (pid == want) { var t = new StringBuilder(256); GetWindowText(h, t, 256); r.Add(t.ToString()); } return true; }, IntPtr.Zero); + return r.ToArray(); + } +} +'@ + } + [Cs16Win]::Titles($processId) +} + # An earlier version (2026-10-15) hid this Steam setting while starting the server; this puts it # back if a start was interrupted then. Harmless otherwise. $Script:SteamKey = 'HKCU:\Software\Valve\Steam\ActiveProcess'