diff --git a/src/PSLauncher.Core/Health/OpenVR/OpenVrService.cs b/src/PSLauncher.Core/Health/OpenVR/OpenVrService.cs
index 2872132..0eea724 100644
--- a/src/PSLauncher.Core/Health/OpenVR/OpenVrService.cs
+++ b/src/PSLauncher.Core/Health/OpenVR/OpenVrService.cs
@@ -27,6 +27,7 @@ public sealed class OpenVrService : IOpenVrService, IDisposable
private bool _resolverEnsured;
private bool _initAttempted;
+ private VrRuntimeState _lastLoggedState = (VrRuntimeState)(-99); // sentinelle « jamais loggé »
private uint _initToken;
private IntPtr _vrSystemVTable = IntPtr.Zero;
@@ -50,6 +51,7 @@ public sealed class OpenVrService : IOpenVrService, IDisposable
lock (_lock)
{
var state = EnsureReady();
+ LogStateTransition(state);
var label = ResolveLabel(deviceAlias);
if (state != VrRuntimeState.Ready)
{
@@ -317,6 +319,28 @@ public sealed class OpenVrService : IOpenVrService, IDisposable
catch { return null; }
}
+ ///
+ /// Log au niveau INFO la première occurrence d'un état + chaque transition.
+ /// Évite de spammer (un check s'exécute toutes les 5 s, on aurait 700 messages
+ /// par heure si on loggait à chaque tick) tout en laissant une trace claire
+ /// dans le journal au cas où ça re-crasherait — la dernière ligne avant le
+ /// silence de Serilog dirait par exemple « OpenVR state: HmdAbsent ».
+ ///
+ private void LogStateTransition(VrRuntimeState newState)
+ {
+ if (newState == _lastLoggedState) return;
+ _lastLoggedState = newState;
+ var detail = newState switch
+ {
+ VrRuntimeState.RuntimeMissing => "openvr_api.dll introuvable (SteamVR pas installé)",
+ VrRuntimeState.HmdAbsent => "vrserver.exe pas lancé ou aucun HMD branché",
+ VrRuntimeState.InitFailed => "VR_InitInternal2 a échoué",
+ VrRuntimeState.Ready => "OK, vtable IVRSystem_022 bindée",
+ _ => "?",
+ };
+ _logger.LogInformation("OpenVR state: {State} ({Detail})", newState, detail);
+ }
+
///
/// vrserver.exe est le process central de SteamVR ; sa présence garantit qu'on
/// peut init OpenVR sans déclencher de chargement de drivers risqué. Cache de