Pushed updates for release v1.1.0

This commit is contained in:
2026-10-20 23:42:30 +02:00
parent be7891f066
commit d75c345d36
26 changed files with 606 additions and 217 deletions

View File

@@ -7,6 +7,7 @@ import json
import math
import os
from pathlib import Path
import re
import secrets
import threading
from typing import Any
@@ -45,6 +46,7 @@ class Settings:
runtime: str = "auto"
proton_sync: str = "auto"
proton_path: str | None = None
renderer: str = "auto"
game_source: str | None = None
download_speed_limit_mbps: float | None = None
low_bandwidth_mode: bool = False
@@ -78,6 +80,7 @@ def save_settings(paths: AppPaths, settings: Settings) -> Settings:
"""
_validate(settings)
validate_proton_path_setting(settings.proton_path)
paths.config.mkdir(parents=True, exist_ok=True)
with launcher_operation_lock(paths.settings_lock, "settings-save"):
existing = _read_settings_object(paths.settings_file)
@@ -102,6 +105,7 @@ def update_settings(paths: AppPaths, **changes: Any) -> Settings:
)
updated = replace(current, **changes)
_validate(updated)
validate_proton_path_setting(updated.proton_path)
_write_settings(paths, updated, existing)
return updated
@@ -155,6 +159,15 @@ def _read_settings_object(path: Path) -> dict[str, object] | None:
def _settings_from_object(value: dict[str, object]) -> Settings:
proton_path = _optional_string(value, "proton_path")
renderer = _string(value, "renderer", "auto")
# Older settings exposed only a path field. Recover the exact renderer
# assignment seen in telemetry without interpreting arbitrary shell input.
legacy_renderer = _legacy_renderer_assignment(proton_path)
if legacy_renderer is not None:
proton_path = None
if renderer == "auto":
renderer = legacy_renderer
settings = Settings(
realm=_string(value, "realm", "Babel").strip(),
ui_scale=_string(value, "ui_scale", "auto"),
@@ -177,7 +190,8 @@ def _settings_from_object(value: dict[str, object]) -> Settings:
),
runtime=_string(value, "runtime", "auto"),
proton_sync=_string(value, "proton_sync", "auto"),
proton_path=_optional_string(value, "proton_path"),
proton_path=proton_path,
renderer=renderer,
game_source=_optional_string(value, "game_source"),
download_speed_limit_mbps=_optional_positive_number(
value,
@@ -224,9 +238,36 @@ def _settings_need_migration(value: dict[str, object]) -> bool:
or not _SETTINGS_FIELD_NAMES.issubset(value)
or value.get(_TITLE_FRAME_DEFAULT_MIGRATION_KEY) is not True
or bool(_RETIRED_SETTINGS.intersection(value))
or _legacy_renderer_assignment(value.get("proton_path")) is not None
)
def _legacy_renderer_assignment(value: object) -> str | None:
if not isinstance(value, str):
return None
return {
"PROTON_USE_WINED3D=1": "wined3d",
"PROTON_USE_WINED3D=0": "dxvk",
}.get(value.strip())
def validate_proton_path_setting(value: str | None) -> None:
"""Reject launch options in a filesystem field, without requiring a mounted disk."""
if value is None:
return
if not value.strip() or any(ord(character) < 32 for character in value):
raise ValueError("Proton script must be a filesystem path")
if re.match(r"(?:env\s+)?[A-Za-z_][A-Za-z0-9_]*=", value.strip()):
raise ValueError(
"Proton script must be a filesystem path. Choose WineD3D or DXVK "
"under Renderer; put other environment variables in the launcher "
"process environment. Leave Proton script blank for automatic detection."
)
if "%command%" in value:
raise ValueError("Proton script accepts a path, not Steam launch options")
def _write_settings(
paths: AppPaths,
settings: Settings,
@@ -278,8 +319,10 @@ def _validate(settings: Settings) -> None:
raise ValueError("realm must be a non-empty display name")
if settings.ui_scale not in UI_SCALE_CHOICES:
raise ValueError(f"unsupported launcher UI scale: {settings.ui_scale}")
if settings.runtime not in {"auto", "proton7", "proton7-container", "umu"}:
if settings.runtime not in {"auto", "proton7", "proton7-container", "umu", "ge-proton"}:
raise ValueError(f"unsupported runtime selection: {settings.runtime}")
if settings.renderer not in {"auto", "dxvk", "wined3d"}:
raise ValueError(f"unsupported renderer: {settings.renderer}")
if settings.proton_sync not in {"auto", "fsync", "esync"}:
raise ValueError(f"unsupported Proton synchronization mode: {settings.proton_sync}")
if settings.update_channel not in SUPPORTED_CHANNELS: