From 966e92b304c6150b1462125bbf66330f56a4b901 Mon Sep 17 00:00:00 2001 From: funman300 Date: Thu, 20 Aug 2026 19:57:16 +0000 Subject: [PATCH] fix(launcher): run LSX locally on Windows (only autopatch is in-process) The prior Windows branch treated BOTH companions as in-process and started neither. That is wrong for LSX: FIFA dials the Origin/LSX emulator on 127.0.0.1:4216 and it must run locally on the client (the STEAMPUNKS stp-origin_emu.dll is the crack's activation emu, not OpenFUT's LSX). Only autopatch is genuinely in-process on Windows (its ProtoSSL cert patch is done by the version.dll hook), so skip just that one and spawn LSX through the normal path. Also resolve the companion as openfut-lsx.exe on Windows. --- src/local_services.rs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/local_services.rs b/src/local_services.rs index 4094628..89e5887 100644 --- a/src/local_services.rs +++ b/src/local_services.rs @@ -80,12 +80,18 @@ impl Service { /// keeps `spawn` responsible for reporting a missing binary, with one error message /// instead of two. fn resolve_binary(service: Service) -> PathBuf { - let name = service.binary(); + let base = service.binary(); + // On Windows the built companion is `openfut-lsx.exe`; a bare name without the + // extension matches neither the sibling file nor CreateProcess resolution. + #[cfg(windows)] + let name = format!("{base}.exe"); + #[cfg(unix)] + let name = base.to_string(); if let Some(dir) = std::env::current_exe() .ok() .and_then(|p| p.parent().map(Path::to_path_buf)) { - let sibling = dir.join(name); + let sibling = dir.join(&name); if sibling.is_file() { return sibling; } @@ -434,21 +440,18 @@ impl ServiceSupervisor { /// Start `service` only if it is not already usable. Never restarts a healthy /// service, and never adopts a foreign one as ours. pub fn ensure_running(&mut self, service: Service, spec: SpawnSpec) -> Result { - // On native Windows the "companion services" are NOT separate processes: - // LSX/Origin login and the ProtoSSL cert path are provided in-process by - // stp-origin_emu.dll and the version.dll hook once the game runs. There is - // nothing for the launcher to spawn or supervise, so report ready. + // On Windows the ProtoSSL cert-verify patch (autopatch's job on unix, via + // /proc/PID/mem) is performed in-process by the version.dll hook, so there + // is no autopatch process to run. LSX is different: the game dials it on + // 127.0.0.1:4216, so it MUST run locally here exactly as on unix. #[cfg(windows)] - { - let _ = spec; - self.log.lock().push(format!( - "[launcher] {} is in-process on Windows (stp/hook) — nothing to start.", - service.label() - )); + if service == Service::Autopatch { + self.log.lock().push( + "[launcher] autopatch runs in-process on Windows (version.dll hook) — nothing to start." + .to_string(), + ); return Ok(Ensured::Reused); } - #[cfg(unix)] - { let runtime = self.observe(service); if runtime.ready() { self.log.lock().push(format!( @@ -476,7 +479,6 @@ impl ServiceSupervisor { .map_err(|e| e.to_string())?; *self.slot(service) = ManagedService::from_child(child); Ok(Ensured::Started) - } } /// Stop a service the launcher owns. A foreign process is reported, never