Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions WheelWizard.Test/Features/Recomp/RecompLinuxTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public void ReleaseResolver_PicksTheAssetItIsAskedFor()
new GithubAsset { Name = "WiiCompiled-Setup.exe", BrowserDownloadUrl = "https://example.com/exe" },
new GithubAsset { Name = "WiiCompiled-Setup-x86_64.AppImage", BrowserDownloadUrl = "https://example.com/x86_64" },
new GithubAsset { Name = "WiiCompiled-Setup-aarch64.AppImage", BrowserDownloadUrl = "https://example.com/aarch64" },
new GithubAsset { Name = RecompPlatform.MacReleaseAssetName, BrowserDownloadUrl = "https://example.com/macos" },
],
};
var windowsOnly = new GithubRelease
Expand All @@ -93,6 +94,12 @@ public void ReleaseResolver_PicksTheAssetItIsAskedFor()

Assert.Equal("v0.3.0", RecompReleaseResolver.FindLatest([release, windowsOnly], "WiiCompiled-Setup.exe")?.TagName);
Assert.Null(RecompReleaseResolver.FindLatest([windowsOnly], "WiiCompiled-Setup-aarch64.AppImage"));

Assert.Equal(
"https://example.com/macos",
RecompReleaseResolver.FindLatest([release, windowsOnly], RecompPlatform.MacReleaseAssetName)?.SetupDownloadUrl
);
Assert.Null(RecompReleaseResolver.FindLatest([windowsOnly], RecompPlatform.MacReleaseAssetName));
}

[Fact]
Expand Down
19 changes: 19 additions & 0 deletions WheelWizard.Test/Features/Recomp/RecompPathsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,23 @@ public void LinuxLayout_LeavesBackendStateInXdgData_WhenLauncherDataMoves(Archit
Assert.Equal("/relocated/Recomp/Install/install-state.json", paths.InstallStateFilePath);
Assert.Equal("/relocated/Recomp/Nand", paths.NandCopyFolderPath);
}

[Fact]
public void MacLayout_KeepsBackendStateInApplicationSupport_AndInstallsTheDownloadedRun()
{
var fs = new MockFileSystem(options => options.SimulatingOperatingSystem(SimulationMode.MacOS));
var location = Substitute.For<IApplicationDataLocation>();
location.DirectoryPath.Returns("/first");
var environment = Substitute.For<IRuntimeEnvironment>();
environment.IsMacOS.Returns(true);
environment.OSArchitecture.Returns(Architecture.Arm64);
environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData).Returns("/support");
var paths = new RecompPaths(location, fs, environment);

