More changes and fixes to use the new native world (game.dll) fixes.

This commit is contained in:
2026-08-28 20:34:31 +02:00
parent 7f6330a617
commit b344506071
7 changed files with 230 additions and 65 deletions

View File

@@ -29,6 +29,7 @@ from .news import (
fetch_news_image,
fetch_official_logo,
)
from .overlay import RuntimeCompatibility, inspect_runtime_compatibility
from .paths import AppPaths
from .settings import Settings, ensure_settings, save_settings
from .self_update import LauncherUpdateCheck, check_for_launcher_update
@@ -568,9 +569,12 @@ def run_dashboard(paths: AppPaths) -> None:
operation_stage = 0
operation_stage_total = 0
operation_message = ""
operation_refreshes_compatibility = False
last_elapsed_second = -1
official_snapshot: DepotSnapshot | None = None
launcher_update_check: LauncherUpdateCheck | None = None
runtime_compatibility: RuntimeCompatibility | None = None
compatibility_check_generation = 0
buttons = (
play_button,
update_button,
@@ -753,18 +757,21 @@ def run_dashboard(paths: AppPaths) -> None:
*,
show_preloader: bool = False,
restart_on_success: bool = False,
game_files_may_change: bool = False,
) -> None:
nonlocal operation_active
nonlocal operation_started_at
nonlocal operation_stage
nonlocal operation_stage_total
nonlocal operation_message
nonlocal operation_refreshes_compatibility
nonlocal last_elapsed_second
operation_active = True
operation_started_at = time.monotonic()
operation_stage = 0
operation_stage_total = 0
operation_message = ""
operation_refreshes_compatibility = game_files_may_change
last_elapsed_second = -1
progress_updates.clear()
transfer_rate.reset()
@@ -1068,8 +1075,21 @@ def run_dashboard(paths: AppPaths) -> None:
installation = inspect_game_installation(
paths,
official_snapshot.build if official_snapshot is not None else None,
compatibility_ready=(
runtime_compatibility.compatible
if runtime_compatibility is not None
else None
),
)
play_button.configure(text=installation.action.value)
if not operation_active:
play_button.configure(
state=(
"disabled"
if installation.action is PrimaryAction.CHECKING
else "normal"
),
)
if not update_activity or operation_active:
return installation
if installation.action is PrimaryAction.INSTALL:
@@ -1089,11 +1109,42 @@ def run_dashboard(paths: AppPaths) -> None:
f"Installed depot {installation.local_build} · "
f"official depot {official_build}"
)
elif installation.action is PrimaryAction.CHECKING:
status.set("Checking game compatibility…")
progress_text.set("The installed release is being inspected without modifying it.")
elif installation.action is PrimaryAction.LAUNCHER_UPDATE:
status.set("Launcher compatibility update required.")
progress_text.set("This installed game release is not recognized by the launcher.")
else:
status.set("Ready")
progress_text.set("Click Play to start your journey")
return installation
def refresh_runtime_compatibility(*, update_activity: bool = True) -> None:
nonlocal compatibility_check_generation, runtime_compatibility
compatibility_check_generation += 1
check_generation = compatibility_check_generation
runtime_compatibility = None
local_status = inspect_game_installation(paths)
refresh_primary_action(update_activity=update_activity)
if not local_status.installed:
return
def worker() -> None:
result = inspect_runtime_compatibility(paths, paths.source_game)
events.put(
(
"compatibility",
(check_generation, result, update_activity),
)
)
threading.Thread(
target=worker,
name="ptlinux-compatibility",
daemon=True,
).start()
def refresh_remote_content() -> None:
def broadcast_worker() -> None:
events.put(("broadcast", fetch_latest_broadcast(paths.broadcast_cache)))
@@ -1127,8 +1178,10 @@ def run_dashboard(paths: AppPaths) -> None:
).start()
def finish_operation(returncode: int) -> None:
nonlocal operation_active, operation_started_at
nonlocal operation_active, operation_refreshes_compatibility, operation_started_at
refresh_compatibility = operation_refreshes_compatibility
operation_active = False
operation_refreshes_compatibility = False
operation_started_at = None
progress_updates.clear()
transfer_rate.reset()
@@ -1138,13 +1191,16 @@ def run_dashboard(paths: AppPaths) -> None:
root.deiconify()
root.lift()
set_busy(False)
refresh_primary_action(update_activity=returncode == 0)
if refresh_compatibility:
refresh_runtime_compatibility(update_activity=returncode == 0)
else:
refresh_primary_action(update_activity=returncode == 0)
if returncode != 0:
status.set(f"Operation failed (exit {returncode})")
progress_text.set("See the activity log for details.")
def poll_events() -> None:
nonlocal launcher_update_check
nonlocal launcher_update_check, runtime_compatibility
processed = 0
try:
while processed < EVENT_BATCH_SIZE:
@@ -1192,6 +1248,29 @@ def run_dashboard(paths: AppPaths) -> None:
install_news_image(value)
elif kind == "logo_image":
install_official_logo(value)
elif (
kind == "compatibility"
and isinstance(value, tuple)
and len(value) == 3
and isinstance(value[0], int)
and isinstance(value[1], RuntimeCompatibility)
and isinstance(value[2], bool)
):
check_generation, checked, update_activity = value
if check_generation == compatibility_check_generation:
runtime_compatibility = checked
if checked.compatible:
append_log(
"Compatibility check passed: "
f"scene={checked.scene_action}, "
f"binaries={checked.binary_action}"
)
else:
append_log(
"Launcher compatibility update required: "
f"{checked.reason or 'unknown release profile'}"
)
refresh_primary_action(update_activity=update_activity)
elif kind == "version" and isinstance(value, DepotSnapshot):
version.set(
f"Launcher {__version__} · {value.version} · depot {value.build}"
@@ -1241,18 +1320,29 @@ def run_dashboard(paths: AppPaths) -> None:
def command_for(*arguments: str) -> list[str]:
return [sys.executable, "-m", "ptlinux", *arguments]
def run_launcher_update() -> None:
def run_launcher_update(required_reason: str | None = None) -> None:
check = launcher_update_check
if check is None:
launcher_update_button.configure(text="CHECKING…", state="disabled")
if required_reason is not None:
status.set("Checking for a compatible launcher update…")
progress_text.set("Play remains disabled until this release is supported.")
refresh_remote_content()
return
if not check.available:
messagebox.showinfo(
"Launcher update",
check.reason,
parent=root,
)
if required_reason is None:
messagebox.showinfo(
"Launcher update",
check.reason,
parent=root,
)
else:
messagebox.showwarning(
"Compatibility update required",
"The installed game needs a launcher compatibility update:\n\n"
f"{required_reason}\n\n{check.reason}",
parent=root,
)
return
if not check.supported:
messagebox.showwarning(
@@ -1287,11 +1377,19 @@ def run_dashboard(paths: AppPaths) -> None:
run_operation(
"Installing official game files…",
command_for("update"),
game_files_may_change=True,
)
else:
elif installation.action is PrimaryAction.UPDATE:
run_operation(
"Synchronizing official game files…",
command_for("update"),
game_files_may_change=True,
)
elif installation.action is PrimaryAction.LAUNCHER_UPDATE:
run_launcher_update(
runtime_compatibility.reason
if runtime_compatibility is not None
else "The installed release profile is not recognized.",
)
play_button.configure(command=run_primary_action)
@@ -1299,12 +1397,14 @@ def run_dashboard(paths: AppPaths) -> None:
command=lambda: run_operation(
"Synchronizing official game files…",
command_for("update"),
game_files_may_change=True,
)
)
repair_button.configure(
command=lambda: run_operation(
"Checking every game file against the official depot…",
command_for("update", "--no-import", "--repair"),
game_files_may_change=True,
)
)
doctor_button.configure(
@@ -1603,6 +1703,7 @@ def run_dashboard(paths: AppPaths) -> None:
run_operation(
"Importing the existing game into the managed installation…",
command_for("import-game", source),
game_files_may_change=True,
)
import_button.configure(command=choose_import_source)
@@ -1619,6 +1720,7 @@ def run_dashboard(paths: AppPaths) -> None:
news_content.bind("<Configure>", update_news_viewport)
news_canvas.bind("<Configure>", resize_news_content)
refresh_primary_action()
refresh_runtime_compatibility()
poll_events()
load_official_logo()
refresh_remote_content()