Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
72c363e
Cherry-pick Launcher from xplat-editor branch
Kryptos-FR Jan 7, 2026
2c247ce
Update packages
Kryptos-FR Dec 30, 2025
9631523
Cherry-pick minimum changes to presentation libraries
Kryptos-FR Dec 30, 2025
4950387
Upgrade to Avalonia 12
Kryptos-FR Apr 21, 2026
726e083
ci: fix potential parallel build issue for the launcher job
Kryptos-FR Apr 21, 2026
3ebbe54
docs: add contributor documentation for the Stride Launcher
Kryptos-FR Apr 21, 2026
477ae6e
docs: add launcher port-status document with gap analysis and roadmap
Kryptos-FR Apr 21, 2026
a9b7c5b
docs: add Phase 5 (test infrastructure with Avalonia headless) to lau…
Kryptos-FR Apr 21, 2026
1f29517
feat(launcher): add close-confirmation localized strings
Kryptos-FR Apr 21, 2026
3a51352
feat(launcher): persist tab selection immediately on change
Kryptos-FR Apr 21, 2026
dd54dc9
feat(launcher): add MainViewModel.TryCloseAsync for close-confirmatio…
Kryptos-FR Apr 21, 2026
cc902fa
feat(launcher): restore close-confirmation prompt on main window
Kryptos-FR Apr 21, 2026
0a959a6
feat(launcher): capture Win32 HWND on main window for /LauncherWindow…
Kryptos-FR Apr 21, 2026
6595f65
docs(launcher): reflect restored window-lifecycle parity
Kryptos-FR Apr 21, 2026
b2ea7d7
fix(launcher): bind Escape key to 'Keep launcher open' in close-confi…
Kryptos-FR Apr 23, 2026
c737d51
docs(launcher): add 'beyond parity' section with alternate-version pe…
Kryptos-FR Apr 23, 2026
677f0a2
feat(launcher): add file-backed CompletedTasks storage API
Kryptos-FR Apr 23, 2026
8b8a8f0
refactor(launcher): route HasDoneTask/SaveTaskAsDone through Launcher…
Kryptos-FR Apr 23, 2026
c2555d0
feat(launcher): cross-platform 'Show in Explorer' for recent projects
Kryptos-FR Apr 23, 2026
eb4c2b6
docs(launcher): reflect cross-platform services parity
Kryptos-FR Apr 23, 2026
73d9945
docs(launcher): log Linux right-click hit-test offset on recent-proje…
Kryptos-FR Apr 23, 2026
c076b34
fix: Avalonia.Controls.DataGrid doesn't necessarily follow Avalonia's…
Kryptos-FR Apr 27, 2026
60d5ad2
refactor(xunit-runner): replace CommunityToolkit.Mvvm with Stride's o…
Kryptos-FR Apr 27, 2026
8d8000a
fix: missing package reference
Kryptos-FR Apr 27, 2026
8b95b69
feat(launcher): Phase 3 — slide animations for release-notes and anno…
Kryptos-FR Apr 27, 2026
f2a9fcb
fix(launcher): restore .md → .html URL rewriting in OnLinkClicked
Kryptos-FR Apr 27, 2026
d04bcb0
feat(launcher): add ILauncherSettingsService interface and LauncherSe…
Kryptos-FR Apr 27, 2026
24e9015
refactor(launcher): inject ILauncherSettingsService into MainViewModel
Kryptos-FR Apr 27, 2026
6b457a9
refactor(launcher): migrate AnnouncementViewModel to ILauncherSetting…
Kryptos-FR Apr 27, 2026
3f8bea5
refactor(launcher): migrate StrideVersionViewModel and MainView code-…
Kryptos-FR Apr 27, 2026
b5fd82b
test(launcher): bootstrap Stride.Launcher.Tests project with helpers
Kryptos-FR Apr 27, 2026
bdfda02
test(launcher): add MainViewModel unit tests (HasDoneTask, CurrentTab…
Kryptos-FR Apr 27, 2026
d48fe70
docs(launcher): reflect Phase 5 viewmodel tests and ILauncherSettings…
Kryptos-FR Apr 27, 2026
9f482bb
ci(launcher): restore parallel build
Kryptos-FR Apr 27, 2026
e7d7d9c
fix(launcher): three high-priority bug fixes
Kryptos-FR May 2, 2026
656f934
chore(launcher): remove legacy PrivacyPolicyHelper placeholder
Kryptos-FR May 2, 2026
f1752aa
docs(launcher): clarify MinimalApp empty OnFrameworkInitializationCom…
Kryptos-FR May 2, 2026
eb2568d
fix(launcher): move recent-project ContextMenu to Button to fix Linux…
Kryptos-FR Apr 27, 2026
7be44f2
docs(launcher): update port-status.md corrections
Kryptos-FR May 2, 2026
1a7538f
Merge branch 'master' into feature/launcher-avalonia-cherrypick
Kryptos-FR May 3, 2026
cb7f8e1
fix(launcher): alignment and text trimming in recent projects
Kryptos-FR May 10, 2026
9f2d406
feat(launcher): cross-platform GameStudio IPC
Kryptos-FR May 15, 2026
6d262d6
feat(launcher): preferred-editor selector, companion package install
Kryptos-FR May 10, 2026
5b8f325
feat(launcher): restrict editor detection to Avalonia on non-Windows
Kryptos-FR May 15, 2026
57ba31f
Remove Xenko compatibility and beta version toggle from launcher
Kryptos-FR May 24, 2026
2c2c44f
docs(launcher): remove Xenko and beta-versions references
Kryptos-FR May 24, 2026
6d9c727
docs(launcher): rewrite port-status.md for pre-merge review
Kryptos-FR May 24, 2026
a5b1025
Merge origin/master into feature/launcher-avalonia-cherrypick
xen2 Jun 29, 2026
11559ae
A few fixes following merge from master
Kryptos-FR Jun 29, 2026
88eacaf
build: convert Stride.Launcher.sln to slnx format
Kryptos-FR Jul 5, 2026
427a325
Merge branch 'master' into feature/launcher-avalonia-cherrypick
Kryptos-FR Jul 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build-launcher.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ jobs:
- name: Build
run: |
dotnet build build\Stride.Launcher.slnx `
-nr:false `
-v:m -p:WarningLevel=0 `
-p:Configuration=${{ github.event.inputs.build-type || inputs.build-type || 'Debug' }} `
-p:StridePlatforms=Windows `
Expand Down
40 changes: 25 additions & 15 deletions build/Stride.Launcher.slnx
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
<Solution>
<Project Path="../sources/assets/Stride.Core.Packages/Stride.Core.Packages.csproj" />
<Project Path="../sources/core/Stride.Core.Design/Stride.Core.Design.csproj" />
<Project Path="../sources/core/Stride.Core.IO/Stride.Core.IO.csproj" />
<Project Path="../sources/core/Stride.Core.Mathematics/Stride.Core.Mathematics.csproj" />
<Project Path="../sources/core/Stride.Core.MicroThreading/Stride.Core.MicroThreading.csproj" />
<Project Path="../sources/core/Stride.Core.Reflection/Stride.Core.Reflection.csproj" />
<Project Path="../sources/core/Stride.Core.Serialization/Stride.Core.Serialization.csproj" />
<Project Path="../sources/core/Stride.Core.Translation/Stride.Core.Translation.csproj" />
<Project Path="../sources/core/Stride.Core.Yaml/Stride.Core.Yaml.csproj" />
<Project Path="../sources/core/Stride.Core/Stride.Core.csproj" />
<Project Path="../sources/editor/Stride.Editor.CrashReport/Stride.Editor.CrashReport.csproj" />
<Folder Name="/10-CoreRuntime/">
<Project Path="../sources/core/Stride.Core.CompilerServices/Stride.Core.CompilerServices.csproj" />
<Project Path="../sources/core/Stride.Core.IO/Stride.Core.IO.csproj" />
<Project Path="../sources/core/Stride.Core.Mathematics/Stride.Core.Mathematics.csproj" />
<Project Path="../sources/core/Stride.Core.MicroThreading/Stride.Core.MicroThreading.csproj" />
<Project Path="../sources/core/Stride.Core.Serialization/Stride.Core.Serialization.csproj" />
<Project Path="../sources/core/Stride.Core/Stride.Core.csproj" />
</Folder>
<Folder Name="/30-CoreDesign/">
<Project Path="../sources/core/Stride.Core.Design/Stride.Core.Design.csproj" />
<Project Path="../sources/core/Stride.Core.Reflection/Stride.Core.Reflection.csproj" />
<Project Path="../sources/core/Stride.Core.Translation/Stride.Core.Translation.csproj" />
<Project Path="../sources/core/Stride.Core.Yaml/Stride.Core.Yaml.csproj" />
</Folder>
<Folder Name="/40-Assets/">
<Project Path="../sources/assets/Stride.Core.Packages/Stride.Core.Packages.csproj" />
</Folder>
<Folder Name="/50-Presentation/">
<Project Path="../sources/presentation/Stride.Core.Presentation.Avalonia/Stride.Core.Presentation.Avalonia.csproj" />
<Project Path="../sources/presentation/Stride.Core.Presentation/Stride.Core.Presentation.csproj" />
</Folder>
<Folder Name="/90-Tools/">
<Project Path="../sources/launcher/Stride.VisualStudio.Commands.Interfaces.Client/Stride.VisualStudio.Commands.Interfaces.Client.csproj" />
</Folder>
<Project Path="../sources/launcher/Stride.Cli/Stride.Cli.csproj" />
<Project Path="../sources/launcher/Stride.Launcher.Tests/Stride.Launcher.Tests.csproj" />
<Project Path="../sources/launcher/Stride.Launcher/Stride.Launcher.csproj" />
<Project Path="../sources/presentation/Stride.Core.Presentation.Dialogs/Stride.Core.Presentation.Dialogs.csproj" />
<Project Path="../sources/presentation/Stride.Core.Presentation.Wpf/Stride.Core.Presentation.Wpf.csproj" />
<Project Path="../sources/presentation/Stride.Core.Presentation/Stride.Core.Presentation.csproj" />
<Project Path="../sources/presentation/Stride.Core.Translation.Presentation/Stride.Core.Translation.Presentation.csproj" />
</Solution>
99 changes: 99 additions & 0 deletions docs/launcher/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Stride Launcher — Overview

The Stride Launcher is the entry point end users run after installing Stride. It is an Avalonia MVVM application that manages the locally installed Stride versions (download, update, uninstall), exposes recent projects and VSIX extensions for Visual Studio, surfaces release notes, news and documentation, and finally starts the selected version of Game Studio.

The launcher's sources live in [sources/launcher/](../../sources/launcher/). The application itself is [Stride.Launcher](../../sources/launcher/Stride.Launcher/), built against `net10.0` with RIDs `linux-x64` and `win-x64`. It is distributed as a NuGet package (`Stride.Launcher`) and wrapped by an Advanced Installer setup on Windows.

## Big picture

```mermaid
flowchart TD
User["User"]
Setup["StrideSetup.exe<br/>Advanced Installer bundle<br/>sources/launcher/Setup/"]
Prereq["launcher-prerequisites.exe<br/>sources/launcher/Prerequisites/"]
Exe["Stride.Launcher.exe<br/>Avalonia MVVM app<br/>sources/launcher/Stride.Launcher/"]
NuGet["NuGet feed<br/>(packages.stride3d.net, nuget.org)"]
Store["NugetStore<br/>sources/assets/Stride.Core.Packages/"]
GS["Stride.GameStudio<br/>(selected version)"]

User -- "runs" --> Setup
Setup -- "installs" --> Exe
Setup -- "installs" --> Prereq
Exe -- "uses" --> Store
Store -- "fetches packages" --> NuGet
Exe -- "starts" --> GS
GS -. "optional: /LauncherWindowHandle" .-> Exe
```

The launcher has three responsibilities:

1. **Self-update.** On start, check NuGet for a newer `Stride.Launcher` package and optionally replace the current executable before the UI is shown. See [self-update.md](self-update.md).
2. **Version management.** List available Stride versions, download/install/uninstall them through `NugetStore`, and track a single "active" version. See [versions.md](versions.md).
3. **Launch Game Studio.** Locate the main executable of the active version, start it with the right arguments, and optionally auto-close when Game Studio signals back via `/LauncherWindowHandle`. See [lifecycle.md](lifecycle.md).

## Projects

The launcher codebase is small and self-contained under [sources/launcher/](../../sources/launcher/):

| Directory | Role |
|---|---|
| [Stride.Launcher/](../../sources/launcher/Stride.Launcher/) | Avalonia MVVM application (`Stride.Launcher.exe`) |
| [Prerequisites/](../../sources/launcher/Prerequisites/) | Advanced Installer project producing `launcher-prerequisites.exe` (Windows only) |
| [Setup/](../../sources/launcher/Setup/) | Advanced Installer project producing the user-facing `StrideSetup.exe` bundle (Windows only) |

The launcher depends on two Stride libraries:

- [Stride.Core.Packages](../../sources/assets/Stride.Core.Packages/) — the `NugetStore` abstraction used to talk to NuGet feeds.
- [Stride.Core.Presentation.Avalonia](../../sources/presentation/Stride.Core.Presentation.Avalonia/) — the shared Avalonia MVVM framework (dispatcher, dialogs, markdown viewer integration, etc.). The WPF equivalent in the editor is `Stride.Core.Presentation.Wpf`.

A handful of files from the editor are linked in directly (not as project references) to keep the launcher dependency graph minimal:

- `EditorPath.cs` — resolves user data paths (`LauncherSettings.conf`, `launcher.lock`, MRU, etc.).
- `PackageSessionHelper.Solution.cs` — parses `.sln` files to discover the Stride version used by a recent project.
- The `Stride.Core.MostRecentlyUsedFiles` shared project — shared MRU list infrastructure.

See [projects.md](projects.md) for the full layout and each file's role.

## When you need these systems

> **Decision tree:**
>
> - Adding a new UI page/tab or a new version-list entry kind?
> → **A new ViewModel + View under Stride.Launcher.** See [viewmodels.md](viewmodels.md) and [views.md](views.md).
>
> - Changing how a Stride version is downloaded, updated, or uninstalled?
> → **`StrideVersionViewModel` and `PackageVersionViewModel`** — they drive `NugetStore`. See [versions.md](versions.md).
>
> - Changing how the launcher updates itself?
> → **`SelfUpdater`** and the self-update window. See [self-update.md](self-update.md).
>
> - Adding a new command-line argument or action?
> → **`LauncherArguments` + `Launcher.ProcessArguments`.** See [lifecycle.md](lifecycle.md#command-line-arguments).
>
> - Persisting a new user preference?
> → **`LauncherSettings`** (launcher-owned) or **`GameStudioSettings`** (shared with Game Studio). See [settings.md](settings.md).
>
> - Adding a new localized string or URL?
> → **`Assets/Localization/Strings.resx` / `Urls.resx`** (+ `.ja-JP` variants). See [localization.md](localization.md).
>
> - Working on the Windows installer or prerequisites bundle?
> → **Advanced Installer projects under `Prerequisites/` and `Setup/`.** See [packaging.md](packaging.md).
>
> - Running/debugging on Linux and something behaves differently?
> → **Platform-specific code paths.** See [cross-platform.md](cross-platform.md).

## Spoke files

| File | Covers |
|---|---|
| [projects.md](projects.md) | Directory and file layout, external dependencies, linked files |
| [lifecycle.md](lifecycle.md) | Entry point, single-instance mutex, command-line arguments, error codes, crash reporting |
| [viewmodels.md](viewmodels.md) | `MainViewModel`, version view models, recent projects, news/docs/announcement view models |
| [views.md](views.md) | XAML views, windows, converters, markdown viewer integration |
| [versions.md](versions.md) | Version discovery, install/uninstall flow through `NugetStore`, framework selection, beta filter, dev redirects |
| [self-update.md](self-update.md) | Launcher self-update: NuGet update probe, force-reinstall, file swap, restart |
| [settings.md](settings.md) | `LauncherSettings`, `GameStudioSettings`, config file locations |
| [localization.md](localization.md) | `Strings.resx` / `Urls.resx`, designer classes, adding a new language |
| [packaging.md](packaging.md) | `Stride.Launcher.nuspec`, Advanced Installer projects, `StrideSetup.exe`, versioning |
| [cross-platform.md](cross-platform.md) | Windows-only code paths, Registry usage, Linux/macOS porting status (xplat-launcher) |
| [port-status.md](port-status.md) | Full delta vs the WPF launcher on `master` — including silent regressions — and a phased roadmap to close the gap |
79 changes: 79 additions & 0 deletions docs/launcher/cross-platform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Cross-platform notes

The launcher is in the middle of a Windows → Avalonia cross-platform port (`xplat-launcher` stream). It targets `net10.0` with RIDs `linux-x64` and `win-x64`; WPF has been fully replaced by Avalonia 12. This file lists the code paths that still behave differently per OS and what the remaining gaps are.

## Executable shape

| Platform | Game Studio file | How it is started |
|---|---|---|
| Windows | `Stride.GameStudio.Avalonia.Desktop.exe` (with fallback to `Stride.GameStudio.exe`) | `Process.Start(exe, args)` |
| Linux | `Stride.GameStudio.Avalonia.Desktop.dll` | `Process.Start("dotnet", $"{dll} {args}")` |

The choice is in `StrideVersionViewModel.GetExecutableNames` and `MainViewModel.StartStudio`. The switch on `Path.GetExtension(mainExecutable)` decides whether to invoke `dotnet` or the binary directly.

## Windows-only code paths

Searching for `OperatingSystem.IsWindows()` in the launcher shows the remaining divergences.

### Prerequisites installer

`StrideStoreVersionViewModel.RunPrerequisitesInstaller` runs `{InstallPath}/Bin/Prerequisites/install-prerequisites.exe`. That binary is a Windows installer — it is simply skipped on non-Windows since the DirectX / .NET prerequisites it ships don't apply.

### Visual Studio integration

`VsixVersionViewModel` relies on `Stride.Core.CodeEditorSupport.VisualStudio.VisualStudioVersions` to find installed VS instances. This uses `vswhere` internally and returns nothing on Linux/macOS, so the VSIX entries are effectively hidden. The code does not branch explicitly — it just finds no targets and the command stays disabled.

### Installers

Advanced Installer projects ([Prerequisites/](../../sources/launcher/Prerequisites/), [Setup/](../../sources/launcher/Setup/)) are Windows-only by construction. The MSBuild `PackageInstaller` target silently skips when `AdvancedInstaller.com` is not on `PATH`. On Linux/macOS, distribute the launcher via `dotnet publish -r {rid} --self-contained`. See [packaging.md](packaging.md).

## Telemetry and privacy policy

Both `Stride.Metrics` / `MetricsClient` (telemetry) and `PrivacyPolicyHelper` (first-run consent prompt, uninstall-time revoke) have been **intentionally and permanently removed** from the launcher. They will not be ported. No cleanup of legacy privacy-policy state is performed on uninstall — telemetry was removed, so any residual registry keys or settings files from the old WPF launcher are harmless orphans and do not need to be scrubbed.

## Launcher ↔ GameStudio IPC

When `AutoCloseLauncher` is on, the launcher passes IPC information to Game Studio via a CLI argument so Game Studio can signal back once it has started.

| Platform | Argument | Mechanism |
|---|---|---|
| Windows | `/LauncherWindowHandle <hwnd>` | Game Studio sends a Win32 `WM_CLOSE` message to the launcher's HWND. `MainWindow.OnOpened` captures the HWND via `TryGetPlatformHandle()`. |
| Linux (and other non-Windows) | `/LauncherPipe <pipeName>` | The launcher starts a `NamedPipeServerStream` and waits for a connection (up to 2 minutes). Game Studio connects via `NamedPipeClientStream` once its main window is loaded and writes one byte. The launcher raises `CloseRequested` and the window closes gracefully. |

Both paths are implemented:
- **Launcher side:** `MainViewModel.StartStudio` — branches on `OperatingSystem.IsWindows()`. Non-Windows path starts `WaitForGameStudioPipeSignalAsync` and injects `/LauncherPipe <name>`. `MainWindow.axaml.cs` wires `CloseRequested → OnClosingAsync`.
- **Game Studio side:** `Program.ParseLauncherArgs` (in `Stride.GameStudio.Avalonia.Desktop`) parses both argument styles and sets `App.LauncherNotifier`. `MainWindow.OnLoaded` fires it once.

## Settings paths

All config paths go through `EditorPath` (linked file from `Stride.Core.Assets.Editor`). `EditorPath.UserDataPath` resolves to:

- `%LocalAppData%\Stride\` on Windows
- `$XDG_DATA_HOME/Stride/` (or `~/.local/share/Stride/`) on Linux
- `~/Library/Application Support/Stride/` on macOS

The launcher writes `LauncherSettings.conf` and the `launcher.lock` single-instance marker under these paths. No OS-specific branching is needed.

## Icons

Window icons (`Launcher.ico`) are served through Avalonia's resource system. The `.ico` format is used on every platform; Avalonia picks the best-matching size at runtime.

## Recent-project "Show in Explorer"

`RecentProjectViewModel.Explore` reveals the selected recent project in the platform's native file manager:

- **Windows:** `explorer.exe /select,{path}` (unchanged from master).
- **macOS:** `open -R {path}` — reveals the file in Finder.
- **Linux:** `dbus-send` invocation of `org.freedesktop.FileManager1.ShowItems` on the session bus (implemented by GNOME Nautilus, KDE Dolphin, Cinnamon Nemo, XFCE Thunar, LXDE PCManFM, and others). Falls back to `xdg-open {parent-dir}` when the DBus call fails — e.g. on minimal WMs without an `org.freedesktop.FileManager1` implementer, or headless environments without a session bus.

All failures are swallowed silently (no dialog, no crash) since they are not actionable from inside the launcher.

## Testing surface

When exercising changes, run the launcher on both Windows and Linux. Known gaps that will not reproduce on Linux:

- Self-update using the `force-reinstall` path (downloads a `StrideSetup.exe` — Windows only).
- First-install VSIX prompt (no VS instances).
- Prerequisites installer on first run.

Conversely, on Windows the `dotnet` launch path (the `.dll` branch in `StartStudio`) is unreachable unless a Linux-built package is opened.
Loading
Loading