Advertisement
aveyo

CS2_launcher

Feb 19th, 2024 (edited)
9,931
0
Never
2
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Batch 46.73 KB | Gaming | 0 0
  1. @(set ^ "f0=%temp%\CS2.ps1" -desc ')|| Counter-Strike 2 launcher - AveYo, 2024.10.30
  2. @(fc %0 "%f0%"||copy /y /b %0+nul "%f0%")>nul 2>&1& start "@" conhost powershell -nop -ep RemoteSigned -f "%f0%"& exit /b '); . {
  3. <#
  4.   match screen resolution before starting the game, to alleviate input lag, alt-tab & secondary screen issues
  5.   once the game is closed, restores the previous resolution
  6.   + game starts on screen with mouse pointer on and can seamlessly move between displays even if not set as primary & left
  7.   + clear steam verify game integrity after a crash to relaunch quicker; toggle fso
  8.   + unify settings for all users in game\csgo\cfg dir (also helps preserve settings when offline)
  9.   + optionally force specific video settings at every launch
  10. #>
  11.  
  12. #:: override resolution: no -1 max 0 |  if not appearing in res list, create the custom res in gpu driver settings / cru
  13. #:: good custom res for [4:3] = 1080x810  1280x960  1440x1080   [16:10] = 1296x810  1440x900   [16:9] = 1440x810  1632x918
  14. $force_width     = -1
  15. $force_height    = -1
  16. $force_refresh   = -1
  17.  
  18. #:: unify settings for all users in game\csgo\cfg dir: yes 1 no 0
  19. $unify_cfg       =  1
  20.  
  21. #:: override video settings with the preset below: yes 1 no 0  
  22. $force_settings  =  1
  23.  
  24. #:: override specific video settings - prefix with # lines to remain unchanged (adjust those in-game and relaunch)
  25. $video = @{                                                           #        Shadow of a Potato preset        more jpeg:
  26.   "setting.mat_vsync"                                = "0"            #  0     enable vsync in gpu driver instead
  27. # "setting.msaa_samples"                             = "0"            #  2     should enable AA when using FSR           0
  28. # "setting.r_csgo_cmaa_enable"                       = "0"            #  0     use msaa 2 instead                        
  29. # "setting.videocfg_shadow_quality"                  = "0"            #  0     shadows high: 2 | med: 1 | low: 0          
  30.   "setting.videocfg_dynamic_shadows"                 = "1"            #  1     must have for competitive play            0
  31. # "setting.videocfg_texture_detail"                  = "0"            #  0     texture high: 2 | med: 1 | low: 0          
  32. # "setting.r_texturefilteringquality"                = "3"            #  3     anyso16x: 5 | anyso4x: 3 | trilinear: 1   0
  33. # "setting.shaderquality"                            = "0"            #  0     smooth shadows fps--                      
  34. # "setting.videocfg_particle_detail"                 = "0"            #  0     smooth smokes fps--
  35. # "setting.videocfg_ao_detail"                       = "0"            #  0     ambient oclussion fps--
  36. # "setting.videocfg_hdr_detail"                      = "3"            #  -1    HDR quality: -1 | performance 8bit noise: 3
  37. # "setting.videocfg_fsr_detail"                      = "0"            #  0     FSR quality: 2 | balanced: 3 | minecraft: 4
  38.   "setting.r_low_latency"                            = "1"            #  1
  39. }
  40. $machine = @{
  41. # "r_fullscreen_gamma"                               = "2.2"          #  2.2   brightness slider - works on windowed too now
  42. # "r_player_visibility_mode"                         = "0"            #  0     kinda useless
  43. # "r_drawtracers_firstperson"                        = "0"            #  0     tracers
  44.   "engine_no_focus_sleep"                            = "0"            #  20    power saving while alt-tab
  45.   "trusted_launch"                                   = "1"            #  1     trusted launch tracking
  46.   "r_show_build_info"                                = "1"            #  1     build info is a must when reporting issues
  47. }
  48. $extra_launch_options = @()
  49. $extra_launch_options+= '+cl_input_enable_raw_keyboard 0'             #  prevent keyboard issues
  50. #$extra_launch_options+= '-allow_third_party_software'                #  uncomment if recording via obs game capture
  51. #$extra_launch_options+= '-consolelog cfg\console.log'                #  uncomment to autosave cfg\console.log
  52.  
  53. #:: override fullscreen mode: exclusive 1 desktop-friendly 0
  54. $force_exclusive =  0
  55.  
  56. #:: override fullscreen optimizations (FSO): enable 1 disable 0
  57. $enable_fso      =  0
  58.  
  59. #:: override screen or use current -1 | this is 1st number in the screen list; second number is for -sdl_displayindex
  60. $force_screen    = -1
  61.  
  62. #:: set to 1 to wait for external launcher to start the game (ex. gamersclub br) - not needed for faceit web
  63. $external_launcher = 0
  64.  
  65. #:: override script handling or use default 0
  66. $do_not_set_desktop_res_to_match_game = 0
  67. $do_not_restore_res_use_max_available = 0
  68. $do_not_hide_script_window_on_waiting = 0
  69.  
  70. #:: main script section --------------------------------------------------------------------- switch syntax highlight to powershell
  71. $APPID      = 730
  72. $APPNAME    = "cs2"
  73. $INSTALLDIR = "Counter-Strike Global Offensive"
  74. $MOD        = "csgo"
  75. $GAMEBIN    = "bin\win64"
  76. $USER_VCFG  = "${APPNAME}_user_convars_0_slot0.vcfg"
  77. $KEYS_VCFG  = "${APPNAME}_user_keys_0_slot0.vcfg"
  78. $MACH_VCFG  = "${APPNAME}_machine_convars.vcfg"
  79. $VIDEO_TXT  = "${APPNAME}_video.txt"
  80.  
  81. #:: copy-pasted directly into powershell? then do not hide window
  82. if (!$MyInvocation.ScriptName) { $do_not_hide_script_window_on_waiting = 1 }
  83.  
  84. #:: check if already opened
  85. $c = 'HKCU:\Console\@'; ni $c -ea 0 >''; sp $c ScreenColors 0x0b -type dword -ea 0; sp $c QuickEdit 0 -type dword -ea 0
  86. ps | where {$_.MainWindowTitle -eq "$APPNAME launcher"} | kill; $host.ui.RawUI.WindowTitle = "$APPNAME launcher"
  87. if (ps $APPNAME -ea 0) { write-host " $APPNAME is running " -fore Black -back Yellow; sleep 3; exit 0 }
  88.  
  89. #:: detect STEAM and specific APP
  90. $STEAM = resolve-path (gpv "HKCU:\SOFTWARE\Valve\Steam" SteamPath)
  91. gc "$STEAM\steamapps\libraryfolders.vdf" |foreach  {$_ -split '"',5} |where {$_ -like '*:\\*'} |foreach {
  92.   $l = resolve-path $_; $i = "$l\steamapps\common\$INSTALLDIR"; if (test-path "$i\game\$MOD\steam.inf") {
  93.   $STEAMAPPS = "$l\steamapps"; $GAMEROOT = "$i\game"; $GAME = "$i\game\$MOD"
  94. }}
  95.  
  96. #:: detect per-user data path
  97. pushd "$STEAM\userdata"
  98. $USRCLOUD = split-path (dir "localconfig.vdf" -File -Recurse | sort LastWriteTime -Descending | Select -First 1).DirectoryName
  99. $USRLOCAL = "$USRCLOUD\$APPID\local"
  100. popd
  101.  
  102. #:: unify settings for all users in game\csgo\cfg dir
  103. $USRLOCALCSGO_U  = [Environment]::GetEnvironmentVariable("USRLOCALCSGO",1)
  104. $USRLOCALCSGO_M  = [Environment]::GetEnvironmentVariable("USRLOCALCSGO",2)
  105. $USRLOCALCSGO_Ub = ($USRLOCALCSGO_U -and (test-path "$USRLOCALCSGO_U\cfg\$MACH_VCFG"))
  106. $USRLOCALCSGO_Mb = ($USRLOCALCSGO_M -and (test-path "$USRLOCALCSGO_M\cfg\$MACH_VCFG"))
  107. if ($unify_cfg -eq 0) {
  108.   if ($USRLOCALCSGO_Mb) {
  109.     $USRLOCAL = $USRLOCALCSGO_M
  110.     write-host " USRLOCALCSGO is defined at machine level. unable to override cfg location" -fore Yellow
  111.   }
  112.   elseif ($USRLOCALCSGO_Ub) {
  113.     [Environment]::SetEnvironmentVariable("USRLOCALCSGO","",0)
  114.     [Environment]::SetEnvironmentVariable("USRLOCALCSGO","",1)
  115.     robocopy "$USRLOCALCSGO_U\cfg/" "$USRCLOUD\$APPID\local\cfg/" *.txt *.cfg *.vcfg /XO >''
  116.     if (ps "Steam" -ea 0) {
  117.       write-host " will try closing Steam to refresh USRLOCAL gamevar" -fore Yellow
  118.       start "$STEAM\Steam.exe" -args '-shutdown' -wait; sleep 5
  119.     }
  120.   }
  121. }
  122. if ($unify_cfg -eq 1) {
  123.   if ($USRLOCALCSGO_Mb) {
  124.     $USRLOCAL = "$USRLOCALCSGO_M"
  125.   }
  126.   elseif ($USRLOCALCSGO_Ub -and $USRLOCALCSGO_U -eq "$GAME") {
  127.     $USRLOCAL = "$GAME"
  128.     [Environment]::SetEnvironmentVariable("USRLOCALCSGO","$GAME",0)
  129.     [Environment]::SetEnvironmentVariable("USRLOCALCSGO","$GAME",1)
  130.     robocopy "$USRCLOUD\$APPID\local\cfg/" "$GAME\cfg/" *.vcfg *video*.txt /XO >''
  131.     robocopy "$USRCLOUD\$APPID\local/" "$GAME/" socache.dt /XO >''
  132.   }  
  133.   else {
  134.     $USRLOCAL = "$GAME"
  135.     [Environment]::SetEnvironmentVariable("USRLOCALCSGO","$GAME",0)
  136.     [Environment]::SetEnvironmentVariable("USRLOCALCSGO","$GAME",1)
  137.     if ($USRLOCALCSGO_Ub) {
  138.       robocopy "$USRLOCALCSGO_U\cfg/" "$GAME\cfg/" *.vcfg *video*.txt /XO >''
  139.       robocopy "$USRLOCALCSGO_U/" "$GAME/" socache.dt /XO >''
  140.     }
  141.     if (ps "Steam" -ea 0) {
  142.       write-host " will try closing Steam to refresh USRLOCAL gamevar" -fore Yellow
  143.       start "$STEAM\Steam.exe" -args '-shutdown' -wait; sleep 5
  144.     }
  145.   }
  146. }
  147.  
  148. #:: generate a blank autoexec.cfg if not already found
  149. if (-not (test-path "$GAME\cfg\autoexec.cfg")) { sc "$GAME\cfg\autoexec.cfg" "" }
  150.  
  151. #:: decide which sets of video options overrides to use: script has priority, then launch options, then cfg
  152. $exclusive = 0; $screen = 0; $width = 0; $height = 0; $refresh = 0; $numer = -1; $denom = -1
  153.  
  154. #:: parse video txt file
  155. $video_config = "$USRLOCAL\cfg\$VIDEO_TXT"
  156. if ($video_config -ne '') {
  157.   $lines = (gc $video_config); $txt = $lines -join "`n"
  158.   if ($txt -match '"setting.fullscreen"\s+"([^"]*)"')              { $exclusive = [int]$matches[1] }
  159.   if ($txt -match '"setting.monitor_index"\s+"([^"]*)"')           { $screen    = [int]$matches[1] }
  160.   if ($txt -match '"setting.defaultres"\s+"([^"]*)"')              { $width     = [int]$matches[1] }
  161.   if ($txt -match '"setting.defaultresheight"\s+"([^"]*)"')        { $height    = [int]$matches[1] }
  162.   if ($txt -match '"setting.refreshrate_numerator"\s+"([^"]*)"')   { $numer     = [int]$matches[1] }
  163.   if ($txt -match '"setting.refreshrate_denominator"\s+"([^"]*)"') { $denom     = [int]$matches[1] }
  164.   #:: compute numerator / denominator = refresh for video txt file
  165.   if ($numer -gt 0 -and $denom -gt 0) { $refresh = [decimal]$numer / $denom }
  166. }
  167.  
  168. #:: parse game launch options
  169. $lo = (gc "$USRCLOUD\config\localconfig.vdf") -join "`n"
  170. $lo = (($lo -split '\n\s{5}"' + $APPID + '"\n\s{5}{\n')[1] -split '\n\s{5}}\n')[0]
  171. $lo = (($lo -split '\n\s{6}"LaunchOptions"\s+"')[1] -split '"\n')[0]
  172. if ($lo -ne '') {
  173.   if ($lo -match '-fullscreen\s+')            { $exclusive = 1 }
  174.   if ($lo -match '-sdl_displayindex\s+(\d+)') { $screen    = [int]$matches[1] }
  175.   if ($lo -match '-w(idth)?\s+(\d+)')         { $width     = [int]$matches[2] }
  176.   if ($lo -match '-h(eight)?\s+(\d+)')        { $height    = [int]$matches[2] }
  177.   if ($lo -match '-r(efresh)?\s+([\d.]+)')    { $refresh   = [decimal]$matches[2] }
  178. }
  179.  
  180. #:: script overrides
  181. if ($force_exclusive -ge 0) { $exclusive = $force_exclusive }
  182. if ($force_screen -ge 0)    { $screen    = $force_screen }
  183. if ($force_width -ge 0)     { $width     = $force_width }
  184. if ($force_height -ge 0)    { $height    = $force_height }
  185. if ($force_refresh -ge 0)   { $refresh   = $force_refresh }
  186. if ($refresh -gt 0) {
  187.   $hz = ([string]$refresh).Split('.'); $denom = 1000
  188.   if ($hz.length -eq 2) { $numer = [int]($hz[0] + $hz[1].PadRight(3,'0')) } else { $numer = [int]($hz[0] + "000") }
  189. }
  190.  
  191. #:: set screen resolution via SetRes before launching the game, to alleviate input lag, alt-tab and secondary screens issues
  192. $library1 = "SetRes"; $version1 = "2024.3.10.0"; $about1 = "set screen resolution"; $path1 = "$env:APPDATA\AveYo\$library1.dll"
  193. <# usage:
  194.   [SetRes.Displays]::Change(output=[0:none 1:def], screen, width, height, refresh=[0:def], test=[0:change 1:test])
  195.   [SetRes.Displays]::List(output=[0:none 1:filter 2:all], screen, minw=[1024], maxw=[16384], maxh=[16384])
  196.   returns array of: sdl_idx, screen, current_width, current_height, current_refresh, max_width, max_height, max_refresh
  197.   the c# typefinition at the end of the script gets pre-compiled rather than let powershell do it slowly every launch #>
  198. if ((gi $path1 -force -ea 0).VersionInfo.FileVersion -ne $version1) { del $path1 -force -ea 0 } ; if (-not (test-path $path1)) {
  199.   mkdir "$env:APPDATA\AveYo" -ea 0 >'' 2>''; pushd $env:APPDATA\AveYo; " one-time initialization of $library1 library..."
  200.   [io.file]::WriteAllText("$env:APPDATA\AveYo\$library1.cs", ($MyInvocation.MyCommand -split '<#[:]LIBRARY1[:].*')[1])
  201.   $csc = join-path $([Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory()) 'csc.exe'
  202.   start $csc -args "/out:$library1.dll /target:library /platform:anycpu /optimize /nologo $library1.cs" -nonew -wait; popd
  203. }
  204. Import-Module $path1
  205. $display = [SetRes.Displays]::Init($screen)
  206. $sdl_idx = $display[0];  $screen = $display[1];  $primary = $display[2] -gt 0;  $multimon = $display[3] -gt 1
  207.  
  208. #:: restore previous resolution if game was not gracefully closed last time
  209. if ($do_not_set_desktop_res_to_match_game -le 0 -and (test-path "$GAME\cfg\SetRes.cfg")) {
  210.   $restore = (gc "$GAME\cfg\SetRes.cfg") -split ','
  211.   if ($null -eq (ps $APPNAME -ea 0)) {
  212.     $c = [SetRes.Displays]::Change(0, $restore[1], $restore[2], $restore[3], $restore[4])
  213.   }
  214. }
  215.  
  216. #:: SetRes automatically picks a usable mode if the change is invalid so result might differ from the request
  217. $oldres  = [SetRes.Displays]::List(1, $screen)
  218. if ($width   -le 0) { $width  = $oldres[2] }
  219. if ($height  -le 0) { $height = $oldres[3] }
  220. if ($refresh -le 0) { $max_refresh = [SetRes.Displays]::List(0, $screen, $width, $width, $height); $refresh = $max_refresh[7] }
  221. $newres  = [SetRes.Displays]::Change(1, $screen, $width, $height, $refresh, 1)
  222. $width   = $newres[5]; $restore_width   = $newres[2]
  223. $height  = $newres[6]; $restore_height  = $newres[3]
  224. $refresh = $newres[7]; $restore_refresh = $newres[4]
  225. function max {$r = [SetRes.Displays]::Change(1, $oldres[1], $oldres[5], $oldres[6], $oldres[7])} # console command to set max res
  226. function min {$r = [SetRes.Displays]::Change(1, $oldres[1], 1024,       768,        $oldres[7])} # console command to set min res
  227. if ($do_not_restore_res_use_max_available -ge 1) {
  228.   $restore_width = $oldres[5]; $restore_height = $oldres[6]; $restore_refresh = $oldres[7]
  229. }
  230. $sameres = $width -eq $restore_width -and $height -eq $restore_height -and $refresh -eq $restore_refresh
  231. $ratio   = $width / $height
  232. if ($ratio -le 4/3) {$ar = 0} elseif ($ratio -le 16/10) {$ar = 2} elseif ($ratio -le 16/8.9) {$ar = 1} else {$ar = 3}
  233. $mode = "{0,4} x {1,4} {2,3}Hz" -f ($width, $height, $refresh)
  234. $rend = ('Desktop-friendly','Exclusive')[$exclusive -gt 0] + (' + FSO','')[$enable_fso -eq 0]
  235.  
  236. #::  many thanks to /u/wazernet for testing and suggestions
  237. write-host " $screen $mode $rend mode requested" -fore Yellow
  238.  
  239. #:: update video overrides in case the initial mode was invalid and SetRes applied a fallback
  240. if ($force_settings -le 0) { $video = @{} }
  241. $video["setting.fullscreen"]                   = (0,1)[$exclusive -eq 1]
  242. $video["setting.coop_fullscreen"]              = (0,1)[$exclusive -ne 1]
  243. $video["setting.nowindowborder"]               = 1
  244. $video["setting.fullscreen_min_on_focus_loss"] = 0
  245. $video["setting.monitor_index"]                = $sdl_idx
  246. $video["setting.defaultres"]                   = $width
  247. $video["setting.defaultresheight"]             = $height
  248. $video["setting.refreshrate_numerator"]        = $refresh
  249. $video["setting.refreshrate_denominator"]      = 1
  250. $video["setting.aspectratiomode"]              = $ar
  251.  
  252. #:: update cfg files with the overrides
  253. $video_config = "$USRLOCAL\cfg\$VIDEO_TXT"
  254. if (-not (test-path $video_config)) {sc $video_config "`"video.cfg`"`n{`n`t`"Version`"`t`t`"13`"`n}`n" -force -ea 0 }
  255. if ((test-path $video_config) -and $force_settings -ge 1) {
  256.   $lines = (gc $video_config); $txt = $lines -join "`n"; $cfg = new-object System.Text.StringBuilder # dos line-endings
  257.   foreach ($k in $video.Keys) {
  258.     if ($k -like 'setting.*' -and $txt -notmatch "`"$k`"") { $cfg.Append("`r`n`t`"$k`"`t`t`"$($video.$k)`"")>'' }
  259.   }
  260.   if ($cfg.length -gt 0) { -1..-10 |foreach { if ($lines[$_] -match "^}$") { $lines[$_ - 1] += $cfg.ToString(); return } } }
  261.   if ($cfg.length -gt 0) {sc $video_config $lines -force -ea 0 }
  262.   (gc $video_config) |foreach {
  263.     foreach ($k in $video.Keys) { if ($_ -like "*$k`"*") {
  264.       $_ = $_ -replace "(`"$k`"\s+)(`"[^`"]*`")","`$1`"$($video.$k)`"" } }; $_ } | sc $video_config -force -ea 0
  265. }
  266. $machine_config = "$USRLOCAL\cfg\$MACH_VCFG"
  267. if (-not (test-path $machine_config)) {sc $machine_config "`"config`"`n{`n`t`"convars`"`n`t{`n`t`t`n`t}`n}`n" -force -ea 0 }
  268. if ((test-path $machine_config) -and $force_settings -ge 1) {
  269.   $lines = (gc $machine_config); $txt = $lines -join "`n"; $cfg = new-object System.Text.StringBuilder # unix line-endings
  270.   foreach ($k in $machine.Keys) { if ($txt -notmatch "`"$k`"") { $cfg.Append("`n`t`t`"$k`"`t`t`"$($machine.$k)`"")>'' } }
  271.   if ($cfg.length -gt 0) { -1..-10 |foreach { if ($lines[$_] -match "^\s}$") { $lines[$_ - 1] += $cfg.ToString(); return } } }
  272.   if ($cfg.length -gt 0) { sc $machine_config (($lines -join "`n") + "`n") -noNewLine -force -ea 0 }
  273.   (gc $machine_config) |foreach {
  274.     foreach ($k in $machine.Keys) { if ($_ -like "*$k`"*") {
  275.       $_ = $_ -replace "(`"$k`"\s+)(`"[^`"]*`")","`$1`"$($machine.$k)`"" } }; $_ } | sc $machine_config -force -ea 0
  276. }
  277. if ($unify_cfg -gt 0 -and $USRLOCAL -ne "$USRCLOUD\$APPID\local") {
  278.   robocopy "$USRLOCAL\cfg/" "$USRCLOUD\$APPID\local\cfg/" *convars.vcfg *slot0.vcfg *video*.txt /XO >''
  279. }
  280.  
  281. #:: clear verify integrity flags after a crash for quicker relaunch
  282. $appmanifest="$STEAMAPPS\appmanifest_$APPID.acf"
  283. if (test-path $appmanifest) {
  284.   $ACF = [io.file]::ReadAllText($appmanifest)
  285.   if ($ACF -match '"FullValidateAfterNextUpdate"\s+"1"' -or $ACF -notmatch '"StateFlags"\s+"4"') {
  286.     write-host " update or verify integrity flags detected, will clear them and restart Steam...`n" -fore Yellow
  287.     'dota2','cs2','steamwebhelper','steam' |foreach {kill -name $_ -force -ea 0} ; sleep 3; del "$STEAM\.crash" -force -ea 0
  288.     $ACF = $ACF -replace '("FullValidateAfterNextUpdate"\s+)("\d+")',"`$1`"0`"" -replace '("StateFlags"\s+)("\d+")',"`$1`"4`""
  289.     [io.file]::WriteAllText($appmanifest, $ACF)
  290.   }
  291. } else {
  292.   write-host " $appmanifest missing or wrong lib path detected! continuing with a default manifest...`n" -fore Yellow
  293.   $blank = "`"AppState`"`n{`n`"AppID`" `"$APPID`"`n`"Universe`" `"1`"`n`"installdir`" `"$INSTALLDIR`"`n`"StateFlags`" `"4`"`n}`n"
  294.   sc $appmanifest $blank -force
  295. }
  296.  
  297. #:: toggle fullscreen optimizations for game launcher - FSO as a concept is an abomination - ofc it causes input lag
  298. $progr = "$GAMEROOT\$GAMEBIN\$APPNAME.exe"
  299. $flags = 'HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers'
  300. $found = (gi $flags -ea Ignore).Property -contains $progr
  301. $valid = $found -and (gpv $flags $progr) -like '*DISABLEDXMAXIMIZEDWINDOWEDMODE*'
  302. if ($enable_fso -eq 0 -and (!$found -or !$valid)) {
  303.   write-host " disabling $APPNAME os fullscreen (un)optimizations"
  304.   ni $flags -ea 0; sp $flags $progr '~ DISABLEDXMAXIMIZEDWINDOWEDMODE HIGHDPIAWARE' -force -ea 0
  305. }
  306. if ($enable_fso -eq 1 -and $valid) {rp $flags $progr -force -ea 0}
  307.  
  308. #:: prepare video launch options
  309. $window = @("-force_allow_coop_fullscreen -coop_fullscreen", "-force_allow_excl_fullscreen -fullscreen")[$exclusive -ge 1]
  310. $video_options = "$window -noborder -width $width -height $height -refresh $refresh -sdl_displayindex $sdl_idx "
  311. write-host " $video_options`n" -fore Green
  312. write-host " $GAMEROOT\$GAMEBIN\$APPNAME.exe" -fore Gray
  313. write-host " $GAME\cfg\autoexec.cfg" -fore Gray
  314. write-host " $video_config" -fore Gray
  315. #pause
  316.  
  317. #:: prepare steam quick options
  318. $quick = '-quicklogin -vgui -oldtraymenu -vrdisable -nofriendsui -skipstreamingdrivers -silent '
  319. $quick+= '-cef-force-occlusion -cef-single-process -cef-disable-gpu -no-dwrite -forceservice'
  320. $steam_options = "$quick -applaunch $APPID $video_options $extra_launch_options "
  321.  
  322. #:: here you can insert anything to run before starting the game like start "some\program" -args "etc";
  323.  
  324. #:: start game (and steam if not already running)
  325. if ($external_launcher -le 0) {
  326.   write-host "`n waiting for Steam to start $($APPNAME.ToUpper())... `t too long? run script again" -fore Yellow
  327.   powershell.exe -nop -c "Start-Process \`"$STEAM\steam.exe\`" \`"$steam_options\`""
  328. } else {
  329.   write-host "`n waiting for external launcher to start $($APPNAME.ToUpper())... `t too long? run script again" -fore Yellow
  330. }
  331.  
  332. #:: restore res after game closes if it was changed
  333. if ($do_not_set_desktop_res_to_match_game -le 0 -and -not $sameres) {
  334.   sc "$GAME\cfg\SetRes.cfg" "$sdl_idx,$screen,$restore_width,$restore_height,$restore_refresh,`r`n" -force -ea 0
  335.   "`n will restore res to $restore_width x $restore_height ${restore_refresh}Hz after $($APPNAME.ToUpper()) closes..."
  336.   while ($null -eq ($wait = ps $APPNAME -ea 0)) { sleep -m 250 }
  337.   $change  = [SetRes.Displays]::Change(1, $screen, $width, $height, $refresh)
  338.   if ($do_not_hide_script_window_on_waiting -le 0) { sleep 3; powershell -win 1 -nop -c ';' }
  339.   while (-not $wait.HasExited) { sleep 5 }
  340.   $restore = [SetRes.Displays]::Change(1, $screen, $restore_width, $restore_height, $restore_refresh)
  341.   del "$GAME\cfg\SetRes.cfg" -force -ea 0
  342. } else {
  343.   #:: change even if res matches, to address a rare bug where game starts in a blank window and can only \ q-tab enter out of it
  344.   $change  = [SetRes.Displays]::Change(1, $screen, $restore_width, $restore_height, $restore_refresh)
  345. }
  346. " can enter: max for $($oldres[5])x$($oldres[6]) or: min for 1024x768 if needed"
  347.  
  348. #:: here you can insert anything to run after game is closed like start "some\program" -args "etc";
  349.  
  350. #:: done, script closes
  351. if ($do_not_hide_script_window_on_waiting -ge 1) { return }
  352. [Environment]::Exit(0)
  353.  
  354. <#:LIBRARY1: start <# ------------------------------------------------------------------------------ switch syntax highlight to C#
  355. /// SetRes - loosely based on code by Rick Strahl
  356. using System; using System.Runtime.InteropServices; using System.Collections.Generic; using System.Linq; using System.Reflection;
  357. [assembly:AssemblyVersion("2024.3.10.0")] [assembly: AssemblyTitle("AveYo")]
  358. namespace SetRes
  359. {
  360.   public static class Displays
  361.   {
  362.     private const short CCDEVICENAME = 32,  CCFORMNAME  = 32;
  363.  
  364.     public const int SUCCESS       = 0,  ENUM_CURRENT  = -1,  MONITOR_DEFAULTTONEAREST = 0x00000002;
  365.     public const int DMDFO_DEFAULT = 0,  DMDFO_STRETCH =  1,  DMDFO_CENTER = 2;
  366.     public const int DMDO_DEFAULT  = 0,  DMDO_90       =  1,  DMDO_180     = 2,  DMDO_270 = 3;
  367.  
  368.     [Flags()]
  369.     private enum EdsFlags : int
  370.     {
  371.       EDS_ATTACHEDTODESKTOP = 0x00000001,  EDS_MULTIDRIVER   = 0x00000002,  EDS_PRIMARYDEVICE = 0x00000004,
  372.       EDS_MIRRORINGDRIVER   = 0x00000008,  EDS_VGACOMPATIBLE = 0x00000010,  EDS_REMOVABLE     = 0x00000020,
  373.       EDS_MODESPRUNED       = 0x08000000,  EDS_REMOTE        = 0x04000000,  EDS_DISCONNECT    = 0x02000000
  374.     }
  375.  
  376.     [Flags()]
  377.     private enum CdsFlags : uint
  378.     {
  379.       CDS_NONE            = 0x00000000,  CDS_UPDATEREGISTRY      = 0x00000001,  CDS_TEST                 = 0x00000002,
  380.       CDS_FULLSCREEN      = 0x00000004,  CDS_GLOBAL              = 0x00000008,  CDS_SET_PRIMARY          = 0x00000010,
  381.       CDS_VIDEOPARAMETERS = 0x00000020,  CDS_ENABLE_UNSAFE_MODES = 0x00000100,  CDS_DISABLE_UNSAFE_MODES = 0x00000200,
  382.       CDS_RESET           = 0x40000000,  CDS_RESET_EX            = 0x20000000,  CDS_NORESET             = 0x10000000
  383.     }
  384.  
  385.     [Flags()]
  386.     private enum DmFlags : int
  387.     {
  388.       DM_ORIENTATION   = 0x00000001,  DM_PAPERSIZE          = 0x00000002,  DM_PAPERLENGTH        = 0x00000004,
  389.       DM_PAPERWIDTH    = 0x00000008,  DM_SCALE              = 0x00000010,  DM_POSITION           = 0x00000020,
  390.       DM_NUP           = 0x00000040,  DM_DISPLAYORIENTATION = 0x00000080,  DM_COPIES             = 0x00000100,
  391.       DM_DEFAULTSOURCE = 0x00000200,  DM_PRINTQUALITY       = 0x00000400,  DM_COLOR              = 0x00000800,
  392.       DM_DUPLEX        = 0x00001000,  DM_YRESOLUTION        = 0x00002000,  DM_TTOPTION           = 0x00004000,
  393.       DM_COLLATE       = 0x00008000,  DM_FORMNAME           = 0x00010000,  DM_LOGPIXELS          = 0x00020000,
  394.       DM_BITSPERPEL    = 0x00040000,  DM_PELSWIDTH          = 0x00080000,  DM_PELSHEIGHT         = 0x00100000,
  395.       DM_DISPLAYFLAGS  = 0x00200000,  DM_DISPLAYFREQUENCY   = 0x00400000,  DM_ICMMETHOD          = 0x00800000,
  396.       DM_ICMINTENT     = 0x01000000,  DM_MEDIATYPE          = 0x02000000,  DM_DITHERTYPE         = 0x04000000,
  397.       DM_PANNINGWIDTH  = 0x08000000,  DM_PANNINGHEIGHT      = 0x10000000,  DM_DISPLAYFIXEDOUTPUT = 0x20000000
  398.     }
  399.  
  400.     [StructLayout(LayoutKind.Sequential)]
  401.     public struct POINTL { public int x; public int y; }
  402.  
  403.     [StructLayout(LayoutKind.Sequential)]
  404.     public struct RECT { public int left; public int top; public int right; public int bottom; }
  405.  
  406.     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  407.     private struct DISPLAY_DEVICE
  408.     {
  409.       [MarshalAs(UnmanagedType.U4)]                       public int      cb;
  410.       [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]  public string   DeviceName;
  411.       [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] public string   DeviceString;
  412.       [MarshalAs(UnmanagedType.U4)]                       public EdsFlags StateFlags;
  413.       [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] public string   DeviceID;
  414.       [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)] public string   DeviceKey;
  415.       public void Initialize()
  416.       {
  417.         this.DeviceName   = new string(new char[32]);
  418.         this.DeviceString = new string(new char[128]);
  419.         this.DeviceID     = new string(new char[128]);
  420.         this.DeviceKey    = new string(new char[128]);
  421.         this.cb           = Marshal.SizeOf(this);
  422.       }
  423.     }
  424.  
  425.     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  426.     private struct DEVMODE
  427.     {
  428.       [MarshalAs(UnmanagedType.ByValTStr, SizeConst=CCDEVICENAME)]
  429.                                     public string  dmDeviceName;
  430.       [MarshalAs(UnmanagedType.U2)] public ushort  dmSpecVersion;
  431.       [MarshalAs(UnmanagedType.U2)] public ushort  dmDriverVersion;
  432.       [MarshalAs(UnmanagedType.U2)] public ushort  dmSize;
  433.       [MarshalAs(UnmanagedType.U2)] public ushort  dmDriverExtra;
  434.       [MarshalAs(UnmanagedType.U4)] public DmFlags dmFields;
  435.                                     public POINTL  dmPosition;
  436.       [MarshalAs(UnmanagedType.U4)] public uint    dmDisplayOrientation;
  437.       [MarshalAs(UnmanagedType.U4)] public uint    dmDisplayFixedOutput;
  438.       [MarshalAs(UnmanagedType.I2)] public short   dmColor;
  439.       [MarshalAs(UnmanagedType.I2)] public short   dmDuplex;
  440.       [MarshalAs(UnmanagedType.I2)] public short   dmYResolution;
  441.       [MarshalAs(UnmanagedType.I2)] public short   dmTTOption;
  442.       [MarshalAs(UnmanagedType.I2)] public short   dmCollate;
  443.       [MarshalAs(UnmanagedType.ByValTStr, SizeConst=CCFORMNAME)]
  444.                                     public string  dmFormName;
  445.       [MarshalAs(UnmanagedType.U2)] public ushort  dmLogPixels;
  446.       [MarshalAs(UnmanagedType.U4)] public uint    dmBitsPerPel;
  447.       [MarshalAs(UnmanagedType.U4)] public uint    dmPelsWidth;
  448.       [MarshalAs(UnmanagedType.U4)] public uint    dmPelsHeight;
  449.       [MarshalAs(UnmanagedType.U4)] public uint    dmDisplayFlags;
  450.       [MarshalAs(UnmanagedType.U4)] public uint    dmDisplayFrequency;
  451.       [MarshalAs(UnmanagedType.U4)] public uint    dmICMMethod;
  452.       [MarshalAs(UnmanagedType.U4)] public uint    dmICMIntent;
  453.       [MarshalAs(UnmanagedType.U4)] public uint    dmMediaType;
  454.       [MarshalAs(UnmanagedType.U4)] public uint    dmDitherType;
  455.       [MarshalAs(UnmanagedType.U4)] public uint    dmReserved1;
  456.       [MarshalAs(UnmanagedType.U4)] public uint    dmReserved2;
  457.       [MarshalAs(UnmanagedType.U4)] public uint    dmPanningWidth;
  458.       [MarshalAs(UnmanagedType.U4)] public uint    dmPanningHeight;
  459.       public void Initialize()
  460.       {
  461.         this.dmDeviceName = new string(new char[CCDEVICENAME]);
  462.         this.dmFormName   = new string(new char[CCFORMNAME]);
  463.         this.dmSize       = (ushort)Marshal.SizeOf(this);
  464.       }
  465.     }
  466.  
  467.     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
  468.     private struct MONITORINFOEX
  469.     {
  470.       public uint cbSize;
  471.       public RECT rcMonitor;
  472.       public RECT rcWork;
  473.       public int dwFlags;
  474.       [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szDevice;
  475.       public void Initialize()
  476.       {
  477.         this.rcMonitor = new RECT();
  478.         this.rcWork    = new RECT();
  479.         this.szDevice  = new string(new char[32]);
  480.         this.cbSize    = (uint)Marshal.SizeOf(this);
  481.       }
  482.     }
  483.  
  484.     [DllImport("kernel32", ExactSpelling = true)] private static extern IntPtr
  485.     GetConsoleWindow();
  486.  
  487.     [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool
  488.     GetWindowRect(IntPtr hWnd, out RECT lpRect);
  489.  
  490.     [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool
  491.     MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
  492.  
  493.     [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool
  494.     GetCursorPos(out POINTL lpPoint);
  495.  
  496.     [DllImport("user32", SetLastError = true)] private static extern IntPtr
  497.     MonitorFromPoint(POINTL pt, int dwFlags);
  498.  
  499.     [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)]
  500.     [return: MarshalAs(UnmanagedType.Bool)] private static extern bool
  501.     GetMonitorInfo(IntPtr hMonitor, [In, Out] ref MONITORINFOEX lpmi);
  502.  
  503.     [DllImport("user32", CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool
  504.     EnumDisplayMonitors(IntPtr hdc, IntPtr lpRect, EnumDisplayMonitorsDelegate lpfnEnum, IntPtr dwData);
  505.  
  506.     [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool
  507.     EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);
  508.  
  509.     [DllImport("user32", SetLastError=true, BestFitMapping=false, ThrowOnUnmappableChar=true)]
  510.     [return: MarshalAs(UnmanagedType.Bool)] private static extern bool
  511.     EnumDisplaySettings(byte[] lpszDeviceName, [param: MarshalAs(UnmanagedType.U4)] int iModeNum, [In,Out] ref DEVMODE lpDevMode);
  512.  
  513.     [DllImport("user32")] private static extern int
  514.     ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, CdsFlags dwflags, IntPtr lParam);
  515.  
  516.     //[DllImport("user32")] private static extern int
  517.     //ChangeDisplaySettingsEx(IntPtr lpszDeviceName, IntPtr lpDevMode, IntPtr hwnd, int dwflags, IntPtr lParam);
  518.  
  519.     [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool
  520.     SetProcessDPIAware();
  521.  
  522.     private delegate bool EnumDisplayMonitorsDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);
  523.  
  524.     private static IntPtr consolehWnd = GetConsoleWindow();
  525.  
  526.     public static class StringExtensions
  527.     {
  528.       public static byte[] ToLPTStr(string str)
  529.       {
  530.         return (str == null) ? null : Array.ConvertAll((str + '\0').ToCharArray(), Convert.ToByte);
  531.       }
  532.     }
  533.  
  534.     public class DisplayInfo
  535.     {
  536.       public int    Index      { get; set; }
  537.       public int    SDLIndex   { get; set; }
  538.       public string DeviceName { get; set; }
  539.       public int    Height     { get; set; }
  540.       public int    Width      { get; set; }
  541.       public RECT   Bounds     { get; set; }
  542.       public RECT   WorkArea   { get; set; }
  543.       public bool   IsPrimary  { get; set; }
  544.       public bool   IsCurrent  { get; set; }
  545.  
  546.       public override string ToString()
  547.       {
  548.         return string.Format("{0} {1} {2} {3} {4} ({5},{6},{7},{8}){9}{10}", Index, SDLIndex, DeviceName,
  549.           Height, Width, Bounds.left, Bounds.top, Bounds.right, Bounds.bottom,
  550.           IsPrimary ? " [primary]" : "", IsCurrent ? " [current]" : !!)
  551.       }
  552.     }
  553.  
  554.     public class DisplayDevice
  555.     {
  556.       public int    Index        { get; set; }
  557.       public int    MonitorIndex { get; set; }
  558.       public int    SDLIndex     { get; set; }
  559.       public string Id           { get; set; }
  560.       public string DriverName   { get; set; }
  561.       public string DisplayName  { get; set; }
  562.       public string AdapterName  { get; set; }
  563.       public RECT   Bounds       { get; set; }
  564.       public bool   IsPrimary    { get; set; }
  565.       public bool   IsCurrent    { get; set; }
  566.  
  567.       public override string ToString()
  568.       {
  569.         return ToString(false);
  570.       }
  571.       public string ToString(bool Detail)
  572.       {
  573.         if (Detail)
  574.         {
  575.           var sb = new System.Text.StringBuilder(9);
  576.           sb.AppendFormat(" Index:        {0}\n", Index);
  577.           sb.AppendFormat(" MonitorIndex: {0}\n", MonitorIndex);
  578.           sb.AppendFormat(" SDLIndex:     {0}\n", SDLIndex);
  579.           sb.AppendFormat(" Id:           {0}\n", Id);
  580.           sb.AppendFormat(" DriverName:   {0}\n", DriverName);
  581.           sb.AppendFormat(" DisplayName:  {0}\n", DisplayName);
  582.           sb.AppendFormat(" AdapterName:  {0}\n", AdapterName);
  583.           sb.AppendFormat(" Resolution:   {0} x {1}\n", Bounds.right - Bounds.left, Bounds.bottom - Bounds.top);
  584.           sb.AppendFormat(" Bounds:       {0},{1},{2},{3}\n", Bounds.left, Bounds.top, Bounds.right, Bounds.bottom);
  585.           sb.AppendFormat(" IsPrimary:    {0}\n", IsPrimary);
  586.           sb.AppendFormat(" IsCurrent:    {0}\n", IsCurrent);
  587.           return sb.ToString();
  588.         }
  589.         return string.Format(" {0} {1} {2} - {3}{4}{5}", MonitorIndex, SDLIndex, AdapterName, DisplayName,
  590.           IsPrimary ? " [primary]" : "", IsCurrent ? " [current]" : !!)
  591.       }
  592.     }
  593.  
  594.     public class DisplaySettings
  595.     {
  596.       public int  Index       { get; set; }
  597.       public uint Width       { get; set; }
  598.       public uint Height      { get; set; }
  599.       public uint Refresh     { get; set; }
  600.       public uint Orientation { get; set; }
  601.       public uint FixedOutput { get; set; }
  602.  
  603.       public override string ToString()
  604.       {
  605.         return ToString(false);
  606.       }
  607.  
  608.       public string ToString(bool Detail)
  609.       {
  610.         var culture = System.Globalization.CultureInfo.CurrentCulture;
  611.         if (!Detail)
  612.           return string.Format(culture, "   {0,4} x {1,4}", Width, Height);
  613.  
  614.         var degrees = Orientation == DMDO_90  ? " 90\u00b0" : Orientation == DMDO_180 ? " 180\u00b0" :
  615.           Orientation == DMDO_270 ? " 270\u00b0" : !!
  616.         var scaling = FixedOutput == DMDFO_CENTER ? " C" : FixedOutput == DMDFO_STRETCH ? " F" : !!
  617.         return string.Format(culture, "   {0,4} x {1,4} {2,3}Hz {3}{4}", Width, Height, Refresh, degrees, scaling);
  618.       }
  619.  
  620.       public override bool Equals(object d)
  621.       {
  622.         var disp = d as DisplaySettings;
  623.         return (disp.Width == Width && disp.Height == Height && disp.Refresh == Refresh && disp.Orientation == Orientation);
  624.       }
  625.  
  626.       public override int GetHashCode()
  627.       {
  628.         return (string.Format("W{0}H{1}R{2}O{3}", Width, Height, Refresh, Orientation)).GetHashCode();
  629.       }
  630.     }
  631.  
  632.     private static DEVMODE GetDeviceMode(string deviceName = null)
  633.     {
  634.       var mode = new DEVMODE();
  635.       mode.Initialize();
  636.  
  637.       if (EnumDisplaySettings(StringExtensions.ToLPTStr(deviceName), ENUM_CURRENT, ref mode))
  638.         return mode;
  639.       else
  640.         throw new InvalidOperationException(":(");
  641.     }
  642.  
  643.     private static DisplaySettings CreateDisplaySettingsObject(int idx, DEVMODE mode)
  644.     {
  645.       return new DisplaySettings()
  646.       {
  647.         Index       = idx,
  648.         Width       = mode.dmPelsWidth,
  649.         Height      = mode.dmPelsHeight,
  650.         Refresh     = mode.dmDisplayFrequency,
  651.         Orientation = mode.dmDisplayOrientation,
  652.         FixedOutput = mode.dmDisplayFixedOutput
  653.       };
  654.     }
  655.  
  656.     public static List<DisplayDevice> GetAllDisplayDevices()
  657.     {
  658.       var list = new List<DisplayDevice>();
  659.       uint idx = 0;
  660.       uint size = 256;
  661.       var device = new DISPLAY_DEVICE();
  662.       device.Initialize();
  663.  
  664.       /// AveYo: detect current monitor via cursor pointer and save Bounds rect for all
  665.       var currentCursorP = new POINTL();
  666.       GetCursorPos(out currentCursorP);
  667.       var currentMonitor = MonitorFromPoint(currentCursorP, MONITOR_DEFAULTTONEAREST);
  668.       var currentMonInfo = new MONITORINFOEX();
  669.       currentMonInfo.Initialize();
  670.       var currentDevice = GetMonitorInfo(currentMonitor, ref currentMonInfo) ? currentMonInfo.szDevice : !!
  671.  
  672.       var monitors = new List<DisplayInfo>();
  673.       EnumDisplayMonitors( IntPtr.Zero, IntPtr.Zero,
  674.         delegate (IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor,  IntPtr dwData)
  675.         {
  676.           var mi = new MONITORINFOEX();
  677.           mi.Initialize();
  678.           var success = GetMonitorInfo(hMonitor, ref mi);
  679.           if (success)
  680.           {
  681.             var di = new DisplayInfo();
  682.             di.Index      = monitors.Count + 1;
  683.             di.SDLIndex   = monitors.Count + 1;
  684.             di.DeviceName = mi.szDevice;
  685.             di.Width      = mi.rcMonitor.right - mi.rcMonitor.left;
  686.             di.Height     = mi.rcMonitor.bottom - mi.rcMonitor.top;
  687.             di.Bounds     = mi.rcMonitor;
  688.             di.WorkArea   = mi.rcWork;
  689.             di.IsPrimary  = (mi.dwFlags > 0);
  690.             di.IsCurrent  = (mi.szDevice == currentDevice);
  691.             monitors.Add(di);
  692.           }
  693.           return true;
  694.         }, IntPtr.Zero
  695.       );
  696.  
  697.       /// AveYo: calculate equivalent for sdl_displayindex to use as game launch option
  698.       var primary = monitors.FirstOrDefault(d => d.IsPrimary == true);
  699.       primary.SDLIndex = 0;
  700.       if (primary.Index == 1) {
  701.         for (var i = 1; i < monitors.Count; i++) { monitors[i].SDLIndex = i; }
  702.       }
  703.       else if (primary.Index <= monitors.Count - 1) {
  704.         for (var i = primary.Index; i <= monitors.Count - 1; i++) { monitors[i].SDLIndex = i; }
  705.       }
  706.       //foreach (var mon in monitors) Console.WriteLine(mon.ToString());
  707.  
  708.       while (EnumDisplayDevices(null, idx, ref device, size) )
  709.       {
  710.         if (device.StateFlags.HasFlag(EdsFlags.EDS_ATTACHEDTODESKTOP))
  711.         {
  712.           var isPrimary  = device.StateFlags.HasFlag(EdsFlags.EDS_PRIMARYDEVICE);
  713.           var isCurrent  = currentDevice != "" ? (device.DeviceName == currentDevice) : !REG3XP0!>isPrimary;
  714.           var monitor = monitors.FirstOrDefault(d => d.DeviceName == device.DeviceName);
  715.           var deviceName = device.DeviceName; var deviceString = device.DeviceString;
  716.  
  717.           EnumDisplayDevices(device.DeviceName, 0, ref device, 0);
  718.           var dev = new DisplayDevice()
  719.           {
  720.             Index        = list.Count + 1,
  721.             MonitorIndex = monitor.Index > 0 ? monitor.Index : list.Count + 1,
  722.             SDLIndex     = monitor.Index > 0 ? monitor.SDLIndex : list.Count + 1,
  723.             Id           = device.DeviceID,
  724.             DriverName   = deviceName,
  725.             DisplayName  = device.DeviceString,
  726.             AdapterName  = deviceString,
  727.             Bounds       = monitor.Bounds,
  728.             IsPrimary    = isPrimary,
  729.             IsCurrent    = isCurrent
  730.           };
  731.           list.Add(dev);
  732.         }
  733.         idx++;
  734.         device = new DISPLAY_DEVICE();
  735.         device.Initialize();
  736.       }
  737.       return list;
  738.     }
  739.  
  740.     public static List<DisplaySettings> GetAllDisplaySettings(string deviceName = null)
  741.     {
  742.       var list = new List<DisplaySettings>();
  743.       DEVMODE mode = new DEVMODE();
  744.       mode.Initialize();
  745.       int idx = 0;
  746.  
  747.       while (EnumDisplaySettings(StringExtensions.ToLPTStr(deviceName), idx, ref mode))
  748.         list.Add(CreateDisplaySettingsObject(idx++, mode));
  749.       return list;
  750.     }
  751.  
  752.     public static DisplaySettings GetCurrentSettings(string deviceName = null)
  753.     {
  754.       return CreateDisplaySettingsObject(-1, GetDeviceMode(deviceName));
  755.     }
  756.  
  757.     public static DisplaySettings GetCurrentDisplaySetting(string deviceName = null)
  758.     {
  759.       var mode = GetDeviceMode(deviceName);
  760.       return CreateDisplaySettingsObject(0, mode);
  761.     }
  762.  
  763.     public static int[] List(int Output = 1, int Screen = -1, int MinWidth = 1024, int MaxWidth = 16384, int MaxHeight = 16384)
  764.     {
  765.       var devices = GetAllDisplayDevices();
  766.       var monitor = devices.FirstOrDefault(d => d.IsCurrent);
  767.       if (Screen > 0 && Screen <= devices.Count) monitor = devices.FirstOrDefault(d => d.MonitorIndex == Screen);
  768.  
  769.       if (Output != 0) foreach (var display in devices) Console.WriteLine(display.ToString());
  770.  
  771.       var displayModes = GetAllDisplaySettings(monitor.DriverName);
  772.       var current      = GetCurrentDisplaySetting(monitor.DriverName);
  773.       IList<DisplaySettings> filtered = displayModes;
  774.  
  775.       /// AveYo: MaxWidth & MaxHeight are used to aggregate the list further by Refresh rate
  776.       if (Output == 1)
  777.       {
  778.         filtered = displayModes
  779.           .Where(d => d.Width >= MinWidth && d.Width <= MaxWidth && d.Height <= MaxHeight && d.Orientation == current.Orientation)
  780.           .OrderByDescending(d => d.Width).ThenByDescending(d => d.Refresh)
  781.           .GroupBy(d => new {d.Width, d.Height}).Select(g => g.First()).ToList();
  782.       }
  783.       else if (Output == 2 || Output == 0 && MaxWidth != 16384)
  784.       {
  785.         filtered = displayModes
  786.           .Where(d => d.Width >= MinWidth && d.Width <= MaxWidth && d.Height <= MaxHeight)
  787.           .OrderByDescending(d => d.Width).ThenByDescending(d => d.Refresh).ToList();
  788.       }
  789.  
  790.       if (filtered.Count == 0)
  791.         filtered.Add(current);
  792.  
  793.       var max = filtered.Aggregate((top, atm) => {
  794.           return atm.Width > top.Width || atm.Height > top.Height ? atm :
  795.             atm.Width == top.Width && atm.Height == top.Height && atm.Refresh > top.Refresh ? atm : !!
  796.       });
  797.  
  798.       foreach (var set in filtered)
  799.       {
  800.         if (set.Equals(current))
  801.         {
  802.           if (Output != 0) Console.WriteLine(set.ToString(true) + " [current]");
  803.         }
  804.         else
  805.         {
  806.           if (Output != 0) Console.WriteLine(set.ToString(true));
  807.         }
  808.       }
  809.       if (Output != 0) Console.WriteLine();
  810.       return new int[] { monitor.SDLIndex, monitor.MonitorIndex,
  811.         (int)current.Width, (int)current.Height, (int)current.Refresh, (int)max.Width, (int)max.Height, (int)max.Refresh };
  812.     }
  813.  
  814.     public static int[] Change(int Output = 1, int Screen = -1, int Width = 0, int Height = 0, decimal Refresh = 0, int Test = 0)
  815.     {
  816.       var devices = GetAllDisplayDevices();
  817.       var monitor = devices.FirstOrDefault(d => d.IsCurrent);
  818.       if (Screen > 0 && Screen <= devices.Count) monitor = devices.FirstOrDefault(d => d.MonitorIndex == Screen);
  819.  
  820.       var deviceName = monitor.DriverName;
  821.       var current    = GetCurrentDisplaySetting(deviceName);
  822.       //var position = new POINTL(); position.x = monitor.Bounds.left; position.y = monitor.Bounds.top;
  823.  
  824.       if (Width == 0 || Height == 0)
  825.       {
  826.         if (Output != 0) Console.WriteLine(" Width and Height parameters required.\n");
  827.         return new int[] { monitor.SDLIndex, monitor.MonitorIndex,
  828.           (int)current.Width, (int)current.Height, (int)current.Refresh, 0, 0, 0, 1 };
  829.       }
  830.  
  831.       /// AveYo: Refresh fallback from fractional ex: 59.976 - to nearest integer ex: 60 - to highest supported
  832.       uint Orientation = 0, FixedOutput = 0, Temporary = 0; /// for testing
  833.       var displayModes = GetAllDisplaySettings(deviceName);
  834.       var filtered = displayModes
  835.         .Where(d => d.Width == Width && d.Height == Height && d.Orientation == current.Orientation)
  836.         .OrderByDescending(d => d.Width).ThenByDescending(d => d.Refresh).ToList();
  837.  
  838.       var ref1 = filtered.FirstOrDefault(d => d.Refresh == (uint)Decimal.Truncate(Refresh));
  839.       var ref2 = filtered.FirstOrDefault(d => d.Refresh == (uint)Decimal.Truncate(Refresh + 1));
  840.       var set = Refresh == 0 ? filtered.FirstOrDefault() : ref1 != null ? ref1 : class="re0">ref2 != null ? ref2 : !REG3XP0!>filtered.FirstOrDefault();
  841.       if (set == null)
  842.       {
  843.         /// AveYo: Resolution fallback to current
  844.         if (Output != 0) Console.WriteLine(" No matching display mode!\n");
  845.         set = current;
  846.         return new int[] { monitor.SDLIndex, monitor.MonitorIndex,
  847.           (int)set.Width, (int)set.Height, (int)set.Refresh, (int)set.Width, (int)set.Height, (int)set.Refresh, 2 };
  848.       }
  849.  
  850.       try
  851.       {
  852.         DEVMODE mode = GetDeviceMode(deviceName);
  853.         //mode.dmPosition           = position;
  854.         mode.dmPelsWidth          = set.Width;
  855.         mode.dmPelsHeight         = set.Height;
  856.         mode.dmDisplayFrequency   = set.Refresh;
  857.         mode.dmDisplayOrientation = Orientation > 0 ? Orientation : set.Orientation;
  858.         mode.dmDisplayFixedOutput = FixedOutput > 0 ? FixedOutput : set.FixedOutput;
  859.         mode.dmFields             = DmFlags.DM_PELSWIDTH | DmFlags.DM_PELSHEIGHT; //DmFlags.DM_POSITION
  860.         if (Refresh > 0)     mode.dmFields |= DmFlags.DM_DISPLAYFREQUENCY;
  861.         if (FixedOutput > 0) mode.dmFields |= DmFlags.DM_DISPLAYORIENTATION;
  862.         if (Temporary > 0)   mode.dmFields |= DmFlags.DM_DISPLAYFIXEDOUTPUT;
  863.  
  864.         /// AveYo: test and apply the target res even if it's the same as the current one
  865.         CdsFlags flags = CdsFlags.CDS_TEST | CdsFlags.CDS_RESET | CdsFlags.CDS_UPDATEREGISTRY; //CdsFlags.CDS_NORESET
  866.         if (Temporary > 0) flags |= CdsFlags.CDS_FULLSCREEN;
  867.  
  868.         int result = ChangeDisplaySettingsEx(deviceName, ref mode, IntPtr.Zero, flags, IntPtr.Zero);
  869.         if (Test != 0)
  870.           return new int[] { monitor.SDLIndex, monitor.MonitorIndex,
  871.             (int)current.Width, (int)current.Height, (int)current.Refresh, (int)set.Width, (int)set.Height, (int)set.Refresh, 0 };
  872.         if (result != SUCCESS)
  873.           throw new InvalidOperationException(string.Format("{0} : {1} = N/A", set.ToString(true), monitor.DisplayName));
  874.         flags &= ~CdsFlags.CDS_TEST;
  875.         result = ChangeDisplaySettingsEx(deviceName, ref mode, IntPtr.Zero, flags, IntPtr.Zero);
  876.         if (result != SUCCESS)
  877.           throw new InvalidOperationException(string.Format("{0} : {1} = FAIL", set.ToString(true), monitor.DisplayName));
  878.  
  879.         //ChangeDisplaySettingsEx(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero);
  880.         if (Output != 0) Console.WriteLine(string.Format("{0} : class="re0">{1} = OK", set.ToString(true), monitor.DisplayName));
  881.         return new int[] { monitor.SDLIndex, monitor.MonitorIndex,
  882.           (int)current.Width, (int)current.Height, (int)current.Refresh, (int)set.Width, (int)set.Height, (int)set.Refresh, 0 };
  883.       }
  884.       catch(Exception ex)
  885.       {
  886.         if (Output != 0) Console.WriteLine(ex.Message);
  887.         return new int[] { monitor.SDLIndex, monitor.MonitorIndex,
  888.           (int)current.Width, (int)current.Height, (int)current.Refresh, 0, 0, 0, 3 };
  889.       }
  890.     }
  891.  
  892.     public static int[] Init(int Screen = -1)
  893.     {
  894.       SetProcessDPIAware(); /// AveYo: calculate using real screen values, not windows dpi scaling ones
  895.       var devices = GetAllDisplayDevices();
  896.       var monitor = devices.FirstOrDefault(d => d.IsCurrent);
  897.       if (Screen > 0 && Screen <= devices.Count) monitor = devices.FirstOrDefault(d => d.MonitorIndex == Screen);
  898.       RECT cR = new RECT(), mR = monitor.Bounds;
  899.       GetWindowRect(consolehWnd, out cR);
  900.       /// AveYo: move console window to Screen index or currently active
  901.       MoveWindow(consolehWnd, mR.left + 100, mR.top + 100, cR.right - cR.left, cR.bottom - cR.top, true);
  902.       return new int[] { monitor.SDLIndex, monitor.MonitorIndex, monitor.IsPrimary ? 1 : 0, devices.Count };
  903.     }
  904.   }
  905. }
  906. <#:LIBRARY1: end -------------------------------------------------------------------------------------------------------------- #>
  907. } @args; return; ${ press Enter if copy-pasted in powershell }
  908.  
Advertisement
Comments
  • ariashark
    145 days
    # text 0.07 KB | 0 0
    1. turning off FSO and then setting cs to windowed? thats crazy bad input lag
    • aveyo
      58 days
      # text 0.21 KB | 0 0
      1. not at all! cs2 is set to desktop-friendly fullscreen (independent flip mode) and since desktop res is made to match in-game you get the best experience - check it with something like nvidia FrameView (works on any gpu)
Add Comment
Please, Sign In to add comment
Advertisement