Assert.False(paths.IsPortableInstall);
Assert.Equal("/support/WiiCompiled/Config.toml", paths.ConfigFilePath);
Assert.Equal("/support/WiiCompiled/NAND", paths.PrivateNandFolderPath);
Assert.Equal("/support/WiiCompiled/install-state.json", paths.LinuxBackendStateFilePath);
Assert.Equal("/first/Recomp/Install/WiiCompiled-Setup-macos.run", paths.SetupFilePath);
}
}
10 changes: 5 additions & 5 deletions WheelWizard/Features/Recomp/RecompExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ public static class RecompExtensions
{
/// <summary>
/// Registers the Mario Kart Wii recomp frontend.
/// The recomp only ships for Windows and Linux, so on every other platform nothing is registered at
/// all; <c>ISettingsManager.IsRecompModeActive()</c> is false there, so nothing ever resolves these.
/// Both platforms share how a setup release is found and downloaded; what that setup is then told to
/// do differs, so each gets its own environment and install service.
/// The recomp only runs on Windows, Linux and macOS, so on every other platform nothing is registered
/// at all; <c>ISettingsManager.IsRecompModeActive()</c> is false elsewhere, so nothing ever resolves
/// these. Windows uses the v1 setup contract; Linux and macOS share the subcommand setup, so they share
/// an environment and install service.
/// </summary>
public static IServiceCollection AddRecomp(this IServiceCollection services)
{
Expand All @@ -38,7 +38,7 @@ public static IServiceCollection AddRecomp(this IServiceCollection services)
services.AddSingleton<IRecompRetroWfcPayloadProbe, RecompRetroWfcPayloadProbe>();
services.AddSingleton<RecompSetupHostAcquirer>();

if (RecompPlatform.IsLinux)
if (RecompPlatform.UsesSubcommandSetup)
{
services.AddSingleton<IRecompEnvironment, RecompLinuxEnvironment>();
services.AddSingleton<RecompLinuxProductInspector>();
Expand Down
10 changes: 8 additions & 2 deletions WheelWizard/Features/Recomp/RecompLinuxInstallService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,17 @@ public async Task<OperationResult> InstallAsync(
}

/// <summary>
/// Decides based on the setup file path whether or not this is a bundled recomp setup binary
/// Decides based on the setup file path whether or not this is a bundled recomp setup binary. A
/// downloaded setup (the Linux AppImage or the macOS .run) shares the extension of this platform's
/// release asset; a bundled one, such as the Flatpak extension's wrapper, does not.
/// </summary>
private bool IsBundledRecomp(string setupFilePath)
{
return !setupFilePath.EndsWith(".AppImage", StringComparison.OrdinalIgnoreCase);
return !string.Equals(
fileSystem.Path.GetExtension(setupFilePath),
fileSystem.Path.GetExtension(RecompPlatform.SetupFileName),
StringComparison.OrdinalIgnoreCase
);
}

private async Task<OperationResult> InstallCoreAsync(
Expand Down
17 changes: 13 additions & 4 deletions WheelWizard/Features/Recomp/RecompPaths.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,31 @@ public sealed class RecompPaths(IApplicationDataLocation applicationData, IFileS
{
public const string InstallStateFileName = "install-state.json";
private bool IsLinux => environment.IsLinux && RecompPlatform.LinuxReleaseAssetName(environment.OSArchitecture) is not null;
private bool IsMacOS => environment.IsMacOS;

// Linux and macOS both run a setup that keeps its products, Config.toml and NAND in its own backend folder.
private bool UsesBackendFolder => IsLinux || IsMacOS;
private bool IsFlatpak => environment.IsFlatpakSandboxed(fileSystem);
public string RootFolderPath => fileSystem.Path.Combine(applicationData.DirectoryPath, "Recomp");
public string InstallFolderPath => fileSystem.Path.Combine(RootFolderPath, "Install");
public bool IsPortableInstall => !IsLinux;
public bool IsPortableInstall => !UsesBackendFolder;
public string CacheFolderPath => fileSystem.Path.Combine(RootFolderPath, "Cache");
public string UserDataFolderPath => fileSystem.Path.Combine(RootFolderPath, "UserData");
public string InstallStateFilePath => fileSystem.Path.Combine(InstallFolderPath, InstallStateFileName);
public string SetupFilePath =>
IsFlatpak
? "/app/extensions/backends/wiicompiled/bin/wiicompiled-setup"
: fileSystem.Path.Combine(InstallFolderPath, IsLinux ? "WiiCompiled-Setup.AppImage" : RecompSetupCommandBuilder.SetupFileName);
: fileSystem.Path.Combine(
InstallFolderPath,
IsLinux ? "WiiCompiled-Setup.AppImage"
: IsMacOS ? RecompPlatform.MacReleaseAssetName
: RecompSetupCommandBuilder.SetupFileName
);
public string LinuxBackendFolderPath =>
fileSystem.Path.Combine(environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "WiiCompiled");
public string LinuxBackendStateFilePath => fileSystem.Path.Combine(LinuxBackendFolderPath, InstallStateFileName);
public string ConfigFilePath => fileSystem.Path.Combine(IsLinux ? LinuxBackendFolderPath : UserDataFolderPath, "Config.toml");
public string ConfigFilePath => fileSystem.Path.Combine(UsesBackendFolder ? LinuxBackendFolderPath : UserDataFolderPath, "Config.toml");
public string NandCopyFolderPath => fileSystem.Path.Combine(RootFolderPath, "Nand");
public string PortableMarkerFilePath => fileSystem.Path.Combine(RootFolderPath, "portable.txt");
public string PrivateNandFolderPath => fileSystem.Path.Combine(IsLinux ? LinuxBackendFolderPath : UserDataFolderPath, "NAND");
public string PrivateNandFolderPath => fileSystem.Path.Combine(UsesBackendFolder ? LinuxBackendFolderPath : UserDataFolderPath, "NAND");
}
29 changes: 22 additions & 7 deletions WheelWizard/Features/Recomp/RecompPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ namespace WheelWizard.Recomp;
/// <summary>
/// Which platforms the WiiCompiled integration runs on, and which setup asset each of them downloads.
/// Windows drives <c>WiiCompiled-Setup.exe</c> through the v1 command-line contract. Linux drives the
/// AppImage through its own subcommand interface (see <see cref="RecompLinuxInstallService"/>). Every
/// other platform is unsupported, so <c>ISettingsManager.IsRecompModeActive()</c> is false there and
/// nothing recomp-related is ever registered or shown.
/// AppImage through its own subcommand interface (see <see cref="RecompLinuxInstallService"/>), and macOS
/// drives the self-extracting <c>.run</c> with that same interface. Every other platform is unsupported, so
/// <c>ISettingsManager.IsRecompModeActive()</c> is false elsewhere and nothing recomp-related is ever
/// registered or shown.
/// </summary>
public static class RecompPlatform
{
Expand All @@ -18,14 +19,28 @@ public static class RecompPlatform
/// </summary>
public static bool IsLinux { get; } = OperatingSystem.IsLinux() && LinuxReleaseAssetName(RuntimeInformation.OSArchitecture) is not null;

public static bool IsSupported => OperatingSystem.IsWindows() || IsLinux;
/// <summary>
/// Whether this is a macOS build. macOS downloads <see cref="MacReleaseAssetName"/>, a self-extracting
/// setup for both architectures that speaks the same subcommand interface as the Linux AppImage.
/// </summary>
public static bool IsMacOS { get; } = OperatingSystem.IsMacOS();

/// <summary>Whether this platform drives the setup through its subcommand interface (Linux and macOS).</summary>
public static bool UsesSubcommandSetup => IsLinux || IsMacOS;

public static bool IsSupported => OperatingSystem.IsWindows() || UsesSubcommandSetup;

/// <summary>The macOS release asset, fixed by the recomp's packaging workflow. It is also the installed host's name.</summary>
public const string MacReleaseAssetName = "WiiCompiled-Setup-macos.run";

/// <summary>The name of the installed host copy inside Wheel Wizard's recomp install directory.</summary>
public static string SetupFileName => IsLinux ? "WiiCompiled-Setup.AppImage" : RecompSetupCommandBuilder.SetupFileName;
public static string SetupFileName =>
IsLinux ? "WiiCompiled-Setup.AppImage"
: IsMacOS ? MacReleaseAssetName
: RecompSetupCommandBuilder.SetupFileName;

/// <summary>The release asset to download on this machine.</summary>
public static string ReleaseAssetName =>
IsLinux ? LinuxReleaseAssetName(RuntimeInformation.OSArchitecture)! : RecompSetupCommandBuilder.SetupFileName;
public static string ReleaseAssetName => IsLinux ? LinuxReleaseAssetName(RuntimeInformation.OSArchitecture)! : SetupFileName;

/// <summary>
/// The AppImage the recomp publishes for a Linux architecture, or <see langword="null"/> when it
Expand Down
10 changes: 7 additions & 3 deletions WheelWizard/Features/Recomp/RecompVideoConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,21 @@ public static class RecompVideoConfig
/// <summary>
/// The graphics APIs WheelWizard offers, in the order they are shown. The backend enumerates more
/// (auto, d3d11, opengl, ...), but only these actually run the game reliably, so nothing else is
/// ever offered; Linux has no DirectX, so only Vulkan remains there. A value outside this list
/// stays untouched until the user picks one of these.
/// ever offered; Linux has no DirectX, so only Vulkan remains there, and macOS only builds Metal.
/// A value outside this list stays untouched until the user picks one of these.
/// </summary>
public static IReadOnlyList<string> OfferedGraphicsApis { get; } = RecompPlatform.IsLinux ? ["vulkan"] : ["d3d12", "vulkan"];
public static IReadOnlyList<string> OfferedGraphicsApis { get; } =
RecompPlatform.IsLinux ? ["vulkan"]
: RecompPlatform.IsMacOS ? ["metal"]
: ["d3d12", "vulkan"];

/// <summary>The label for a graphics API value, for example <c>DirectX 12</c> for <c>d3d12</c>.</summary>
public static string DescribeGraphicsApi(string api) =>
api switch
{
"d3d12" => "DirectX 12",
"vulkan" => "Vulkan",
"metal" => "Metal",
_ => api,
};

Expand Down
4 changes: 2 additions & 2 deletions WheelWizard/Resources/Languages/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -620,12 +620,12 @@ en:
helper_text:
topbar:
location_warning: "Settings are disabled, complete the location settings first"
enable_recomp: "Uses WiiCompiled as the home-page launcher. Turn this off to use Dolphin and Retro Rewind instead. Windows only."
enable_recomp: "Uses WiiCompiled as the home-page launcher. Turn this off to use Dolphin and Retro Rewind instead. Windows, Linux, and macOS only."
recomp_use_dolphin_data: "Use Dolphin's existing Wii folder in place so WiiCompiled shares saves, Miis, and Wii settings. A change takes effect the next time WiiCompiled launches."
recomp_share_dolphin_data: "WiiCompiled and Dolphin use the same saves, Miis, and Wii settings."
recomp_shared_nand_warning: "Do not run Dolphin and WiiCompiled at the same time while sharing NAND data."
recomp_clone_dolphin_data: "Copies Dolphin's current saves, Miis, and Wii settings into private WiiCompiled data."
recomp_graphics_api: "Only DirectX 12 and Vulkan run WiiCompiled reliably, so nothing else is offered."
recomp_graphics_api: "Only the graphics APIs that run WiiCompiled reliably on this system are offered."
recomp_dolphin_data_not_found: "Set an existing Dolphin User Folder in Location Settings first. It must contain a Wii folder."
recomp_prevent_stutters: "While a shader is still compiling, the objects that need it are skipped for a few frames instead of the whole game stalling until it is ready. You get a tiny bit of pop-in instead of a stutter."
launch_with_dolphin: "Will launch dolphins main window along with the game"
Expand Down