mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 23:18:44 -07:00
26786527cd
Steam-purchased Rec Room ships with SteamStub Variant 3.1 wrapping Recroom_Release.exe so it refuses to launch without Steam loaded. DorkNet spawns the exe directly, so for Steam installs we have to unwrap it first or the user gets a silent crash on Launch. - SteamDrmStripper.StripIfNeededAsync: PE-walks the exe's section table looking for the .bind section SteamStub adds, and only invokes Steamless when that section is present. Re-runs detect the already-unwrapped exe and short-circuit. Backs up the original next to the exe as Recroom_Release.exe.steamwrapped. - SteamlessInstaller: resolves a usable Steamless.CLI.exe via side-by-side -> %LOCALAPPDATA%\DorkNet\Steamless\ cache -> download v3.1.0.5 from atom0s/Steamless GitHub releases. Same pattern as CloudflaredInstaller. - Inserted as a step between "Download client patcher" and "Patch your Rec Room install" in both host (5 -> 6 steps) and join (2 -> 3 steps). Step detail reports Stripped / AlreadyUnpacked / NotApplicable so the user sees what happened. Oculus / Quest builds and already-unwrapped installs skip the Steamless download entirely.
92 lines
3.4 KiB
C#
92 lines
3.4 KiB
C#
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace DorkNet.Launcher.Backend;
|
|
|
|
/// <summary>A single visible step in the host/join startup flow. The
|
|
/// XAML <c>ItemsControl</c> binds to a collection of these and the
|
|
/// DataTemplate switches presentation off <see cref="State"/>.
|
|
///
|
|
/// <para>This is a tiny INotifyPropertyChanged DTO on purpose — no MVVM
|
|
/// framework, no commands, no view-model layer. Code-behind owns the
|
|
/// collection and mutates fields as the flow progresses.</para></summary>
|
|
public sealed class StartupStep : INotifyPropertyChanged
|
|
{
|
|
public StartupStep(string title) { Title = title; }
|
|
|
|
public string Title { get; }
|
|
|
|
private StepState _state = StepState.Pending;
|
|
public StepState State
|
|
{
|
|
get => _state;
|
|
set { if (_state == value) return; _state = value; OnChanged(); OnChanged(nameof(IsActive)); }
|
|
}
|
|
|
|
private string _detail = "";
|
|
public string Detail
|
|
{
|
|
get => _detail;
|
|
set { if (_detail == value) return; _detail = value; OnChanged(); OnChanged(nameof(HasDetail)); }
|
|
}
|
|
|
|
/// <summary>0..1 progress fraction, or null for "no progress bar"
|
|
/// (e.g. an indeterminate phase like "starting server"). The
|
|
/// DataTemplate hides the bar when null.</summary>
|
|
private double? _progress;
|
|
public double? Progress
|
|
{
|
|
get => _progress;
|
|
set { if (_progress == value) return; _progress = value; OnChanged(); OnChanged(nameof(HasProgress)); OnChanged(nameof(ProgressPercent)); }
|
|
}
|
|
|
|
public bool HasDetail => !string.IsNullOrEmpty(_detail);
|
|
public bool HasProgress => _progress.HasValue;
|
|
public bool IsActive => _state == StepState.Active;
|
|
|
|
/// <summary>0..100 for the ProgressBar Value binding.</summary>
|
|
public double ProgressPercent => (_progress ?? 0) * 100;
|
|
|
|
public event PropertyChangedEventHandler? PropertyChanged;
|
|
private void OnChanged([CallerMemberName] string? name = null)
|
|
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name!));
|
|
}
|
|
|
|
public enum StepState
|
|
{
|
|
/// <summary>Hasn't started yet. Dim icon, no detail.</summary>
|
|
Pending,
|
|
/// <summary>In progress right now. Brand-coloured icon, detail +
|
|
/// optional progress bar visible.</summary>
|
|
Active,
|
|
/// <summary>Finished successfully. Green checkmark.</summary>
|
|
Done,
|
|
/// <summary>Failed — error in <see cref="StartupStep.Detail"/>. Red
|
|
/// X, the rest of the flow won't proceed.</summary>
|
|
Failed,
|
|
}
|
|
|
|
/// <summary>Helpers for the two known flows. Centralising the step
|
|
/// names here keeps the XAML free of hardcoded strings and makes it
|
|
/// obvious what stages a user will see.</summary>
|
|
public static class StartupFlow
|
|
{
|
|
public static ObservableCollection<StartupStep> NewHostFlow(bool isLocalNetwork) => new()
|
|
{
|
|
new StartupStep("Download server binary"),
|
|
new StartupStep(isLocalNetwork ? "Find your local network address" : "Set up Cloudflare tunnel"),
|
|
new StartupStep("Start the server"),
|
|
new StartupStep("Download client patcher"),
|
|
new StartupStep("Unlock Rec Room from Steam (if needed)"),
|
|
new StartupStep("Patch your Rec Room install"),
|
|
};
|
|
|
|
public static ObservableCollection<StartupStep> NewJoinFlow() => new()
|
|
{
|
|
new StartupStep("Download client patcher"),
|
|
new StartupStep("Unlock Rec Room from Steam (if needed)"),
|
|
new StartupStep("Patch your Rec Room install"),
|
|
};
|
|
}
|