Fixed issues with encodings and wine / proton compatibilities.
This commit is contained in:
@@ -34,6 +34,9 @@ WINETRICKS_CODEPAGE_PROBE = (
|
||||
WINETRICKS_PROTON7_PROBE = 'winetricks_early_wine_arch cmd.exe /c "echo %$1%"'
|
||||
RUNTIME_DEFAULT_SYNC = "runtime-default"
|
||||
CACHYOS_MARKER = "cachyos"
|
||||
CURRENT_UMU_DISTRIBUTIONS = frozenset(
|
||||
{"arch", "cachyos", "endeavouros", "garuda", "manjaro"}
|
||||
)
|
||||
GAME_RUNTIME_CONFIGURATION_VERSION = 1
|
||||
|
||||
|
||||
@@ -52,10 +55,30 @@ class RuntimeSelection:
|
||||
def select_runtime(
|
||||
settings: Settings,
|
||||
environment: Mapping[str, str] | None = None,
|
||||
*,
|
||||
distribution_id: str | None = None,
|
||||
kernel_release: str | None = None,
|
||||
) -> RuntimeSelection:
|
||||
env = os.environ if environment is None else environment
|
||||
umu = shutil.which("umu-run", path=env.get("PATH"))
|
||||
if settings.proton_path:
|
||||
current_umu_host = prefers_current_umu_host(
|
||||
distribution_id=distribution_id,
|
||||
kernel_release=kernel_release,
|
||||
)
|
||||
auto_container = (
|
||||
settings.runtime == "auto"
|
||||
and bool(umu)
|
||||
and not current_umu_host
|
||||
)
|
||||
if settings.runtime == "umu":
|
||||
if umu:
|
||||
return RuntimeSelection("umu", umu, None, None)
|
||||
raise RuntimeErrorPT("UMU was requested but umu-run was not found")
|
||||
if settings.proton_path and settings.runtime in {
|
||||
"auto",
|
||||
"proton7",
|
||||
"proton7-container",
|
||||
}:
|
||||
proton = Path(settings.proton_path).expanduser().resolve()
|
||||
if not proton.is_file():
|
||||
raise RuntimeErrorPT(f"configured Proton script does not exist: {proton}")
|
||||
@@ -71,7 +94,8 @@ def select_runtime(
|
||||
str(proton),
|
||||
str(steam_root),
|
||||
)
|
||||
if settings.runtime == "auto" and umu:
|
||||
if auto_container:
|
||||
assert umu is not None
|
||||
return RuntimeSelection(
|
||||
"proton7-container",
|
||||
umu,
|
||||
@@ -79,13 +103,17 @@ def select_runtime(
|
||||
str(steam_root),
|
||||
)
|
||||
return RuntimeSelection("proton7", sys.executable, str(proton), str(steam_root))
|
||||
# Current UMU avoids several rolling-distribution container/media failures and
|
||||
# remains the broad Arch-family compatibility default. Direct Proton 7 is also
|
||||
# known to authenticate on CachyOS, so this is a compatibility policy rather
|
||||
# than an assertion that Proton 7 itself causes server-side Code 1/Code 3.
|
||||
if settings.runtime == "auto" and current_umu_host and umu:
|
||||
return RuntimeSelection("umu", umu, None, None)
|
||||
if settings.runtime in {"auto", "proton7", "proton7-container"}:
|
||||
proton_result = find_steam_proton7(env)
|
||||
if proton_result is not None:
|
||||
proton, steam_root = proton_result
|
||||
if settings.runtime == "proton7-container" or (
|
||||
settings.runtime == "auto" and umu
|
||||
):
|
||||
if settings.runtime == "proton7-container" or auto_container:
|
||||
if not umu:
|
||||
raise RuntimeErrorPT(
|
||||
"containerized Proton 7 was requested but umu-run was not found"
|
||||
@@ -377,6 +405,49 @@ def run_proton_prefix_command(
|
||||
)
|
||||
|
||||
|
||||
def run_runtime_prefix_command(
|
||||
paths: AppPaths,
|
||||
selection: RuntimeSelection,
|
||||
runner: CommandRunner,
|
||||
arguments: Sequence[str],
|
||||
*,
|
||||
check: bool = True,
|
||||
timeout_seconds: float = 60.0,
|
||||
) -> CommandOutcome:
|
||||
"""Run a credential-free helper inside the selected game's Wine prefix."""
|
||||
|
||||
if not arguments:
|
||||
raise ValueError("runtime-prefix command arguments cannot be empty")
|
||||
if selection.kind == "umu":
|
||||
command = [selection.executable, *arguments]
|
||||
environment = _umu_environment(paths)
|
||||
elif selection.kind == "proton7-container":
|
||||
if not selection.proton_path or not selection.steam_root:
|
||||
raise RuntimeErrorPT("incomplete Proton 7 runtime selection")
|
||||
command = [selection.executable, *arguments]
|
||||
environment = _umu_proton7_environment(paths, selection)
|
||||
elif selection.kind == "proton7":
|
||||
if not selection.proton_path or not selection.steam_root:
|
||||
raise RuntimeErrorPT("incomplete Proton 7 runtime selection")
|
||||
command = [
|
||||
sys.executable,
|
||||
"-m",
|
||||
"ptlinux.proton_compat",
|
||||
selection.proton_path,
|
||||
"runinprefix",
|
||||
*arguments,
|
||||
]
|
||||
environment = _proton_environment(paths, selection)
|
||||
else:
|
||||
raise RuntimeErrorPT(f"unsupported runtime kind: {selection.kind}")
|
||||
return runner.run(
|
||||
command,
|
||||
env_overrides=environment,
|
||||
timeout_seconds=timeout_seconds,
|
||||
check=check,
|
||||
)
|
||||
|
||||
|
||||
def _runtime_python_path(existing: str | None) -> str:
|
||||
"""Make the installed package importable after changing into runtime_view."""
|
||||
package_root = str(Path(__file__).resolve().parent.parent)
|
||||
@@ -455,6 +526,38 @@ def detect_distribution_id() -> str:
|
||||
return value.strip().casefold()
|
||||
|
||||
|
||||
def is_cachyos_host(
|
||||
*,
|
||||
distribution_id: str | None = None,
|
||||
kernel_release: str | None = None,
|
||||
) -> bool:
|
||||
"""Identify CachyOS narrowly for runtime compatibility policy."""
|
||||
|
||||
distribution = detect_distribution_id() if distribution_id is None else distribution_id
|
||||
kernel = platform.release() if kernel_release is None else kernel_release
|
||||
return (
|
||||
CACHYOS_MARKER in distribution.casefold()
|
||||
or CACHYOS_MARKER in kernel.casefold()
|
||||
)
|
||||
|
||||
|
||||
def prefers_current_umu_host(
|
||||
*,
|
||||
distribution_id: str | None = None,
|
||||
kernel_release: str | None = None,
|
||||
) -> bool:
|
||||
"""Use current UMU automatically on rolling Arch-family hosts."""
|
||||
|
||||
distribution = detect_distribution_id() if distribution_id is None else distribution_id
|
||||
return (
|
||||
distribution.strip().casefold() in CURRENT_UMU_DISTRIBUTIONS
|
||||
or is_cachyos_host(
|
||||
distribution_id=distribution,
|
||||
kernel_release=kernel_release,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def resolve_proton_sync_mode(
|
||||
configured: str,
|
||||
*,
|
||||
@@ -467,9 +570,10 @@ def resolve_proton_sync_mode(
|
||||
raise ValueError(f"unsupported Proton synchronization mode: {configured}")
|
||||
if configured != "auto":
|
||||
return configured
|
||||
distribution = detect_distribution_id() if distribution_id is None else distribution_id
|
||||
kernel = platform.release() if kernel_release is None else kernel_release
|
||||
if CACHYOS_MARKER in distribution.casefold() or CACHYOS_MARKER in kernel.casefold():
|
||||
if is_cachyos_host(
|
||||
distribution_id=distribution_id,
|
||||
kernel_release=kernel_release,
|
||||
):
|
||||
return "esync"
|
||||
return RUNTIME_DEFAULT_SYNC
|
||||
|
||||
@@ -552,21 +656,23 @@ def prepare_proton7_winetricks(
|
||||
dry_run: bool = False,
|
||||
) -> Path:
|
||||
try:
|
||||
content = source.read_text(encoding="utf-8")
|
||||
content = source.read_bytes()
|
||||
except OSError as exc:
|
||||
raise RuntimeErrorPT(f"could not read Winetricks script {source}: {exc}") from exc
|
||||
if WINETRICKS_CODEPAGE_PROBE not in content:
|
||||
probe = WINETRICKS_CODEPAGE_PROBE.encode("utf-8")
|
||||
replacement = WINETRICKS_PROTON7_PROBE.encode("utf-8")
|
||||
if probe not in content:
|
||||
return source
|
||||
if dry_run:
|
||||
return destination
|
||||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||||
patched = content.replace(
|
||||
WINETRICKS_CODEPAGE_PROBE,
|
||||
WINETRICKS_PROTON7_PROBE,
|
||||
probe,
|
||||
replacement,
|
||||
1,
|
||||
)
|
||||
temporary = destination.with_name(f".{destination.name}.{os.getpid()}.tmp")
|
||||
temporary.write_text(patched, encoding="utf-8")
|
||||
temporary.write_bytes(patched)
|
||||
temporary.chmod(source.stat().st_mode & 0o777)
|
||||
temporary.replace(destination)
|
||||
return destination
|
||||
|
||||
Reference in New Issue
Block a user