Skip to content

Add WiiForwarder: disc image channels on the Wii System Menu#14508

Open
Gavin-S-Dev wants to merge 2 commits intodolphin-emu:masterfrom
Gavin-S-Dev:wii-forwarder-channels
Open

Add WiiForwarder: disc image channels on the Wii System Menu#14508
Gavin-S-Dev wants to merge 2 commits intodolphin-emu:masterfrom
Gavin-S-Dev:wii-forwarder-channels

Conversation

@Gavin-S-Dev
Copy link
Copy Markdown

Adds a virtual forwarder channel system that maps disc images (.rvz, .iso, .wbfs, .gcz, .ciso, .wia) to launchable channel tiles on the Wii System Menu with animated banners.

Features:

  • Auto-install forwarder channels when Wii disc games are added to the game list; auto-remove when games are removed
  • Right-click context menu: "Add to Wii Menu" / "Remove from Wii Menu"
  • Tools menu: "Add Disc Image to Wii Menu..." file picker
  • Extracts real opening.bnr from disc (icon, banner animation, sound); falls back to minimal text-only IMET if extraction fails
  • ES intercepts forwarder title launch and boots the disc image
  • Skips stop-confirmation dialog for forwarder-initiated boots
  • Forwarder state stored in dolphin_forwarders.ini on host filesystem
  • Writes directly to emulated NAND (bypasses ES import encryption)
  • Deterministic title IDs via SHA1 hash of game ID XOR'd with "DFWD"

AI Disclosure

Yes, I have thoroughly read the "Generative AI" section, and I'm not going to sugarcoat things, Claude Code was heavily used throughout the development of this. This is moreso just a "Hey, I made this, if you want to add it to the main, go for it" sort of thing. Was thinking it was worth a pitch, if you, of course, justifiably turn down this request ill be sure to keep developing more quality of life builds going solo, as I know the approval of this PR goes against your contributing section. Just for your guys' sanity, AI was not used to obtain any information about Wii/IOS console behavior, and the forwarder system is a host-side Dolphin feature that writes synthetic data to the emulated NAND and does not change how the emulated console behaves.

Adds a virtual forwarder channel system that maps disc images (.rvz,
.iso, .wbfs, .gcz, .ciso, .wia) to launchable channel tiles on the
Wii System Menu with real animated banners.

Features:
- Auto-install forwarder channels when Wii disc games are added to
  the game list; auto-remove when games are removed
- Right-click context menu: "Add to Wii Menu" / "Remove from Wii Menu"
- Tools menu: "Add Disc Image to Wii Menu..." file picker
- Extracts real opening.bnr from disc (icon, banner animation, sound);
  falls back to minimal text-only IMET if extraction fails
- ES intercepts forwarder title launch and boots the disc image
- Skips stop-confirmation dialog for forwarder-initiated boots
- Forwarder state stored in dolphin_forwarders.ini on host filesystem
- Writes directly to emulated NAND (bypasses ES import encryption)
- Deterministic title IDs via SHA1 hash of game ID XOR'd with "DFWD"
@jordan-woyak
Copy link
Copy Markdown
Member

I don't think auto installing every game in the game list should be the default behavior.
There should probably be a setting to enable that functionality.

Copy link
Copy Markdown
Contributor

@sepalani sepalani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a cursory review of what I could find. Though, I'm clearly not familiar enough to review some of the implementation details related to the boot process and IOS/ES codebase.

Just wondering but what happen when you add a forwarder and the NAND is/becomes full?

- Add MAIN_WII_FORWARDER_AUTO_SYNC setting (off by default) with
  checkbox in Wii > Misc Settings, gating auto-install/remove behavior
- Sync existing games when the setting is toggled on
- Use std::span<const u8> instead of const std::vector<u8>&
- Use std::size_t and constexpr throughout
- Replace TryParse("0x" + key) with std::stoull(key, nullptr, 16)
- Make disc_file const in MenuBar
- Update copyright to 2026
- Remove superfluous header comments
@Gavin-S-Dev
Copy link
Copy Markdown
Author

I don't think auto installing every game in the game list should be the default behavior. There should probably be a setting to enable that functionality.

There's now a checkbox in Config > Wii > Misc Settings to enable it. I set it to auto off, unless of course the user wants the feature on.

@Gavin-S-Dev
Copy link
Copy Markdown
Author

Here is a cursory review of what I could find. Though, I'm clearly not familiar enough to review some of the implementation details related to the boot process and IOS/ES codebase.

Just wondering but what happen when you add a forwarder and the NAND is/becomes full?

If the NAND is full, the file writes in InstallForwarder will fail, and the function returns false with an error log. When in silent mode (auto-sync) it would be logged and skipped. In manual mode, the user would get a error dialog.

@Gavin-S-Dev
Copy link
Copy Markdown
Author

Pushed a new commit addressing/implementing all the new feedback. Willing to work any new issues out to get this pushed.

Copy link
Copy Markdown
Contributor

@sepalani sepalani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please ensure the changes you're committing compile properly and make sense before pushing them.

For instance, your last commit description is slightly off, e.g. Use std::size_t and constexpr throughout whereas your commit doesn't change constexprness. It does affect constness but isn't relevant to the std:: namespace change.

Moreover, on top of the review comments below, you also need to update the appropriate Visual Studio project files (.props and/or .vcxproj), see the git history for some examples.

Comment on lines +132 to +140
if (TryParse(std::string("0x") + key, &title_id))
try
{
title_id = std::stoull(key, nullptr, 16);
result[title_id] = value;
}
catch (const std::exception&)
{
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, Dolphin has exceptions disabled (it might work on Windows but that's an exception). Not sure why you changed it that way, couldn't you use TryParse(key, &title_id, 16) as previously suggested?

Comment on lines +49 to +55
connect(&Settings::Instance(), &Settings::ConfigChanged, this, [this] {
const bool now_enabled = Config::Get(Config::MAIN_WII_FORWARDER_AUTO_SYNC);
if (now_enabled && !m_forwarder_auto_sync_enabled)
SyncForwarders();
m_forwarder_auto_sync_enabled = now_enabled;
});
m_forwarder_auto_sync_enabled = Config::Get(Config::MAIN_WII_FORWARDER_AUTO_SYNC);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this hook overkill? Wouldn't it be better to only monitor m_forwarder_auto_sync_checkbox's state instead?

Comment on lines -36 to -48
// Uninstall a forwarder channel from NAND and remove the mapping entry.
bool UninstallForwarder(u64 forwarder_title_id);

// Get the disc image path associated with a forwarder title ID.
std::optional<std::string> GetDiscImagePath(u64 forwarder_title_id);

// Check if a forwarder is already installed for a given disc image path.
bool IsForwarderInstalled(const std::string& disc_image_path);

// Get all installed forwarders as {title_id -> disc_image_path}.
std::map<u64, std::string> GetInstalledForwarders();

// Get the path to the forwarder mapping file on the host filesystem.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually don't leave blank lines between each function declaration, see other header files. We usually use a blank line:

  • to divide function declarations into logical blocks; or
  • when we use comments to describe them.

This comment applies to this highlighted piece of code and to the ones before and after it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants