diff --git a/configs/releng/airootfs/usr/local/share/fws/gameboot-windows/fws-play.ps1 b/configs/releng/airootfs/usr/local/share/fws/gameboot-windows/fws-play.ps1 index b56e12c..38024f9 100644 --- a/configs/releng/airootfs/usr/local/share/fws/gameboot-windows/fws-play.ps1 +++ b/configs/releng/airootfs/usr/local/share/fws/gameboot-windows/fws-play.ps1 @@ -1,57 +1,136 @@ <# - fws-play.ps1 — session de jeu Windows orchestree pour le retour vers FWS. + fws-play.ps1 — session de jeu Windows orchestree, lancement AUTO du jeu choisi. - Flux robuste : - - on desactive la tache ONSTART (evite qu'un declenchement tardif ne rearme - FWS EN PLEIN MATCH) ; - - on arme le boot suivant vers WINDOWS (un crash/reboot pendant le jeu revient - sur Windows, pas ejecte vers FWS au milieu d'un match) ; - - on lance Valorant et on attend sa fermeture OU son crash ; - - dans un FINALLY (donc quoi qu'il arrive) : on rearme le boot suivant vers - FWS, on reactive la tache ONSTART, et on reboote — SEULEMENT si le jeu a - bien ete vu (pas de reboot force en plein 1er telechargement de patch). + Lit (et CONSOMME) le jeton depose par FWS sur l'ESP + (\EFI\FWS\launch.json = {"game":""}), cherche dans games.json, lance + le jeu, attend sa fermeture/crash, puis rebascule vers FWS. - Le filet permanent BootOrder[0]=FWS couvre tout ce que ce script raterait. - A lancer a l'ouverture de session du compte gaming (autologin) ou a la main. - Doit tourner EN ADMIN. #> + Robustesse (aucune interaction requise) : + - resolution du jeton sur TOUTES les ESP (dual-disque) + suppression apres + lecture (consume-once : pas de rejeu d'un ancien choix) ; + - resolution du Riot Client par sa source canonique (pas de chemin en dur) ; + - re-affirmation de BootNext=Windows apres le lancement, pour gagner la course + contre la tache ONSTART (fws-play = dernier ecrivain) — un crash pendant le + jeu revient donc bien sur Windows ; + - FINALLY : rearme FWS et reboote SI le jeu a bien ete vu. + + Filet permanent cote FWS : BootOrder[0]=FWS. A lancer a l'ouverture de session + (autologin du compte gaming, qui DOIT etre admin local). Tourne EN ADMIN. #> $ErrorActionPreference = 'Stop' $here = Split-Path -Parent $MyInvocation.MyCommand.Path $return = Join-Path $here 'fws-return.ps1' -$taskName = 'FWS-Return-OnStart' +$gamesDb = Join-Path $here 'games.json' $seen = $false -try { - # Neutraliser la course avec la tache ONSTART pendant la session. - try { Disable-ScheduledTask -TaskName $taskName -ErrorAction Stop | Out-Null } catch { } +$EFI_TYPE = '{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}' # GUID GPT "EFI System Partition" +function Get-RequestedGame { + # Sonde toutes les ESP, lit \EFI\FWS\launch.json, le SUPPRIME (consume-once). + # Defaut : valorant. Distingue "jeton absent" de "jeton illisible" (log). + $default = 'valorant'; $result = $default + $mounts = @() + try { $esps = Get-Partition -ErrorAction SilentlyContinue | Where-Object { $_.GptType -eq $EFI_TYPE } } + catch { $esps = @() } + + foreach ($p in $esps) { + $used = (Get-PSDrive -PSProvider FileSystem -ErrorAction SilentlyContinue).Name + $letter = (67..90 | ForEach-Object { [char]$_ }) | + Where-Object { $used -notcontains "$_" -and ($mounts.Letter -notcontains "$_`:") } | + Select-Object -First 1 + if (-not $letter) { continue } + try { + Add-PartitionAccessPath -DiskNumber $p.DiskNumber -PartitionNumber $p.PartitionNumber -AccessPath "$letter`:" -ErrorAction Stop + $mounts += @{ Letter = "$letter`:"; Disk = $p.DiskNumber; Part = $p.PartitionNumber } + } catch { } + } + + foreach ($m in $mounts) { + $tok = "$($m.Letter)\EFI\FWS\launch.json" + if (Test-Path $tok) { + try { + $g = (Get-Content $tok -Raw -ErrorAction Stop | ConvertFrom-Json).game + if ($g) { $result = "$g".ToLower() } + } catch { Write-Warning "Jeton illisible ($tok) : $_ — repli sur $default." } + Remove-Item $tok -Force -ErrorAction SilentlyContinue # consume-once + break + } + } + + foreach ($m in $mounts) { + try { Remove-PartitionAccessPath -DiskNumber $m.Disk -PartitionNumber $m.Part -AccessPath $m.Letter -ErrorAction SilentlyContinue } catch { } + } + return $result +} + +function Resolve-RiotClient { + # Riot s'installe par defaut a la RACINE (C:\Riot Games\...), pas sous + # Program Files. Source canonique : RiotClientInstalls.json (rc_default). + $cands = @() + $inst = Join-Path $Env:ProgramData 'Riot Games\RiotClientInstalls.json' + if (Test-Path $inst) { try { $cands += (Get-Content $inst -Raw | ConvertFrom-Json).rc_default } catch { } } + $cands += 'C:\Riot Games\Riot Client\RiotClientServices.exe' + $cands += (Join-Path ${Env:ProgramFiles} 'Riot Games\Riot Client\RiotClientServices.exe') + if (${Env:ProgramFiles(x86)}) { $cands += (Join-Path ${Env:ProgramFiles(x86)} 'Riot Games\Riot Client\RiotClientServices.exe') } + return $cands | Where-Object { $_ -and (Test-Path $_) } | Select-Object -First 1 +} + +function Start-Game($entry) { + switch ($entry.type) { + 'riot' { + $riot = Resolve-RiotClient + if ($riot) { Start-Process $riot -ArgumentList "--launch-product=$($entry.product)","--launch-patchline=$($entry.patchline)" } + else { Write-Warning "Riot Client introuvable (ni RiotClientInstalls.json, ni chemins connus)." } + } + 'uri' { Start-Process $entry.uri } + 'exe' { + if ($entry.args) { Start-Process -FilePath $entry.path -ArgumentList @($entry.args) } + else { Start-Process -FilePath $entry.path } + } + default { Write-Warning "Type de lancement inconnu : $($entry.type)" } + } +} + +try { # Pendant la session, un crash/reboot doit rester sur WINDOWS. try { & $return -Target Windows } catch { Write-Warning "Arm Windows a echoue : $_" } - # Lancer Valorant via le Riot Client (adapter le chemin si necessaire). - $riot = Join-Path $Env:ProgramFiles 'Riot Games\Riot Client\RiotClientServices.exe' - if (Test-Path $riot) { - Start-Process $riot -ArgumentList '--launch-product=valorant','--launch-patchline=live' - } else { - Write-Warning "Riot Client introuvable : $riot — lance Valorant manuellement." + # Resoudre + VALIDER le jeu (rejeter les cles '_*' et les entrees sans .type). + $game = Get-RequestedGame + $games = Get-Content $gamesDb -Raw | ConvertFrom-Json + $entry = $games.$game + if ($game -like '_*' -or -not $entry -or -not $entry.type) { + Write-Warning "Jeu '$game' invalide/absent de games.json — repli sur valorant." + $game = 'valorant'; $entry = $games.valorant } + if (-not $entry) { throw "Entree 'valorant' absente de games.json." } + Write-Host "Lancement du jeu : $game" + Start-Game $entry - # Attendre l'apparition du process (SANS plafond serre : un 1er patch Riot / - # une MAJ Vanguard peuvent etre longs), puis attendre sa fermeture/crash. - $proc = 'VALORANT-Win64-Shipping' - for ($i = 0; $i -lt 1440; $i++) { # ~2 h max d'attente d'apparition - if (Get-Process $proc -ErrorAction SilentlyContinue) { $seen = $true; break } - Start-Sleep -Seconds 5 - } - if ($seen) { - Get-Process $proc -ErrorAction SilentlyContinue | ForEach-Object { $_.WaitForExit() } + # Course avec la tache ONSTART (qui arme FWS au boot) : on la laisse passer + # puis on RE-AFFIRME Windows → fws-play est le dernier ecrivain de BootNext. + Start-Sleep -Seconds 25 + try { & $return -Target Windows } catch { Write-Warning "Re-arm Windows a echoue : $_" } + + # Attendre l'apparition PUIS la disparition du process (boucle de presence, + # robuste aux relances client). Ne rebooter que si le jeu a ete VU. + $proc = $entry.process + if ($proc) { + for ($i = 0; $i -lt 1440; $i++) { # ~2 h max d'attente d'apparition + if (Get-Process $proc -ErrorAction SilentlyContinue) { $seen = $true; break } + Start-Sleep -Seconds 5 + } + if ($seen) { + while (Get-Process $proc -ErrorAction SilentlyContinue) { Start-Sleep -Seconds 5 } + } else { + Write-Warning "Process '$proc' jamais detecte — pas de reboot automatique." + } } else { - Write-Warning "Jeu jamais detecte — pas de reboot automatique." + Write-Warning "Aucun 'process' defini pour '$game' — pas d'attente ni de reboot auto." } } finally { - # Rearmer FWS et reactiver la tache, QUOI QU'IL ARRIVE. + # Rearmer FWS, QUOI QU'IL ARRIVE. try { & $return -Target FWS } catch { Write-Warning "Arm FWS a echoue : $_ — BootOrder[0]=FWS reste le filet." } - try { Enable-ScheduledTask -TaskName $taskName -ErrorAction Stop | Out-Null } catch { } if ($seen) { Start-Sleep -Seconds 2 Restart-Computer -Force