More changes and fixes to use the new native world (game.dll) fixes.
This commit is contained in:
122
ptlinux/ui.py
122
ptlinux/ui.py
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user